feat: add more auth features and remove auth module
Some checks failed
Build, Lint & Test Lib / Build, Lint and Test Library (push) Has been cancelled
Some checks failed
Build, Lint & Test Lib / Build, Lint and Test Library (push) Has been cancelled
This commit is contained in:
parent
c8c4fc847d
commit
fe10ed2850
@ -26,7 +26,7 @@ pnpm add oidc-client-rx @outposts/injection-js @abraham/reflection
|
|||||||
```typescript
|
```typescript
|
||||||
import '@abraham/reflection'; // or 'reflect-metadata' | 'core-js/es7/reflect'
|
import '@abraham/reflection'; // or 'reflect-metadata' | 'core-js/es7/reflect'
|
||||||
import { type Injector, ReflectiveInjector } from '@outposts/injection-js';
|
import { type Injector, ReflectiveInjector } from '@outposts/injection-js';
|
||||||
import { LogLevel, OidcSecurityService, provideAuth } from 'oidc-client-rx';
|
import { LogLevel, OidcSecurityService, provideAuth, withDefaultFeatures } from 'oidc-client-rx';
|
||||||
|
|
||||||
const injector = ReflectiveInjector.resolveAndCreate(
|
const injector = ReflectiveInjector.resolveAndCreate(
|
||||||
provideAuth(
|
provideAuth(
|
||||||
@ -43,7 +43,8 @@ const injector = ReflectiveInjector.resolveAndCreate(
|
|||||||
logLevel: LogLevel.Debug,
|
logLevel: LogLevel.Debug,
|
||||||
...
|
...
|
||||||
},
|
},
|
||||||
}
|
},
|
||||||
|
withDefaultFeatures()
|
||||||
)
|
)
|
||||||
) as Injector;
|
) as Injector;
|
||||||
|
|
||||||
|
@ -1,7 +1,12 @@
|
|||||||
import '@abraham/reflection'; // or 'reflect-metadata' | 'core-js/es7/reflect'
|
import '@abraham/reflection'; // or 'reflect-metadata' | 'core-js/es7/reflect'
|
||||||
import { type Injector, ReflectiveInjector } from '@outposts/injection-js';
|
import { type Injector, ReflectiveInjector } from '@outposts/injection-js';
|
||||||
import { RouterProvider, createRouter } from '@tanstack/react-router';
|
import { RouterProvider, createRouter } from '@tanstack/react-router';
|
||||||
import { LogLevel, OidcSecurityService, provideAuth } from 'oidc-client-rx';
|
import {
|
||||||
|
LogLevel,
|
||||||
|
OidcSecurityService,
|
||||||
|
provideAuth,
|
||||||
|
withDefaultFeatures,
|
||||||
|
} from 'oidc-client-rx';
|
||||||
import {
|
import {
|
||||||
InjectorContextVoidInjector,
|
InjectorContextVoidInjector,
|
||||||
InjectorProvider,
|
InjectorProvider,
|
||||||
@ -51,6 +56,11 @@ const injector = ReflectiveInjector.resolveAndCreate(
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
withDefaultFeatures(
|
||||||
|
// the after feature will replace the before same type feature
|
||||||
|
// so the following line can be ignored
|
||||||
|
{ router: { enabled: false } }
|
||||||
|
),
|
||||||
withTanstackRouter(router)
|
withTanstackRouter(router)
|
||||||
)
|
)
|
||||||
) as Injector;
|
) as Injector;
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { InjectionToken, inject } from '@outposts/injection-js';
|
import { InjectionToken, inject } from '@outposts/injection-js';
|
||||||
import type { Router } from '@tanstack/react-router';
|
import type { Router } from '@tanstack/react-router';
|
||||||
import { AbstractRouter } from 'src/router';
|
import type { AuthFeature } from '../../features';
|
||||||
import type { AuthFeature } from '../../provide-auth';
|
import { AbstractRouter } from '../../router';
|
||||||
|
|
||||||
export type TanStackRouter = Router<any, any, any, any, any, any>;
|
export type TanStackRouter = Router<any, any, any, any, any, any>;
|
||||||
|
|
||||||
|
@ -1,17 +1,17 @@
|
|||||||
import { TestBed } from '@/testing';
|
import { TestBed } from '@/testing';
|
||||||
import {
|
import {
|
||||||
|
type DefaultHttpTestingController,
|
||||||
HTTP_CLIENT_TEST_CONTROLLER,
|
HTTP_CLIENT_TEST_CONTROLLER,
|
||||||
provideHttpClientTesting,
|
provideHttpClientTesting,
|
||||||
} from '@/testing/http';
|
} from '@/testing/http';
|
||||||
import { HttpHeaders } from '@ngify/http';
|
import { HttpHeaders } from '@ngify/http';
|
||||||
import type { HttpTestingController } from '@ngify/http/testing';
|
|
||||||
import { ReplaySubject, firstValueFrom, share } from 'rxjs';
|
import { ReplaySubject, firstValueFrom, share } from 'rxjs';
|
||||||
import { DataService } from './data.service';
|
import { DataService } from './data.service';
|
||||||
import { HttpBaseService } from './http-base.service';
|
import { HttpBaseService } from './http-base.service';
|
||||||
|
|
||||||
describe('Data Service', () => {
|
describe('Data Service', () => {
|
||||||
let dataService: DataService;
|
let dataService: DataService;
|
||||||
let httpMock: HttpTestingController;
|
let httpMock: DefaultHttpTestingController;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
TestBed.configureTestingModule({
|
TestBed.configureTestingModule({
|
||||||
|
@ -1,11 +1,10 @@
|
|||||||
import { HttpClient, type HttpHeaders } from '@ngify/http';
|
|
||||||
import { Injectable, inject } from '@outposts/injection-js';
|
import { Injectable, inject } from '@outposts/injection-js';
|
||||||
import type { Observable } from 'rxjs';
|
import type { Observable } from 'rxjs';
|
||||||
import type { HttpParams } from '../http';
|
import { HTTP_CLIENT, type HttpHeaders, type HttpParams } from '../http';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class HttpBaseService {
|
export class HttpBaseService {
|
||||||
private readonly http = inject(HttpClient);
|
private readonly http = inject(HTTP_CLIENT);
|
||||||
|
|
||||||
get<T>(
|
get<T>(
|
||||||
url: string,
|
url: string,
|
||||||
@ -22,7 +21,7 @@ export class HttpBaseService {
|
|||||||
body: unknown,
|
body: unknown,
|
||||||
options: { headers?: HttpHeaders; params?: HttpParams } = {}
|
options: { headers?: HttpHeaders; params?: HttpParams } = {}
|
||||||
): Observable<T> {
|
): Observable<T> {
|
||||||
return this.http.post<T>(url, body, {
|
return this.http.post<T>(url, body as any, {
|
||||||
...options,
|
...options,
|
||||||
params: options.params?.toNgify(),
|
params: options.params?.toNgify(),
|
||||||
});
|
});
|
||||||
|
@ -1,66 +0,0 @@
|
|||||||
import { TestBed } from '@/testing';
|
|
||||||
import { of } from 'rxjs';
|
|
||||||
import { PASSED_CONFIG } from './auth-config';
|
|
||||||
import { AuthModule } from './auth.module';
|
|
||||||
import { ConfigurationService } from './config/config.service';
|
|
||||||
import {
|
|
||||||
StsConfigHttpLoader,
|
|
||||||
StsConfigLoader,
|
|
||||||
StsConfigStaticLoader,
|
|
||||||
} from './config/loader/config-loader';
|
|
||||||
import { mockProvider } from './testing/mock';
|
|
||||||
|
|
||||||
describe('AuthModule', () => {
|
|
||||||
describe('APP_CONFIG', () => {
|
|
||||||
let authModule: AuthModule;
|
|
||||||
beforeEach(async () => {
|
|
||||||
await TestBed.configureTestingModule({
|
|
||||||
imports: [AuthModule.forRoot({ config: { authority: 'something' } })],
|
|
||||||
providers: [mockProvider(ConfigurationService)],
|
|
||||||
}).compileComponents();
|
|
||||||
authModule = TestBed.getImportByType(AuthModule);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should create', () => {
|
|
||||||
expect(AuthModule).toBeDefined();
|
|
||||||
expect(authModule).toBeDefined();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should provide config', () => {
|
|
||||||
const config = authModule.get(PASSED_CONFIG);
|
|
||||||
|
|
||||||
expect(config).toEqual({ config: { authority: 'something' } });
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should create StsConfigStaticLoader if config is passed', () => {
|
|
||||||
const configLoader = authModule.get(StsConfigLoader);
|
|
||||||
|
|
||||||
expect(configLoader instanceof StsConfigStaticLoader).toBe(true);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('StsConfigHttpLoader', () => {
|
|
||||||
let authModule: AuthModule;
|
|
||||||
|
|
||||||
beforeEach(async () => {
|
|
||||||
await TestBed.configureTestingModule({
|
|
||||||
imports: [
|
|
||||||
AuthModule.forRoot({
|
|
||||||
loader: {
|
|
||||||
provide: StsConfigLoader,
|
|
||||||
useFactory: () => new StsConfigHttpLoader(of({})),
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
],
|
|
||||||
providers: [mockProvider(ConfigurationService)],
|
|
||||||
}).compileComponents();
|
|
||||||
authModule = TestBed.getImportByType(AuthModule);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should create StsConfigStaticLoader if config is passed', () => {
|
|
||||||
const configLoader = authModule.get(StsConfigLoader);
|
|
||||||
|
|
||||||
expect(configLoader instanceof StsConfigHttpLoader).toBe(true);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
@ -1,41 +0,0 @@
|
|||||||
import {
|
|
||||||
type InjectionToken,
|
|
||||||
Injector,
|
|
||||||
ReflectiveInjector,
|
|
||||||
type Type,
|
|
||||||
} from '@outposts/injection-js';
|
|
||||||
import type { PassedInitialConfig } from './auth-config';
|
|
||||||
import type { Module } from './injection';
|
|
||||||
import { _provideAuth } from './provide-auth';
|
|
||||||
|
|
||||||
export interface AuthModuleOptions {
|
|
||||||
passedConfig: PassedInitialConfig;
|
|
||||||
parentInjector?: ReflectiveInjector;
|
|
||||||
}
|
|
||||||
|
|
||||||
export class AuthModule extends Injector {
|
|
||||||
passedConfig: PassedInitialConfig;
|
|
||||||
injector: ReflectiveInjector;
|
|
||||||
parentInjector?: Injector;
|
|
||||||
|
|
||||||
constructor(passedConfig?: PassedInitialConfig, parentInjector?: Injector) {
|
|
||||||
super();
|
|
||||||
this.passedConfig = passedConfig ?? {};
|
|
||||||
this.parentInjector = parentInjector;
|
|
||||||
this.injector = ReflectiveInjector.resolveAndCreate(
|
|
||||||
[..._provideAuth(this.passedConfig)],
|
|
||||||
this.parentInjector
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
static forRoot(passedConfig?: PassedInitialConfig): Module {
|
|
||||||
return (parentInjector?: Injector) =>
|
|
||||||
new AuthModule(passedConfig, parentInjector);
|
|
||||||
}
|
|
||||||
|
|
||||||
get<T>(token: Type<T> | InjectionToken<T>, notFoundValue?: T): T;
|
|
||||||
get(token: any, notFoundValue?: any): any;
|
|
||||||
get(token: unknown, notFoundValue?: unknown): any {
|
|
||||||
return this.injector.get(token, notFoundValue);
|
|
||||||
}
|
|
||||||
}
|
|
131
src/features.ts
Normal file
131
src/features.ts
Normal file
@ -0,0 +1,131 @@
|
|||||||
|
import type { HttpFeature } from '@ngify/http';
|
||||||
|
import type { Provider } from '@outposts/injection-js';
|
||||||
|
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';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A feature to be used with `provideAuth`.
|
||||||
|
*/
|
||||||
|
export interface AuthFeature {
|
||||||
|
ɵproviders: Provider[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface BrowserPlatformFeatureOptions {
|
||||||
|
enabled?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function withBrowserPlatform({
|
||||||
|
enabled = true,
|
||||||
|
}: BrowserPlatformFeatureOptions = {}): AuthFeature {
|
||||||
|
return {
|
||||||
|
ɵproviders: enabled
|
||||||
|
? [
|
||||||
|
{
|
||||||
|
provide: DOCUMENT,
|
||||||
|
useFactory: () => document,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
provide: PLATFORM_ID,
|
||||||
|
useValue: 'browser',
|
||||||
|
},
|
||||||
|
]
|
||||||
|
: [],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface HttpClientFeatureOptions {
|
||||||
|
enabled?: boolean;
|
||||||
|
features?: HttpFeature[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export function withHttpClient({
|
||||||
|
features,
|
||||||
|
enabled = true,
|
||||||
|
}: HttpClientFeatureOptions = {}): AuthFeature {
|
||||||
|
return {
|
||||||
|
ɵproviders: enabled ? provideHttpClient(features) : [],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export type SecurityStorageType = 'session-storage' | 'local-storage';
|
||||||
|
|
||||||
|
export interface SecurityStorageFeatureOptions {
|
||||||
|
enabled?: boolean;
|
||||||
|
type?: SecurityStorageType;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function withSecurityStorage({
|
||||||
|
enabled = true,
|
||||||
|
type = 'session-storage',
|
||||||
|
}: SecurityStorageFeatureOptions = {}): AuthFeature {
|
||||||
|
return {
|
||||||
|
ɵproviders: enabled
|
||||||
|
? [
|
||||||
|
type === 'session-storage'
|
||||||
|
? {
|
||||||
|
provide: AbstractSecurityStorage,
|
||||||
|
useClass: DefaultLocalStorageService,
|
||||||
|
}
|
||||||
|
: {
|
||||||
|
provide: AbstractSecurityStorage,
|
||||||
|
useClass: DefaultSessionStorageService,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
: [],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export type VanillaRouterType = 'location' | 'history';
|
||||||
|
|
||||||
|
export interface VanillaRouterFeatureOptions {
|
||||||
|
enabled?: boolean;
|
||||||
|
type?: VanillaRouterType;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function withVanillaRouter({
|
||||||
|
enabled = true,
|
||||||
|
type = 'history',
|
||||||
|
}: VanillaRouterFeatureOptions = {}): AuthFeature {
|
||||||
|
return {
|
||||||
|
ɵproviders: enabled
|
||||||
|
? [
|
||||||
|
type === 'location'
|
||||||
|
? {
|
||||||
|
provide: AbstractRouter,
|
||||||
|
useClass: VanillaLocationRouter,
|
||||||
|
}
|
||||||
|
: {
|
||||||
|
provide: AbstractRouter,
|
||||||
|
useClass: VanillaHistoryRouter,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
: [],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface DefaultFeaturesOptions {
|
||||||
|
browserPlatform?: BrowserPlatformFeatureOptions;
|
||||||
|
securityStorage?: SecurityStorageFeatureOptions;
|
||||||
|
router?: VanillaRouterFeatureOptions;
|
||||||
|
httpClient?: HttpClientFeatureOptions;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function withDefaultFeatures(
|
||||||
|
options: DefaultFeaturesOptions = {}
|
||||||
|
): AuthFeature[] {
|
||||||
|
return [
|
||||||
|
withBrowserPlatform(options.browserPlatform),
|
||||||
|
withSecurityStorage(options.securityStorage),
|
||||||
|
withHttpClient(options.httpClient),
|
||||||
|
withVanillaRouter(options.router),
|
||||||
|
].filter(Boolean) as AuthFeature[];
|
||||||
|
}
|
@ -1,10 +1,15 @@
|
|||||||
import {
|
import {
|
||||||
|
// biome-ignore lint/nursery/noExportedImports: <explanation>
|
||||||
|
HttpClient as DefaultHttpClient,
|
||||||
type HttpBackend,
|
type HttpBackend,
|
||||||
HttpClient,
|
|
||||||
type HttpFeature,
|
type HttpFeature,
|
||||||
HttpFeatureKind,
|
HttpFeatureKind,
|
||||||
|
// biome-ignore lint/nursery/noExportedImports: <explanation>
|
||||||
|
HttpHeaders,
|
||||||
type HttpInterceptor,
|
type HttpInterceptor,
|
||||||
type HttpInterceptorFn,
|
type HttpInterceptorFn,
|
||||||
|
type HttpRequest,
|
||||||
|
type HttpParams as NgifyHttpParams,
|
||||||
withInterceptors,
|
withInterceptors,
|
||||||
withLegacyInterceptors,
|
withLegacyInterceptors,
|
||||||
} from '@ngify/http';
|
} from '@ngify/http';
|
||||||
@ -13,8 +18,12 @@ import {
|
|||||||
Optional,
|
Optional,
|
||||||
type Provider,
|
type Provider,
|
||||||
} from '@outposts/injection-js';
|
} from '@outposts/injection-js';
|
||||||
|
import type { Observable } from 'rxjs';
|
||||||
import type { ArrayOrNullableOne } from '../utils/types';
|
import type { ArrayOrNullableOne } from '../utils/types';
|
||||||
export { HttpParams, type HttpParamsOptions } from './params';
|
// biome-ignore lint/nursery/noExportedImports: <explanation>
|
||||||
|
import { HttpParams, type HttpParamsOptions } from './params';
|
||||||
|
|
||||||
|
export { HttpParams, HttpHeaders, type HttpParamsOptions, DefaultHttpClient };
|
||||||
|
|
||||||
export const HTTP_FEATURES = new InjectionToken<HttpFeature[]>('HTTP_FEATURES');
|
export const HTTP_FEATURES = new InjectionToken<HttpFeature[]>('HTTP_FEATURES');
|
||||||
|
|
||||||
@ -112,14 +121,29 @@ export function provideHttpClient(features: HttpFeature[] = []): Provider[] {
|
|||||||
multi: true,
|
multi: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
provide: HttpClient,
|
provide: HTTP_CLIENT,
|
||||||
useFactory: (features: ArrayOrNullableOne<HttpFeature>[]) => {
|
useFactory: (features: ArrayOrNullableOne<HttpFeature>[]) => {
|
||||||
const normalizedFeatures = [features]
|
const normalizedFeatures = [features]
|
||||||
.flat(Number.MAX_SAFE_INTEGER)
|
.flat(Number.MAX_SAFE_INTEGER)
|
||||||
.filter(Boolean) as HttpFeature[];
|
.filter(Boolean) as HttpFeature[];
|
||||||
return new HttpClient(...normalizedFeatures);
|
return new DefaultHttpClient(...normalizedFeatures);
|
||||||
},
|
},
|
||||||
deps: [HTTP_FEATURES],
|
deps: [HTTP_FEATURES],
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type HttpClient = {
|
||||||
|
get<T>(
|
||||||
|
url: string,
|
||||||
|
options?: { headers?: HttpHeaders; params?: NgifyHttpParams }
|
||||||
|
): Observable<T>;
|
||||||
|
|
||||||
|
post<T>(
|
||||||
|
url: string,
|
||||||
|
body?: HttpRequest<any>['body'],
|
||||||
|
options?: { headers?: HttpHeaders; params?: NgifyHttpParams }
|
||||||
|
): Observable<T>;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const HTTP_CLIENT = new InjectionToken<HttpClient>('HTTP_CLIENT');
|
||||||
|
@ -4,7 +4,6 @@ export type { PassedInitialConfig } from './auth-config';
|
|||||||
export * from './auth-options';
|
export * from './auth-options';
|
||||||
export * from './auth-state/auth-result';
|
export * from './auth-state/auth-result';
|
||||||
export * from './auth-state/auth-state';
|
export * from './auth-state/auth-state';
|
||||||
export * from './auth.module';
|
|
||||||
export * from './auto-login/auto-login-partial-routes.guard';
|
export * from './auto-login/auto-login-partial-routes.guard';
|
||||||
export * from './config/auth-well-known/auth-well-known-endpoints';
|
export * from './config/auth-well-known/auth-well-known-endpoints';
|
||||||
export * from './config/config.service';
|
export * from './config/config.service';
|
||||||
@ -31,3 +30,4 @@ export * from './validation/validation-result';
|
|||||||
export * from './injection';
|
export * from './injection';
|
||||||
export * from './router';
|
export * from './router';
|
||||||
export * from './http';
|
export * from './http';
|
||||||
|
export * from './features';
|
||||||
|
@ -1,11 +1,15 @@
|
|||||||
import { TestBed } from '@/testing';
|
|
||||||
import {
|
import {
|
||||||
|
type DefaultHttpTestingController,
|
||||||
HTTP_CLIENT_TEST_CONTROLLER,
|
HTTP_CLIENT_TEST_CONTROLLER,
|
||||||
|
TestBed,
|
||||||
provideHttpClientTesting,
|
provideHttpClientTesting,
|
||||||
} from '@/testing';
|
} from '@/testing';
|
||||||
import { HttpClient } from '@ngify/http';
|
import {
|
||||||
import type { HttpTestingController } from '@ngify/http/testing';
|
type DefaultHttpClient,
|
||||||
import { HTTP_INTERCEPTOR_FNS, HTTP_LEGACY_INTERCEPTORS } from 'oidc-client-rx';
|
HTTP_CLIENT,
|
||||||
|
HTTP_INTERCEPTOR_FNS,
|
||||||
|
HTTP_LEGACY_INTERCEPTORS,
|
||||||
|
} from 'oidc-client-rx';
|
||||||
import { ReplaySubject, firstValueFrom, share } from 'rxjs';
|
import { ReplaySubject, firstValueFrom, share } from 'rxjs';
|
||||||
import { vi } from 'vitest';
|
import { vi } from 'vitest';
|
||||||
import { AuthStateService } from '../auth-state/auth-state.service';
|
import { AuthStateService } from '../auth-state/auth-state.service';
|
||||||
@ -16,9 +20,9 @@ import { AuthInterceptor, authInterceptor } from './auth.interceptor';
|
|||||||
import { ClosestMatchingRouteService } from './closest-matching-route.service';
|
import { ClosestMatchingRouteService } from './closest-matching-route.service';
|
||||||
|
|
||||||
describe('AuthHttpInterceptor', () => {
|
describe('AuthHttpInterceptor', () => {
|
||||||
let httpTestingController: HttpTestingController;
|
let httpTestingController: DefaultHttpTestingController;
|
||||||
let configurationService: ConfigurationService;
|
let configurationService: ConfigurationService;
|
||||||
let httpClient: HttpClient;
|
let httpClient: DefaultHttpClient;
|
||||||
let authStateService: AuthStateService;
|
let authStateService: AuthStateService;
|
||||||
let closestMatchingRouteService: ClosestMatchingRouteService;
|
let closestMatchingRouteService: ClosestMatchingRouteService;
|
||||||
|
|
||||||
@ -40,7 +44,7 @@ describe('AuthHttpInterceptor', () => {
|
|||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
|
||||||
httpClient = TestBed.inject(HttpClient);
|
httpClient = TestBed.inject(HTTP_CLIENT) as DefaultHttpClient;
|
||||||
httpTestingController = TestBed.inject(HTTP_CLIENT_TEST_CONTROLLER);
|
httpTestingController = TestBed.inject(HTTP_CLIENT_TEST_CONTROLLER);
|
||||||
configurationService = TestBed.inject(ConfigurationService);
|
configurationService = TestBed.inject(ConfigurationService);
|
||||||
authStateService = TestBed.inject(AuthStateService);
|
authStateService = TestBed.inject(AuthStateService);
|
||||||
@ -72,7 +76,7 @@ describe('AuthHttpInterceptor', () => {
|
|||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
|
||||||
httpClient = TestBed.inject(HttpClient);
|
httpClient = TestBed.inject(HTTP_CLIENT) as DefaultHttpClient;
|
||||||
httpTestingController = TestBed.inject(HTTP_CLIENT_TEST_CONTROLLER);
|
httpTestingController = TestBed.inject(HTTP_CLIENT_TEST_CONTROLLER);
|
||||||
configurationService = TestBed.inject(ConfigurationService);
|
configurationService = TestBed.inject(ConfigurationService);
|
||||||
authStateService = TestBed.inject(AuthStateService);
|
authStateService = TestBed.inject(AuthStateService);
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
import { HttpClient } from '@ngify/http';
|
|
||||||
import type { Provider } from '@outposts/injection-js';
|
import type { Provider } from '@outposts/injection-js';
|
||||||
import { DataService } from './api/data.service';
|
import { DataService } from './api/data.service';
|
||||||
import { HttpBaseService } from './api/http-base.service';
|
import { HttpBaseService } from './api/http-base.service';
|
||||||
@ -24,6 +23,7 @@ import { StsConfigLoader } from './config/loader/config-loader';
|
|||||||
import { ConfigValidationService } from './config/validation/config-validation.service';
|
import { ConfigValidationService } from './config/validation/config-validation.service';
|
||||||
import { DOCUMENT } from './dom';
|
import { DOCUMENT } from './dom';
|
||||||
import { JwkExtractor } from './extractors/jwk.extractor';
|
import { JwkExtractor } from './extractors/jwk.extractor';
|
||||||
|
import type { AuthFeature } from './features';
|
||||||
import { CodeFlowCallbackHandlerService } from './flows/callback-handling/code-flow-callback-handler.service';
|
import { CodeFlowCallbackHandlerService } from './flows/callback-handling/code-flow-callback-handler.service';
|
||||||
import { HistoryJwtKeysCallbackHandlerService } from './flows/callback-handling/history-jwt-keys-callback-handler.service';
|
import { HistoryJwtKeysCallbackHandlerService } from './flows/callback-handling/history-jwt-keys-callback-handler.service';
|
||||||
import { ImplicitFlowCallbackHandlerService } from './flows/callback-handling/implicit-flow-callback-handler.service';
|
import { ImplicitFlowCallbackHandlerService } from './flows/callback-handling/implicit-flow-callback-handler.service';
|
||||||
@ -62,10 +62,7 @@ import { UserService } from './user-data/user.service';
|
|||||||
import { CryptoService } from './utils/crypto/crypto.service';
|
import { CryptoService } from './utils/crypto/crypto.service';
|
||||||
import { EqualityService } from './utils/equality/equality.service';
|
import { EqualityService } from './utils/equality/equality.service';
|
||||||
import { FlowHelper } from './utils/flowHelper/flow-helper.service';
|
import { FlowHelper } from './utils/flowHelper/flow-helper.service';
|
||||||
import {
|
import { PlatformProvider } from './utils/platform-provider/platform.provider';
|
||||||
PLATFORM_ID,
|
|
||||||
PlatformProvider,
|
|
||||||
} from './utils/platform-provider/platform.provider';
|
|
||||||
import { RedirectService } from './utils/redirect/redirect.service';
|
import { RedirectService } from './utils/redirect/redirect.service';
|
||||||
import { TokenHelperService } from './utils/tokenHelper/token-helper.service';
|
import { TokenHelperService } from './utils/tokenHelper/token-helper.service';
|
||||||
import { CurrentUrlService } from './utils/url/current-url.service';
|
import { CurrentUrlService } from './utils/url/current-url.service';
|
||||||
@ -75,20 +72,17 @@ import { JwtWindowCryptoService } from './validation/jwt-window-crypto.service';
|
|||||||
import { StateValidationService } from './validation/state-validation.service';
|
import { StateValidationService } from './validation/state-validation.service';
|
||||||
import { TokenValidationService } from './validation/token-validation.service';
|
import { TokenValidationService } from './validation/token-validation.service';
|
||||||
|
|
||||||
/**
|
|
||||||
* A feature to be used with `provideAuth`.
|
|
||||||
*/
|
|
||||||
export interface AuthFeature {
|
|
||||||
ɵproviders: Provider[];
|
|
||||||
}
|
|
||||||
|
|
||||||
export function provideAuth(
|
export function provideAuth(
|
||||||
passedConfig: PassedInitialConfig,
|
passedConfig: PassedInitialConfig,
|
||||||
...features: AuthFeature[]
|
...features: (AuthFeature | AuthFeature[])[]
|
||||||
): Provider[] {
|
): Provider[] {
|
||||||
const providers = _provideAuth(passedConfig);
|
const providers = _provideAuth(passedConfig);
|
||||||
|
|
||||||
for (const feature of features) {
|
const normailizedFeatures = features
|
||||||
|
.flat(Number.MAX_SAFE_INTEGER)
|
||||||
|
.filter(Boolean) as AuthFeature[];
|
||||||
|
|
||||||
|
for (const feature of normailizedFeatures) {
|
||||||
providers.push(...feature.ɵproviders);
|
providers.push(...feature.ɵproviders);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -97,15 +91,6 @@ export function provideAuth(
|
|||||||
|
|
||||||
export function _provideAuth(passedConfig: PassedInitialConfig): Provider[] {
|
export function _provideAuth(passedConfig: PassedInitialConfig): Provider[] {
|
||||||
return [
|
return [
|
||||||
{
|
|
||||||
provide: DOCUMENT,
|
|
||||||
useFactory: () => document,
|
|
||||||
},
|
|
||||||
HttpClient,
|
|
||||||
{
|
|
||||||
provide: PLATFORM_ID,
|
|
||||||
useValue: 'browser',
|
|
||||||
},
|
|
||||||
// Make the PASSED_CONFIG available through injection
|
// Make the PASSED_CONFIG available through injection
|
||||||
{ provide: PASSED_CONFIG, useValue: passedConfig },
|
{ provide: PASSED_CONFIG, useValue: passedConfig },
|
||||||
// Create the loader: Either the one getting passed or a static one
|
// Create the loader: Either the one getting passed or a static one
|
||||||
|
@ -1,3 +1,6 @@
|
|||||||
|
import { inject } from '@outposts/injection-js';
|
||||||
|
import { DOCUMENT } from 'src/dom';
|
||||||
|
|
||||||
export type RouteData = {
|
export type RouteData = {
|
||||||
[key: string | symbol]: any;
|
[key: string | symbol]: any;
|
||||||
};
|
};
|
||||||
@ -26,3 +29,55 @@ export abstract class AbstractRouter<
|
|||||||
|
|
||||||
abstract getCurrentNavigation(): NAVIGATION;
|
abstract getCurrentNavigation(): NAVIGATION;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export class VanillaLocationRouter extends AbstractRouter {
|
||||||
|
private document = inject(DOCUMENT);
|
||||||
|
|
||||||
|
private get location(): Location {
|
||||||
|
const location = this.document.defaultView?.window?.location;
|
||||||
|
if (!location) {
|
||||||
|
throw new Error('current document do not support Location API');
|
||||||
|
}
|
||||||
|
return location;
|
||||||
|
}
|
||||||
|
|
||||||
|
navigateByUrl(url: string): void {
|
||||||
|
this.location.href = url;
|
||||||
|
}
|
||||||
|
|
||||||
|
getCurrentNavigation() {
|
||||||
|
return {
|
||||||
|
extractedUrl: `${this.location.pathname}${this.location.search}${this.location.hash}`,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class VanillaHistoryRouter extends AbstractRouter<string> {
|
||||||
|
private document = inject(DOCUMENT);
|
||||||
|
|
||||||
|
private get history(): History {
|
||||||
|
const history = this.document.defaultView?.window?.history;
|
||||||
|
if (!history) {
|
||||||
|
throw new Error('current document do not support History API');
|
||||||
|
}
|
||||||
|
return history;
|
||||||
|
}
|
||||||
|
|
||||||
|
private get location(): Location {
|
||||||
|
const location = this.document.defaultView?.window?.location;
|
||||||
|
if (!location) {
|
||||||
|
throw new Error('current document do not support Location API');
|
||||||
|
}
|
||||||
|
return location;
|
||||||
|
}
|
||||||
|
|
||||||
|
navigateByUrl(url: string): void {
|
||||||
|
this.history.pushState({}, '', url);
|
||||||
|
}
|
||||||
|
|
||||||
|
getCurrentNavigation() {
|
||||||
|
return {
|
||||||
|
extractedUrl: `${this.location.pathname}${this.location.search}${this.location.hash}`,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -2,6 +2,8 @@ import { HttpClientTestingBackend } from '@ngify/http/testing';
|
|||||||
import { InjectionToken, type Provider } from '@outposts/injection-js';
|
import { InjectionToken, type Provider } from '@outposts/injection-js';
|
||||||
import { HTTP_BACKEND, provideHttpClient } from 'oidc-client-rx';
|
import { HTTP_BACKEND, provideHttpClient } from 'oidc-client-rx';
|
||||||
|
|
||||||
|
export { HttpTestingController as DefaultHttpTestingController } from '@ngify/http/testing';
|
||||||
|
|
||||||
export const HTTP_CLIENT_TEST_CONTROLLER =
|
export const HTTP_CLIENT_TEST_CONTROLLER =
|
||||||
new InjectionToken<HttpClientTestingBackend>('HTTP_CLIENT_TEST_CONTROLLER');
|
new InjectionToken<HttpClientTestingBackend>('HTTP_CLIENT_TEST_CONTROLLER');
|
||||||
|
|
||||||
|
@ -6,4 +6,8 @@ export {
|
|||||||
} from './spy';
|
} from './spy';
|
||||||
export { createRetriableStream } from './create-retriable-stream.helper';
|
export { createRetriableStream } from './create-retriable-stream.helper';
|
||||||
export { MockRouter, mockRouterProvider } from './router';
|
export { MockRouter, mockRouterProvider } from './router';
|
||||||
export { provideHttpClientTesting, HTTP_CLIENT_TEST_CONTROLLER } from './http';
|
export {
|
||||||
|
provideHttpClientTesting,
|
||||||
|
HTTP_CLIENT_TEST_CONTROLLER,
|
||||||
|
DefaultHttpTestingController,
|
||||||
|
} from './http';
|
||||||
|
Loading…
Reference in New Issue
Block a user