feat: add solid-js support

This commit is contained in:
2025-03-01 23:22:02 +08:00
parent 3aabcd6442
commit dff1e1f9a6
11 changed files with 533 additions and 64 deletions

View File

@@ -0,0 +1,41 @@
import { InjectionToken, inject } from '@outposts/injection-js';
import type { AnyRouter } from '@tanstack/solid-router';
import type { AuthFeature } from '../../features';
import { AbstractRouter, ROUTER_ABS_PATH_PATTERN } from '../../router';
export type TanStackRouter = AnyRouter;
export const TANSTACK_ROUTER = new InjectionToken<TanStackRouter>(
'TANSTACK_ROUTER'
);
export class TanStackRouterAdapter implements AbstractRouter<string> {
private router = inject(TANSTACK_ROUTER);
navigateByUrl(url: string): void {
this.router.navigate({
href: ROUTER_ABS_PATH_PATTERN.test(url) ? url : `/${url}`,
});
}
getCurrentNavigation() {
return {
extractedUrl: this.router.state.location.href,
};
}
}
export function withTanstackRouter(router: TanStackRouter): AuthFeature {
return {
ɵproviders: [
{
provide: TANSTACK_ROUTER,
useValue: router,
},
{
provide: AbstractRouter,
useClass: TanStackRouterAdapter,
},
],
};
}

View File

@@ -6,7 +6,7 @@ import {
useContext,
useMemo,
} from 'react';
import { OidcSecurityService } from '../..';
import { OidcSecurityService } from '../../oidc.security.service';
export const InjectorContextVoidInjector: Injector = {
get: <T>(_token: Type<T> | InjectionToken<T>, _notFoundValue?: T): T => {

View File

@@ -0,0 +1,44 @@
import type { InjectionToken, Injector, Type } from '@outposts/injection-js';
import {
type ParentProps,
createContext,
createMemo,
mergeProps,
splitProps,
useContext,
} from 'solid-js';
import h from 'solid-js/h';
import { OidcSecurityService } from '../../oidc.security.service';
export const InjectorContextVoidInjector: Injector = {
get: <T>(_token: Type<T> | InjectionToken<T>, _notFoundValue?: T): T => {
throw new Error('Please wrap with a InjectorContext.Provider first');
},
};
export const InjectorContext = createContext<Injector>(
InjectorContextVoidInjector
);
export function InjectorProvider(props: ParentProps<{ injector: Injector }>) {
const [local, others] = splitProps(props, ['children', 'injector']);
const providerProps = mergeProps(others, { value: local.injector });
return h(InjectorContext.Provider, providerProps, local.children);
}
export function useInjector() {
return useContext(InjectorContext);
}
export function useOidcClient() {
const injector = useInjector();
const oidcSecurityService = createMemo(() =>
injector.get(OidcSecurityService)
);
return {
injector,
oidcSecurityService,
};
}

View File

@@ -1,16 +1,16 @@
import type { HttpFeature } from '@ngify/http';
import type { Provider } from '@outposts/injection-js';
import { DOCUMENT } from './dom';
import { provideHttpClient } from './http';
import { DOCUMENT } from '../dom';
import { provideHttpClient } from '../http';
import {
AbstractRouter,
VanillaHistoryRouter,
VanillaLocationRouter,
} from './router';
import { AbstractSecurityStorage } from './storage/abstract-security-storage';
import { DefaultLocalStorageService } from './storage/default-localstorage.service';
import { DefaultSessionStorageService } from './storage/default-sessionstorage.service';
import { PLATFORM_ID } from './utils/platform-provider/platform.provider';
} from '../router';
import { AbstractSecurityStorage } from '../storage/abstract-security-storage';
import { DefaultLocalStorageService } from '../storage/default-localstorage.service';
import { DefaultSessionStorageService } from '../storage/default-sessionstorage.service';
import { PLATFORM_ID } from '../utils/platform-provider/platform.provider';
/**
* A feature to be used with `provideAuth`.

8
src/features/index.ts Normal file
View File

@@ -0,0 +1,8 @@
export type * from './core';
export * from './core';
export {
CHECK_AUTH_RESULT_EVENT,
withCheckAuthResultEvent,
type CheckAuthResultEventType,
type WithCheckAuthResultEventProps,
} from './with-check-auth-result-event';

View File

@@ -0,0 +1,45 @@
import { InjectionToken, inject } from '@outposts/injection-js';
import { type Observable, filter, shareReplay } from 'rxjs';
import { EventTypes } from '../public-events/event-types';
import { PublicEventsService } from '../public-events/public-events.service';
import type { AuthFeature } from './core';
export type CheckAuthResultEventType =
| { type: EventTypes.CheckingAuthFinished }
| {
type: EventTypes.CheckingAuthFinishedWithError;
value: string;
};
export const CHECK_AUTH_RESULT_EVENT = new InjectionToken<
Observable<CheckAuthResultEventType>
>('CHECK_AUTH_RESULT_EVENT');
export interface WithCheckAuthResultEventProps {
shareReplayCount?: number;
}
export function withCheckAuthResultEvent({
shareReplayCount = 1,
}: WithCheckAuthResultEventProps = {}): AuthFeature {
return {
ɵproviders: [
{
provide: CHECK_AUTH_RESULT_EVENT,
useFactory: () => {
const publishEventService = inject(PublicEventsService);
return publishEventService.registerForEvents().pipe(
filter(
(e) =>
e.type === EventTypes.CheckingAuthFinishedWithError ||
e.type === EventTypes.CheckingAuthFinished
),
shareReplay(shareReplayCount)
);
},
deps: [PublicEventsService],
},
],
};
}