@securitydept/client 0.3.0-beta.1 → 0.3.0-beta.11
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.
- package/README.md +6 -0
- package/dist/create-i5VyYgN6.mjs +989 -0
- package/dist/create-i5VyYgN6.mjs.map +1 -0
- package/dist/handle-DwMgqe7R.mjs +638 -0
- package/dist/handle-DwMgqe7R.mjs.map +1 -0
- package/dist/index-Bo1BtjZH.d.mts +132 -0
- package/dist/index-CFAJ969E.d.mts +674 -0
- package/dist/index-CbeZ3AfB.d.mts +1680 -0
- package/dist/index.d.mts +3 -353
- package/dist/index.mjs +1196 -401
- package/dist/index.mjs.map +1 -1
- package/dist/router-at5bTdJQ.mjs +245 -0
- package/dist/router-at5bTdJQ.mjs.map +1 -0
- package/dist/rx/index.d.mts +68 -0
- package/dist/rx/index.mjs +2 -0
- package/dist/rx-DM6Ouv-m.mjs +1119 -0
- package/dist/rx-DM6Ouv-m.mjs.map +1 -0
- package/dist/server/index.d.mts +20 -0
- package/dist/server/index.mjs +29 -0
- package/dist/server/index.mjs.map +1 -0
- package/dist/test/index.d.mts +101 -0
- package/dist/test/index.mjs +270 -0
- package/dist/test/index.mjs.map +1 -0
- package/dist/uri-string-BPNbIMgv.mjs +300 -0
- package/dist/uri-string-BPNbIMgv.mjs.map +1 -0
- package/dist/web/index.d.mts +82 -337
- package/dist/web/index.mjs +334 -337
- package/dist/web/index.mjs.map +1 -1
- package/dist/webext/index.d.mts +73 -0
- package/dist/webext/index.mjs +231 -0
- package/dist/webext/index.mjs.map +1 -0
- package/package.json +28 -21
- package/dist/auth-coordination/index.d.mts +0 -198
- package/dist/auth-coordination/index.mjs +0 -107
- package/dist/auth-coordination/index.mjs.map +0 -1
- package/dist/events/index.d.mts +0 -2
- package/dist/events/index.mjs +0 -2
- package/dist/events-BUlfsRfl.mjs +0 -127
- package/dist/events-BUlfsRfl.mjs.map +0 -1
- package/dist/fetch-transport-Bd5RyWj2.d.mts +0 -339
- package/dist/fetch-transport-DtnSRWAH.mjs +0 -631
- package/dist/fetch-transport-DtnSRWAH.mjs.map +0 -1
- package/dist/index-C_wgl6dW.d.mts +0 -102
- package/dist/index-DbYSFHDe.d.mts +0 -39
- package/dist/persistence/index.d.mts +0 -3
- package/dist/persistence/index.mjs +0 -2
- package/dist/persistence/web/index.d.mts +0 -16
- package/dist/persistence/web/index.mjs +0 -51
- package/dist/persistence/web/index.mjs.map +0 -1
- package/dist/persistence-CSB8770k.mjs +0 -108
- package/dist/persistence-CSB8770k.mjs.map +0 -1
- package/dist/planner-host-CPyGNyQV.d.mts +0 -190
- package/dist/planner-host-CV38bMSn.mjs +0 -195
- package/dist/planner-host-CV38bMSn.mjs.map +0 -1
- package/dist/types-C59fcM5W.d.mts +0 -52
- package/dist/types-DQc088ZP.d.mts +0 -32
- package/dist/web-router/index.d.mts +0 -259
- package/dist/web-router/index.mjs +0 -395
- package/dist/web-router/index.mjs.map +0 -1
|
@@ -1,198 +0,0 @@
|
|
|
1
|
-
import { a as PlannerHostResult, c as ScopedRequirementsClientSet, i as PlannerHost, l as createPlannerHost, n as CandidateSelector, o as RequirementsClientSet, r as CreatePlannerHostOptions, s as RequirementsClientSetComposition, t as AuthGuardClientOption, u as resolveEffectiveClientSet } from "../planner-host-CPyGNyQV.mjs";
|
|
2
|
-
|
|
3
|
-
//#region src/auth-coordination/requirement-planner.d.ts
|
|
4
|
-
/** A single auth requirement within an orchestration plan. */
|
|
5
|
-
interface AuthRequirement {
|
|
6
|
-
/** Unique identifier for this requirement within the plan. */
|
|
7
|
-
id: string;
|
|
8
|
-
/**
|
|
9
|
-
* The kind of auth requirement.
|
|
10
|
-
*
|
|
11
|
-
* An opaque string. Each auth-context family (token-set, session, basic-auth)
|
|
12
|
-
* or adopter project may define its own named constants.
|
|
13
|
-
*
|
|
14
|
-
* @example "session", "frontend_oidc", "backend_oidc", "custom"
|
|
15
|
-
*/
|
|
16
|
-
kind: string;
|
|
17
|
-
/** Human-readable label (for logging / debugging). */
|
|
18
|
-
label?: string;
|
|
19
|
-
/** Arbitrary metadata the adopter can attach. */
|
|
20
|
-
attributes?: Record<string, unknown>;
|
|
21
|
-
}
|
|
22
|
-
/** Outcome of resolving a single requirement. */
|
|
23
|
-
declare const ResolutionStatus: {
|
|
24
|
-
readonly Fulfilled: "fulfilled";
|
|
25
|
-
readonly Failed: "failed";
|
|
26
|
-
readonly Skipped: "skipped";
|
|
27
|
-
};
|
|
28
|
-
type ResolutionStatus = (typeof ResolutionStatus)[keyof typeof ResolutionStatus];
|
|
29
|
-
/** The resolution result for a single requirement. */
|
|
30
|
-
interface RequirementResolution {
|
|
31
|
-
/** The requirement ID this resolution applies to. */
|
|
32
|
-
requirementId: string;
|
|
33
|
-
/** Outcome status. */
|
|
34
|
-
status: ResolutionStatus;
|
|
35
|
-
/** Optional error or reason for failure/skip. */
|
|
36
|
-
reason?: string;
|
|
37
|
-
}
|
|
38
|
-
/** Overall plan status. */
|
|
39
|
-
declare const PlanStatus: {
|
|
40
|
-
/** There are still pending requirements. */readonly Pending: "pending"; /** All requirements have been resolved. */
|
|
41
|
-
readonly Settled: "settled";
|
|
42
|
-
};
|
|
43
|
-
type PlanStatus = (typeof PlanStatus)[keyof typeof PlanStatus];
|
|
44
|
-
/** Read-only snapshot of the current plan state. */
|
|
45
|
-
interface PlanSnapshot {
|
|
46
|
-
/** Overall plan status. */
|
|
47
|
-
status: PlanStatus;
|
|
48
|
-
/** The next pending requirement, or `null` if settled. */
|
|
49
|
-
nextPending: AuthRequirement | null;
|
|
50
|
-
/** All resolutions collected so far (in order). */
|
|
51
|
-
resolutions: readonly RequirementResolution[];
|
|
52
|
-
/** Total requirement count. */
|
|
53
|
-
total: number;
|
|
54
|
-
/** Number of resolved requirements. */
|
|
55
|
-
resolved: number;
|
|
56
|
-
}
|
|
57
|
-
/** Error thrown when a planner operation is invalid. */
|
|
58
|
-
declare class RequirementPlannerError extends Error {
|
|
59
|
-
constructor(message: string);
|
|
60
|
-
}
|
|
61
|
-
/** Options for creating a {@link RequirementPlanner}. */
|
|
62
|
-
interface CreateRequirementPlannerOptions {
|
|
63
|
-
/** Ordered list of requirements to fulfill. */
|
|
64
|
-
requirements: readonly AuthRequirement[];
|
|
65
|
-
}
|
|
66
|
-
/**
|
|
67
|
-
* Headless multi-requirement planner.
|
|
68
|
-
*
|
|
69
|
-
* Drives a sequential requirement fulfillment flow:
|
|
70
|
-
* 1. Call {@link snapshot} to see what's pending.
|
|
71
|
-
* 2. Resolve the {@link PlanSnapshot.nextPending} requirement.
|
|
72
|
-
* 3. Call {@link resolve} with the result.
|
|
73
|
-
* 4. Repeat until {@link PlanSnapshot.status} is `"settled"`.
|
|
74
|
-
*
|
|
75
|
-
* @example
|
|
76
|
-
* ```ts
|
|
77
|
-
* import { createRequirementPlanner, PlanStatus, ResolutionStatus } from "@securitydept/client/auth-coordination";
|
|
78
|
-
*
|
|
79
|
-
* const planner = createRequirementPlanner({
|
|
80
|
-
* requirements: [
|
|
81
|
-
* { id: "session", kind: "session" },
|
|
82
|
-
* { id: "api-token", kind: "backend_oidc" },
|
|
83
|
-
* ],
|
|
84
|
-
* });
|
|
85
|
-
*
|
|
86
|
-
* let snap = planner.snapshot();
|
|
87
|
-
* while (snap.status === PlanStatus.Pending) {
|
|
88
|
-
* const req = snap.nextPending!;
|
|
89
|
-
* // ... perform auth action for req.kind ...
|
|
90
|
-
* planner.resolve({ requirementId: req.id, status: ResolutionStatus.Fulfilled });
|
|
91
|
-
* snap = planner.snapshot();
|
|
92
|
-
* }
|
|
93
|
-
* // snap.status === PlanStatus.Settled
|
|
94
|
-
* ```
|
|
95
|
-
*/
|
|
96
|
-
interface RequirementPlanner {
|
|
97
|
-
/** Get a read-only snapshot of the current plan state. */
|
|
98
|
-
snapshot(): PlanSnapshot;
|
|
99
|
-
/** Resolve the next pending requirement. */
|
|
100
|
-
resolve(resolution: RequirementResolution): void;
|
|
101
|
-
/** Reset the planner to its initial state. */
|
|
102
|
-
reset(): void;
|
|
103
|
-
}
|
|
104
|
-
/**
|
|
105
|
-
* Create a headless requirement planner.
|
|
106
|
-
*
|
|
107
|
-
* @see {@link RequirementPlanner} for usage.
|
|
108
|
-
*/
|
|
109
|
-
declare function createRequirementPlanner(options: CreateRequirementPlannerOptions): RequirementPlanner;
|
|
110
|
-
//#endregion
|
|
111
|
-
//#region src/auth-coordination/route-orchestrator.d.ts
|
|
112
|
-
/**
|
|
113
|
-
* A single node in a matched route chain.
|
|
114
|
-
*
|
|
115
|
-
* The adopter maps their framework's route match result into this contract:
|
|
116
|
-
* - Angular: `ActivatedRouteSnapshot` → `RouteMatchNode`
|
|
117
|
-
* - TanStack Router: matched route entry → `RouteMatchNode`
|
|
118
|
-
* - Any other: route guard / middleware context → `RouteMatchNode`
|
|
119
|
-
*/
|
|
120
|
-
interface RouteMatchNode {
|
|
121
|
-
/** Route segment identifier (e.g. route name or path pattern). */
|
|
122
|
-
routeId: string;
|
|
123
|
-
/** Auth requirements declared on this route segment. */
|
|
124
|
-
requirements: readonly AuthRequirement[];
|
|
125
|
-
}
|
|
126
|
-
/** Chooser decision: which provider/action to use for a pending requirement. */
|
|
127
|
-
interface ChooserDecision {
|
|
128
|
-
/** The requirement ID this decision applies to. */
|
|
129
|
-
requirementId: string;
|
|
130
|
-
/** The chosen provider or action identifier. */
|
|
131
|
-
providerId: string;
|
|
132
|
-
/** Optional metadata for the chosen action. */
|
|
133
|
-
metadata?: Record<string, unknown>;
|
|
134
|
-
}
|
|
135
|
-
/** Snapshot of the current route orchestration state. */
|
|
136
|
-
interface RouteOrchestrationSnapshot {
|
|
137
|
-
/** The matched route chain, or empty if no route is active. */
|
|
138
|
-
matchedRoutes: readonly RouteMatchNode[];
|
|
139
|
-
/** The leaf route ID (last in chain), or null if no route is active. */
|
|
140
|
-
activeRouteId: string | null;
|
|
141
|
-
/** The planner snapshot for the merged requirements, or null if no route. */
|
|
142
|
-
plan: PlanSnapshot | null;
|
|
143
|
-
/** Whether all merged requirements are fully settled. */
|
|
144
|
-
settled: boolean;
|
|
145
|
-
/** The pending requirement that needs a chooser decision, or null. */
|
|
146
|
-
pendingRequirement: AuthRequirement | null;
|
|
147
|
-
}
|
|
148
|
-
/** Options for {@link createRouteRequirementOrchestrator}. */
|
|
149
|
-
interface CreateRouteRequirementOrchestratorOptions {
|
|
150
|
-
/**
|
|
151
|
-
* Optional callback fired when the orchestrator needs the adopter to
|
|
152
|
-
* act on a pending requirement (e.g. show a chooser UI or auto-redirect).
|
|
153
|
-
*/
|
|
154
|
-
onPendingRequirement?: (requirement: AuthRequirement) => void;
|
|
155
|
-
/**
|
|
156
|
-
* Optional callback fired when all requirements for the active route
|
|
157
|
-
* are settled.
|
|
158
|
-
*/
|
|
159
|
-
onSettled?: (routeId: string, resolutions: readonly RequirementResolution[]) => void;
|
|
160
|
-
}
|
|
161
|
-
/**
|
|
162
|
-
* Headless route requirement orchestrator.
|
|
163
|
-
*
|
|
164
|
-
* Driven by a matched route chain: the adopter maps their framework's
|
|
165
|
-
* route match result into `RouteMatchNode[]` and calls `activateMatchedRoutes`.
|
|
166
|
-
* Parent requirements are inherited; children append.
|
|
167
|
-
*/
|
|
168
|
-
interface RouteRequirementOrchestrator {
|
|
169
|
-
/** Get a snapshot of the current route orchestration state. */
|
|
170
|
-
snapshot(): RouteOrchestrationSnapshot;
|
|
171
|
-
/**
|
|
172
|
-
* Activate a matched route chain.
|
|
173
|
-
*
|
|
174
|
-
* Requirements are inherited: parent requirements come first, children append.
|
|
175
|
-
* On route transition, shared-prefix requirements and their resolutions
|
|
176
|
-
* are preserved; diverging requirements are re-planned.
|
|
177
|
-
*/
|
|
178
|
-
activateMatchedRoutes(matchedRoutes: readonly RouteMatchNode[]): void;
|
|
179
|
-
/**
|
|
180
|
-
* Resolve the current pending requirement.
|
|
181
|
-
* Advances to the next requirement or settles the plan.
|
|
182
|
-
*/
|
|
183
|
-
resolve(resolution: RequirementResolution): void;
|
|
184
|
-
/**
|
|
185
|
-
* Record a chooser decision for the current pending requirement.
|
|
186
|
-
*/
|
|
187
|
-
applyChooserDecision(decision: ChooserDecision): void;
|
|
188
|
-
/**
|
|
189
|
-
* Reset the active route (e.g. on navigation away or logout).
|
|
190
|
-
*/
|
|
191
|
-
deactivateRoute(): void;
|
|
192
|
-
/** All chooser decisions made during the current route activation. */
|
|
193
|
-
readonly decisions: readonly ChooserDecision[];
|
|
194
|
-
}
|
|
195
|
-
declare function createRouteRequirementOrchestrator(options?: CreateRouteRequirementOrchestratorOptions): RouteRequirementOrchestrator;
|
|
196
|
-
//#endregion
|
|
197
|
-
export { type AuthGuardClientOption, type AuthRequirement, type CandidateSelector, type ChooserDecision, type CreatePlannerHostOptions, type CreateRequirementPlannerOptions, type CreateRouteRequirementOrchestratorOptions, type PlanSnapshot, PlanStatus, type PlannerHost, type PlannerHostResult, type RequirementPlanner, RequirementPlannerError, type RequirementResolution, type RequirementsClientSet, RequirementsClientSetComposition, ResolutionStatus, type RouteMatchNode, type RouteOrchestrationSnapshot, type RouteRequirementOrchestrator, type ScopedRequirementsClientSet, createPlannerHost, createRequirementPlanner, createRouteRequirementOrchestrator, resolveEffectiveClientSet };
|
|
198
|
-
//# sourceMappingURL=index.d.mts.map
|
|
@@ -1,107 +0,0 @@
|
|
|
1
|
-
import { a as RequirementPlannerError, i as PlanStatus, n as createPlannerHost, o as ResolutionStatus, r as resolveEffectiveClientSet, s as createRequirementPlanner, t as RequirementsClientSetComposition } from "../planner-host-CV38bMSn.mjs";
|
|
2
|
-
//#region src/auth-coordination/route-orchestrator.ts
|
|
3
|
-
/** Merge a matched route chain into a flat requirement list (parent-first). */
|
|
4
|
-
function mergeChainRequirements(chain) {
|
|
5
|
-
const merged = [];
|
|
6
|
-
const seenIds = /* @__PURE__ */ new Set();
|
|
7
|
-
for (const node of chain) for (const req of node.requirements) {
|
|
8
|
-
if (seenIds.has(req.id)) continue;
|
|
9
|
-
seenIds.add(req.id);
|
|
10
|
-
merged.push(req);
|
|
11
|
-
}
|
|
12
|
-
return merged;
|
|
13
|
-
}
|
|
14
|
-
/**
|
|
15
|
-
* Find the length of the shared requirement prefix between old and new chains.
|
|
16
|
-
* Used to determine which resolutions can be preserved on route transition.
|
|
17
|
-
*/
|
|
18
|
-
function sharedPrefixLength(oldReqs, newReqs) {
|
|
19
|
-
const limit = Math.min(oldReqs.length, newReqs.length);
|
|
20
|
-
for (let i = 0; i < limit; i++) if (oldReqs[i].id !== newReqs[i].id || oldReqs[i].kind !== newReqs[i].kind) return i;
|
|
21
|
-
return limit;
|
|
22
|
-
}
|
|
23
|
-
function createRouteRequirementOrchestrator(options = {}) {
|
|
24
|
-
let matchedRoutes = [];
|
|
25
|
-
let activeRouteId = null;
|
|
26
|
-
let planner = null;
|
|
27
|
-
let decisions = [];
|
|
28
|
-
let currentMergedReqs = [];
|
|
29
|
-
function emitPendingIfNeeded() {
|
|
30
|
-
if (!planner || !options.onPendingRequirement) return;
|
|
31
|
-
const snap = planner.snapshot();
|
|
32
|
-
if (snap.nextPending) options.onPendingRequirement(snap.nextPending);
|
|
33
|
-
}
|
|
34
|
-
function emitSettledIfNeeded() {
|
|
35
|
-
if (!planner || !activeRouteId || !options.onSettled) return;
|
|
36
|
-
const snap = planner.snapshot();
|
|
37
|
-
if (snap.status === PlanStatus.Settled) options.onSettled(activeRouteId, snap.resolutions);
|
|
38
|
-
}
|
|
39
|
-
function activateWithChain(chain) {
|
|
40
|
-
const newMerged = mergeChainRequirements(chain);
|
|
41
|
-
if (newMerged.length === 0) {
|
|
42
|
-
matchedRoutes = [...chain];
|
|
43
|
-
activeRouteId = chain.length > 0 ? chain[chain.length - 1].routeId : null;
|
|
44
|
-
planner = null;
|
|
45
|
-
currentMergedReqs = [];
|
|
46
|
-
decisions = [];
|
|
47
|
-
return;
|
|
48
|
-
}
|
|
49
|
-
const shared = sharedPrefixLength(currentMergedReqs, newMerged);
|
|
50
|
-
let preservedResolutions = [];
|
|
51
|
-
if (planner && shared > 0) preservedResolutions = planner.snapshot().resolutions.slice(0, shared);
|
|
52
|
-
const sharedReqIds = new Set(newMerged.slice(0, shared).map((r) => r.id));
|
|
53
|
-
decisions = decisions.filter((d) => sharedReqIds.has(d.requirementId));
|
|
54
|
-
matchedRoutes = [...chain];
|
|
55
|
-
activeRouteId = chain[chain.length - 1].routeId;
|
|
56
|
-
currentMergedReqs = newMerged;
|
|
57
|
-
planner = createRequirementPlanner({ requirements: newMerged });
|
|
58
|
-
for (const res of preservedResolutions) planner.resolve(res);
|
|
59
|
-
emitPendingIfNeeded();
|
|
60
|
-
emitSettledIfNeeded();
|
|
61
|
-
}
|
|
62
|
-
return {
|
|
63
|
-
snapshot() {
|
|
64
|
-
if (!planner || !activeRouteId) return {
|
|
65
|
-
matchedRoutes: [...matchedRoutes],
|
|
66
|
-
activeRouteId,
|
|
67
|
-
plan: null,
|
|
68
|
-
settled: matchedRoutes.length > 0 && currentMergedReqs.length === 0,
|
|
69
|
-
pendingRequirement: null
|
|
70
|
-
};
|
|
71
|
-
const plan = planner.snapshot();
|
|
72
|
-
return {
|
|
73
|
-
matchedRoutes: [...matchedRoutes],
|
|
74
|
-
activeRouteId,
|
|
75
|
-
plan,
|
|
76
|
-
settled: plan.status === PlanStatus.Settled,
|
|
77
|
-
pendingRequirement: plan.nextPending
|
|
78
|
-
};
|
|
79
|
-
},
|
|
80
|
-
activateMatchedRoutes(chain) {
|
|
81
|
-
activateWithChain(chain);
|
|
82
|
-
},
|
|
83
|
-
resolve(resolution) {
|
|
84
|
-
if (!planner) throw new Error("Cannot resolve: no active route");
|
|
85
|
-
planner.resolve(resolution);
|
|
86
|
-
emitSettledIfNeeded();
|
|
87
|
-
if (planner.snapshot().status === PlanStatus.Pending) emitPendingIfNeeded();
|
|
88
|
-
},
|
|
89
|
-
applyChooserDecision(decision) {
|
|
90
|
-
decisions.push(decision);
|
|
91
|
-
},
|
|
92
|
-
deactivateRoute() {
|
|
93
|
-
activeRouteId = null;
|
|
94
|
-
planner = null;
|
|
95
|
-
matchedRoutes = [];
|
|
96
|
-
decisions = [];
|
|
97
|
-
currentMergedReqs = [];
|
|
98
|
-
},
|
|
99
|
-
get decisions() {
|
|
100
|
-
return decisions;
|
|
101
|
-
}
|
|
102
|
-
};
|
|
103
|
-
}
|
|
104
|
-
//#endregion
|
|
105
|
-
export { PlanStatus, RequirementPlannerError, RequirementsClientSetComposition, ResolutionStatus, createPlannerHost, createRequirementPlanner, createRouteRequirementOrchestrator, resolveEffectiveClientSet };
|
|
106
|
-
|
|
107
|
-
//# sourceMappingURL=index.mjs.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":[],"sources":["../../src/auth-coordination/route-orchestrator.ts"],"sourcesContent":["// Shared auth route orchestrator — headless router integration baseline\n//\n// Canonical location: @securitydept/client/auth-coordination\n//\n// Provides a minimal, framework-agnostic glue layer between route-level auth\n// requirements and the RequirementPlanner, driven by a matched route chain\n// (not a single flat routeId).\n//\n// Core design choices (absorbing Angular Router + TanStack Router patterns):\n// - Input is a **matched route chain** (parent → child → grandchild),\n// mirroring Angular's `ActivatedRouteSnapshot[]` and TanStack's matched route tree.\n// - Parent requirements are **inherited** by children by default.\n// - Children can **append** additional requirements.\n// - The orchestrator merges the full chain into a single effective requirement plan.\n// - Route transitions diff the chain: shared prefix requirements/decisions\n// are preserved; diverging suffix requirements/decisions are discarded.\n//\n// Architecture boundary:\n// - This module does NOT own the router, render UI, or manage navigation.\n// - It provides the headless orchestration contract that the router calls into.\n// - The adopter is responsible for translating \"pending requirement\" into\n// the appropriate auth action (redirect, popup, etc.) and calling back\n// with the resolution.\n//\n// Owner rationale: This orchestrator depends only on RouteMatchNode[] (a shared\n// contract) and RequirementPlanner (also in this module). It does not depend on\n// token-set material, OIDC protocol details, or any framework specifics.\n// Canonical owner is @securitydept/client.\n\nimport type {\n\tAuthRequirement,\n\tPlanSnapshot,\n\tRequirementPlanner,\n\tRequirementResolution,\n} from \"./requirement-planner\";\nimport { createRequirementPlanner, PlanStatus } from \"./requirement-planner\";\n\n// ---------------------------------------------------------------------------\n// Route match node types\n// ---------------------------------------------------------------------------\n\n/**\n * A single node in a matched route chain.\n *\n * The adopter maps their framework's route match result into this contract:\n * - Angular: `ActivatedRouteSnapshot` → `RouteMatchNode`\n * - TanStack Router: matched route entry → `RouteMatchNode`\n * - Any other: route guard / middleware context → `RouteMatchNode`\n */\nexport interface RouteMatchNode {\n\t/** Route segment identifier (e.g. route name or path pattern). */\n\trouteId: string;\n\t/** Auth requirements declared on this route segment. */\n\trequirements: readonly AuthRequirement[];\n}\n\n/** Chooser decision: which provider/action to use for a pending requirement. */\nexport interface ChooserDecision {\n\t/** The requirement ID this decision applies to. */\n\trequirementId: string;\n\t/** The chosen provider or action identifier. */\n\tproviderId: string;\n\t/** Optional metadata for the chosen action. */\n\tmetadata?: Record<string, unknown>;\n}\n\n/** Snapshot of the current route orchestration state. */\nexport interface RouteOrchestrationSnapshot {\n\t/** The matched route chain, or empty if no route is active. */\n\tmatchedRoutes: readonly RouteMatchNode[];\n\t/** The leaf route ID (last in chain), or null if no route is active. */\n\tactiveRouteId: string | null;\n\t/** The planner snapshot for the merged requirements, or null if no route. */\n\tplan: PlanSnapshot | null;\n\t/** Whether all merged requirements are fully settled. */\n\tsettled: boolean;\n\t/** The pending requirement that needs a chooser decision, or null. */\n\tpendingRequirement: AuthRequirement | null;\n}\n\n// ---------------------------------------------------------------------------\n// Route requirement orchestrator\n// ---------------------------------------------------------------------------\n\n/** Options for {@link createRouteRequirementOrchestrator}. */\nexport interface CreateRouteRequirementOrchestratorOptions {\n\t/**\n\t * Optional callback fired when the orchestrator needs the adopter to\n\t * act on a pending requirement (e.g. show a chooser UI or auto-redirect).\n\t */\n\tonPendingRequirement?: (requirement: AuthRequirement) => void;\n\n\t/**\n\t * Optional callback fired when all requirements for the active route\n\t * are settled.\n\t */\n\tonSettled?: (\n\t\trouteId: string,\n\t\tresolutions: readonly RequirementResolution[],\n\t) => void;\n}\n\n/**\n * Headless route requirement orchestrator.\n *\n * Driven by a matched route chain: the adopter maps their framework's\n * route match result into `RouteMatchNode[]` and calls `activateMatchedRoutes`.\n * Parent requirements are inherited; children append.\n */\nexport interface RouteRequirementOrchestrator {\n\t/** Get a snapshot of the current route orchestration state. */\n\tsnapshot(): RouteOrchestrationSnapshot;\n\n\t/**\n\t * Activate a matched route chain.\n\t *\n\t * Requirements are inherited: parent requirements come first, children append.\n\t * On route transition, shared-prefix requirements and their resolutions\n\t * are preserved; diverging requirements are re-planned.\n\t */\n\tactivateMatchedRoutes(matchedRoutes: readonly RouteMatchNode[]): void;\n\n\t/**\n\t * Resolve the current pending requirement.\n\t * Advances to the next requirement or settles the plan.\n\t */\n\tresolve(resolution: RequirementResolution): void;\n\n\t/**\n\t * Record a chooser decision for the current pending requirement.\n\t */\n\tapplyChooserDecision(decision: ChooserDecision): void;\n\n\t/**\n\t * Reset the active route (e.g. on navigation away or logout).\n\t */\n\tdeactivateRoute(): void;\n\n\t/** All chooser decisions made during the current route activation. */\n\treadonly decisions: readonly ChooserDecision[];\n}\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\n/** Merge a matched route chain into a flat requirement list (parent-first). */\nfunction mergeChainRequirements(\n\tchain: readonly RouteMatchNode[],\n): AuthRequirement[] {\n\tconst merged: AuthRequirement[] = [];\n\tconst seenIds = new Set<string>();\n\tfor (const node of chain) {\n\t\tfor (const req of node.requirements) {\n\t\t\t// Deduplicate by requirement ID — later (child) definitions win.\n\t\t\tif (seenIds.has(req.id)) continue;\n\t\t\tseenIds.add(req.id);\n\t\t\tmerged.push(req);\n\t\t}\n\t}\n\treturn merged;\n}\n\n/**\n * Find the length of the shared requirement prefix between old and new chains.\n * Used to determine which resolutions can be preserved on route transition.\n */\nfunction sharedPrefixLength(\n\toldReqs: readonly AuthRequirement[],\n\tnewReqs: readonly AuthRequirement[],\n): number {\n\tconst limit = Math.min(oldReqs.length, newReqs.length);\n\tfor (let i = 0; i < limit; i++) {\n\t\tif (oldReqs[i].id !== newReqs[i].id || oldReqs[i].kind !== newReqs[i].kind)\n\t\t\treturn i;\n\t}\n\treturn limit;\n}\n\n// ---------------------------------------------------------------------------\n// Factory\n// ---------------------------------------------------------------------------\n\nexport function createRouteRequirementOrchestrator(\n\toptions: CreateRouteRequirementOrchestratorOptions = {},\n): RouteRequirementOrchestrator {\n\tlet matchedRoutes: RouteMatchNode[] = [];\n\tlet activeRouteId: string | null = null;\n\tlet planner: RequirementPlanner | null = null;\n\tlet decisions: ChooserDecision[] = [];\n\tlet currentMergedReqs: AuthRequirement[] = [];\n\n\tfunction emitPendingIfNeeded(): void {\n\t\tif (!planner || !options.onPendingRequirement) return;\n\t\tconst snap = planner.snapshot();\n\t\tif (snap.nextPending) {\n\t\t\toptions.onPendingRequirement(snap.nextPending);\n\t\t}\n\t}\n\n\tfunction emitSettledIfNeeded(): void {\n\t\tif (!planner || !activeRouteId || !options.onSettled) return;\n\t\tconst snap = planner.snapshot();\n\t\tif (snap.status === PlanStatus.Settled) {\n\t\t\toptions.onSettled(activeRouteId, snap.resolutions);\n\t\t}\n\t}\n\n\tfunction activateWithChain(chain: readonly RouteMatchNode[]): void {\n\t\tconst newMerged = mergeChainRequirements(chain);\n\t\tif (newMerged.length === 0) {\n\t\t\t// No requirements — treat as deactivation.\n\t\t\tmatchedRoutes = [...chain];\n\t\t\tactiveRouteId = chain.length > 0 ? chain[chain.length - 1].routeId : null;\n\t\t\tplanner = null;\n\t\t\tcurrentMergedReqs = [];\n\t\t\tdecisions = [];\n\t\t\treturn;\n\t\t}\n\n\t\t// Determine shared prefix to preserve existing resolutions.\n\t\tconst shared = sharedPrefixLength(currentMergedReqs, newMerged);\n\n\t\t// Collect resolutions from the current planner that can be preserved.\n\t\tlet preservedResolutions: RequirementResolution[] = [];\n\t\tif (planner && shared > 0) {\n\t\t\tconst oldSnap = planner.snapshot();\n\t\t\tpreservedResolutions = oldSnap.resolutions.slice(0, shared);\n\t\t}\n\n\t\t// Preserve decisions whose requirementIds are in the shared prefix.\n\t\tconst sharedReqIds = new Set(newMerged.slice(0, shared).map((r) => r.id));\n\t\tdecisions = decisions.filter((d) => sharedReqIds.has(d.requirementId));\n\n\t\t// Create new planner with full merged requirements.\n\t\tmatchedRoutes = [...chain];\n\t\tactiveRouteId = chain[chain.length - 1].routeId;\n\t\tcurrentMergedReqs = newMerged;\n\t\tplanner = createRequirementPlanner({ requirements: newMerged });\n\n\t\t// Re-apply preserved resolutions.\n\t\tfor (const res of preservedResolutions) {\n\t\t\tplanner.resolve(res);\n\t\t}\n\n\t\temitPendingIfNeeded();\n\t\temitSettledIfNeeded();\n\t}\n\n\treturn {\n\t\tsnapshot(): RouteOrchestrationSnapshot {\n\t\t\tif (!planner || !activeRouteId) {\n\t\t\t\treturn {\n\t\t\t\t\tmatchedRoutes: [...matchedRoutes],\n\t\t\t\t\tactiveRouteId,\n\t\t\t\t\tplan: null,\n\t\t\t\t\tsettled: matchedRoutes.length > 0 && currentMergedReqs.length === 0,\n\t\t\t\t\tpendingRequirement: null,\n\t\t\t\t};\n\t\t\t}\n\t\t\tconst plan = planner.snapshot();\n\t\t\treturn {\n\t\t\t\tmatchedRoutes: [...matchedRoutes],\n\t\t\t\tactiveRouteId,\n\t\t\t\tplan,\n\t\t\t\tsettled: plan.status === PlanStatus.Settled,\n\t\t\t\tpendingRequirement: plan.nextPending,\n\t\t\t};\n\t\t},\n\n\t\tactivateMatchedRoutes(chain: readonly RouteMatchNode[]): void {\n\t\t\tactivateWithChain(chain);\n\t\t},\n\n\t\tresolve(resolution: RequirementResolution): void {\n\t\t\tif (!planner) {\n\t\t\t\tthrow new Error(\"Cannot resolve: no active route\");\n\t\t\t}\n\t\t\tplanner.resolve(resolution);\n\t\t\temitSettledIfNeeded();\n\t\t\tif (planner.snapshot().status === PlanStatus.Pending) {\n\t\t\t\temitPendingIfNeeded();\n\t\t\t}\n\t\t},\n\n\t\tapplyChooserDecision(decision: ChooserDecision): void {\n\t\t\tdecisions.push(decision);\n\t\t},\n\n\t\tdeactivateRoute(): void {\n\t\t\tactiveRouteId = null;\n\t\t\tplanner = null;\n\t\t\tmatchedRoutes = [];\n\t\t\tdecisions = [];\n\t\t\tcurrentMergedReqs = [];\n\t\t},\n\n\t\tget decisions(): readonly ChooserDecision[] {\n\t\t\treturn decisions;\n\t\t},\n\t};\n}\n"],"mappings":"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"}
|
package/dist/events/index.d.mts
DELETED
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
import { C as EventSource, D as ReplaySubjectTrait, E as EventSubscriptionTrait, O as RuntimeEventEnvelope, S as EventObserver, T as EventStreamTrait, _ as createEventStream, a as filter, b as fromRxObservable, c as merge, d as shareReplay, f as switchMap, g as withLatestFromSignal, h as throttleTime, i as exhaustMap, k as SubjectTrait, l as pipe, m as tap, n as concatMap, o as finalize, p as takeUntil, r as debounceTime, s as map, t as EventOperator, u as share, v as createReplaySubject, w as EventSourceKind, x as toRxObservable, y as createSubject } from "../index-C_wgl6dW.mjs";
|
|
2
|
-
export { EventObserver, EventOperator, EventSource, EventSourceKind, EventStreamTrait, EventSubscriptionTrait, ReplaySubjectTrait, RuntimeEventEnvelope, SubjectTrait, concatMap, createEventStream, createReplaySubject, createSubject, debounceTime, exhaustMap, filter, finalize, fromRxObservable, map, merge, pipe, share, shareReplay, switchMap, takeUntil, tap, throttleTime, toRxObservable, withLatestFromSignal };
|
package/dist/events/index.mjs
DELETED
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
import { _ as createEventStream, a as filter, b as fromRxObservable, c as merge, d as shareReplay, f as switchMap, g as withLatestFromSignal, h as throttleTime, i as exhaustMap, l as pipe, m as tap, n as concatMap, o as finalize, p as takeUntil, r as debounceTime, s as map, t as EventSourceKind, u as share, v as createReplaySubject, x as toRxObservable, y as createSubject } from "../events-BUlfsRfl.mjs";
|
|
2
|
-
export { EventSourceKind, concatMap, createEventStream, createReplaySubject, createSubject, debounceTime, exhaustMap, filter, finalize, fromRxObservable, map, merge, pipe, share, shareReplay, switchMap, takeUntil, tap, throttleTime, toRxObservable, withLatestFromSignal };
|
package/dist/events-BUlfsRfl.mjs
DELETED
|
@@ -1,127 +0,0 @@
|
|
|
1
|
-
import { Observable, ReplaySubject, Subject, merge } from "rxjs";
|
|
2
|
-
import { concatMap, debounceTime, exhaustMap, filter, finalize, map, share, shareReplay, switchMap, takeUntil, tap, throttleTime, withLatestFrom } from "rxjs/operators";
|
|
3
|
-
//#region src/events/event-stream.ts
|
|
4
|
-
const RX_OBSERVABLE = Symbol("securitydept.rxObservable");
|
|
5
|
-
/**
|
|
6
|
-
* Create a new event stream from a producer function.
|
|
7
|
-
*
|
|
8
|
-
* The producer receives an observer and should call `next()` to emit values,
|
|
9
|
-
* `error()` to signal an error, and `complete()` to signal completion.
|
|
10
|
-
* It may return a teardown function that will be called on unsubscribe.
|
|
11
|
-
*/
|
|
12
|
-
function createEventStream(producer) {
|
|
13
|
-
return fromRxObservable(new Observable((subscriber) => {
|
|
14
|
-
const teardown = producer({
|
|
15
|
-
next: (value) => subscriber.next(value),
|
|
16
|
-
error: (error) => subscriber.error(error),
|
|
17
|
-
complete: () => subscriber.complete()
|
|
18
|
-
});
|
|
19
|
-
return () => teardown?.();
|
|
20
|
-
}));
|
|
21
|
-
}
|
|
22
|
-
function createSubject() {
|
|
23
|
-
return wrapSubject(new Subject());
|
|
24
|
-
}
|
|
25
|
-
function createReplaySubject(bufferSize = 1) {
|
|
26
|
-
const subject = wrapSubject(new ReplaySubject(bufferSize));
|
|
27
|
-
return Object.assign(subject, { bufferSize });
|
|
28
|
-
}
|
|
29
|
-
function toRxObservable(stream) {
|
|
30
|
-
const maybeBacked = stream;
|
|
31
|
-
if (maybeBacked[RX_OBSERVABLE]) return maybeBacked[RX_OBSERVABLE];
|
|
32
|
-
return new Observable((subscriber) => {
|
|
33
|
-
const subscription = stream.subscribe({
|
|
34
|
-
next: (value) => subscriber.next(value),
|
|
35
|
-
error: (error) => subscriber.error(error),
|
|
36
|
-
complete: () => subscriber.complete()
|
|
37
|
-
});
|
|
38
|
-
return () => subscription.unsubscribe();
|
|
39
|
-
});
|
|
40
|
-
}
|
|
41
|
-
function fromRxObservable(observable) {
|
|
42
|
-
return {
|
|
43
|
-
[RX_OBSERVABLE]: observable,
|
|
44
|
-
subscribe(observer) {
|
|
45
|
-
const subscription = observable.subscribe({
|
|
46
|
-
next: (value) => observer.next?.(value),
|
|
47
|
-
error: (error) => observer.error?.(error),
|
|
48
|
-
complete: () => observer.complete?.()
|
|
49
|
-
});
|
|
50
|
-
return { unsubscribe: () => subscription.unsubscribe() };
|
|
51
|
-
}
|
|
52
|
-
};
|
|
53
|
-
}
|
|
54
|
-
function wrapSubject(subject) {
|
|
55
|
-
return Object.assign(fromRxObservable(subject.asObservable()), {
|
|
56
|
-
next: (value) => subject.next(value),
|
|
57
|
-
error: (error) => subject.error(error),
|
|
58
|
-
complete: () => subject.complete()
|
|
59
|
-
});
|
|
60
|
-
}
|
|
61
|
-
//#endregion
|
|
62
|
-
//#region src/events/operators.ts
|
|
63
|
-
function pipe(source, ...operators) {
|
|
64
|
-
return operators.reduce((acc, op) => op(acc), source);
|
|
65
|
-
}
|
|
66
|
-
function map$1(fn) {
|
|
67
|
-
return (source) => fromRxObservable(toRxObservable(source).pipe(map(fn)));
|
|
68
|
-
}
|
|
69
|
-
function filter$1(predicate) {
|
|
70
|
-
return (source) => fromRxObservable(toRxObservable(source).pipe(filter(predicate)));
|
|
71
|
-
}
|
|
72
|
-
function tap$1(fn) {
|
|
73
|
-
return (source) => fromRxObservable(toRxObservable(source).pipe(tap(fn)));
|
|
74
|
-
}
|
|
75
|
-
function takeUntil$1(notifier) {
|
|
76
|
-
return (source) => fromRxObservable(toRxObservable(source).pipe(takeUntil(toRxObservable(notifier))));
|
|
77
|
-
}
|
|
78
|
-
function finalize$1(fn) {
|
|
79
|
-
return (source) => fromRxObservable(toRxObservable(source).pipe(finalize(fn)));
|
|
80
|
-
}
|
|
81
|
-
function merge$1(...sources) {
|
|
82
|
-
return fromRxObservable(merge(...sources.map(toRxObservable)));
|
|
83
|
-
}
|
|
84
|
-
function share$1() {
|
|
85
|
-
return (source) => fromRxObservable(toRxObservable(source).pipe(share()));
|
|
86
|
-
}
|
|
87
|
-
function shareReplay$1(bufferSize = 1) {
|
|
88
|
-
return (source) => fromRxObservable(toRxObservable(source).pipe(shareReplay({
|
|
89
|
-
bufferSize,
|
|
90
|
-
refCount: true
|
|
91
|
-
})));
|
|
92
|
-
}
|
|
93
|
-
function switchMap$1(fn) {
|
|
94
|
-
return (source) => fromRxObservable(toRxObservable(source).pipe(switchMap((value) => toRxObservable(fn(value)))));
|
|
95
|
-
}
|
|
96
|
-
function concatMap$1(fn) {
|
|
97
|
-
return (source) => fromRxObservable(toRxObservable(source).pipe(concatMap((value) => toRxObservable(fn(value)))));
|
|
98
|
-
}
|
|
99
|
-
function exhaustMap$1(fn) {
|
|
100
|
-
return (source) => fromRxObservable(toRxObservable(source).pipe(exhaustMap((value) => toRxObservable(fn(value)))));
|
|
101
|
-
}
|
|
102
|
-
function debounceTime$1(durationMs) {
|
|
103
|
-
return (source) => fromRxObservable(toRxObservable(source).pipe(debounceTime(durationMs)));
|
|
104
|
-
}
|
|
105
|
-
function throttleTime$1(durationMs) {
|
|
106
|
-
return (source) => fromRxObservable(toRxObservable(source).pipe(throttleTime(durationMs)));
|
|
107
|
-
}
|
|
108
|
-
function withLatestFromSignal(signal) {
|
|
109
|
-
return (source) => fromRxObservable(toRxObservable(source).pipe(withLatestFrom(toRxObservable(createEventStream((observer) => {
|
|
110
|
-
observer.next?.(signal.get());
|
|
111
|
-
return signal.subscribe(() => observer.next?.(signal.get()));
|
|
112
|
-
})))));
|
|
113
|
-
}
|
|
114
|
-
//#endregion
|
|
115
|
-
//#region src/events/types.ts
|
|
116
|
-
const EventSourceKind = {
|
|
117
|
-
User: "user",
|
|
118
|
-
Timer: "timer",
|
|
119
|
-
Http: "http",
|
|
120
|
-
Storage: "storage",
|
|
121
|
-
Framework: "framework",
|
|
122
|
-
System: "system"
|
|
123
|
-
};
|
|
124
|
-
//#endregion
|
|
125
|
-
export { createEventStream as _, filter$1 as a, fromRxObservable as b, merge$1 as c, shareReplay$1 as d, switchMap$1 as f, withLatestFromSignal as g, throttleTime$1 as h, exhaustMap$1 as i, pipe as l, tap$1 as m, concatMap$1 as n, finalize$1 as o, takeUntil$1 as p, debounceTime$1 as r, map$1 as s, EventSourceKind as t, share$1 as u, createReplaySubject as v, toRxObservable as x, createSubject as y };
|
|
126
|
-
|
|
127
|
-
//# sourceMappingURL=events-BUlfsRfl.mjs.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"events-BUlfsRfl.mjs","names":["map","rxMap","filter","rxFilter","tap","rxTap","takeUntil","rxTakeUntil","finalize","rxFinalize","merge","rxMerge","share","rxShare","shareReplay","rxShareReplay","switchMap","rxSwitchMap","concatMap","rxConcatMap","exhaustMap","rxExhaustMap","debounceTime","rxDebounceTime","throttleTime","rxThrottleTime","rxWithLatestFrom"],"sources":["../src/events/event-stream.ts","../src/events/operators.ts","../src/events/types.ts"],"sourcesContent":["import { Observable, ReplaySubject, Subject } from \"rxjs\";\nimport type {\n\tEventObserver,\n\tEventStreamTrait,\n\tEventSubscriptionTrait,\n\tReplaySubjectTrait,\n\tSubjectTrait,\n} from \"./types\";\n\nconst RX_OBSERVABLE = Symbol(\"securitydept.rxObservable\");\n\ntype RxBackedEventStream<T> = EventStreamTrait<T> & {\n\treadonly [RX_OBSERVABLE]: Observable<T>;\n};\n\n/**\n * Create a new event stream from a producer function.\n *\n * The producer receives an observer and should call `next()` to emit values,\n * `error()` to signal an error, and `complete()` to signal completion.\n * It may return a teardown function that will be called on unsubscribe.\n */\nexport function createEventStream<T>(\n\tproducer: (observer: EventObserver<T>) => (() => void) | void,\n): EventStreamTrait<T> {\n\treturn fromRxObservable(\n\t\tnew Observable<T>((subscriber) => {\n\t\t\tconst teardown = producer({\n\t\t\t\tnext: (value) => subscriber.next(value),\n\t\t\t\terror: (error) => subscriber.error(error),\n\t\t\t\tcomplete: () => subscriber.complete(),\n\t\t\t});\n\t\t\treturn () => teardown?.();\n\t\t}),\n\t);\n}\n\nexport function createSubject<T>(): SubjectTrait<T> {\n\treturn wrapSubject(new Subject<T>());\n}\n\nexport function createReplaySubject<T>(bufferSize = 1): ReplaySubjectTrait<T> {\n\tconst subject = wrapSubject(new ReplaySubject<T>(bufferSize));\n\treturn Object.assign(subject, { bufferSize });\n}\n\nexport function toRxObservable<T>(stream: EventStreamTrait<T>): Observable<T> {\n\tconst maybeBacked = stream as Partial<RxBackedEventStream<T>>;\n\tif (maybeBacked[RX_OBSERVABLE]) {\n\t\treturn maybeBacked[RX_OBSERVABLE];\n\t}\n\n\treturn new Observable<T>((subscriber) => {\n\t\tconst subscription = stream.subscribe({\n\t\t\tnext: (value) => subscriber.next(value),\n\t\t\terror: (error) => subscriber.error(error),\n\t\t\tcomplete: () => subscriber.complete(),\n\t\t});\n\t\treturn () => subscription.unsubscribe();\n\t});\n}\n\nexport function fromRxObservable<T>(\n\tobservable: Observable<T>,\n): EventStreamTrait<T> {\n\treturn {\n\t\t[RX_OBSERVABLE]: observable,\n\t\tsubscribe(observer: EventObserver<T>): EventSubscriptionTrait {\n\t\t\tconst subscription = observable.subscribe({\n\t\t\t\tnext: (value) => observer.next?.(value),\n\t\t\t\terror: (error) => observer.error?.(error),\n\t\t\t\tcomplete: () => observer.complete?.(),\n\t\t\t});\n\t\t\treturn { unsubscribe: () => subscription.unsubscribe() };\n\t\t},\n\t} as RxBackedEventStream<T>;\n}\n\nfunction wrapSubject<T>(subject: Subject<T>): SubjectTrait<T> {\n\treturn Object.assign(fromRxObservable(subject.asObservable()), {\n\t\tnext: (value: T) => subject.next(value),\n\t\terror: (error: unknown) => subject.error(error),\n\t\tcomplete: () => subject.complete(),\n\t});\n}\n","import { merge as rxMerge } from \"rxjs\";\nimport {\n\tconcatMap as rxConcatMap,\n\tdebounceTime as rxDebounceTime,\n\texhaustMap as rxExhaustMap,\n\tfilter as rxFilter,\n\tfinalize as rxFinalize,\n\tmap as rxMap,\n\tshare as rxShare,\n\tshareReplay as rxShareReplay,\n\tswitchMap as rxSwitchMap,\n\ttakeUntil as rxTakeUntil,\n\ttap as rxTap,\n\tthrottleTime as rxThrottleTime,\n\twithLatestFrom as rxWithLatestFrom,\n} from \"rxjs/operators\";\nimport type { ReadableSignalTrait } from \"../signals\";\nimport {\n\tcreateEventStream,\n\tfromRxObservable,\n\ttoRxObservable,\n} from \"./event-stream\";\nimport type { EventStreamTrait } from \"./types\";\n\n// --- Operator types ---\n\nexport type EventOperator<A, B> = (\n\tsource: EventStreamTrait<A>,\n) => EventStreamTrait<B>;\n\n// --- pipe ---\n\nexport function pipe<A>(source: EventStreamTrait<A>): EventStreamTrait<A>;\nexport function pipe<A, B>(\n\tsource: EventStreamTrait<A>,\n\top1: EventOperator<A, B>,\n): EventStreamTrait<B>;\nexport function pipe<A, B, C>(\n\tsource: EventStreamTrait<A>,\n\top1: EventOperator<A, B>,\n\top2: EventOperator<B, C>,\n): EventStreamTrait<C>;\nexport function pipe<A, B, C, D>(\n\tsource: EventStreamTrait<A>,\n\top1: EventOperator<A, B>,\n\top2: EventOperator<B, C>,\n\top3: EventOperator<C, D>,\n): EventStreamTrait<D>;\nexport function pipe(\n\tsource: EventStreamTrait<unknown>,\n\t...operators: EventOperator<unknown, unknown>[]\n): EventStreamTrait<unknown> {\n\treturn operators.reduce((acc, op) => op(acc), source);\n}\n\n// --- map ---\n\nexport function map<A, B>(fn: (value: A) => B): EventOperator<A, B> {\n\treturn (source) => fromRxObservable(toRxObservable(source).pipe(rxMap(fn)));\n}\n\n// --- filter ---\n\nexport function filter<A>(\n\tpredicate: (value: A) => boolean,\n): EventOperator<A, A> {\n\treturn (source) =>\n\t\tfromRxObservable(toRxObservable(source).pipe(rxFilter(predicate)));\n}\n\n// --- tap ---\n\nexport function tap<A>(fn: (value: A) => void): EventOperator<A, A> {\n\treturn (source) => fromRxObservable(toRxObservable(source).pipe(rxTap(fn)));\n}\n\n// --- takeUntil ---\n\nexport function takeUntil<A>(\n\tnotifier: EventStreamTrait<unknown>,\n): EventOperator<A, A> {\n\treturn (source) =>\n\t\tfromRxObservable(\n\t\t\ttoRxObservable(source).pipe(rxTakeUntil(toRxObservable(notifier))),\n\t\t);\n}\n\n// --- finalize ---\n\nexport function finalize<A>(fn: () => void): EventOperator<A, A> {\n\treturn (source) =>\n\t\tfromRxObservable(toRxObservable(source).pipe(rxFinalize(fn)));\n}\n\n// --- merge ---\n\nexport function merge<A>(\n\t...sources: EventStreamTrait<A>[]\n): EventStreamTrait<A> {\n\treturn fromRxObservable(rxMerge(...sources.map(toRxObservable)));\n}\n\nexport function share<A>(): EventOperator<A, A> {\n\treturn (source) => fromRxObservable(toRxObservable(source).pipe(rxShare()));\n}\n\nexport function shareReplay<A>(bufferSize = 1): EventOperator<A, A> {\n\treturn (source) =>\n\t\tfromRxObservable(\n\t\t\ttoRxObservable(source).pipe(\n\t\t\t\trxShareReplay({ bufferSize, refCount: true }),\n\t\t\t),\n\t\t);\n}\n\nexport function switchMap<A, B>(\n\tfn: (value: A) => EventStreamTrait<B>,\n): EventOperator<A, B> {\n\treturn (source) =>\n\t\tfromRxObservable(\n\t\t\ttoRxObservable(source).pipe(\n\t\t\t\trxSwitchMap((value) => toRxObservable(fn(value))),\n\t\t\t),\n\t\t);\n}\n\nexport function concatMap<A, B>(\n\tfn: (value: A) => EventStreamTrait<B>,\n): EventOperator<A, B> {\n\treturn (source) =>\n\t\tfromRxObservable(\n\t\t\ttoRxObservable(source).pipe(\n\t\t\t\trxConcatMap((value) => toRxObservable(fn(value))),\n\t\t\t),\n\t\t);\n}\n\nexport function exhaustMap<A, B>(\n\tfn: (value: A) => EventStreamTrait<B>,\n): EventOperator<A, B> {\n\treturn (source) =>\n\t\tfromRxObservable(\n\t\t\ttoRxObservable(source).pipe(\n\t\t\t\trxExhaustMap((value) => toRxObservable(fn(value))),\n\t\t\t),\n\t\t);\n}\n\nexport function debounceTime<A>(durationMs: number): EventOperator<A, A> {\n\treturn (source) =>\n\t\tfromRxObservable(toRxObservable(source).pipe(rxDebounceTime(durationMs)));\n}\n\nexport function throttleTime<A>(durationMs: number): EventOperator<A, A> {\n\treturn (source) =>\n\t\tfromRxObservable(toRxObservable(source).pipe(rxThrottleTime(durationMs)));\n}\n\nexport function withLatestFromSignal<A, B>(\n\tsignal: ReadableSignalTrait<B>,\n): EventOperator<A, [A, B]> {\n\treturn (source) =>\n\t\tfromRxObservable(\n\t\t\ttoRxObservable(source).pipe(\n\t\t\t\trxWithLatestFrom(\n\t\t\t\t\ttoRxObservable(\n\t\t\t\t\t\tcreateEventStream<B>((observer) => {\n\t\t\t\t\t\t\tobserver.next?.(signal.get());\n\t\t\t\t\t\t\treturn signal.subscribe(() => observer.next?.(signal.get()));\n\t\t\t\t\t\t}),\n\t\t\t\t\t),\n\t\t\t\t),\n\t\t\t),\n\t\t);\n}\n","// --- Event system trait types ---\n\n/** Subscription handle with explicit unsubscribe. */\nexport interface EventSubscriptionTrait {\n\tunsubscribe(): void;\n}\n\n/** Observer for event streams — mirrors the Observable observer pattern. */\nexport interface EventObserver<T> {\n\tnext?(value: T): void;\n\terror?(error: unknown): void;\n\tcomplete?(): void;\n}\n\n/** Read-only event stream — lazy push-based sequence. */\nexport interface EventStreamTrait<T> {\n\tsubscribe(observer: EventObserver<T>): EventSubscriptionTrait;\n}\n\n/** Hot event producer. */\nexport interface SubjectTrait<T> extends EventStreamTrait<T> {\n\tnext(value: T): void;\n\terror(error: unknown): void;\n\tcomplete(): void;\n}\n\n/** Hot event producer that replays recent values to late subscribers. */\nexport interface ReplaySubjectTrait<T> extends SubjectTrait<T> {\n\treadonly bufferSize: number;\n}\n\n// --- Event envelope ---\n\nexport const EventSourceKind = {\n\tUser: \"user\",\n\tTimer: \"timer\",\n\tHttp: \"http\",\n\tStorage: \"storage\",\n\tFramework: \"framework\",\n\tSystem: \"system\",\n} as const;\n\nexport type EventSourceKind =\n\t(typeof EventSourceKind)[keyof typeof EventSourceKind];\n\nexport type EventSource =\n\t| { kind: typeof EventSourceKind.User; actor?: string }\n\t| { kind: typeof EventSourceKind.Timer; timer: string }\n\t| { kind: typeof EventSourceKind.Http; requestId: string; endpoint?: string }\n\t| { kind: typeof EventSourceKind.Storage; operation: string }\n\t| { kind: typeof EventSourceKind.Framework; name: string }\n\t| { kind: typeof EventSourceKind.System; subsystem: string };\n\nexport interface RuntimeEventEnvelope<TType extends string, TPayload> {\n\tid: string;\n\ttype: TType;\n\tat: number;\n\tsource: EventSource;\n\tpayload: TPayload;\n}\n"],"mappings":"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"}
|