@securitydept/client-angular 0.3.0-beta.1 → 0.3.0-beta.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -1,9 +1,42 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
2
|
import { InjectionToken, makeEnvironmentProviders, inject, Injectable } from '@angular/core';
|
|
3
|
+
import { assertResolveEnvironment } from '@securitydept/client/web';
|
|
3
4
|
import { createPlannerHost, resolveEffectiveClientSet, RequirementsClientSetComposition } from '@securitydept/client/auth-coordination';
|
|
4
5
|
export { resolveEffectiveClientSet } from '@securitydept/client/auth-coordination';
|
|
5
6
|
import { Observable } from 'rxjs';
|
|
6
7
|
|
|
8
|
+
const PAGE_CLIENT_ENVIRONMENT = new InjectionToken("PAGE_CLIENT_ENVIRONMENT", {
|
|
9
|
+
providedIn: "root",
|
|
10
|
+
factory: () => undefined,
|
|
11
|
+
});
|
|
12
|
+
function providePageClientEnvironment(options) {
|
|
13
|
+
return {
|
|
14
|
+
provide: PAGE_CLIENT_ENVIRONMENT,
|
|
15
|
+
useValue: options.environment,
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
function resolvePageClientEnvironmentSource(source, onMissing) {
|
|
19
|
+
const resolvedSource = assertResolveEnvironment(source, onMissing);
|
|
20
|
+
if (isPageClientEnvironmentResolver(resolvedSource)) {
|
|
21
|
+
return Promise.resolve(resolvedSource()).then((environment) => assertResolveEnvironment(environment, onMissing));
|
|
22
|
+
}
|
|
23
|
+
if (isPageClientEnvironmentService(resolvedSource)) {
|
|
24
|
+
return resolvedSource
|
|
25
|
+
.resolvePageEnvironment()
|
|
26
|
+
.then((environment) => assertResolveEnvironment(environment, onMissing));
|
|
27
|
+
}
|
|
28
|
+
return Promise.resolve(resolvedSource);
|
|
29
|
+
}
|
|
30
|
+
function isPageClientEnvironmentResolver(source) {
|
|
31
|
+
return typeof source === "function";
|
|
32
|
+
}
|
|
33
|
+
function isPageClientEnvironmentService(source) {
|
|
34
|
+
return (typeof source === "object" &&
|
|
35
|
+
source !== null &&
|
|
36
|
+
"resolvePageEnvironment" in source &&
|
|
37
|
+
typeof source.resolvePageEnvironment === "function");
|
|
38
|
+
}
|
|
39
|
+
|
|
7
40
|
// Angular planner-host integration — DI-based planner provider / lookup
|
|
8
41
|
//
|
|
9
42
|
// Canonical import path:
|
|
@@ -280,10 +313,10 @@ class AuthRouteAdapter {
|
|
|
280
313
|
return "__index__";
|
|
281
314
|
return path;
|
|
282
315
|
}
|
|
283
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.
|
|
284
|
-
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.
|
|
316
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.12", ngImport: i0, type: AuthRouteAdapter, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
317
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.12", ngImport: i0, type: AuthRouteAdapter, providedIn: "root" });
|
|
285
318
|
}
|
|
286
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.
|
|
319
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.12", ngImport: i0, type: AuthRouteAdapter, decorators: [{
|
|
287
320
|
type: Injectable,
|
|
288
321
|
args: [{ providedIn: "root" }]
|
|
289
322
|
}] });
|
|
@@ -525,5 +558,5 @@ function signalToObservable(source) {
|
|
|
525
558
|
* Generated bundle index. Do not edit.
|
|
526
559
|
*/
|
|
527
560
|
|
|
528
|
-
export { AUTH_PLANNER_HOST, AUTH_REQUIREMENTS_CLIENT_SET, AuthRouteAdapter, DEFAULT_ROUTE_REQUIREMENTS_KEY, ROUTE_REQUIREMENTS_COMPOSITION_DATA_KEY, ROUTE_REQUIREMENTS_DATA_KEY, bridgeToAngularSignal, extractFullRouteRequirements, injectPlannerHost, provideAuthPlannerHost, provideRouteScopedRequirements, resolveEffectiveRequirements, signalToObservable, withRouteRequirements };
|
|
561
|
+
export { AUTH_PLANNER_HOST, AUTH_REQUIREMENTS_CLIENT_SET, AuthRouteAdapter, DEFAULT_ROUTE_REQUIREMENTS_KEY, PAGE_CLIENT_ENVIRONMENT, ROUTE_REQUIREMENTS_COMPOSITION_DATA_KEY, ROUTE_REQUIREMENTS_DATA_KEY, bridgeToAngularSignal, extractFullRouteRequirements, injectPlannerHost, provideAuthPlannerHost, providePageClientEnvironment, provideRouteScopedRequirements, resolveEffectiveRequirements, resolvePageClientEnvironmentSource, signalToObservable, withRouteRequirements };
|
|
529
562
|
//# sourceMappingURL=securitydept-client-angular.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"securitydept-client-angular.mjs","sources":["../../src/lib/planner-host.ts","../../src/lib/router.ts","../../src/lib/route-requirements.ts","../../src/lib/signal-bridge.ts","../../src/public-api.ts","../../src/securitydept-client-angular.ts"],"sourcesContent":["// Angular planner-host integration — DI-based planner provider / lookup\n//\n// Canonical import path:\n// import { AUTH_PLANNER_HOST, provideAuthPlannerHost, ... } from \"@securitydept/client-angular\"\n//\n// Provides Angular DI glue for the shared planner-host contract:\n// - InjectionToken for PlannerHost\n// - Provider helpers for app / module / route scoped planners\n// - InjectionToken + provider helpers for ScopedRequirementsClientSet\n// - injectPlannerHost() convenience function with fail-fast\n//\n// Architecture boundary:\n// - Does NOT own the planner-host contract (that lives in @securitydept/client)\n// - Does NOT carry token-set-specific mapping\n// - Provides the Angular DI wiring for the shared contract\n//\n// Stability: provisional\n\nimport {\n\ttype EnvironmentProviders,\n\tInjectionToken,\n\tinject,\n\tmakeEnvironmentProviders,\n} from \"@angular/core\";\nimport type {\n\tAuthGuardClientOption,\n\tCandidateSelector,\n\tCreatePlannerHostOptions,\n\tPlannerHost,\n\tScopedRequirementsClientSet,\n} from \"@securitydept/client/auth-coordination\";\nimport {\n\tcreatePlannerHost,\n\tresolveEffectiveClientSet,\n} from \"@securitydept/client/auth-coordination\";\n\n// ---------------------------------------------------------------------------\n// PlannerHost injection token\n// ---------------------------------------------------------------------------\n\n/**\n * DI token for the shared {@link PlannerHost}.\n *\n * Provide at the app level via {@link provideAuthPlannerHost}.\n * Guards use {@link injectPlannerHost} to look up the nearest instance.\n */\nexport const AUTH_PLANNER_HOST = new InjectionToken<PlannerHost>(\n\t\"AUTH_PLANNER_HOST\",\n);\n\n/**\n * Options for {@link provideAuthPlannerHost}.\n */\nexport interface ProvideAuthPlannerHostOptions {\n\t/**\n\t * Custom candidate selection strategy.\n\t * @see {@link CandidateSelector}\n\t */\n\tselectCandidate?: CandidateSelector;\n}\n\n/**\n * Provide an {@link AUTH_PLANNER_HOST} at the current injector level.\n *\n * Use in app config, route providers, or NgModule providers to establish\n * a planner-host scope. Child routes inherit the nearest parent's planner.\n *\n * @example\n * ```ts\n * // app.config.ts — app-level planner (default sequential strategy)\n * export const appConfig: ApplicationConfig = {\n * providers: [provideAuthPlannerHost()],\n * };\n *\n * // Feature route — override with custom async chooser strategy\n * {\n * path: \"admin\",\n * providers: [provideAuthPlannerHost({\n * selectCandidate: async (candidates) => showAdminChooser(candidates),\n * })],\n * children: [...]\n * }\n * ```\n */\nexport function provideAuthPlannerHost(\n\toptions?: ProvideAuthPlannerHostOptions,\n): EnvironmentProviders {\n\tconst plannerOptions: CreatePlannerHostOptions = {};\n\tif (options?.selectCandidate) {\n\t\tplannerOptions.selectCandidate = options.selectCandidate;\n\t}\n\treturn makeEnvironmentProviders([\n\t\t{ provide: AUTH_PLANNER_HOST, useValue: createPlannerHost(plannerOptions) },\n\t]);\n}\n\n/**\n * Inject the nearest {@link PlannerHost} from the DI hierarchy.\n *\n * Throws an explicit error if no planner-host is provided, preventing\n * silent fallback behavior.\n *\n * @example\n * ```ts\n * const plannerHost = injectPlannerHost();\n * const result = await plannerHost.evaluate(candidates);\n * ```\n */\nexport function injectPlannerHost(): PlannerHost {\n\tconst host = inject(AUTH_PLANNER_HOST, { optional: true });\n\tif (!host) {\n\t\tthrow new Error(\n\t\t\t\"[injectPlannerHost] No AUTH_PLANNER_HOST found in the injector hierarchy. \" +\n\t\t\t\t\"Use provideAuthPlannerHost() in your app config or route providers.\",\n\t\t);\n\t}\n\treturn host;\n}\n\n// ---------------------------------------------------------------------------\n// Requirements client set injection token — stores the already-resolved\n// effective options for the current scope (parent + child composed).\n// ---------------------------------------------------------------------------\n\n/**\n * DI token for the effective requirements client set at the current scope.\n *\n * The value is always the **resolved** options after composing all ancestor\n * scopes — it is NOT the raw `ScopedRequirementsClientSet` declaration.\n *\n * Provide via {@link provideRouteScopedRequirements}.\n * Guards inject this token to get the effective scope requirements and then\n * merge their own declared candidates on top.\n */\nexport const AUTH_REQUIREMENTS_CLIENT_SET = new InjectionToken<\n\treadonly AuthGuardClientOption[]\n>(\"AUTH_REQUIREMENTS_CLIENT_SET\");\n\n/**\n * Provide a {@link ScopedRequirementsClientSet} at the current route/module scope.\n *\n * Internally, the provider resolves the effective client set by composing the\n * declared `scopedSet` with the parent scope's already-resolved options\n * (injected via `skipSelf: true`). The token value stored in DI is the\n * resolved `readonly AuthGuardClientOption[]`, not the raw declaration.\n *\n * This mirrors the React `AuthRequirementsClientSetProvider` semantics:\n * each level stores its resolved effective options, so children inherit\n * the composed result without re-resolving the full ancestor chain.\n *\n * The `scopedSet` argument may also be a **factory function** — it will be\n * called inside Angular's `useFactory` context, so `inject()` is valid.\n * Use this when the requirement options need DI-resolved services (e.g. a\n * token-set registry or a redirect service).\n *\n * @example\n * ```ts\n * // routes.ts — static declaration (no DI needed)\n * {\n * path: \"\",\n * providers: [\n * provideRouteScopedRequirements({\n * composition: RequirementsClientSetComposition.Replace,\n * options: [sessionClientOption],\n * }),\n * ],\n * }\n *\n * // Feature route merges OIDC on top of the parent's session requirement\n * {\n * path: \"confluence\",\n * providers: [\n * provideRouteScopedRequirements({\n * composition: RequirementsClientSetComposition.Merge,\n * options: [confluenceOidcClientOption],\n * }),\n * ],\n * // Route-level DI scope only. Angular Router adopters should prefer\n * // secureRouteRoot()/secureRoute() over direct guard wiring.\n * }\n *\n * // Factory form — use when options depend on injected services\n * {\n * path: \"protected\",\n * providers: [\n * provideRouteScopedRequirements(() => {\n * const registry = inject(TokenSetAuthRegistry);\n * const authService = inject(AuthService);\n * return {\n * composition: RequirementsClientSetComposition.Replace,\n * options: [{\n * requirementId: \"oidc\",\n * requirementKind: \"frontend_oidc\",\n * checkAuthenticated: () => registry.require(clientKey).isAuthenticated(),\n * onUnauthenticated: () => { authService.redirectToLogin(clientKey).subscribe(); return false; },\n * }],\n * };\n * }),\n * ],\n * }\n * ```\n */\nexport function provideRouteScopedRequirements(\n\tscopedSet: ScopedRequirementsClientSet | (() => ScopedRequirementsClientSet),\n): EnvironmentProviders {\n\treturn makeEnvironmentProviders([\n\t\t{\n\t\t\tprovide: AUTH_REQUIREMENTS_CLIENT_SET,\n\t\t\tuseFactory: (): readonly AuthGuardClientOption[] => {\n\t\t\t\t// Walk up to the nearest parent scope's already-resolved effective set.\n\t\t\t\t// skipSelf: true ensures we don't read our own (not-yet-set) value.\n\t\t\t\tconst parentOptions: readonly AuthGuardClientOption[] =\n\t\t\t\t\tinject(AUTH_REQUIREMENTS_CLIENT_SET, {\n\t\t\t\t\t\toptional: true,\n\t\t\t\t\t\tskipSelf: true,\n\t\t\t\t\t}) ?? [];\n\t\t\t\t// Support factory form so callers can use inject() to resolve\n\t\t\t\t// DI services (e.g. auth registry, redirect service) inside their\n\t\t\t\t// option callbacks without bypassing this helper.\n\t\t\t\tconst resolved =\n\t\t\t\t\ttypeof scopedSet === \"function\" ? scopedSet() : scopedSet;\n\t\t\t\treturn resolveEffectiveClientSet(parentOptions, resolved);\n\t\t\t},\n\t\t},\n\t]);\n}\n\n// Re-export composition helpers so consumers don't need a second import\nexport { resolveEffectiveClientSet };\n","// Angular Router route adapter for auth-coordination\n//\n// Canonical import path:\n// import { ... } from \"@securitydept/client-angular\"\n//\n// Provides the projection layer between Angular Router's ActivatedRouteSnapshot\n// tree and the SDK's framework-agnostic RouteMatchNode[] contract.\n// Uses real @angular/router types (ActivatedRouteSnapshot) so consuming apps\n// get full type-safety and IDE autocomplete without any casting.\n//\n// Architecture boundary:\n// - Does NOT own the Angular router, guards, or navigation lifecycle.\n// - Does NOT re-export core orchestration primitives.\n// - Does NOT carry token-set-specific mapping or policy.\n// - The adopter wires this into their guards / resolvers.\n//\n// Stability: provisional\n\nimport { Injectable } from \"@angular/core\";\nimport type { ActivatedRouteSnapshot } from \"@angular/router\";\nimport type {\n\tAuthRequirement,\n\tRouteMatchNode,\n} from \"@securitydept/client/auth-coordination\";\n\n// ---------------------------------------------------------------------------\n// Projection options\n// ---------------------------------------------------------------------------\n\n/** Options for {@link AuthRouteAdapter} projection methods. */\nexport interface AuthRouteAdapterOptions {\n\t/**\n\t * Key used to read auth requirements from route `data`.\n\t *\n\t * @default \"authRequirements\"\n\t */\n\trequirementsKey?: string;\n}\n\n/** Default key for auth requirements in Angular route `data`. */\nexport const DEFAULT_ROUTE_REQUIREMENTS_KEY = \"authRequirements\";\n\n// ---------------------------------------------------------------------------\n// Guard adapter result\n// ---------------------------------------------------------------------------\n\n/** Result from {@link AuthRouteAdapter.check}. */\nexport interface RouteGuardResult {\n\t/** Whether all requirements are settled (route can activate). */\n\tcanActivate: boolean;\n\t/** The pending requirement still awaiting resolution, if any. */\n\tpendingRequirement: AuthRequirement | null;\n}\n\n// ---------------------------------------------------------------------------\n// Service\n// ---------------------------------------------------------------------------\n\n/**\n * Angular service that bridges Angular Router's `ActivatedRouteSnapshot` to\n * the SDK's framework-agnostic `RouteMatchNode[]` contract.\n *\n * Inject this into `CanActivateFn` guards or class-based guards.\n *\n * @example\n * ```ts\n * export const authGuard: CanActivateFn = (route) => {\n * const adapter = inject(AuthRouteAdapter);\n * const result = adapter.check(route, orchestrator);\n * if (!result.canActivate && result.pendingRequirement) {\n * // Trigger auth flow for the pending requirement\n * }\n * return result.canActivate;\n * };\n * ```\n */\n@Injectable({ providedIn: \"root\" })\nexport class AuthRouteAdapter {\n\t/**\n\t * Project the `pathFromRoot` of an `ActivatedRouteSnapshot` into the SDK's\n\t * `RouteMatchNode[]` chain.\n\t *\n\t * Route segments without a `routeConfig` (e.g. the root segment) are\n\t * assigned routeId `\"__root__\"`. Segments with a config use the `path`\n\t * as their routeId (or `\"__index__\"` for empty-path segments).\n\t */\n\tprojectRouteMatch(\n\t\tleafRoute: ActivatedRouteSnapshot,\n\t\toptions?: AuthRouteAdapterOptions,\n\t): RouteMatchNode[] {\n\t\tconst key = options?.requirementsKey ?? DEFAULT_ROUTE_REQUIREMENTS_KEY;\n\t\tconst chain = leafRoute.pathFromRoot ?? [leafRoute];\n\t\treturn chain.map((segment) => this.segmentToNode(segment, key));\n\t}\n\n\t/**\n\t * Project an explicit array of `ActivatedRouteSnapshot` segments into the\n\t * SDK's `RouteMatchNode[]` chain.\n\t *\n\t * Use when you already have a flattened chain (e.g. from\n\t * `ActivatedRoute.pathFromRoot`).\n\t */\n\tprojectRouteSegments(\n\t\tsegments: readonly ActivatedRouteSnapshot[],\n\t\toptions?: AuthRouteAdapterOptions,\n\t): RouteMatchNode[] {\n\t\tconst key = options?.requirementsKey ?? DEFAULT_ROUTE_REQUIREMENTS_KEY;\n\t\treturn segments.map((segment) => this.segmentToNode(segment, key));\n\t}\n\n\t/**\n\t * Project the route snapshot and check whether all requirements are settled.\n\t *\n\t * @param leafRoute - The leaf `ActivatedRouteSnapshot` from the guard call.\n\t * @param orchestrator - The SDK orchestrator managing the requirement plan.\n\t * @param options - Optional projection options.\n\t */\n\tcheck(\n\t\tleafRoute: ActivatedRouteSnapshot,\n\t\torchestrator: {\n\t\t\tactivateMatchedRoutes(chain: readonly RouteMatchNode[]): void;\n\t\t\tsnapshot(): {\n\t\t\t\tsettled: boolean;\n\t\t\t\tpendingRequirement: AuthRequirement | null;\n\t\t\t};\n\t\t},\n\t\toptions?: AuthRouteAdapterOptions,\n\t): RouteGuardResult {\n\t\tconst chain = this.projectRouteMatch(leafRoute, options);\n\t\torchestrator.activateMatchedRoutes(chain);\n\t\tconst snap = orchestrator.snapshot();\n\t\treturn {\n\t\t\tcanActivate: snap.settled,\n\t\t\tpendingRequirement: snap.pendingRequirement,\n\t\t};\n\t}\n\n\tprivate segmentToNode(\n\t\tsegment: ActivatedRouteSnapshot,\n\t\tkey: string,\n\t): RouteMatchNode {\n\t\tconst routeId = this.resolveRouteId(segment);\n\t\tconst rawRequirements =\n\t\t\tsegment.data[key] ?? segment.routeConfig?.data?.[key];\n\t\tconst requirements: AuthRequirement[] = Array.isArray(rawRequirements)\n\t\t\t? rawRequirements\n\t\t\t: [];\n\t\treturn { routeId, requirements };\n\t}\n\n\tprivate resolveRouteId(segment: ActivatedRouteSnapshot): string {\n\t\tif (!segment.routeConfig) return \"__root__\";\n\t\tconst path = segment.routeConfig.path;\n\t\tif (path === undefined || path === null || path === \"\") return \"__index__\";\n\t\treturn path;\n\t}\n}\n","// Angular route metadata requirement helper\n//\n// Canonical import path:\n// import { withRouteRequirements, extractFullRouteRequirements, ... } from \"@securitydept/client-angular\"\n//\n// Provides the canonical route-metadata layer for Angular Router auth requirement\n// declaration. Requirements are stored in route `data` rather than in DI scope,\n// enabling full-route aggregation guards to collect the complete requirement set\n// from the entire path-from-root chain in a single pass.\n//\n// Architecture boundary:\n// - Does NOT own auth enforcement or planner logic.\n// - Does NOT carry token-set-specific mapping or policy.\n// - Provides typed helpers for declaring and reading requirements from route data.\n// - framework-specific (Angular Router types) but requirement-system-agnostic.\n//\n// Relationship to provideRouteScopedRequirements():\n// - provideRouteScopedRequirements() is a lower-level DI-scope helper.\n// - This module is the canonical path for Angular Router auth requirement\n// declaration when full-route aggregation is needed.\n//\n// Key sentinel note:\n// DEFAULT_ROUTE_REQUIREMENTS_KEY is defined in router.ts (AuthRouteAdapter's\n// companion constant). ROUTE_REQUIREMENTS_DATA_KEY exported here is its\n// semantic alias — both hold the same value (\"authRequirements\").\n// Adopters may use either name; they are interchangeable.\n//\n// Stability: provisional\n\nimport type { ActivatedRouteSnapshot } from \"@angular/router\";\nimport {\n\ttype AuthRequirement,\n\tRequirementsClientSetComposition,\n} from \"@securitydept/client/auth-coordination\";\nimport { DEFAULT_ROUTE_REQUIREMENTS_KEY } from \"./router\";\n\n// ---------------------------------------------------------------------------\n// Route data key\n// ---------------------------------------------------------------------------\n\n/**\n * Default key for auth requirements in Angular route `data`.\n *\n * Semantic alias for {@link DEFAULT_ROUTE_REQUIREMENTS_KEY} (defined in\n * `router.ts`). Both hold the same value (`\"authRequirements\"`).\n * Use either name — they are interchangeable.\n *\n * Set this key in `Route.data` to declare auth requirements for a route segment:\n * ```ts\n * { path: \"dashboard\", data: withRouteRequirements([{ id: \"session\", kind: \"session\" }]) }\n * ```\n *\n * The key is also read by {@link AuthRouteAdapter} when projecting snapshots.\n *\n * @see {@link withRouteRequirements}\n * @see {@link extractFullRouteRequirements}\n */\nexport const ROUTE_REQUIREMENTS_DATA_KEY = DEFAULT_ROUTE_REQUIREMENTS_KEY;\n\n/**\n * Default key for the route-level composition strategy in Angular route `data`.\n *\n * Used together with {@link ROUTE_REQUIREMENTS_DATA_KEY}. The default\n * composition is `merge` when the key is omitted.\n */\nexport const ROUTE_REQUIREMENTS_COMPOSITION_DATA_KEY =\n\t\"authRequirementsComposition\";\n\n/**\n * Route-level auth requirement declaration stored in Angular route `data`.\n */\nexport interface RouteRequirementsDeclaration {\n\trequirements: readonly AuthRequirement[];\n\tcomposition: RequirementsClientSetComposition;\n}\n\n/**\n * Options for {@link withRouteRequirements}.\n */\nexport interface WithRouteRequirementsOptions {\n\t/**\n\t * How this route segment composes with its parent route chain.\n\t * @default RequirementsClientSetComposition.Merge\n\t */\n\tcomposition?: RequirementsClientSetComposition;\n\n\t/**\n\t * Additional route data properties to merge into the returned object.\n\t */\n\textra?: Record<string, unknown>;\n}\n\n// ---------------------------------------------------------------------------\n// Declaration helper\n// ---------------------------------------------------------------------------\n\n/**\n * Build an Angular route `data` object declaring auth requirements for a\n * single route segment.\n *\n * Use this as the `data` field in an Angular `Route` config. Nested routes\n * can declare their own requirements; a full-route aggregation guard will\n * walk the entire `pathFromRoot` chain to collect all requirements in one pass.\n *\n * @example\n * ```ts\n * // Parent route declares base requirement\n * {\n * path: \"app\",\n * data: withRouteRequirements([{ id: \"session\", kind: \"session\" }]),\n * children: [\n * // Child route adds an additional requirement\n * {\n * path: \"admin\",\n * data: withRouteRequirements([{ id: \"admin-oidc\", kind: \"backend_oidc\" }]),\n * canActivate: [createTokenSetRouteAggregationGuard(...)],\n * },\n * ],\n * }\n * ```\n *\n * @param requirements - One or more auth requirements for this route segment.\n * @param extra - Optional additional data properties to merge.\n */\nexport function withRouteRequirements(\n\trequirements: AuthRequirement[],\n\toptionsOrExtra?: WithRouteRequirementsOptions | Record<string, unknown>,\n\tmaybeExtra?: Record<string, unknown>,\n): Record<string, unknown> {\n\tconst { composition, extra } = normalizeRequirementOptions(\n\t\toptionsOrExtra,\n\t\tmaybeExtra,\n\t);\n\treturn {\n\t\t...extra,\n\t\t[ROUTE_REQUIREMENTS_DATA_KEY]: requirements,\n\t\t[ROUTE_REQUIREMENTS_COMPOSITION_DATA_KEY]: composition,\n\t};\n}\n\n// ---------------------------------------------------------------------------\n// Aggregation helper\n// ---------------------------------------------------------------------------\n\n/**\n * Extract and flatten auth requirements from a complete Angular route chain.\n *\n * Walks all segments from root to leaf (from `leafRoute.pathFromRoot`)\n * and concatenates the declared {@link AuthRequirement} arrays in order.\n * Requirements from ancestor routes appear before requirements from\n * descendant routes. Duplicate `id` values are NOT de-duplicated here —\n * the caller (guard / enforcement layer) is responsible for deduplication\n * or merge logic.\n *\n * This is the extraction counter-part to {@link withRouteRequirements}.\n * A full-route aggregation guard calls this once and hands the complete\n * flat array to the planner / enforcement layer.\n *\n * @param leafRoute - The leaf `ActivatedRouteSnapshot` from the guard call.\n * @param requirementsKey - Override the route data key (default: `\"authRequirements\"`).\n */\nexport function extractFullRouteRequirements(\n\tleafRoute: ActivatedRouteSnapshot,\n\trequirementsKey = ROUTE_REQUIREMENTS_DATA_KEY,\n\tcompositionKey = ROUTE_REQUIREMENTS_COMPOSITION_DATA_KEY,\n): AuthRequirement[] {\n\tconst chain = leafRoute.pathFromRoot ?? [leafRoute];\n\tlet result: AuthRequirement[] = [];\n\tfor (const segment of chain) {\n\t\tconst raw =\n\t\t\tsegment.data[requirementsKey] ??\n\t\t\tsegment.routeConfig?.data?.[requirementsKey];\n\t\tconst composition =\n\t\t\treadRouteComposition(segment, compositionKey) ??\n\t\t\tRequirementsClientSetComposition.Merge;\n\t\tconst requirements = Array.isArray(raw) ? (raw as AuthRequirement[]) : [];\n\t\tresult = resolveEffectiveRequirements(result, {\n\t\t\tcomposition,\n\t\t\trequirements,\n\t\t});\n\t}\n\treturn result;\n}\n\n/**\n * Resolve the effective auth requirements by composing the parent chain with a\n * child route declaration.\n *\n * Composition semantics mirror `resolveEffectiveClientSet()`:\n * - `inherit` keeps the parent requirements unchanged\n * - `merge` appends child requirements and replaces same-id parent entries\n * - `replace` discards the parent chain and uses only the child's requirements\n */\nexport function resolveEffectiveRequirements(\n\tparentRequirements: readonly AuthRequirement[],\n\tchild: RouteRequirementsDeclaration,\n): AuthRequirement[] {\n\tswitch (child.composition) {\n\t\tcase RequirementsClientSetComposition.Inherit:\n\t\t\treturn [...parentRequirements];\n\n\t\tcase RequirementsClientSetComposition.Merge: {\n\t\t\tconst merged = new Map<string, AuthRequirement>();\n\t\t\tfor (const requirement of parentRequirements) {\n\t\t\t\tmerged.set(requirement.id, requirement);\n\t\t\t}\n\t\t\tfor (const requirement of child.requirements) {\n\t\t\t\tmerged.set(requirement.id, requirement);\n\t\t\t}\n\t\t\treturn [...merged.values()];\n\t\t}\n\n\t\tcase RequirementsClientSetComposition.Replace:\n\t\t\treturn [...child.requirements];\n\n\t\tdefault: {\n\t\t\tconst _exhaustive: never = child.composition;\n\t\t\tthrow new Error(\n\t\t\t\t`[resolveEffectiveRequirements] Unknown composition: ${_exhaustive}`,\n\t\t\t);\n\t\t}\n\t}\n}\n\nfunction normalizeRequirementOptions(\n\toptionsOrExtra?: WithRouteRequirementsOptions | Record<string, unknown>,\n\tmaybeExtra?: Record<string, unknown>,\n): {\n\tcomposition: RequirementsClientSetComposition;\n\textra?: Record<string, unknown>;\n} {\n\tif (\n\t\toptionsOrExtra &&\n\t\t(\"composition\" in optionsOrExtra || \"extra\" in optionsOrExtra)\n\t) {\n\t\tconst options = optionsOrExtra as WithRouteRequirementsOptions;\n\t\treturn {\n\t\t\tcomposition:\n\t\t\t\toptions.composition ?? RequirementsClientSetComposition.Merge,\n\t\t\textra: maybeExtra ?? options.extra,\n\t\t};\n\t}\n\n\treturn {\n\t\tcomposition: RequirementsClientSetComposition.Merge,\n\t\textra: optionsOrExtra as Record<string, unknown> | undefined,\n\t};\n}\n\nfunction readRouteComposition(\n\tsegment: ActivatedRouteSnapshot,\n\tcompositionKey: string,\n): RequirementsClientSetComposition | undefined {\n\tconst raw =\n\t\tsegment.data[compositionKey] ?? segment.routeConfig?.data?.[compositionKey];\n\tif (\n\t\traw === RequirementsClientSetComposition.Inherit ||\n\t\traw === RequirementsClientSetComposition.Merge ||\n\t\traw === RequirementsClientSetComposition.Replace\n\t) {\n\t\treturn raw;\n\t}\n\treturn undefined;\n}\n","// Angular signal / Observable bridge utilities\n//\n// Canonical import path:\n// import { bridgeToAngularSignal, signalToObservable } from \"@securitydept/client-angular\"\n//\n// These utilities convert SDK-native ReadableSignalTrait values to Angular-native\n// primitives (WritableSignal, Observable) so that framework adapter packages\n// can surface reactive state using idiomatic Angular APIs.\n//\n// Owner: @securitydept/client-angular — these are generic framework bridges,\n// not token-set-specific utilities. All Angular adapters (basic-auth, session,\n// token-set, …) should import from here instead of implementing their own.\n//\n// Stability: provisional (framework adapter)\n\nimport type { WritableSignal } from \"@angular/core\";\nimport type { ReadableSignalTrait } from \"@securitydept/client\";\nimport { Observable } from \"rxjs\";\n\n/**\n * Bridge an SDK `ReadableSignalTrait` to an Angular writable signal.\n *\n * Immediately syncs the current value, then subscribes to future changes.\n *\n * @returns Cleanup function that unsubscribes from the SDK signal.\n */\nexport function bridgeToAngularSignal<T>(\n\tsource: ReadableSignalTrait<T>,\n\ttarget: WritableSignal<T>,\n): () => void {\n\ttarget.set(source.get());\n\treturn source.subscribe(() => {\n\t\ttarget.set(source.get());\n\t});\n}\n\n/**\n * Bridge an SDK `ReadableSignalTrait` to an RxJS Observable.\n *\n * The observable emits the current value immediately on subscribe, then\n * emits whenever the SDK signal value changes. Completes on unsubscribe.\n */\nexport function signalToObservable<T>(\n\tsource: ReadableSignalTrait<T>,\n): Observable<T> {\n\treturn new Observable<T>((subscriber) => {\n\t\tsubscriber.next(source.get());\n\t\tconst unsubscribe = source.subscribe(() => {\n\t\t\tsubscriber.next(source.get());\n\t\t});\n\t\treturn () => unsubscribe();\n\t});\n}\n","/*\n * Public API Surface of @securitydept/client-angular\n */\n\nexport * from \"./lib/planner-host\";\nexport * from \"./lib/route-requirements\";\nexport * from \"./lib/router\";\nexport * from \"./lib/signal-bridge\";\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":";;;;;;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAoBA;AACA;AACA;AAEA;;;;;AAKG;MACU,iBAAiB,GAAG,IAAI,cAAc,CAClD,mBAAmB;AAcpB;;;;;;;;;;;;;;;;;;;;;;AAsBG;AACG,SAAU,sBAAsB,CACrC,OAAuC,EAAA;IAEvC,MAAM,cAAc,GAA6B,EAAE;AACnD,IAAA,IAAI,OAAO,EAAE,eAAe,EAAE;AAC7B,QAAA,cAAc,CAAC,eAAe,GAAG,OAAO,CAAC,eAAe;IACzD;AACA,IAAA,OAAO,wBAAwB,CAAC;QAC/B,EAAE,OAAO,EAAE,iBAAiB,EAAE,QAAQ,EAAE,iBAAiB,CAAC,cAAc,CAAC,EAAE;AAC3E,KAAA,CAAC;AACH;AAEA;;;;;;;;;;;AAWG;SACa,iBAAiB,GAAA;AAChC,IAAA,MAAM,IAAI,GAAG,MAAM,CAAC,iBAAiB,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;IAC1D,IAAI,CAAC,IAAI,EAAE;QACV,MAAM,IAAI,KAAK,CACd,4EAA4E;AAC3E,YAAA,qEAAqE,CACtE;IACF;AACA,IAAA,OAAO,IAAI;AACZ;AAEA;AACA;AACA;AACA;AAEA;;;;;;;;;AASG;MACU,4BAA4B,GAAG,IAAI,cAAc,CAE5D,8BAA8B;AAEhC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA+DG;AACG,SAAU,8BAA8B,CAC7C,SAA4E,EAAA;AAE5E,IAAA,OAAO,wBAAwB,CAAC;AAC/B,QAAA;AACC,YAAA,OAAO,EAAE,4BAA4B;YACrC,UAAU,EAAE,MAAuC;;;AAGlD,gBAAA,MAAM,aAAa,GAClB,MAAM,CAAC,4BAA4B,EAAE;AACpC,oBAAA,QAAQ,EAAE,IAAI;AACd,oBAAA,QAAQ,EAAE,IAAI;iBACd,CAAC,IAAI,EAAE;;;;AAIT,gBAAA,MAAM,QAAQ,GACb,OAAO,SAAS,KAAK,UAAU,GAAG,SAAS,EAAE,GAAG,SAAS;AAC1D,gBAAA,OAAO,yBAAyB,CAAC,aAAa,EAAE,QAAQ,CAAC;YAC1D,CAAC;AACD,SAAA;AACD,KAAA,CAAC;AACH;;ACjOA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAuBA;AACO,MAAM,8BAA8B,GAAG;AAc9C;AACA;AACA;AAEA;;;;;;;;;;;;;;;;;AAiBG;MAEU,gBAAgB,CAAA;AAC5B;;;;;;;AAOG;IACH,iBAAiB,CAChB,SAAiC,EACjC,OAAiC,EAAA;AAEjC,QAAA,MAAM,GAAG,GAAG,OAAO,EAAE,eAAe,IAAI,8BAA8B;QACtE,MAAM,KAAK,GAAG,SAAS,CAAC,YAAY,IAAI,CAAC,SAAS,CAAC;AACnD,QAAA,OAAO,KAAK,CAAC,GAAG,CAAC,CAAC,OAAO,KAAK,IAAI,CAAC,aAAa,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC;IAChE;AAEA;;;;;;AAMG;IACH,oBAAoB,CACnB,QAA2C,EAC3C,OAAiC,EAAA;AAEjC,QAAA,MAAM,GAAG,GAAG,OAAO,EAAE,eAAe,IAAI,8BAA8B;AACtE,QAAA,OAAO,QAAQ,CAAC,GAAG,CAAC,CAAC,OAAO,KAAK,IAAI,CAAC,aAAa,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC;IACnE;AAEA;;;;;;AAMG;AACH,IAAA,KAAK,CACJ,SAAiC,EACjC,YAMC,EACD,OAAiC,EAAA;QAEjC,MAAM,KAAK,GAAG,IAAI,CAAC,iBAAiB,CAAC,SAAS,EAAE,OAAO,CAAC;AACxD,QAAA,YAAY,CAAC,qBAAqB,CAAC,KAAK,CAAC;AACzC,QAAA,MAAM,IAAI,GAAG,YAAY,CAAC,QAAQ,EAAE;QACpC,OAAO;YACN,WAAW,EAAE,IAAI,CAAC,OAAO;YACzB,kBAAkB,EAAE,IAAI,CAAC,kBAAkB;SAC3C;IACF;IAEQ,aAAa,CACpB,OAA+B,EAC/B,GAAW,EAAA;QAEX,MAAM,OAAO,GAAG,IAAI,CAAC,cAAc,CAAC,OAAO,CAAC;AAC5C,QAAA,MAAM,eAAe,GACpB,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,OAAO,CAAC,WAAW,EAAE,IAAI,GAAG,GAAG,CAAC;AACtD,QAAA,MAAM,YAAY,GAAsB,KAAK,CAAC,OAAO,CAAC,eAAe;AACpE,cAAE;cACA,EAAE;AACL,QAAA,OAAO,EAAE,OAAO,EAAE,YAAY,EAAE;IACjC;AAEQ,IAAA,cAAc,CAAC,OAA+B,EAAA;QACrD,IAAI,CAAC,OAAO,CAAC,WAAW;AAAE,YAAA,OAAO,UAAU;AAC3C,QAAA,MAAM,IAAI,GAAG,OAAO,CAAC,WAAW,CAAC,IAAI;QACrC,IAAI,IAAI,KAAK,SAAS,IAAI,IAAI,KAAK,IAAI,IAAI,IAAI,KAAK,EAAE;AAAE,YAAA,OAAO,WAAW;AAC1E,QAAA,OAAO,IAAI;IACZ;uGA9EY,gBAAgB,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,UAAA,EAAA,CAAA;AAAhB,IAAA,OAAA,KAAA,GAAA,EAAA,CAAA,qBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,QAAA,EAAA,QAAA,EAAA,EAAA,EAAA,IAAA,EAAA,gBAAgB,cADH,MAAM,EAAA,CAAA;;2FACnB,gBAAgB,EAAA,UAAA,EAAA,CAAA;kBAD5B,UAAU;mBAAC,EAAE,UAAU,EAAE,MAAM,EAAE;;;AC5ElC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AASA;AACA;AACA;AAEA;;;;;;;;;;;;;;;;AAgBG;AACI,MAAM,2BAA2B,GAAG;AAE3C;;;;;AAKG;AACI,MAAM,uCAAuC,GACnD;AA0BD;AACA;AACA;AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;AA2BG;SACa,qBAAqB,CACpC,YAA+B,EAC/B,cAAuE,EACvE,UAAoC,EAAA;AAEpC,IAAA,MAAM,EAAE,WAAW,EAAE,KAAK,EAAE,GAAG,2BAA2B,CACzD,cAAc,EACd,UAAU,CACV;IACD,OAAO;AACN,QAAA,GAAG,KAAK;QACR,CAAC,2BAA2B,GAAG,YAAY;QAC3C,CAAC,uCAAuC,GAAG,WAAW;KACtD;AACF;AAEA;AACA;AACA;AAEA;;;;;;;;;;;;;;;;AAgBG;AACG,SAAU,4BAA4B,CAC3C,SAAiC,EACjC,eAAe,GAAG,2BAA2B,EAC7C,cAAc,GAAG,uCAAuC,EAAA;IAExD,MAAM,KAAK,GAAG,SAAS,CAAC,YAAY,IAAI,CAAC,SAAS,CAAC;IACnD,IAAI,MAAM,GAAsB,EAAE;AAClC,IAAA,KAAK,MAAM,OAAO,IAAI,KAAK,EAAE;AAC5B,QAAA,MAAM,GAAG,GACR,OAAO,CAAC,IAAI,CAAC,eAAe,CAAC;YAC7B,OAAO,CAAC,WAAW,EAAE,IAAI,GAAG,eAAe,CAAC;AAC7C,QAAA,MAAM,WAAW,GAChB,oBAAoB,CAAC,OAAO,EAAE,cAAc,CAAC;YAC7C,gCAAgC,CAAC,KAAK;AACvC,QAAA,MAAM,YAAY,GAAG,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,GAAI,GAAyB,GAAG,EAAE;AACzE,QAAA,MAAM,GAAG,4BAA4B,CAAC,MAAM,EAAE;YAC7C,WAAW;YACX,YAAY;AACZ,SAAA,CAAC;IACH;AACA,IAAA,OAAO,MAAM;AACd;AAEA;;;;;;;;AAQG;AACG,SAAU,4BAA4B,CAC3C,kBAA8C,EAC9C,KAAmC,EAAA;AAEnC,IAAA,QAAQ,KAAK,CAAC,WAAW;QACxB,KAAK,gCAAgC,CAAC,OAAO;AAC5C,YAAA,OAAO,CAAC,GAAG,kBAAkB,CAAC;AAE/B,QAAA,KAAK,gCAAgC,CAAC,KAAK,EAAE;AAC5C,YAAA,MAAM,MAAM,GAAG,IAAI,GAAG,EAA2B;AACjD,YAAA,KAAK,MAAM,WAAW,IAAI,kBAAkB,EAAE;gBAC7C,MAAM,CAAC,GAAG,CAAC,WAAW,CAAC,EAAE,EAAE,WAAW,CAAC;YACxC;AACA,YAAA,KAAK,MAAM,WAAW,IAAI,KAAK,CAAC,YAAY,EAAE;gBAC7C,MAAM,CAAC,GAAG,CAAC,WAAW,CAAC,EAAE,EAAE,WAAW,CAAC;YACxC;AACA,YAAA,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC;QAC5B;QAEA,KAAK,gCAAgC,CAAC,OAAO;AAC5C,YAAA,OAAO,CAAC,GAAG,KAAK,CAAC,YAAY,CAAC;QAE/B,SAAS;AACR,YAAA,MAAM,WAAW,GAAU,KAAK,CAAC,WAAW;AAC5C,YAAA,MAAM,IAAI,KAAK,CACd,uDAAuD,WAAW,CAAA,CAAE,CACpE;QACF;;AAEF;AAEA,SAAS,2BAA2B,CACnC,cAAuE,EACvE,UAAoC,EAAA;AAKpC,IAAA,IACC,cAAc;SACb,aAAa,IAAI,cAAc,IAAI,OAAO,IAAI,cAAc,CAAC,EAC7D;QACD,MAAM,OAAO,GAAG,cAA8C;QAC9D,OAAO;AACN,YAAA,WAAW,EACV,OAAO,CAAC,WAAW,IAAI,gCAAgC,CAAC,KAAK;AAC9D,YAAA,KAAK,EAAE,UAAU,IAAI,OAAO,CAAC,KAAK;SAClC;IACF;IAEA,OAAO;QACN,WAAW,EAAE,gCAAgC,CAAC,KAAK;AACnD,QAAA,KAAK,EAAE,cAAqD;KAC5D;AACF;AAEA,SAAS,oBAAoB,CAC5B,OAA+B,EAC/B,cAAsB,EAAA;AAEtB,IAAA,MAAM,GAAG,GACR,OAAO,CAAC,IAAI,CAAC,cAAc,CAAC,IAAI,OAAO,CAAC,WAAW,EAAE,IAAI,GAAG,cAAc,CAAC;AAC5E,IAAA,IACC,GAAG,KAAK,gCAAgC,CAAC,OAAO;QAChD,GAAG,KAAK,gCAAgC,CAAC,KAAK;AAC9C,QAAA,GAAG,KAAK,gCAAgC,CAAC,OAAO,EAC/C;AACD,QAAA,OAAO,GAAG;IACX;AACA,IAAA,OAAO,SAAS;AACjB;;ACvQA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAMA;;;;;;AAMG;AACG,SAAU,qBAAqB,CACpC,MAA8B,EAC9B,MAAyB,EAAA;IAEzB,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,EAAE,CAAC;AACxB,IAAA,OAAO,MAAM,CAAC,SAAS,CAAC,MAAK;QAC5B,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,EAAE,CAAC;AACzB,IAAA,CAAC,CAAC;AACH;AAEA;;;;;AAKG;AACG,SAAU,kBAAkB,CACjC,MAA8B,EAAA;AAE9B,IAAA,OAAO,IAAI,UAAU,CAAI,CAAC,UAAU,KAAI;QACvC,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,EAAE,CAAC;AAC7B,QAAA,MAAM,WAAW,GAAG,MAAM,CAAC,SAAS,CAAC,MAAK;YACzC,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,EAAE,CAAC;AAC9B,QAAA,CAAC,CAAC;AACF,QAAA,OAAO,MAAM,WAAW,EAAE;AAC3B,IAAA,CAAC,CAAC;AACH;;ACpDA;;AAEG;;ACFH;;AAEG;;;;"}
|
|
1
|
+
{"version":3,"file":"securitydept-client-angular.mjs","sources":["../../src/lib/page-environment.ts","../../src/lib/planner-host.ts","../../src/lib/router.ts","../../src/lib/route-requirements.ts","../../src/lib/signal-bridge.ts","../../src/public-api.ts","../../src/securitydept-client-angular.ts"],"sourcesContent":["import { InjectionToken, type Provider } from \"@angular/core\";\nimport {\n\tassertResolveEnvironment,\n\ttype PageClientEnvironment,\n} from \"@securitydept/client/web\";\n\nexport type PageClientEnvironmentValue = PageClientEnvironment;\n\nexport interface PageClientEnvironmentService {\n\tresolvePageEnvironment(): Promise<PageClientEnvironmentValue>;\n}\n\nexport type PageClientEnvironmentResolver = () =>\n\t| PageClientEnvironmentValue\n\t| Promise<PageClientEnvironmentValue>;\n\nexport type PageClientEnvironmentSource =\n\t| PageClientEnvironmentValue\n\t| PageClientEnvironmentService\n\t| PageClientEnvironmentResolver;\n\nexport const PAGE_CLIENT_ENVIRONMENT = new InjectionToken<\n\tPageClientEnvironmentSource | undefined\n>(\"PAGE_CLIENT_ENVIRONMENT\", {\n\tprovidedIn: \"root\",\n\tfactory: () => undefined,\n});\n\nexport interface ProvidePageClientEnvironmentOptions {\n\t/**\n\t * Stable host-owned page environment source used by Angular page-only helpers.\n\t *\n\t * Accepts an already-materialized page environment object, a provider-scoped\n\t * `ClientEnvironmentService`, or an inject-safe stable resolver returning the\n\t * page capability synchronously or asynchronously.\n\t */\n\tenvironment: PageClientEnvironmentSource;\n}\n\nexport function providePageClientEnvironment(\n\toptions: ProvidePageClientEnvironmentOptions,\n): Provider {\n\treturn {\n\t\tprovide: PAGE_CLIENT_ENVIRONMENT,\n\t\tuseValue: options.environment,\n\t};\n}\n\nexport function resolvePageClientEnvironmentSource(\n\tsource: PageClientEnvironmentSource | undefined,\n\tonMissing: () => never,\n): Promise<PageClientEnvironmentValue> {\n\tconst resolvedSource = assertResolveEnvironment(source, onMissing);\n\n\tif (isPageClientEnvironmentResolver(resolvedSource)) {\n\t\treturn Promise.resolve(resolvedSource()).then((environment) =>\n\t\t\tassertResolveEnvironment(environment, onMissing),\n\t\t);\n\t}\n\n\tif (isPageClientEnvironmentService(resolvedSource)) {\n\t\treturn resolvedSource\n\t\t\t.resolvePageEnvironment()\n\t\t\t.then((environment) => assertResolveEnvironment(environment, onMissing));\n\t}\n\n\treturn Promise.resolve(resolvedSource);\n}\n\nfunction isPageClientEnvironmentResolver(\n\tsource: PageClientEnvironmentSource,\n): source is PageClientEnvironmentResolver {\n\treturn typeof source === \"function\";\n}\n\nfunction isPageClientEnvironmentService(\n\tsource: PageClientEnvironmentSource,\n): source is PageClientEnvironmentService {\n\treturn (\n\t\ttypeof source === \"object\" &&\n\t\tsource !== null &&\n\t\t\"resolvePageEnvironment\" in source &&\n\t\ttypeof source.resolvePageEnvironment === \"function\"\n\t);\n}\n","// Angular planner-host integration — DI-based planner provider / lookup\n//\n// Canonical import path:\n// import { AUTH_PLANNER_HOST, provideAuthPlannerHost, ... } from \"@securitydept/client-angular\"\n//\n// Provides Angular DI glue for the shared planner-host contract:\n// - InjectionToken for PlannerHost\n// - Provider helpers for app / module / route scoped planners\n// - InjectionToken + provider helpers for ScopedRequirementsClientSet\n// - injectPlannerHost() convenience function with fail-fast\n//\n// Architecture boundary:\n// - Does NOT own the planner-host contract (that lives in @securitydept/client)\n// - Does NOT carry token-set-specific mapping\n// - Provides the Angular DI wiring for the shared contract\n//\n// Stability: provisional\n\nimport {\n\ttype EnvironmentProviders,\n\tInjectionToken,\n\tinject,\n\tmakeEnvironmentProviders,\n} from \"@angular/core\";\nimport type {\n\tAuthGuardClientOption,\n\tCandidateSelector,\n\tCreatePlannerHostOptions,\n\tPlannerHost,\n\tScopedRequirementsClientSet,\n} from \"@securitydept/client/auth-coordination\";\nimport {\n\tcreatePlannerHost,\n\tresolveEffectiveClientSet,\n} from \"@securitydept/client/auth-coordination\";\n\n// ---------------------------------------------------------------------------\n// PlannerHost injection token\n// ---------------------------------------------------------------------------\n\n/**\n * DI token for the shared {@link PlannerHost}.\n *\n * Provide at the app level via {@link provideAuthPlannerHost}.\n * Guards use {@link injectPlannerHost} to look up the nearest instance.\n */\nexport const AUTH_PLANNER_HOST = new InjectionToken<PlannerHost>(\n\t\"AUTH_PLANNER_HOST\",\n);\n\n/**\n * Options for {@link provideAuthPlannerHost}.\n */\nexport interface ProvideAuthPlannerHostOptions {\n\t/**\n\t * Custom candidate selection strategy.\n\t * @see {@link CandidateSelector}\n\t */\n\tselectCandidate?: CandidateSelector;\n}\n\n/**\n * Provide an {@link AUTH_PLANNER_HOST} at the current injector level.\n *\n * Use in app config, route providers, or NgModule providers to establish\n * a planner-host scope. Child routes inherit the nearest parent's planner.\n *\n * @example\n * ```ts\n * // app.config.ts — app-level planner (default sequential strategy)\n * export const appConfig: ApplicationConfig = {\n * providers: [provideAuthPlannerHost()],\n * };\n *\n * // Feature route — override with custom async chooser strategy\n * {\n * path: \"admin\",\n * providers: [provideAuthPlannerHost({\n * selectCandidate: async (candidates) => showAdminChooser(candidates),\n * })],\n * children: [...]\n * }\n * ```\n */\nexport function provideAuthPlannerHost(\n\toptions?: ProvideAuthPlannerHostOptions,\n): EnvironmentProviders {\n\tconst plannerOptions: CreatePlannerHostOptions = {};\n\tif (options?.selectCandidate) {\n\t\tplannerOptions.selectCandidate = options.selectCandidate;\n\t}\n\treturn makeEnvironmentProviders([\n\t\t{ provide: AUTH_PLANNER_HOST, useValue: createPlannerHost(plannerOptions) },\n\t]);\n}\n\n/**\n * Inject the nearest {@link PlannerHost} from the DI hierarchy.\n *\n * Throws an explicit error if no planner-host is provided, preventing\n * silent fallback behavior.\n *\n * @example\n * ```ts\n * const plannerHost = injectPlannerHost();\n * const result = await plannerHost.evaluate(candidates);\n * ```\n */\nexport function injectPlannerHost(): PlannerHost {\n\tconst host = inject(AUTH_PLANNER_HOST, { optional: true });\n\tif (!host) {\n\t\tthrow new Error(\n\t\t\t\"[injectPlannerHost] No AUTH_PLANNER_HOST found in the injector hierarchy. \" +\n\t\t\t\t\"Use provideAuthPlannerHost() in your app config or route providers.\",\n\t\t);\n\t}\n\treturn host;\n}\n\n// ---------------------------------------------------------------------------\n// Requirements client set injection token — stores the already-resolved\n// effective options for the current scope (parent + child composed).\n// ---------------------------------------------------------------------------\n\n/**\n * DI token for the effective requirements client set at the current scope.\n *\n * The value is always the **resolved** options after composing all ancestor\n * scopes — it is NOT the raw `ScopedRequirementsClientSet` declaration.\n *\n * Provide via {@link provideRouteScopedRequirements}.\n * Guards inject this token to get the effective scope requirements and then\n * merge their own declared candidates on top.\n */\nexport const AUTH_REQUIREMENTS_CLIENT_SET = new InjectionToken<\n\treadonly AuthGuardClientOption[]\n>(\"AUTH_REQUIREMENTS_CLIENT_SET\");\n\n/**\n * Provide a {@link ScopedRequirementsClientSet} at the current route/module scope.\n *\n * Internally, the provider resolves the effective client set by composing the\n * declared `scopedSet` with the parent scope's already-resolved options\n * (injected via `skipSelf: true`). The token value stored in DI is the\n * resolved `readonly AuthGuardClientOption[]`, not the raw declaration.\n *\n * This mirrors the React `AuthRequirementsClientSetProvider` semantics:\n * each level stores its resolved effective options, so children inherit\n * the composed result without re-resolving the full ancestor chain.\n *\n * The `scopedSet` argument may also be a **factory function** — it will be\n * called inside Angular's `useFactory` context, so `inject()` is valid.\n * Use this when the requirement options need DI-resolved services (e.g. a\n * token-set registry or a redirect service).\n *\n * @example\n * ```ts\n * // routes.ts — static declaration (no DI needed)\n * {\n * path: \"\",\n * providers: [\n * provideRouteScopedRequirements({\n * composition: RequirementsClientSetComposition.Replace,\n * options: [sessionClientOption],\n * }),\n * ],\n * }\n *\n * // Feature route merges OIDC on top of the parent's session requirement\n * {\n * path: \"confluence\",\n * providers: [\n * provideRouteScopedRequirements({\n * composition: RequirementsClientSetComposition.Merge,\n * options: [confluenceOidcClientOption],\n * }),\n * ],\n * // Route-level DI scope only. Angular Router adopters should prefer\n * // secureRouteRoot()/secureRoute() over direct guard wiring.\n * }\n *\n * // Factory form — use when options depend on injected services\n * {\n * path: \"protected\",\n * providers: [\n * provideRouteScopedRequirements(() => {\n * const registry = inject(TokenSetAuthRegistry);\n * const authService = inject(AuthService);\n * return {\n * composition: RequirementsClientSetComposition.Replace,\n * options: [{\n * requirementId: \"oidc\",\n * requirementKind: \"frontend_oidc\",\n * checkAuthenticated: () => registry.require(clientKey).isAuthenticated(),\n * onUnauthenticated: () => { authService.redirectToLogin(clientKey).subscribe(); return false; },\n * }],\n * };\n * }),\n * ],\n * }\n * ```\n */\nexport function provideRouteScopedRequirements(\n\tscopedSet: ScopedRequirementsClientSet | (() => ScopedRequirementsClientSet),\n): EnvironmentProviders {\n\treturn makeEnvironmentProviders([\n\t\t{\n\t\t\tprovide: AUTH_REQUIREMENTS_CLIENT_SET,\n\t\t\tuseFactory: (): readonly AuthGuardClientOption[] => {\n\t\t\t\t// Walk up to the nearest parent scope's already-resolved effective set.\n\t\t\t\t// skipSelf: true ensures we don't read our own (not-yet-set) value.\n\t\t\t\tconst parentOptions: readonly AuthGuardClientOption[] =\n\t\t\t\t\tinject(AUTH_REQUIREMENTS_CLIENT_SET, {\n\t\t\t\t\t\toptional: true,\n\t\t\t\t\t\tskipSelf: true,\n\t\t\t\t\t}) ?? [];\n\t\t\t\t// Support factory form so callers can use inject() to resolve\n\t\t\t\t// DI services (e.g. auth registry, redirect service) inside their\n\t\t\t\t// option callbacks without bypassing this helper.\n\t\t\t\tconst resolved =\n\t\t\t\t\ttypeof scopedSet === \"function\" ? scopedSet() : scopedSet;\n\t\t\t\treturn resolveEffectiveClientSet(parentOptions, resolved);\n\t\t\t},\n\t\t},\n\t]);\n}\n\n// Re-export composition helpers so consumers don't need a second import\nexport { resolveEffectiveClientSet };\n","// Angular Router route adapter for auth-coordination\n//\n// Canonical import path:\n// import { ... } from \"@securitydept/client-angular\"\n//\n// Provides the projection layer between Angular Router's ActivatedRouteSnapshot\n// tree and the SDK's framework-agnostic RouteMatchNode[] contract.\n// Uses real @angular/router types (ActivatedRouteSnapshot) so consuming apps\n// get full type-safety and IDE autocomplete without any casting.\n//\n// Architecture boundary:\n// - Does NOT own the Angular router, guards, or navigation lifecycle.\n// - Does NOT re-export core orchestration primitives.\n// - Does NOT carry token-set-specific mapping or policy.\n// - The adopter wires this into their guards / resolvers.\n//\n// Stability: provisional\n\nimport { Injectable } from \"@angular/core\";\nimport type { ActivatedRouteSnapshot } from \"@angular/router\";\nimport type {\n\tAuthRequirement,\n\tRouteMatchNode,\n} from \"@securitydept/client/auth-coordination\";\n\n// ---------------------------------------------------------------------------\n// Projection options\n// ---------------------------------------------------------------------------\n\n/** Options for {@link AuthRouteAdapter} projection methods. */\nexport interface AuthRouteAdapterOptions {\n\t/**\n\t * Key used to read auth requirements from route `data`.\n\t *\n\t * @default \"authRequirements\"\n\t */\n\trequirementsKey?: string;\n}\n\n/** Default key for auth requirements in Angular route `data`. */\nexport const DEFAULT_ROUTE_REQUIREMENTS_KEY = \"authRequirements\";\n\n// ---------------------------------------------------------------------------\n// Guard adapter result\n// ---------------------------------------------------------------------------\n\n/** Result from {@link AuthRouteAdapter.check}. */\nexport interface RouteGuardResult {\n\t/** Whether all requirements are settled (route can activate). */\n\tcanActivate: boolean;\n\t/** The pending requirement still awaiting resolution, if any. */\n\tpendingRequirement: AuthRequirement | null;\n}\n\n// ---------------------------------------------------------------------------\n// Service\n// ---------------------------------------------------------------------------\n\n/**\n * Angular service that bridges Angular Router's `ActivatedRouteSnapshot` to\n * the SDK's framework-agnostic `RouteMatchNode[]` contract.\n *\n * Inject this into `CanActivateFn` guards or class-based guards.\n *\n * @example\n * ```ts\n * export const authGuard: CanActivateFn = (route) => {\n * const adapter = inject(AuthRouteAdapter);\n * const result = adapter.check(route, orchestrator);\n * if (!result.canActivate && result.pendingRequirement) {\n * // Trigger auth flow for the pending requirement\n * }\n * return result.canActivate;\n * };\n * ```\n */\n@Injectable({ providedIn: \"root\" })\nexport class AuthRouteAdapter {\n\t/**\n\t * Project the `pathFromRoot` of an `ActivatedRouteSnapshot` into the SDK's\n\t * `RouteMatchNode[]` chain.\n\t *\n\t * Route segments without a `routeConfig` (e.g. the root segment) are\n\t * assigned routeId `\"__root__\"`. Segments with a config use the `path`\n\t * as their routeId (or `\"__index__\"` for empty-path segments).\n\t */\n\tprojectRouteMatch(\n\t\tleafRoute: ActivatedRouteSnapshot,\n\t\toptions?: AuthRouteAdapterOptions,\n\t): RouteMatchNode[] {\n\t\tconst key = options?.requirementsKey ?? DEFAULT_ROUTE_REQUIREMENTS_KEY;\n\t\tconst chain = leafRoute.pathFromRoot ?? [leafRoute];\n\t\treturn chain.map((segment) => this.segmentToNode(segment, key));\n\t}\n\n\t/**\n\t * Project an explicit array of `ActivatedRouteSnapshot` segments into the\n\t * SDK's `RouteMatchNode[]` chain.\n\t *\n\t * Use when you already have a flattened chain (e.g. from\n\t * `ActivatedRoute.pathFromRoot`).\n\t */\n\tprojectRouteSegments(\n\t\tsegments: readonly ActivatedRouteSnapshot[],\n\t\toptions?: AuthRouteAdapterOptions,\n\t): RouteMatchNode[] {\n\t\tconst key = options?.requirementsKey ?? DEFAULT_ROUTE_REQUIREMENTS_KEY;\n\t\treturn segments.map((segment) => this.segmentToNode(segment, key));\n\t}\n\n\t/**\n\t * Project the route snapshot and check whether all requirements are settled.\n\t *\n\t * @param leafRoute - The leaf `ActivatedRouteSnapshot` from the guard call.\n\t * @param orchestrator - The SDK orchestrator managing the requirement plan.\n\t * @param options - Optional projection options.\n\t */\n\tcheck(\n\t\tleafRoute: ActivatedRouteSnapshot,\n\t\torchestrator: {\n\t\t\tactivateMatchedRoutes(chain: readonly RouteMatchNode[]): void;\n\t\t\tsnapshot(): {\n\t\t\t\tsettled: boolean;\n\t\t\t\tpendingRequirement: AuthRequirement | null;\n\t\t\t};\n\t\t},\n\t\toptions?: AuthRouteAdapterOptions,\n\t): RouteGuardResult {\n\t\tconst chain = this.projectRouteMatch(leafRoute, options);\n\t\torchestrator.activateMatchedRoutes(chain);\n\t\tconst snap = orchestrator.snapshot();\n\t\treturn {\n\t\t\tcanActivate: snap.settled,\n\t\t\tpendingRequirement: snap.pendingRequirement,\n\t\t};\n\t}\n\n\tprivate segmentToNode(\n\t\tsegment: ActivatedRouteSnapshot,\n\t\tkey: string,\n\t): RouteMatchNode {\n\t\tconst routeId = this.resolveRouteId(segment);\n\t\tconst rawRequirements =\n\t\t\tsegment.data[key] ?? segment.routeConfig?.data?.[key];\n\t\tconst requirements: AuthRequirement[] = Array.isArray(rawRequirements)\n\t\t\t? rawRequirements\n\t\t\t: [];\n\t\treturn { routeId, requirements };\n\t}\n\n\tprivate resolveRouteId(segment: ActivatedRouteSnapshot): string {\n\t\tif (!segment.routeConfig) return \"__root__\";\n\t\tconst path = segment.routeConfig.path;\n\t\tif (path === undefined || path === null || path === \"\") return \"__index__\";\n\t\treturn path;\n\t}\n}\n","// Angular route metadata requirement helper\n//\n// Canonical import path:\n// import { withRouteRequirements, extractFullRouteRequirements, ... } from \"@securitydept/client-angular\"\n//\n// Provides the canonical route-metadata layer for Angular Router auth requirement\n// declaration. Requirements are stored in route `data` rather than in DI scope,\n// enabling full-route aggregation guards to collect the complete requirement set\n// from the entire path-from-root chain in a single pass.\n//\n// Architecture boundary:\n// - Does NOT own auth enforcement or planner logic.\n// - Does NOT carry token-set-specific mapping or policy.\n// - Provides typed helpers for declaring and reading requirements from route data.\n// - framework-specific (Angular Router types) but requirement-system-agnostic.\n//\n// Relationship to provideRouteScopedRequirements():\n// - provideRouteScopedRequirements() is a lower-level DI-scope helper.\n// - This module is the canonical path for Angular Router auth requirement\n// declaration when full-route aggregation is needed.\n//\n// Key sentinel note:\n// DEFAULT_ROUTE_REQUIREMENTS_KEY is defined in router.ts (AuthRouteAdapter's\n// companion constant). ROUTE_REQUIREMENTS_DATA_KEY exported here is its\n// semantic alias — both hold the same value (\"authRequirements\").\n// Adopters may use either name; they are interchangeable.\n//\n// Stability: provisional\n\nimport type { ActivatedRouteSnapshot } from \"@angular/router\";\nimport {\n\ttype AuthRequirement,\n\tRequirementsClientSetComposition,\n} from \"@securitydept/client/auth-coordination\";\nimport { DEFAULT_ROUTE_REQUIREMENTS_KEY } from \"./router\";\n\n// ---------------------------------------------------------------------------\n// Route data key\n// ---------------------------------------------------------------------------\n\n/**\n * Default key for auth requirements in Angular route `data`.\n *\n * Semantic alias for {@link DEFAULT_ROUTE_REQUIREMENTS_KEY} (defined in\n * `router.ts`). Both hold the same value (`\"authRequirements\"`).\n * Use either name — they are interchangeable.\n *\n * Set this key in `Route.data` to declare auth requirements for a route segment:\n * ```ts\n * { path: \"dashboard\", data: withRouteRequirements([{ id: \"session\", kind: \"session\" }]) }\n * ```\n *\n * The key is also read by {@link AuthRouteAdapter} when projecting snapshots.\n *\n * @see {@link withRouteRequirements}\n * @see {@link extractFullRouteRequirements}\n */\nexport const ROUTE_REQUIREMENTS_DATA_KEY = DEFAULT_ROUTE_REQUIREMENTS_KEY;\n\n/**\n * Default key for the route-level composition strategy in Angular route `data`.\n *\n * Used together with {@link ROUTE_REQUIREMENTS_DATA_KEY}. The default\n * composition is `merge` when the key is omitted.\n */\nexport const ROUTE_REQUIREMENTS_COMPOSITION_DATA_KEY =\n\t\"authRequirementsComposition\";\n\n/**\n * Route-level auth requirement declaration stored in Angular route `data`.\n */\nexport interface RouteRequirementsDeclaration {\n\trequirements: readonly AuthRequirement[];\n\tcomposition: RequirementsClientSetComposition;\n}\n\n/**\n * Options for {@link withRouteRequirements}.\n */\nexport interface WithRouteRequirementsOptions {\n\t/**\n\t * How this route segment composes with its parent route chain.\n\t * @default RequirementsClientSetComposition.Merge\n\t */\n\tcomposition?: RequirementsClientSetComposition;\n\n\t/**\n\t * Additional route data properties to merge into the returned object.\n\t */\n\textra?: Record<string, unknown>;\n}\n\n// ---------------------------------------------------------------------------\n// Declaration helper\n// ---------------------------------------------------------------------------\n\n/**\n * Build an Angular route `data` object declaring auth requirements for a\n * single route segment.\n *\n * Use this as the `data` field in an Angular `Route` config. Nested routes\n * can declare their own requirements; a full-route aggregation guard will\n * walk the entire `pathFromRoot` chain to collect all requirements in one pass.\n *\n * @example\n * ```ts\n * // Parent route declares base requirement\n * {\n * path: \"app\",\n * data: withRouteRequirements([{ id: \"session\", kind: \"session\" }]),\n * children: [\n * // Child route adds an additional requirement\n * {\n * path: \"admin\",\n * data: withRouteRequirements([{ id: \"admin-oidc\", kind: \"backend_oidc\" }]),\n * canActivate: [createTokenSetRouteAggregationGuard(...)],\n * },\n * ],\n * }\n * ```\n *\n * @param requirements - One or more auth requirements for this route segment.\n * @param extra - Optional additional data properties to merge.\n */\nexport function withRouteRequirements(\n\trequirements: AuthRequirement[],\n\toptionsOrExtra?: WithRouteRequirementsOptions | Record<string, unknown>,\n\tmaybeExtra?: Record<string, unknown>,\n): Record<string, unknown> {\n\tconst { composition, extra } = normalizeRequirementOptions(\n\t\toptionsOrExtra,\n\t\tmaybeExtra,\n\t);\n\treturn {\n\t\t...extra,\n\t\t[ROUTE_REQUIREMENTS_DATA_KEY]: requirements,\n\t\t[ROUTE_REQUIREMENTS_COMPOSITION_DATA_KEY]: composition,\n\t};\n}\n\n// ---------------------------------------------------------------------------\n// Aggregation helper\n// ---------------------------------------------------------------------------\n\n/**\n * Extract and flatten auth requirements from a complete Angular route chain.\n *\n * Walks all segments from root to leaf (from `leafRoute.pathFromRoot`)\n * and concatenates the declared {@link AuthRequirement} arrays in order.\n * Requirements from ancestor routes appear before requirements from\n * descendant routes. Duplicate `id` values are NOT de-duplicated here —\n * the caller (guard / enforcement layer) is responsible for deduplication\n * or merge logic.\n *\n * This is the extraction counter-part to {@link withRouteRequirements}.\n * A full-route aggregation guard calls this once and hands the complete\n * flat array to the planner / enforcement layer.\n *\n * @param leafRoute - The leaf `ActivatedRouteSnapshot` from the guard call.\n * @param requirementsKey - Override the route data key (default: `\"authRequirements\"`).\n */\nexport function extractFullRouteRequirements(\n\tleafRoute: ActivatedRouteSnapshot,\n\trequirementsKey = ROUTE_REQUIREMENTS_DATA_KEY,\n\tcompositionKey = ROUTE_REQUIREMENTS_COMPOSITION_DATA_KEY,\n): AuthRequirement[] {\n\tconst chain = leafRoute.pathFromRoot ?? [leafRoute];\n\tlet result: AuthRequirement[] = [];\n\tfor (const segment of chain) {\n\t\tconst raw =\n\t\t\tsegment.data[requirementsKey] ??\n\t\t\tsegment.routeConfig?.data?.[requirementsKey];\n\t\tconst composition =\n\t\t\treadRouteComposition(segment, compositionKey) ??\n\t\t\tRequirementsClientSetComposition.Merge;\n\t\tconst requirements = Array.isArray(raw) ? (raw as AuthRequirement[]) : [];\n\t\tresult = resolveEffectiveRequirements(result, {\n\t\t\tcomposition,\n\t\t\trequirements,\n\t\t});\n\t}\n\treturn result;\n}\n\n/**\n * Resolve the effective auth requirements by composing the parent chain with a\n * child route declaration.\n *\n * Composition semantics mirror `resolveEffectiveClientSet()`:\n * - `inherit` keeps the parent requirements unchanged\n * - `merge` appends child requirements and replaces same-id parent entries\n * - `replace` discards the parent chain and uses only the child's requirements\n */\nexport function resolveEffectiveRequirements(\n\tparentRequirements: readonly AuthRequirement[],\n\tchild: RouteRequirementsDeclaration,\n): AuthRequirement[] {\n\tswitch (child.composition) {\n\t\tcase RequirementsClientSetComposition.Inherit:\n\t\t\treturn [...parentRequirements];\n\n\t\tcase RequirementsClientSetComposition.Merge: {\n\t\t\tconst merged = new Map<string, AuthRequirement>();\n\t\t\tfor (const requirement of parentRequirements) {\n\t\t\t\tmerged.set(requirement.id, requirement);\n\t\t\t}\n\t\t\tfor (const requirement of child.requirements) {\n\t\t\t\tmerged.set(requirement.id, requirement);\n\t\t\t}\n\t\t\treturn [...merged.values()];\n\t\t}\n\n\t\tcase RequirementsClientSetComposition.Replace:\n\t\t\treturn [...child.requirements];\n\n\t\tdefault: {\n\t\t\tconst _exhaustive: never = child.composition;\n\t\t\tthrow new Error(\n\t\t\t\t`[resolveEffectiveRequirements] Unknown composition: ${_exhaustive}`,\n\t\t\t);\n\t\t}\n\t}\n}\n\nfunction normalizeRequirementOptions(\n\toptionsOrExtra?: WithRouteRequirementsOptions | Record<string, unknown>,\n\tmaybeExtra?: Record<string, unknown>,\n): {\n\tcomposition: RequirementsClientSetComposition;\n\textra?: Record<string, unknown>;\n} {\n\tif (\n\t\toptionsOrExtra &&\n\t\t(\"composition\" in optionsOrExtra || \"extra\" in optionsOrExtra)\n\t) {\n\t\tconst options = optionsOrExtra as WithRouteRequirementsOptions;\n\t\treturn {\n\t\t\tcomposition:\n\t\t\t\toptions.composition ?? RequirementsClientSetComposition.Merge,\n\t\t\textra: maybeExtra ?? options.extra,\n\t\t};\n\t}\n\n\treturn {\n\t\tcomposition: RequirementsClientSetComposition.Merge,\n\t\textra: optionsOrExtra as Record<string, unknown> | undefined,\n\t};\n}\n\nfunction readRouteComposition(\n\tsegment: ActivatedRouteSnapshot,\n\tcompositionKey: string,\n): RequirementsClientSetComposition | undefined {\n\tconst raw =\n\t\tsegment.data[compositionKey] ?? segment.routeConfig?.data?.[compositionKey];\n\tif (\n\t\traw === RequirementsClientSetComposition.Inherit ||\n\t\traw === RequirementsClientSetComposition.Merge ||\n\t\traw === RequirementsClientSetComposition.Replace\n\t) {\n\t\treturn raw;\n\t}\n\treturn undefined;\n}\n","// Angular signal / Observable bridge utilities\n//\n// Canonical import path:\n// import { bridgeToAngularSignal, signalToObservable } from \"@securitydept/client-angular\"\n//\n// These utilities convert SDK-native ReadableSignalTrait values to Angular-native\n// primitives (WritableSignal, Observable) so that framework adapter packages\n// can surface reactive state using idiomatic Angular APIs.\n//\n// Owner: @securitydept/client-angular — these are generic framework bridges,\n// not token-set-specific utilities. All Angular adapters (basic-auth, session,\n// token-set, …) should import from here instead of implementing their own.\n//\n// Stability: provisional (framework adapter)\n\nimport type { WritableSignal } from \"@angular/core\";\nimport type { ReadableSignalTrait } from \"@securitydept/client\";\nimport { Observable } from \"rxjs\";\n\n/**\n * Bridge an SDK `ReadableSignalTrait` to an Angular writable signal.\n *\n * Immediately syncs the current value, then subscribes to future changes.\n *\n * @returns Cleanup function that unsubscribes from the SDK signal.\n */\nexport function bridgeToAngularSignal<T>(\n\tsource: ReadableSignalTrait<T>,\n\ttarget: WritableSignal<T>,\n): () => void {\n\ttarget.set(source.get());\n\treturn source.subscribe(() => {\n\t\ttarget.set(source.get());\n\t});\n}\n\n/**\n * Bridge an SDK `ReadableSignalTrait` to an RxJS Observable.\n *\n * The observable emits the current value immediately on subscribe, then\n * emits whenever the SDK signal value changes. Completes on unsubscribe.\n */\nexport function signalToObservable<T>(\n\tsource: ReadableSignalTrait<T>,\n): Observable<T> {\n\treturn new Observable<T>((subscriber) => {\n\t\tsubscriber.next(source.get());\n\t\tconst unsubscribe = source.subscribe(() => {\n\t\t\tsubscriber.next(source.get());\n\t\t});\n\t\treturn () => unsubscribe();\n\t});\n}\n","/*\n * Public API Surface of @securitydept/client-angular\n */\n\nexport * from \"./lib/page-environment\";\nexport * from \"./lib/planner-host\";\nexport * from \"./lib/route-requirements\";\nexport * from \"./lib/router\";\nexport * from \"./lib/signal-bridge\";\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@securitydept/client-angular",
|
|
3
|
-
"version": "0.3.0-beta.
|
|
3
|
+
"version": "0.3.0-beta.3",
|
|
4
4
|
"description": "Client Angular of the SecurityDept TypeScript SDK, a layered authentication and authorization toolkit built as reusable Rust crates, a TypeScript client SDK workspace, and reference server/web apps.",
|
|
5
5
|
"author": "Zhou Yeheng <root@aitiotekt.com>",
|
|
6
6
|
"license": "MIT",
|
|
@@ -44,7 +44,7 @@
|
|
|
44
44
|
"@angular/core": ">=19.0.0",
|
|
45
45
|
"@angular/router": ">=19.0.0",
|
|
46
46
|
"rxjs": ">=7.0.0",
|
|
47
|
-
"@securitydept/client": "0.3.0-beta.
|
|
47
|
+
"@securitydept/client": "0.3.0-beta.3"
|
|
48
48
|
},
|
|
49
49
|
"module": "fesm2022/securitydept-client-angular.mjs",
|
|
50
50
|
"typings": "types/securitydept-client-angular.d.ts",
|
|
@@ -1,11 +1,32 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
|
-
import { InjectionToken, EnvironmentProviders, WritableSignal } from '@angular/core';
|
|
2
|
+
import { InjectionToken, Provider, EnvironmentProviders, WritableSignal } from '@angular/core';
|
|
3
|
+
import { PageClientEnvironment } from '@securitydept/client/web';
|
|
3
4
|
import { PlannerHost, AuthGuardClientOption, CandidateSelector, ScopedRequirementsClientSet, AuthRequirement, RequirementsClientSetComposition, RouteMatchNode } from '@securitydept/client/auth-coordination';
|
|
4
5
|
export { resolveEffectiveClientSet } from '@securitydept/client/auth-coordination';
|
|
5
6
|
import { ActivatedRouteSnapshot } from '@angular/router';
|
|
6
7
|
import { ReadableSignalTrait } from '@securitydept/client';
|
|
7
8
|
import { Observable } from 'rxjs';
|
|
8
9
|
|
|
10
|
+
type PageClientEnvironmentValue = PageClientEnvironment;
|
|
11
|
+
interface PageClientEnvironmentService {
|
|
12
|
+
resolvePageEnvironment(): Promise<PageClientEnvironmentValue>;
|
|
13
|
+
}
|
|
14
|
+
type PageClientEnvironmentResolver = () => PageClientEnvironmentValue | Promise<PageClientEnvironmentValue>;
|
|
15
|
+
type PageClientEnvironmentSource = PageClientEnvironmentValue | PageClientEnvironmentService | PageClientEnvironmentResolver;
|
|
16
|
+
declare const PAGE_CLIENT_ENVIRONMENT: InjectionToken<PageClientEnvironmentSource | undefined>;
|
|
17
|
+
interface ProvidePageClientEnvironmentOptions {
|
|
18
|
+
/**
|
|
19
|
+
* Stable host-owned page environment source used by Angular page-only helpers.
|
|
20
|
+
*
|
|
21
|
+
* Accepts an already-materialized page environment object, a provider-scoped
|
|
22
|
+
* `ClientEnvironmentService`, or an inject-safe stable resolver returning the
|
|
23
|
+
* page capability synchronously or asynchronously.
|
|
24
|
+
*/
|
|
25
|
+
environment: PageClientEnvironmentSource;
|
|
26
|
+
}
|
|
27
|
+
declare function providePageClientEnvironment(options: ProvidePageClientEnvironmentOptions): Provider;
|
|
28
|
+
declare function resolvePageClientEnvironmentSource(source: PageClientEnvironmentSource | undefined, onMissing: () => never): Promise<PageClientEnvironmentValue>;
|
|
29
|
+
|
|
9
30
|
/**
|
|
10
31
|
* DI token for the shared {@link PlannerHost}.
|
|
11
32
|
*
|
|
@@ -331,6 +352,6 @@ declare function bridgeToAngularSignal<T>(source: ReadableSignalTrait<T>, target
|
|
|
331
352
|
*/
|
|
332
353
|
declare function signalToObservable<T>(source: ReadableSignalTrait<T>): Observable<T>;
|
|
333
354
|
|
|
334
|
-
export { AUTH_PLANNER_HOST, AUTH_REQUIREMENTS_CLIENT_SET, AuthRouteAdapter, DEFAULT_ROUTE_REQUIREMENTS_KEY, ROUTE_REQUIREMENTS_COMPOSITION_DATA_KEY, ROUTE_REQUIREMENTS_DATA_KEY, bridgeToAngularSignal, extractFullRouteRequirements, injectPlannerHost, provideAuthPlannerHost, provideRouteScopedRequirements, resolveEffectiveRequirements, signalToObservable, withRouteRequirements };
|
|
335
|
-
export type { AuthRouteAdapterOptions, ProvideAuthPlannerHostOptions, RouteGuardResult, RouteRequirementsDeclaration, WithRouteRequirementsOptions };
|
|
355
|
+
export { AUTH_PLANNER_HOST, AUTH_REQUIREMENTS_CLIENT_SET, AuthRouteAdapter, DEFAULT_ROUTE_REQUIREMENTS_KEY, PAGE_CLIENT_ENVIRONMENT, ROUTE_REQUIREMENTS_COMPOSITION_DATA_KEY, ROUTE_REQUIREMENTS_DATA_KEY, bridgeToAngularSignal, extractFullRouteRequirements, injectPlannerHost, provideAuthPlannerHost, providePageClientEnvironment, provideRouteScopedRequirements, resolveEffectiveRequirements, resolvePageClientEnvironmentSource, signalToObservable, withRouteRequirements };
|
|
356
|
+
export type { AuthRouteAdapterOptions, PageClientEnvironmentResolver, PageClientEnvironmentService, PageClientEnvironmentSource, PageClientEnvironmentValue, ProvideAuthPlannerHostOptions, ProvidePageClientEnvironmentOptions, RouteGuardResult, RouteRequirementsDeclaration, WithRouteRequirementsOptions };
|
|
336
357
|
//# sourceMappingURL=securitydept-client-angular.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"securitydept-client-angular.d.ts","sources":["../../src/lib/planner-host.ts","../../src/lib/route-requirements.ts","../../src/lib/router.ts","../../src/lib/signal-bridge.ts"],"mappings":"
|
|
1
|
+
{"version":3,"file":"securitydept-client-angular.d.ts","sources":["../../src/lib/page-environment.ts","../../src/lib/planner-host.ts","../../src/lib/route-requirements.ts","../../src/lib/router.ts","../../src/lib/signal-bridge.ts"],"mappings":";;;;;;;;;AAMM,KAAM,0BAA0B,GAAG,qBAAqB;UAE7C,4BAA4B;AAC5C,8BAA0B,OAAO,CAAC,0BAA0B;AAC5D;AAEK,KAAM,6BAA6B,SACtC,0BAA0B,GAC1B,OAAO,CAAC,0BAA0B;AAE/B,KAAM,2BAA2B,GACpC,0BAA0B,GAC1B,4BAA4B,GAC5B,6BAA6B;AAEhC,cAAa,uBAAuB,EAAA,cAAA,CAAA,2BAAA;UAOnB,mCAAmC;AACnD;;;;;;AAMG;iBACU,2BAA2B;AACxC;AAED,iBAAgB,4BAA4B,UAClC,mCAAmC,GAC1C,QAAQ;AAOX,iBAAgB,kCAAkC,SACzC,2BAA2B,uCAEjC,OAAO,CAAC,0BAA0B;;ACXrC;;;;;AAKG;AACH,cAAa,iBAAiB,EAAA,cAAA,CAAA,WAAA;AAI9B;;AAEG;UACc,6BAA6B;AAC7C;;;AAGG;sBACe,iBAAiB;AACnC;AAED;;;;;;;;;;;;;;;;;;;;;;AAsBG;AACH,iBAAgB,sBAAsB,WAC3B,6BAA6B,GACrC,oBAAoB;AAUvB;;;;;;;;;;;AAWG;AACH,iBAAgB,iBAAiB,IAAI,WAAW;AAgBhD;;;;;;;;;AASG;AACH,cAAa,4BAA4B,EAAA,cAAA,UAAA,qBAAA;AAIzC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA+DG;AACH,iBAAgB,8BAA8B,YAClC,2BAA2B,UAAU,2BAA2B,IACzE,oBAAoB;;ACpKvB;;;;;;;;;;;;;;;;AAgBG;AACH,cAAa,2BAA2B;AAExC;;;;;AAKG;AACH,cAAa,uCAAuC;AAGpD;;AAEG;UACc,4BAA4B;AAC5C,2BAAuB,eAAe;iBACzB,gCAAgC;AAC7C;AAED;;AAEG;UACc,4BAA4B;AAC5C;;;AAGG;kBACW,gCAAgC;AAE9C;;AAEG;YACK,MAAM;AACd;AAMD;;;;;;;;;;;;;;;;;;;;;;;;;;;AA2BG;AACH,iBAAgB,qBAAqB,eACtB,eAAe,qBACZ,4BAA4B,GAAG,MAAM,gCACzC,MAAM,oBACjB,MAAM;AAgBT;;;;;;;;;;;;;;;;AAgBG;AACH,iBAAgB,4BAA4B,YAChC,sBAAsB,sDAG/B,eAAe;AAmBlB;;;;;;;;AAQG;AACH,iBAAgB,4BAA4B,8BACd,eAAe,WACrC,4BAA4B,GACjC,eAAe;;ACvKlB;UACiB,uBAAuB;AACvC;;;;AAIG;;AAEH;AAED;AACA,cAAa,8BAA8B;AAM3C;UACiB,gBAAgB;;;;AAIhC,wBAAoB,eAAe;AACnC;AAMD;;;;;;;;;;;;;;;;;AAiBG;AACH,cACa,gBAAgB;AAC5B;;;;;;;AAOG;iCAES,sBAAsB,YACvB,uBAAuB,GAC/B,cAAc;AAMjB;;;;;;AAMG;AACH,4CACoB,sBAAsB,cAC/B,uBAAuB,GAC/B,cAAc;AAKjB;;;;;;AAMG;AACH,qBACY,sBAAsB;8CAEM,cAAc;AACpD;;AAEC,gCAAoB,eAAe;;AAEpC,iBACS,uBAAuB,GAC/B,gBAAgB;AAUnB;AAaA;yCAzEY,gBAAgB;6CAAhB,gBAAgB;AA+E5B;;ACzID;;;;;;AAMG;AACH,iBAAgB,qBAAqB,YAC5B,mBAAmB,aACnB,cAAc;AAQvB;;;;;AAKG;AACH,iBAAgB,kBAAkB,YACzB,mBAAmB,MACzB,UAAU;;;;","names":[]}
|