@securitydept/client 0.3.0-beta.1 → 0.3.0-beta.10
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
package/dist/index.mjs
CHANGED
|
@@ -1,69 +1,274 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import { i as
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
1
|
+
import { A as RxEventSubject, B as withDisposableStack, E as RxComputedSignal, F as SYMBOL_DISPOSE, G as ErrorPresentationTone, H as ClientError, I as SimpleDisposableStack, K as UserRecovery, L as StdDisposableStack, M as isInteropObservableTrait, N as SYMBOL_ASYNC_DISPOSE, O as RxEventReplaySubject, P as SYMBOL_DISPOSABLE_STACK, R as createDisposableStack, U as ClientErrorKind, V as CLIENT_ERROR_SPAN_ATTRIBUTE_PROVIDER_ID, W as ClientErrorSource, a as ResourceSnapshotUpdateKind, c as whenResourceSnapshotValue, d as ResourceErrorCode, f as CancellationToken, i as rxResource, j as SYMBOL_OBSERVABLE, k as RxEventStream, l as ResourceStatus, m as isCancellationTokenTrait, n as mapResource, o as flattenResourceSnapshot, p as createCancellationTokenSource, r as resourceFromSnapshots, s as reduceResourceSnapshot, u as ResourceError, z as injectDisposableStackFrom } from "./rx-DM6Ouv-m.mjs";
|
|
2
|
+
import { a as createJsonRpcServerAndClient, c as createSignal, d as readErrorPresentationDescriptor, f as SpanSharedAttributeName, i as createJsonRpcServer, l as readonlySignal, n as PopupServerWindowHandle, o as PopupErrorCode, r as createJsonRpcClient, s as readPopupErrorPresentationDescriptor, t as PopupClientWindowHandle, u as formatClientErrorContext } from "./handle-DwMgqe7R.mjs";
|
|
3
|
+
import { $ as notMissingProvider, A as SECURITYDEPT_COMPAT_FRAGMENT_VERSION, B as validateWithSchema, C as SPAN_TRAIT_TOKEN, D as RouterNavigationIntent, E as ROUTER_TRAIT_TOKEN, F as POPUP_TRAIT_TOKEN, G as INJECTOR_TOKEN, H as PAGE_LIFECYCLE_TRAIT_TOKEN, I as PopupAttachFailureReason, J as toRuntimeInjector, K as PARENT_INJECTOR_TOKEN, L as formatValidationFailure, M as isCompatFragmentBlock, N as parseCompatFragment, O as RouterNavigationMode, P as takeCompatFragment, Q as getSecuritydeptProviderToken, R as throwValidationClientError, S as createRootSpan, T as TIME_TRAIT_TOKEN, U as EventSourceKind, V as validateWithSchemaSync, W as isEventStreamTrait, X as SecuritydeptInjectionToken, Y as SecurityDeptOptional, Z as createProviderIfTokenMissing, _ as createTimeForStd, a as TRACING_TRAIT_TOKEN, b as normalizeAbortError, c as createInMemoryRecordStore, d as SESSION_STORAGE_TRAIT_TOKEN, f as StorageChangeEventOrigin, g as TransportErrorCode, h as TRANSPORT_TRAIT_TOKEN, i as TRACING_SPAN_ATTRIBUTE_PROVIDER_ID, j as appendOrReplaceCompatFragment, k as takeCompatFragmentFromRouter, l as PERSISTENT_STORAGE_TRAIT_TOKEN, m as createBaseTransportForStdFetch, n as ENVIRONMENT_TOKEN, o as TracingLevel, p as FetchTransportRedirectKind, q as SecuritydeptInjector, r as OperationTraceEventType, s as createTracing, t as createFoundationEnvironment, u as REALM_STORAGE_TRAIT_TOKEN, v as abortSignalToCancellationToken, w as IDLE_CALLBACK_TRAIT_TOKEN, x as abortSignalToEventStream, y as cancellationTokenToAbortSignal, z as validateTraitInput } from "./create-i5VyYgN6.mjs";
|
|
4
|
+
import { i as UriString, n as UriReferenceString, r as UriRelativeString, t as UriParseError } from "./uri-string-BPNbIMgv.mjs";
|
|
5
|
+
import { v7 } from "uuid";
|
|
6
|
+
import { inject as inject$1, runInInjectionContext as runInInjectionContext$1 } from "injection-js";
|
|
7
|
+
import { EMPTY, NEVER, ReplaySubject, filter, from, merge, take, takeUntil } from "rxjs";
|
|
8
|
+
import { type } from "arktype";
|
|
9
|
+
import { isPromise } from "es-toolkit/predicate";
|
|
10
|
+
//#region src/auth-coordination/contract.ts
|
|
11
|
+
var StaticAttrsAuthRequirement = class StaticAttrsAuthRequirement {
|
|
12
|
+
id;
|
|
13
|
+
label;
|
|
14
|
+
attributes;
|
|
15
|
+
constructor(id, label, attributes) {
|
|
16
|
+
this.id = id;
|
|
17
|
+
this.label = label;
|
|
18
|
+
this.attributes = attributes;
|
|
19
|
+
Object.freeze(this);
|
|
14
20
|
}
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
if (this._isCancelled) return;
|
|
18
|
-
this._isCancelled = true;
|
|
19
|
-
this._reason = reason;
|
|
20
|
-
for (const listener of this._listeners) listener(reason);
|
|
21
|
-
this._listeners.clear();
|
|
21
|
+
static create(input) {
|
|
22
|
+
return new StaticAttrsAuthRequirement(input?.id ?? v7(), input?.label, input?.attributes ? Object.freeze(input.attributes) : void 0);
|
|
22
23
|
}
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
listener(this._reason);
|
|
26
|
-
return { dispose() {} };
|
|
27
|
-
}
|
|
28
|
-
this._listeners.add(listener);
|
|
29
|
-
return { dispose: () => {
|
|
30
|
-
this._listeners.delete(listener);
|
|
31
|
-
} };
|
|
24
|
+
static createList(inputs) {
|
|
25
|
+
return inputs.map((input) => StaticAttrsAuthRequirement.create(input));
|
|
32
26
|
}
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
27
|
+
};
|
|
28
|
+
/** Outcome of resolving a single requirement. */
|
|
29
|
+
const ResolutionStatus = {
|
|
30
|
+
Fulfilled: "fulfilled",
|
|
31
|
+
Failed: "failed",
|
|
32
|
+
Skipped: "skipped"
|
|
33
|
+
};
|
|
34
|
+
/** Overall plan status. */
|
|
35
|
+
const PlanStatus = {
|
|
36
|
+
/** There are still pending requirements. */
|
|
37
|
+
Pending: "pending",
|
|
38
|
+
/** All requirements have been resolved. */
|
|
39
|
+
Settled: "settled"
|
|
40
|
+
};
|
|
41
|
+
/** Error thrown when a planner contract is violated (e.g. duplicate ids). */
|
|
42
|
+
var RequirementPlannerError = class extends Error {
|
|
43
|
+
constructor(message) {
|
|
44
|
+
super(message);
|
|
45
|
+
this.name = "RequirementPlannerError";
|
|
39
46
|
}
|
|
40
47
|
};
|
|
48
|
+
function isRouteStateSnapshotTrait(value) {
|
|
49
|
+
return typeof value === "object" && value !== null && "url" in value;
|
|
50
|
+
}
|
|
51
|
+
function isRouteBehaviourContextExtra(value) {
|
|
52
|
+
return typeof value === "object" && value !== null && "routeState" in value && isRouteStateSnapshotTrait(value.routeState);
|
|
53
|
+
}
|
|
54
|
+
/** Outcome of a pipeline step or run. */
|
|
55
|
+
const PipelineOutcome = {
|
|
56
|
+
/** No candidates remain — the plan is satisfied. */
|
|
57
|
+
Settled: "settled",
|
|
58
|
+
/** A candidate was resolved as fulfilled; more may remain. */
|
|
59
|
+
Resolved: "resolved",
|
|
60
|
+
/** A candidate's handler blocked progress. */
|
|
61
|
+
Blocked: "blocked",
|
|
62
|
+
/** A candidate's handler requested a redirect. */
|
|
63
|
+
Redirect: "redirect"
|
|
64
|
+
};
|
|
41
65
|
/**
|
|
42
|
-
*
|
|
66
|
+
* How a route segment's requirements compose with the inherited parent chain.
|
|
67
|
+
*
|
|
68
|
+
* - `inherit` — keep the parent requirements unchanged (segment adds nothing)
|
|
69
|
+
* - `merge` — inherit parent requirements, then append/override with the
|
|
70
|
+
* segment's own (same-id entries replace the parent's)
|
|
71
|
+
* - `replace` — discard the parent chain, use only the segment's requirements
|
|
43
72
|
*/
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
73
|
+
const RequirementsComposition = {
|
|
74
|
+
Inherit: "inherit",
|
|
75
|
+
Merge: "merge",
|
|
76
|
+
Replace: "replace"
|
|
77
|
+
};
|
|
78
|
+
/**
|
|
79
|
+
* Apply a route requirements declaration onto an effective requirement map.
|
|
80
|
+
*
|
|
81
|
+
* Reuse `effective` across a route chain so merge/replace fold in O(total
|
|
82
|
+
* requirements) without rebuilding parent state each segment. When omitted, a
|
|
83
|
+
* fresh map is created for one-shot composition.
|
|
84
|
+
*/
|
|
85
|
+
function resolveEffectiveRequirements(child, effective = /* @__PURE__ */ new Map()) {
|
|
86
|
+
switch (child.composition) {
|
|
87
|
+
case RequirementsComposition.Inherit: return effective;
|
|
88
|
+
case RequirementsComposition.Merge:
|
|
89
|
+
for (const requirement of child.requirements) effective.set(requirement.id, requirement);
|
|
90
|
+
return effective;
|
|
91
|
+
case RequirementsComposition.Replace:
|
|
92
|
+
effective.clear();
|
|
93
|
+
for (const requirement of child.requirements) effective.set(requirement.id, requirement);
|
|
94
|
+
return effective;
|
|
95
|
+
default: {
|
|
96
|
+
const _exhaustive = child.composition;
|
|
97
|
+
throw new RequirementPlannerError(`Unknown requirements composition: ${String(_exhaustive)}`);
|
|
62
98
|
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
//#endregion
|
|
102
|
+
//#region src/errors/error-attributes.ts
|
|
103
|
+
/** Extract secret-safe diagnostic attributes without copying runtime messages. */
|
|
104
|
+
function describeError(error) {
|
|
105
|
+
if (error instanceof ClientError) return {
|
|
106
|
+
errorName: error.name,
|
|
107
|
+
errorKind: error.kind,
|
|
108
|
+
errorCode: error.code,
|
|
109
|
+
recovery: error.recovery
|
|
63
110
|
};
|
|
111
|
+
return { errorName: error instanceof Error ? error.name : typeof error };
|
|
112
|
+
}
|
|
113
|
+
//#endregion
|
|
114
|
+
//#region src/compat/base64.ts
|
|
115
|
+
const Base64CompatErrorCode = {
|
|
116
|
+
EncoderUnavailable: "compat.base64.encoder_unavailable",
|
|
117
|
+
DecoderUnavailable: "compat.base64.decoder_unavailable"
|
|
118
|
+
};
|
|
119
|
+
function encodeUint8ArrayToBase64(value) {
|
|
120
|
+
const toBase64 = globalThis.Uint8Array.prototype.toBase64;
|
|
121
|
+
if (typeof toBase64 === "function") return toBase64.call(value);
|
|
122
|
+
if (typeof globalThis.btoa === "function") {
|
|
123
|
+
let binary = "";
|
|
124
|
+
for (const byte of value) binary += String.fromCharCode(byte);
|
|
125
|
+
return globalThis.btoa(binary);
|
|
126
|
+
}
|
|
127
|
+
const BufferConstructor = Reflect.get(globalThis, "Buffer");
|
|
128
|
+
if (typeof BufferConstructor?.from === "function") return BufferConstructor.from(value).toString("base64");
|
|
129
|
+
throw new ClientError({
|
|
130
|
+
kind: ClientErrorKind.Configuration,
|
|
131
|
+
code: Base64CompatErrorCode.EncoderUnavailable,
|
|
132
|
+
message: "The current realm does not provide a Base64 encoder.",
|
|
133
|
+
source: "compat.base64"
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
function decodeBase64ToUint8Array(value) {
|
|
137
|
+
const Uint8ArrayConstructor = globalThis.Uint8Array;
|
|
138
|
+
if (typeof Uint8ArrayConstructor.fromBase64 === "function") return Uint8ArrayConstructor.fromBase64(value);
|
|
139
|
+
if (typeof globalThis.atob === "function") {
|
|
140
|
+
const binary = globalThis.atob(value);
|
|
141
|
+
const bytes = new Uint8Array(binary.length);
|
|
142
|
+
for (let index = 0; index < binary.length; index += 1) bytes[index] = binary.charCodeAt(index);
|
|
143
|
+
return bytes;
|
|
144
|
+
}
|
|
145
|
+
const BufferConstructor = Reflect.get(globalThis, "Buffer");
|
|
146
|
+
if (typeof BufferConstructor?.from === "function") return Uint8ArrayConstructor.from(BufferConstructor.from(value, "base64"));
|
|
147
|
+
throw new ClientError({
|
|
148
|
+
kind: ClientErrorKind.Configuration,
|
|
149
|
+
code: Base64CompatErrorCode.DecoderUnavailable,
|
|
150
|
+
message: "The current realm does not provide a Base64 decoder.",
|
|
151
|
+
source: "compat.base64"
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
//#endregion
|
|
155
|
+
//#region src/compat/generator.ts
|
|
156
|
+
async function* promisesToRacedAsyncGenerator(promises) {
|
|
157
|
+
const pending = new Map(promises.map((promise, index) => [index, promise.then((value) => ({
|
|
158
|
+
value,
|
|
159
|
+
index
|
|
160
|
+
}))]));
|
|
161
|
+
while (pending.size > 0) {
|
|
162
|
+
const next = await Promise.race(pending.values());
|
|
163
|
+
pending.delete(next.index);
|
|
164
|
+
yield next.value;
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
//#endregion
|
|
168
|
+
//#region src/injection/context.ts
|
|
169
|
+
function inject(token, options) {
|
|
170
|
+
if (options?.optional === true) return inject$1(token, { optional: true });
|
|
171
|
+
return inject$1(token);
|
|
172
|
+
}
|
|
173
|
+
function tryInjectInInjectionContext(token, options) {
|
|
174
|
+
try {
|
|
175
|
+
if (options?.optional === true) return inject(token, { optional: true });
|
|
176
|
+
return inject(token);
|
|
177
|
+
} catch (error) {
|
|
178
|
+
if (isMissingInjectionContextError(error)) return null;
|
|
179
|
+
throw error;
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
function runInInjectionContext(injector, fn) {
|
|
183
|
+
return runInInjectionContext$1(toRuntimeInjector(injector), fn);
|
|
184
|
+
}
|
|
185
|
+
function isMissingInjectionContextError(error) {
|
|
186
|
+
return error instanceof Error && error.message.includes("can only be used within an injection context");
|
|
64
187
|
}
|
|
65
188
|
//#endregion
|
|
66
|
-
//#region src/
|
|
189
|
+
//#region src/injection/destroy.ts
|
|
190
|
+
var SecuritydeptDestroyRef = class {
|
|
191
|
+
[SYMBOL_DISPOSE]() {
|
|
192
|
+
this.dispose();
|
|
193
|
+
}
|
|
194
|
+
};
|
|
195
|
+
var ManagedSecuritydeptDestroyRef = class extends SecuritydeptDestroyRef {
|
|
196
|
+
destroyedSignal = createSignal(false);
|
|
197
|
+
get destroyed() {
|
|
198
|
+
return this.destroyedSignal.get();
|
|
199
|
+
}
|
|
200
|
+
onDestroy(callback) {
|
|
201
|
+
if (this.destroyedSignal.get()) {
|
|
202
|
+
callback();
|
|
203
|
+
return () => void 0;
|
|
204
|
+
}
|
|
205
|
+
const subscription = from(this.destroyedSignal).pipe(filter((destroyed) => destroyed), take(1)).subscribe({ next: callback });
|
|
206
|
+
return () => {
|
|
207
|
+
subscription.unsubscribe();
|
|
208
|
+
};
|
|
209
|
+
}
|
|
210
|
+
dispose() {
|
|
211
|
+
if (this.destroyedSignal.get()) return;
|
|
212
|
+
this.destroyedSignal.set(true);
|
|
213
|
+
}
|
|
214
|
+
destroy() {
|
|
215
|
+
this.dispose();
|
|
216
|
+
}
|
|
217
|
+
};
|
|
218
|
+
function createSecuritydeptDestroyRef() {
|
|
219
|
+
return new ManagedSecuritydeptDestroyRef();
|
|
220
|
+
}
|
|
221
|
+
//#endregion
|
|
222
|
+
//#region src/validation/schemas/uri.ts
|
|
223
|
+
const UriStringSchema = type("string").narrow((value, context) => UriString.tryParse(value) == null ? context.reject("an absolute URI string") : true);
|
|
224
|
+
const BaseURIStringSchema = UriStringSchema;
|
|
225
|
+
const UriRelativeStringSchema = type("string").narrow((value, context) => UriRelativeString.tryParse(value) == null ? context.reject("a relative URI reference string") : true);
|
|
226
|
+
const UriReferenceStringSchema = type("string").narrow((value, context) => UriReferenceString.tryParse(value) == null ? context.reject("a URI reference string") : true);
|
|
227
|
+
//#endregion
|
|
228
|
+
//#region src/cancellation/linked.ts
|
|
229
|
+
var LinkedCancellationToken = class {
|
|
230
|
+
sources;
|
|
231
|
+
destoryed$ = new ReplaySubject(1);
|
|
232
|
+
token;
|
|
233
|
+
constructor(sources) {
|
|
234
|
+
this.sources = sources;
|
|
235
|
+
if (sources.length === 0) this.token = new CancellationToken();
|
|
236
|
+
if (sources.length === 1) this.token = sources[0];
|
|
237
|
+
for (const source of sources) if (source.isCancellationRequested) {
|
|
238
|
+
this.token = source;
|
|
239
|
+
return;
|
|
240
|
+
}
|
|
241
|
+
const newToken = new CancellationToken();
|
|
242
|
+
merge(...sources).pipe(take(1), takeUntil(this.destoryed$)).subscribe(({ reason }) => {
|
|
243
|
+
newToken._cancel(reason);
|
|
244
|
+
});
|
|
245
|
+
this.token = newToken;
|
|
246
|
+
}
|
|
247
|
+
get isCancellationRequested() {
|
|
248
|
+
return this.token.isCancellationRequested;
|
|
249
|
+
}
|
|
250
|
+
get cancellationError() {
|
|
251
|
+
return this.token.cancellationError;
|
|
252
|
+
}
|
|
253
|
+
get reason() {
|
|
254
|
+
return this.token.reason;
|
|
255
|
+
}
|
|
256
|
+
onCancellationRequested(listener) {
|
|
257
|
+
return this.token.onCancellationRequested(listener);
|
|
258
|
+
}
|
|
259
|
+
throwIfCancellationRequested() {
|
|
260
|
+
this.token.throwIfCancellationRequested();
|
|
261
|
+
}
|
|
262
|
+
dispose() {
|
|
263
|
+
this.destoryed$.next(true);
|
|
264
|
+
}
|
|
265
|
+
[SYMBOL_DISPOSE]() {
|
|
266
|
+
this.dispose();
|
|
267
|
+
}
|
|
268
|
+
[SYMBOL_OBSERVABLE]() {
|
|
269
|
+
return this.token[SYMBOL_OBSERVABLE]();
|
|
270
|
+
}
|
|
271
|
+
};
|
|
67
272
|
/**
|
|
68
273
|
* Create a cancellation token that fires when ANY of the given source tokens
|
|
69
274
|
* is cancelled.
|
|
@@ -79,418 +284,1008 @@ function createCancellationTokenSource() {
|
|
|
79
284
|
* await transport.execute({ ..., cancellationToken: linked });
|
|
80
285
|
*/
|
|
81
286
|
function createLinkedCancellationToken(...sources) {
|
|
82
|
-
|
|
83
|
-
if (sources.length === 1) return sources[0];
|
|
84
|
-
for (const source of sources) if (source.isCancellationRequested) return source;
|
|
85
|
-
const linked = createCancellationTokenSource();
|
|
86
|
-
const subscriptions = sources.map((source) => source.onCancellationRequested((reason) => linked.cancel(reason)));
|
|
87
|
-
linked.token.onCancellationRequested(() => {
|
|
88
|
-
for (const sub of subscriptions) sub.dispose();
|
|
89
|
-
});
|
|
90
|
-
return linked.token;
|
|
287
|
+
return new LinkedCancellationToken(sources.filter((s) => !!s));
|
|
91
288
|
}
|
|
92
289
|
//#endregion
|
|
93
|
-
//#region src/
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
const POPUP_PRESENTATIONS = {
|
|
102
|
-
"popup.blocked": {
|
|
103
|
-
title: "Popup was blocked",
|
|
104
|
-
description: "The browser blocked the popup window before the login flow could start. Allow popups for this site, then try again.",
|
|
105
|
-
tone: ErrorPresentationTone.Warning
|
|
106
|
-
},
|
|
107
|
-
"popup.closed_by_user": {
|
|
108
|
-
title: "Popup login was closed",
|
|
109
|
-
description: "The popup window was closed before the OIDC provider returned a callback. Start the login flow again to continue.",
|
|
110
|
-
tone: ErrorPresentationTone.Warning
|
|
111
|
-
},
|
|
112
|
-
"popup.relay_timeout": {
|
|
113
|
-
title: "Popup relay timed out",
|
|
114
|
-
description: "The popup callback never relayed back to the opener before the timeout window expired.",
|
|
115
|
-
tone: ErrorPresentationTone.Warning
|
|
116
|
-
},
|
|
117
|
-
"popup.relay_error": {
|
|
118
|
-
title: "Popup relay failed",
|
|
119
|
-
description: "The popup callback page returned an error instead of a callback payload.",
|
|
120
|
-
tone: ErrorPresentationTone.Danger
|
|
121
|
-
}
|
|
122
|
-
};
|
|
123
|
-
function readErrorPresentationDescriptor(error, options = {}) {
|
|
124
|
-
if (error instanceof ClientError) return describeClientErrorPresentation(error, options);
|
|
125
|
-
const clientErrorLike = coerceClientErrorLike(error);
|
|
126
|
-
if (clientErrorLike) return describeClientErrorLikePresentation(clientErrorLike, options);
|
|
127
|
-
if (error instanceof Error) return {
|
|
128
|
-
code: null,
|
|
129
|
-
kind: null,
|
|
130
|
-
title: options.fallbackTitle ?? "Operation failed",
|
|
131
|
-
description: error.message || options.fallbackDescription || "An unexpected error prevented the operation from completing.",
|
|
132
|
-
recovery: UserRecovery.None,
|
|
133
|
-
retryable: false,
|
|
134
|
-
tone: ErrorPresentationTone.Danger,
|
|
135
|
-
primaryAction: null
|
|
136
|
-
};
|
|
137
|
-
return {
|
|
138
|
-
code: null,
|
|
139
|
-
kind: null,
|
|
140
|
-
title: options.fallbackTitle ?? "Operation failed",
|
|
141
|
-
description: options.fallbackDescription ?? "An unexpected error prevented the operation from completing.",
|
|
142
|
-
recovery: UserRecovery.None,
|
|
143
|
-
retryable: false,
|
|
144
|
-
tone: ErrorPresentationTone.Danger,
|
|
145
|
-
primaryAction: null
|
|
146
|
-
};
|
|
147
|
-
}
|
|
148
|
-
function describeClientErrorPresentation(error, options) {
|
|
149
|
-
return describeClientErrorLikePresentation({
|
|
150
|
-
code: error.code,
|
|
151
|
-
kind: error.kind,
|
|
152
|
-
message: error.message,
|
|
153
|
-
recovery: error.recovery,
|
|
154
|
-
retryable: error.retryable,
|
|
155
|
-
source: error.source,
|
|
156
|
-
presentation: error.presentation
|
|
157
|
-
}, options);
|
|
158
|
-
}
|
|
159
|
-
function describeClientErrorLikePresentation(error, options) {
|
|
160
|
-
const popupPresentation = POPUP_PRESENTATIONS[error.code];
|
|
161
|
-
const title = popupPresentation?.title ?? readClientErrorTitle(error);
|
|
162
|
-
const description = popupPresentation?.description ?? error.presentation?.message ?? error.message ?? options.fallbackDescription ?? "The operation could not complete.";
|
|
163
|
-
return {
|
|
164
|
-
code: error.code,
|
|
165
|
-
kind: error.kind,
|
|
166
|
-
source: error.source,
|
|
167
|
-
title,
|
|
168
|
-
description,
|
|
169
|
-
recovery: error.recovery,
|
|
170
|
-
retryable: error.retryable,
|
|
171
|
-
tone: popupPresentation?.tone ?? readClientErrorTone(error),
|
|
172
|
-
primaryAction: readPrimaryAction(error.recovery, options)
|
|
173
|
-
};
|
|
290
|
+
//#region src/signals/computed.ts
|
|
291
|
+
/**
|
|
292
|
+
* Create a lazy computed signal.
|
|
293
|
+
*
|
|
294
|
+
* Dependencies are collected dynamically while `compute()` runs.
|
|
295
|
+
*/
|
|
296
|
+
function createComputed(compute, options) {
|
|
297
|
+
return RxComputedSignal.computed(compute, options);
|
|
174
298
|
}
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
if (error.kind === ClientErrorKind.Storage) return "Browser storage failed";
|
|
183
|
-
if (error.kind === ClientErrorKind.Authorization && error.recovery === UserRecovery.RestartFlow) return "Flow needs to restart";
|
|
184
|
-
if (error.kind === ClientErrorKind.Transport) return "Network request failed";
|
|
185
|
-
if (error.kind === ClientErrorKind.Server) return "Server request failed";
|
|
186
|
-
if (error.kind === ClientErrorKind.Protocol) return "Request failed";
|
|
187
|
-
return "Operation failed";
|
|
188
|
-
}
|
|
189
|
-
function readClientErrorTone(error) {
|
|
190
|
-
if (error.kind === ClientErrorKind.Cancelled) return ErrorPresentationTone.Neutral;
|
|
191
|
-
if (error.kind === ClientErrorKind.Unauthenticated || error.kind === ClientErrorKind.Timeout || error.kind === ClientErrorKind.Transport || error.kind === ClientErrorKind.Server || error.recovery === UserRecovery.Retry || error.recovery === UserRecovery.RestartFlow || error.recovery === UserRecovery.Reauthenticate) return ErrorPresentationTone.Warning;
|
|
192
|
-
return ErrorPresentationTone.Danger;
|
|
193
|
-
}
|
|
194
|
-
function coerceClientErrorLike(error) {
|
|
195
|
-
if (typeof error !== "object" || error === null) return null;
|
|
196
|
-
const candidate = error;
|
|
197
|
-
if (typeof candidate.message !== "string") return null;
|
|
198
|
-
return {
|
|
199
|
-
code: typeof candidate.code === "string" ? candidate.code : null,
|
|
200
|
-
kind: typeof candidate.kind === "string" ? candidate.kind : null,
|
|
201
|
-
message: candidate.message,
|
|
202
|
-
recovery: typeof candidate.recovery === "string" ? candidate.recovery : UserRecovery.None,
|
|
203
|
-
retryable: candidate.retryable === true,
|
|
204
|
-
source: typeof candidate.source === "string" ? candidate.source : void 0,
|
|
205
|
-
presentation: isErrorPresentation(candidate.presentation) ? candidate.presentation : void 0
|
|
206
|
-
};
|
|
299
|
+
//#endregion
|
|
300
|
+
//#region src/signals/resource.ts
|
|
301
|
+
function createResource(options) {
|
|
302
|
+
return rxResource({
|
|
303
|
+
...options,
|
|
304
|
+
stream: (context) => from(options.stream(context))
|
|
305
|
+
});
|
|
207
306
|
}
|
|
208
|
-
|
|
209
|
-
|
|
307
|
+
//#endregion
|
|
308
|
+
//#region src/router/metadata.ts
|
|
309
|
+
/** Route-data key holding the SecurityDept metadata blob for a segment. */
|
|
310
|
+
const SECURITYDEPT_ROUTE_METADATA_KEY = "__securitydept__";
|
|
311
|
+
/** Read SecurityDept route metadata from a route `data` bag. */
|
|
312
|
+
function readSecuritydeptRouteMetadata(data) {
|
|
313
|
+
const raw = data?.[SECURITYDEPT_ROUTE_METADATA_KEY];
|
|
314
|
+
if (raw === void 0 || raw === null) return;
|
|
315
|
+
return raw;
|
|
210
316
|
}
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
const
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
href: options.recoveryLinks?.[recovery] ?? null
|
|
317
|
+
/** Merge SecurityDept route metadata into a route `data` bag. */
|
|
318
|
+
function writeSecuritydeptRouteMetadata(base, patch) {
|
|
319
|
+
const data = { ...base ?? {} };
|
|
320
|
+
const previous = data["__securitydept__"] ?? {};
|
|
321
|
+
data[SECURITYDEPT_ROUTE_METADATA_KEY] = {
|
|
322
|
+
...previous,
|
|
323
|
+
...patch
|
|
219
324
|
};
|
|
325
|
+
return data;
|
|
220
326
|
}
|
|
221
327
|
//#endregion
|
|
222
|
-
//#region src/
|
|
223
|
-
function
|
|
224
|
-
return
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
328
|
+
//#region src/std/transport/authorization-interceptor.ts
|
|
329
|
+
function createAuthorizationInterceptedFetch(fetchImpl, options) {
|
|
330
|
+
return async (input, init) => {
|
|
331
|
+
if (!await options.predicate(input, init)) return fetchImpl(input, init);
|
|
332
|
+
const authorization = "whenValue" in options.authorization ? await options.authorization.whenValue() : options.authorization.get();
|
|
333
|
+
if (!authorization) return fetchImpl(input, init);
|
|
334
|
+
const headers = new Headers(typeof Request !== "undefined" && input instanceof Request ? input.headers : void 0);
|
|
335
|
+
if (init?.headers) new Headers(init.headers).forEach((value, key) => {
|
|
336
|
+
headers.set(key, value);
|
|
337
|
+
});
|
|
338
|
+
headers.set("authorization", authorization);
|
|
339
|
+
return fetchImpl(input, {
|
|
340
|
+
...init,
|
|
341
|
+
headers
|
|
342
|
+
});
|
|
343
|
+
};
|
|
228
344
|
}
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
345
|
+
//#endregion
|
|
346
|
+
//#region src/tracing/operation-runner.ts
|
|
347
|
+
var OperationSpan = class OperationSpan {
|
|
348
|
+
span;
|
|
349
|
+
_environment;
|
|
350
|
+
_target;
|
|
351
|
+
constructor(span, _environment, _target) {
|
|
352
|
+
this.span = span;
|
|
353
|
+
this._environment = _environment;
|
|
354
|
+
this._target = _target;
|
|
355
|
+
}
|
|
356
|
+
static start(options) {
|
|
357
|
+
const span = options.span.fork({
|
|
358
|
+
mutable: true,
|
|
359
|
+
idFactory: options.idFactory,
|
|
360
|
+
attributes: { [SpanSharedAttributeName.OperationName]: options.name }
|
|
361
|
+
});
|
|
362
|
+
if (options.traceAttributes) span.setAttributes(options.traceAttributes, { providerId: TRACING_SPAN_ATTRIBUTE_PROVIDER_ID });
|
|
363
|
+
const operationSpan = new OperationSpan(span, options.environment, options.target);
|
|
364
|
+
operationSpan.recordStarted();
|
|
365
|
+
return operationSpan;
|
|
366
|
+
}
|
|
367
|
+
setTraceAttributes(attributes) {
|
|
368
|
+
this.span.setAttributes(attributes, { providerId: TRACING_SPAN_ATTRIBUTE_PROVIDER_ID });
|
|
369
|
+
}
|
|
370
|
+
addEvent(name, fields) {
|
|
371
|
+
this._record(OperationTraceEventType.Event, TracingLevel.Info, {
|
|
372
|
+
eventName: name,
|
|
373
|
+
...fields ?? {}
|
|
374
|
+
});
|
|
375
|
+
}
|
|
376
|
+
recordError(error, fields) {
|
|
377
|
+
this._record(OperationTraceEventType.Error, TracingLevel.Error, {
|
|
378
|
+
...describeError(error),
|
|
379
|
+
...fields ?? {}
|
|
380
|
+
});
|
|
381
|
+
}
|
|
382
|
+
recordStarted() {
|
|
383
|
+
this._record(OperationTraceEventType.Started, TracingLevel.Info);
|
|
384
|
+
}
|
|
385
|
+
recordEnded(outcome) {
|
|
386
|
+
this._record(OperationTraceEventType.Ended, outcome === "succeeded" ? TracingLevel.Info : TracingLevel.Error, { outcome });
|
|
387
|
+
}
|
|
388
|
+
_record(name, level, fields) {
|
|
389
|
+
this._environment.tracing.record({
|
|
390
|
+
name,
|
|
391
|
+
at: this._environment.time.now(),
|
|
392
|
+
span: this.span,
|
|
393
|
+
level,
|
|
394
|
+
target: this._target,
|
|
395
|
+
fields
|
|
396
|
+
});
|
|
397
|
+
}
|
|
398
|
+
};
|
|
399
|
+
function runOperation(options) {
|
|
400
|
+
const operationSpan = OperationSpan.start(options);
|
|
401
|
+
try {
|
|
402
|
+
const result = options.execute(operationSpan);
|
|
403
|
+
if (isPromise(result)) return result.then((value) => completeOperation(operationSpan, value), (error) => failOperation(operationSpan, error, options.clientErrorFromUnknown));
|
|
404
|
+
return completeOperation(operationSpan, result);
|
|
405
|
+
} catch (error) {
|
|
406
|
+
return failOperation(operationSpan, error, options.clientErrorFromUnknown);
|
|
407
|
+
}
|
|
232
408
|
}
|
|
233
|
-
function
|
|
234
|
-
|
|
235
|
-
return
|
|
236
|
-
subject: input.subject,
|
|
237
|
-
displayName: resolveDisplayName(input.displayName, input.subject),
|
|
238
|
-
picture: readOptionalString(input.picture),
|
|
239
|
-
issuer: readOptionalString(input.issuer),
|
|
240
|
-
claims: readClaimsBag(input.claims)
|
|
241
|
-
};
|
|
409
|
+
function completeOperation(operationSpan, result) {
|
|
410
|
+
operationSpan.recordEnded("succeeded");
|
|
411
|
+
return result;
|
|
242
412
|
}
|
|
243
|
-
function
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
issuer: readOptionalString(input.issuer),
|
|
250
|
-
claims: readClaimsBag(input.claims)
|
|
251
|
-
};
|
|
413
|
+
function failOperation(operationSpan, error, clientErrorFromUnknown) {
|
|
414
|
+
const clientError = clientErrorFromUnknown ? clientErrorFromUnknown(error, { span: operationSpan.span }) : error;
|
|
415
|
+
if (clientError instanceof ClientError) clientError.captureSpanContext(operationSpan.span);
|
|
416
|
+
operationSpan.recordError(clientError);
|
|
417
|
+
operationSpan.recordEnded("failed");
|
|
418
|
+
throw clientError;
|
|
252
419
|
}
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
return {
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
420
|
+
//#endregion
|
|
421
|
+
//#region src/tracing/operation-method.ts
|
|
422
|
+
function defineInstrumentMethodDecorator(factory) {
|
|
423
|
+
return (...factoryArgs) => (target, context) => {
|
|
424
|
+
const methodName = String(context.name);
|
|
425
|
+
const resolve = factory({
|
|
426
|
+
factoryArgs,
|
|
427
|
+
methodName
|
|
428
|
+
});
|
|
429
|
+
return function(...args) {
|
|
430
|
+
const resolvedOptions = resolve.call(this, {
|
|
431
|
+
args,
|
|
432
|
+
methodName
|
|
433
|
+
});
|
|
434
|
+
return runOperation({
|
|
435
|
+
environment: resolvedOptions.environment,
|
|
436
|
+
span: resolvedOptions.span,
|
|
437
|
+
name: resolvedOptions.name ?? methodName,
|
|
438
|
+
target: resolvedOptions.target,
|
|
439
|
+
traceAttributes: resolvedOptions.traceAttributes,
|
|
440
|
+
idFactory: resolvedOptions.idFactory,
|
|
441
|
+
clientErrorFromUnknown: resolvedOptions.clientErrorFromUnknown,
|
|
442
|
+
execute: (span) => target.call(this, ...args, span)
|
|
443
|
+
});
|
|
444
|
+
};
|
|
262
445
|
};
|
|
263
446
|
}
|
|
264
447
|
//#endregion
|
|
265
|
-
//#region src/
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
const
|
|
270
|
-
|
|
448
|
+
//#region src/tracing/subscriber/console.ts
|
|
449
|
+
var ConsoleTracingSubscriber = class {
|
|
450
|
+
record(event) {
|
|
451
|
+
const label = `[${event.target}] ${event.name}`;
|
|
452
|
+
const details = {
|
|
453
|
+
...event.fields ?? {},
|
|
454
|
+
spanAttributes: event.span.getRootToNodeAttributes({ providerId: TRACING_SPAN_ATTRIBUTE_PROVIDER_ID })
|
|
455
|
+
};
|
|
456
|
+
switch (event.level) {
|
|
271
457
|
case "debug":
|
|
272
|
-
console.debug(label,
|
|
458
|
+
console.debug(label, details);
|
|
273
459
|
break;
|
|
274
460
|
case "info":
|
|
275
|
-
console.info(label,
|
|
461
|
+
console.info(label, details);
|
|
276
462
|
break;
|
|
277
463
|
case "warn":
|
|
278
|
-
console.warn(label,
|
|
279
|
-
break;
|
|
280
|
-
case "error":
|
|
281
|
-
console.error(label, entry.message, entry.error ?? "", entry.attributes ?? "");
|
|
464
|
+
console.warn(label, details);
|
|
282
465
|
break;
|
|
466
|
+
case "error": console.error(label, details);
|
|
283
467
|
}
|
|
284
|
-
}
|
|
468
|
+
}
|
|
469
|
+
};
|
|
470
|
+
function createConsoleTracingSubscriber() {
|
|
471
|
+
return new ConsoleTracingSubscriber();
|
|
285
472
|
}
|
|
286
473
|
//#endregion
|
|
287
|
-
//#region src/
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
474
|
+
//#region src/struct/ring-buffer.ts
|
|
475
|
+
var FixedCapacityRingBuffer = class {
|
|
476
|
+
capacity;
|
|
477
|
+
values;
|
|
478
|
+
head = 0;
|
|
479
|
+
tail = 0;
|
|
480
|
+
_size = 0;
|
|
481
|
+
constructor(capacity) {
|
|
482
|
+
this.capacity = capacity;
|
|
483
|
+
if (!Number.isInteger(capacity) || capacity <= 0) throw new RangeError("Ring buffer capacity must be a positive integer.");
|
|
484
|
+
this.values = new Array(capacity);
|
|
485
|
+
}
|
|
486
|
+
get size() {
|
|
487
|
+
return this._size;
|
|
488
|
+
}
|
|
489
|
+
append(value) {
|
|
490
|
+
this.values[this.tail] = value;
|
|
491
|
+
this.tail = (this.tail + 1) % this.capacity;
|
|
492
|
+
if (this._size === this.capacity) this.head = this.tail;
|
|
493
|
+
else this._size += 1;
|
|
494
|
+
}
|
|
495
|
+
toArray() {
|
|
496
|
+
const snapshot = new Array(this._size);
|
|
497
|
+
for (let index = 0; index < this._size; index += 1) snapshot[index] = this.values[(this.head + index) % this.capacity];
|
|
498
|
+
return snapshot;
|
|
499
|
+
}
|
|
500
|
+
clear() {
|
|
501
|
+
this.values.fill(void 0);
|
|
502
|
+
this.head = 0;
|
|
503
|
+
this.tail = 0;
|
|
504
|
+
this._size = 0;
|
|
505
|
+
}
|
|
506
|
+
};
|
|
292
507
|
//#endregion
|
|
293
|
-
//#region src/
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
508
|
+
//#region src/tracing/subscriber/timeline-store.ts
|
|
509
|
+
/**
|
|
510
|
+
* Bounded subscriber-side trace timeline.
|
|
511
|
+
*
|
|
512
|
+
* This store consumes tracing events through `record(event)` and keeps a
|
|
513
|
+
* bounded local timeline for tests and UI surfaces. It is not the tracing
|
|
514
|
+
* runtime itself.
|
|
515
|
+
*/
|
|
516
|
+
var TraceTimelineStore = class {
|
|
517
|
+
limit;
|
|
518
|
+
nextId = 1;
|
|
519
|
+
timeline;
|
|
520
|
+
latestEntrySubject = new RxEventSubject();
|
|
521
|
+
constructor(limit = 200) {
|
|
522
|
+
this.limit = limit;
|
|
523
|
+
this.timeline = new FixedCapacityRingBuffer(limit);
|
|
307
524
|
}
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
525
|
+
get latestEntry() {
|
|
526
|
+
return this.latestEntrySubject;
|
|
527
|
+
}
|
|
528
|
+
get entries() {
|
|
529
|
+
return this.timeline.toArray();
|
|
530
|
+
}
|
|
531
|
+
record(event) {
|
|
532
|
+
const { span, ...eventWithoutSpan } = event;
|
|
533
|
+
const entry = {
|
|
534
|
+
...eventWithoutSpan,
|
|
535
|
+
id: this.nextId++,
|
|
536
|
+
recordedAtIso: new Date(event.at).toISOString(),
|
|
537
|
+
span: {
|
|
538
|
+
id: span.id,
|
|
539
|
+
...span.parent ? { parentId: span.parent.id } : {}
|
|
540
|
+
},
|
|
541
|
+
spanAttributes: span.getRootToNodeAttributes({ providerId: TRACING_SPAN_ATTRIBUTE_PROVIDER_ID })
|
|
542
|
+
};
|
|
543
|
+
this.timeline.append(entry);
|
|
544
|
+
this.latestEntrySubject.next(entry);
|
|
545
|
+
}
|
|
546
|
+
clear() {
|
|
547
|
+
if (this.timeline.size > 0) {
|
|
548
|
+
this.timeline.clear();
|
|
549
|
+
this.latestEntrySubject.next(null);
|
|
331
550
|
}
|
|
332
|
-
}
|
|
551
|
+
}
|
|
552
|
+
};
|
|
553
|
+
function createTraceTimelineStore(limit = 200) {
|
|
554
|
+
return new TraceTimelineStore(limit);
|
|
333
555
|
}
|
|
334
556
|
//#endregion
|
|
335
|
-
//#region src/
|
|
557
|
+
//#region src/auth-coordination/planner-host.ts
|
|
558
|
+
const REQUIREMENT_PLANNER_HOST = new SecuritydeptInjectionToken("REQUIREMENT_PLANNER_HOST");
|
|
336
559
|
/**
|
|
337
|
-
*
|
|
560
|
+
* Default candidate selector: first unauthenticated candidate as soon as it is
|
|
561
|
+
* discovered.
|
|
338
562
|
*
|
|
339
|
-
*
|
|
340
|
-
*
|
|
341
|
-
* - `get()` recomputes only when dirty (a dependency changed since last read).
|
|
342
|
-
* - Subscribers are notified only when a dependency changes (dirty-flagged),
|
|
343
|
-
* and the next `get()` will produce the fresh value.
|
|
344
|
-
*
|
|
345
|
-
* Dependency subscriptions are permanent for the lifetime of the computed signal.
|
|
563
|
+
* If every requirement is already fulfilled the stream completes and the
|
|
564
|
+
* selector returns `undefined`.
|
|
346
565
|
*/
|
|
347
|
-
function
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
const markDirty = () => {
|
|
352
|
-
if (!dirty) {
|
|
353
|
-
dirty = true;
|
|
354
|
-
for (const listener of listeners) listener();
|
|
355
|
-
}
|
|
566
|
+
function defaultSelectCandidate() {
|
|
567
|
+
return async function selectFirstCandidate(context) {
|
|
568
|
+
const result = await context.candidateList.next();
|
|
569
|
+
return result.done ? void 0 : result.value;
|
|
356
570
|
};
|
|
357
|
-
|
|
571
|
+
}
|
|
572
|
+
/**
|
|
573
|
+
* A coordination-scope host that resolves behaviour through a parent chain.
|
|
574
|
+
*
|
|
575
|
+
* Construct via {@link RequirementPlannerHost.fromBehaviour}. Each behaviour
|
|
576
|
+
* field is optional at host construction time; missing required behaviour is
|
|
577
|
+
* resolved from `parent` and fails fast during planner build if no host in the
|
|
578
|
+
* chain provides it.
|
|
579
|
+
*
|
|
580
|
+
* @example
|
|
581
|
+
* ```ts
|
|
582
|
+
* const root = RequirementPlannerHost.fromBehaviour({
|
|
583
|
+
* checkAuthenticated: (req) => isAuthenticated(req),
|
|
584
|
+
* onUnauthenticated: (req) => `/login/${req.id}`,
|
|
585
|
+
* });
|
|
586
|
+
*
|
|
587
|
+
* // Feature scope overrides only the chooser, inheriting the rest.
|
|
588
|
+
* const feature = RequirementPlannerHost.fromBehaviour(
|
|
589
|
+
* { selectCandidate: async (ctx) => showChooser(ctx.candidateList) },
|
|
590
|
+
* { parent: root },
|
|
591
|
+
* );
|
|
592
|
+
* ```
|
|
593
|
+
*/
|
|
594
|
+
var RequirementPlannerHost = class RequirementPlannerHost {
|
|
595
|
+
environment;
|
|
596
|
+
parent;
|
|
597
|
+
/** The parent host, or undefined at the root. */
|
|
598
|
+
_behaviour;
|
|
599
|
+
constructor(behaviour, environment, parent) {
|
|
600
|
+
this.environment = environment;
|
|
601
|
+
this.parent = parent;
|
|
602
|
+
this._behaviour = behaviour;
|
|
603
|
+
}
|
|
604
|
+
/** Create a host scope from a partial behaviour and optional parent. */
|
|
605
|
+
static fromBehaviour(behaviour, options = {}) {
|
|
606
|
+
return new RequirementPlannerHost(behaviour, options.environment, options.parent);
|
|
607
|
+
}
|
|
608
|
+
async resolveBehaviourOptionFor(key) {
|
|
609
|
+
return this._behaviour[key] ?? await this.parent?.resolveBehaviourOptionFor(key);
|
|
610
|
+
}
|
|
611
|
+
async resolveBehaviourFor(key, defaultValue) {
|
|
612
|
+
return await this.resolveBehaviourOptionFor(key) ?? await defaultValue();
|
|
613
|
+
}
|
|
614
|
+
async resolveEnvironmentOption() {
|
|
615
|
+
return this.environment ?? await this.parent?.resolveEnvironmentOption();
|
|
616
|
+
}
|
|
617
|
+
async resolveEnvironment(defaultValue) {
|
|
618
|
+
return await this.resolveEnvironmentOption() ?? await defaultValue();
|
|
619
|
+
}
|
|
620
|
+
};
|
|
621
|
+
function provideRequirementPlannerHost(behaviour, options = {}) {
|
|
358
622
|
return {
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
623
|
+
provide: REQUIREMENT_PLANNER_HOST,
|
|
624
|
+
useFactory: (parentInjector, environment) => {
|
|
625
|
+
const parent = options.parent ?? parentInjector?.get(REQUIREMENT_PLANNER_HOST, null) ?? void 0;
|
|
626
|
+
const resolved = typeof behaviour === "function" ? behaviour() : behaviour;
|
|
627
|
+
return RequirementPlannerHost.fromBehaviour(resolved, {
|
|
628
|
+
parent,
|
|
629
|
+
environment: options.environment ?? environment ?? void 0
|
|
630
|
+
});
|
|
365
631
|
},
|
|
366
|
-
|
|
367
|
-
listeners.add(listener);
|
|
368
|
-
return () => {
|
|
369
|
-
listeners.delete(listener);
|
|
370
|
-
};
|
|
371
|
-
}
|
|
632
|
+
deps: [[new SecurityDeptOptional(), PARENT_INJECTOR_TOKEN], [new SecurityDeptOptional(), ENVIRONMENT_TOKEN]]
|
|
372
633
|
};
|
|
373
634
|
}
|
|
635
|
+
function injectRequirementPlannerHost(options) {
|
|
636
|
+
return options.injector.get(REQUIREMENT_PLANNER_HOST, null);
|
|
637
|
+
}
|
|
374
638
|
//#endregion
|
|
375
|
-
//#region src/
|
|
639
|
+
//#region src/auth-coordination/planner/base-planner.ts
|
|
376
640
|
/**
|
|
377
|
-
*
|
|
378
|
-
*
|
|
641
|
+
* Abstract base for all requirement planners.
|
|
642
|
+
*
|
|
643
|
+
* Subclasses supply requirements via {@link buildRequirementList}. Pipeline
|
|
644
|
+
* state lives on {@link RequirementPlan}, produced by {@link buildPlan}.
|
|
379
645
|
*/
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
646
|
+
var BaseRequirementPlanner = class {
|
|
647
|
+
host;
|
|
648
|
+
initialResolutions;
|
|
649
|
+
constructor(host, initialResolutions = []) {
|
|
650
|
+
this.host = host;
|
|
651
|
+
this.initialResolutions = initialResolutions.map((resolution) => Object.freeze({ ...resolution }));
|
|
652
|
+
}
|
|
653
|
+
/**
|
|
654
|
+
* Pipeline step 0: resolve host behaviour and materialize requirements into
|
|
655
|
+
* a {@link RequirementPlan}.
|
|
656
|
+
*
|
|
657
|
+
* Behaviour and the requirement list stay fixed on the returned plan until
|
|
658
|
+
* the next `buildPlan()` call. Resolve host parent chains (and any
|
|
659
|
+
* injection-context capture) here — not between async steps.
|
|
660
|
+
*/
|
|
661
|
+
async buildPlan() {
|
|
662
|
+
return {
|
|
663
|
+
planContext: this.planContext,
|
|
664
|
+
environment: await this.host.resolveEnvironment(() => {
|
|
665
|
+
throw new RequirementPlannerError("No environment resolved");
|
|
666
|
+
}),
|
|
667
|
+
checkAuthenticated: await this.host.resolveBehaviourFor("checkAuthenticated", () => {
|
|
668
|
+
throw new RequirementPlannerError("No checkAuthenticated resolved");
|
|
669
|
+
}),
|
|
670
|
+
onUnauthenticated: await this.host.resolveBehaviourFor("onUnauthenticated", () => {
|
|
671
|
+
throw new RequirementPlannerError("No onUnauthenticated behaviour resolved");
|
|
672
|
+
}),
|
|
673
|
+
selectCandidate: await this.host.resolveBehaviourFor("selectCandidate", defaultSelectCandidate),
|
|
674
|
+
requirements: await this.resolveRequirementList(),
|
|
675
|
+
resolutionList: [...this.initialResolutions]
|
|
676
|
+
};
|
|
677
|
+
}
|
|
678
|
+
/**
|
|
679
|
+
* Materialize the effective requirement list (also invoked by {@link buildPlan}).
|
|
680
|
+
*/
|
|
681
|
+
async resolveRequirementList() {
|
|
682
|
+
return [...(await this.buildRequirementList()).values()];
|
|
683
|
+
}
|
|
684
|
+
/**
|
|
685
|
+
* Pipeline step 1 — one loop iteration: select a candidate, run
|
|
686
|
+
* `onUnauthenticated`, then reduce `plan` state.
|
|
687
|
+
*/
|
|
688
|
+
async runStep(plan) {
|
|
689
|
+
const candidate = await plan.selectCandidate({
|
|
690
|
+
...plan,
|
|
691
|
+
candidateList: this.createCandidateStream(plan)
|
|
692
|
+
});
|
|
693
|
+
if (!candidate) return { outcome: PipelineOutcome.Settled };
|
|
694
|
+
const action = await plan.onUnauthenticated(candidate, plan);
|
|
695
|
+
return this.reduceFromAction(plan, candidate, action);
|
|
696
|
+
}
|
|
697
|
+
reduceFromAction(plan, candidate, action) {
|
|
698
|
+
if (action === true) {
|
|
699
|
+
this.recordFulfilled(plan, candidate);
|
|
700
|
+
return {
|
|
701
|
+
outcome: PipelineOutcome.Resolved,
|
|
702
|
+
requirement: candidate
|
|
396
703
|
};
|
|
397
704
|
}
|
|
398
|
-
|
|
399
|
-
|
|
705
|
+
if (action === false) return {
|
|
706
|
+
outcome: PipelineOutcome.Blocked,
|
|
707
|
+
requirement: candidate
|
|
708
|
+
};
|
|
709
|
+
return {
|
|
710
|
+
outcome: PipelineOutcome.Redirect,
|
|
711
|
+
requirement: candidate,
|
|
712
|
+
location: action
|
|
713
|
+
};
|
|
714
|
+
}
|
|
715
|
+
/**
|
|
716
|
+
* Run the full pipeline: {@link buildPlan}, step 1, then loop step 2 until
|
|
717
|
+
* settled or a terminal outcome (`blocked`, `redirect`, or a never-settling
|
|
718
|
+
* action).
|
|
719
|
+
*/
|
|
720
|
+
async runUntilSettled() {
|
|
721
|
+
const plan = await this.buildPlan();
|
|
722
|
+
return this.runUntilSettledWithPlan(plan);
|
|
723
|
+
}
|
|
724
|
+
async runUntilSettledWithPlan(plan) {
|
|
725
|
+
while (true) {
|
|
726
|
+
const step = await this.runStep(plan);
|
|
727
|
+
if (step.outcome === PipelineOutcome.Settled) return {
|
|
728
|
+
outcome: PipelineOutcome.Settled,
|
|
729
|
+
resolutions: plan.resolutionList
|
|
730
|
+
};
|
|
731
|
+
if (step.outcome === PipelineOutcome.Resolved) continue;
|
|
732
|
+
if (step.outcome === PipelineOutcome.Blocked) return step;
|
|
733
|
+
if (step.outcome === PipelineOutcome.Redirect) return step;
|
|
734
|
+
}
|
|
735
|
+
}
|
|
736
|
+
async *createCandidateStream(plan) {
|
|
737
|
+
const context = {
|
|
738
|
+
planContext: this.planContext,
|
|
739
|
+
requirements: plan.requirements,
|
|
740
|
+
resolutionList: plan.resolutionList,
|
|
741
|
+
environment: plan.environment
|
|
742
|
+
};
|
|
743
|
+
const checked = plan.requirements.filter((requirement) => !plan.resolutionList.some((resolution) => resolution.requirementId === requirement.id)).map(async (requirement) => {
|
|
744
|
+
return {
|
|
745
|
+
requirement,
|
|
746
|
+
satisfied: await plan.checkAuthenticated(requirement, context)
|
|
747
|
+
};
|
|
748
|
+
});
|
|
749
|
+
for await (const { requirement, satisfied } of promisesToRacedAsyncGenerator(checked)) {
|
|
750
|
+
if (satisfied) {
|
|
751
|
+
this.recordFulfilled(plan, requirement);
|
|
752
|
+
continue;
|
|
753
|
+
}
|
|
754
|
+
yield requirement;
|
|
755
|
+
}
|
|
756
|
+
}
|
|
757
|
+
recordFulfilled(plan, requirement) {
|
|
758
|
+
if (plan.resolutionList.some((resolution) => resolution.requirementId === requirement.id)) return;
|
|
759
|
+
plan.resolutionList.push(Object.freeze({
|
|
760
|
+
requirementId: requirement.id,
|
|
761
|
+
status: ResolutionStatus.Fulfilled
|
|
762
|
+
}));
|
|
763
|
+
}
|
|
764
|
+
};
|
|
765
|
+
//#endregion
|
|
766
|
+
//#region src/auth-coordination/planner/merge-planner.ts
|
|
400
767
|
/**
|
|
401
|
-
*
|
|
768
|
+
* A planner whose effective requirements are the ordered union of its source
|
|
769
|
+
* planners. Overlapping ids follow Map semantics (later source wins).
|
|
770
|
+
*
|
|
771
|
+
* @example
|
|
772
|
+
* ```ts
|
|
773
|
+
* const planner = MergeRequirementPlanner.fromPlanners(host, [
|
|
774
|
+
* sessionPlanner,
|
|
775
|
+
* oidcPlanner,
|
|
776
|
+
* ]);
|
|
777
|
+
* ```
|
|
402
778
|
*/
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
}
|
|
408
|
-
|
|
779
|
+
var MergeRequirementPlanner = class MergeRequirementPlanner extends BaseRequirementPlanner {
|
|
780
|
+
sources;
|
|
781
|
+
get planContext() {
|
|
782
|
+
return Object.assign({}, ...this.sources.map((source) => source.planContext));
|
|
783
|
+
}
|
|
784
|
+
constructor(host, sources) {
|
|
785
|
+
super(host);
|
|
786
|
+
this.sources = sources;
|
|
787
|
+
}
|
|
788
|
+
/** Create a merge planner from an ordered list of source planners. */
|
|
789
|
+
static fromPlanners(host, planners) {
|
|
790
|
+
return new MergeRequirementPlanner(host, planners);
|
|
791
|
+
}
|
|
792
|
+
async buildRequirementList() {
|
|
793
|
+
const map = /* @__PURE__ */ new Map();
|
|
794
|
+
for (const source of this.sources) for (const requirement of await source.resolveRequirementList()) map.set(requirement.id, requirement);
|
|
795
|
+
return map;
|
|
796
|
+
}
|
|
797
|
+
};
|
|
409
798
|
//#endregion
|
|
410
|
-
//#region src/
|
|
799
|
+
//#region src/auth-coordination/planner/route-composition-planner.ts
|
|
800
|
+
/** Fold a matched route chain into its effective requirement list. */
|
|
801
|
+
function foldSegments(segments) {
|
|
802
|
+
const effective = /* @__PURE__ */ new Map();
|
|
803
|
+
for (const segment of segments) resolveEffectiveRequirements({
|
|
804
|
+
composition: segment.composition ?? RequirementsComposition.Merge,
|
|
805
|
+
requirements: segment.requirements
|
|
806
|
+
}, effective);
|
|
807
|
+
return [...effective.values()];
|
|
808
|
+
}
|
|
809
|
+
/** Length of the shared requirement-id prefix between two effective lists. */
|
|
810
|
+
function sharedPrefixLength(previous, next) {
|
|
811
|
+
const limit = Math.min(previous.length, next.length);
|
|
812
|
+
let shared = 0;
|
|
813
|
+
while (shared < limit && previous[shared].id === next[shared].id) shared += 1;
|
|
814
|
+
return shared;
|
|
815
|
+
}
|
|
411
816
|
/**
|
|
412
|
-
*
|
|
817
|
+
* A planner driven by a matched route chain with composition semantics.
|
|
413
818
|
*
|
|
414
|
-
*
|
|
415
|
-
*
|
|
416
|
-
*
|
|
819
|
+
* Construct via {@link fromRouteSegments} for a matched route chain, or
|
|
820
|
+
* {@link fromRouteTransition} for a transition that preserves shared-prefix
|
|
821
|
+
* resolutions from the previous planner instance.
|
|
822
|
+
*/
|
|
823
|
+
var RouteCompositionRequirementPlanner = class RouteCompositionRequirementPlanner extends BaseRequirementPlanner {
|
|
824
|
+
_segments;
|
|
825
|
+
_effective;
|
|
826
|
+
_planContext;
|
|
827
|
+
constructor(host, segments, routeState, preservedResolutions = []) {
|
|
828
|
+
super(host, preservedResolutions);
|
|
829
|
+
this._segments = segments;
|
|
830
|
+
this._effective = foldSegments(segments);
|
|
831
|
+
this._planContext = Object.freeze({ routeState: Object.freeze({ ...routeState }) });
|
|
832
|
+
}
|
|
833
|
+
/** Build a planner from a matched route chain. */
|
|
834
|
+
static fromRouteSegments(host, segments, routeState) {
|
|
835
|
+
return new RouteCompositionRequirementPlanner(host, segments, routeState);
|
|
836
|
+
}
|
|
837
|
+
/**
|
|
838
|
+
* Build a planner for a route transition, preserving resolutions for the
|
|
839
|
+
* shared requirement prefix carried over from `previousPlan`.
|
|
840
|
+
*/
|
|
841
|
+
static fromRouteTransition(host, currentSegments, routeState, previousPlanner, previousPlan) {
|
|
842
|
+
const nextEffective = foldSegments(currentSegments);
|
|
843
|
+
const shared = sharedPrefixLength(previousPlanner.effectiveRequirements, nextEffective);
|
|
844
|
+
const sharedIds = new Set(nextEffective.slice(0, shared).map((requirement) => requirement.id));
|
|
845
|
+
const preserved = previousPlan.resolutionList.filter((resolution) => sharedIds.has(resolution.requirementId));
|
|
846
|
+
return new RouteCompositionRequirementPlanner(host, currentSegments, routeState, preserved);
|
|
847
|
+
}
|
|
848
|
+
get planContext() {
|
|
849
|
+
return this._planContext;
|
|
850
|
+
}
|
|
851
|
+
/** The matched route chain backing this planner. */
|
|
852
|
+
get segments() {
|
|
853
|
+
return this._segments;
|
|
854
|
+
}
|
|
855
|
+
/** The folded effective requirement list (composition applied). */
|
|
856
|
+
get effectiveRequirements() {
|
|
857
|
+
return this._effective;
|
|
858
|
+
}
|
|
859
|
+
buildRequirementList() {
|
|
860
|
+
return new Map(this._effective.map((requirement) => [requirement.id, requirement]));
|
|
861
|
+
}
|
|
862
|
+
};
|
|
863
|
+
//#endregion
|
|
864
|
+
//#region src/auth-coordination/planner/static-planner.ts
|
|
865
|
+
/**
|
|
866
|
+
* A planner whose effective requirement list is a fixed array supplied at
|
|
867
|
+
* construction time.
|
|
417
868
|
*
|
|
418
869
|
* @example
|
|
419
870
|
* ```ts
|
|
420
|
-
*
|
|
421
|
-
*
|
|
422
|
-
*
|
|
423
|
-
* const
|
|
424
|
-
* const
|
|
425
|
-
*
|
|
426
|
-
* console.log(result.value.name);
|
|
427
|
-
* } else {
|
|
428
|
-
* console.error(result.issues);
|
|
429
|
-
* }
|
|
871
|
+
* const planner = StaticRequirementPlanner.fromRequirements(host, [
|
|
872
|
+
* StaticAttrsAuthRequirement.create({ id: "session" }),
|
|
873
|
+
* ] as Readonly<AuthRequirement[]>);
|
|
874
|
+
* const plan = await planner.buildPlan();
|
|
875
|
+
* const step = await planner.runStep(plan);
|
|
876
|
+
* // or: const result = await planner.runUntilSettled();
|
|
430
877
|
* ```
|
|
431
878
|
*/
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
879
|
+
var StaticRequirementPlanner = class StaticRequirementPlanner extends BaseRequirementPlanner {
|
|
880
|
+
staticRequirements;
|
|
881
|
+
get planContext() {
|
|
882
|
+
return {};
|
|
883
|
+
}
|
|
884
|
+
constructor(host, requirements) {
|
|
885
|
+
super(host);
|
|
886
|
+
this.staticRequirements = requirements;
|
|
887
|
+
}
|
|
888
|
+
/** Create a static planner from an ordered requirement list. */
|
|
889
|
+
static fromRequirements(host, requirements) {
|
|
890
|
+
return new StaticRequirementPlanner(host, requirements);
|
|
891
|
+
}
|
|
892
|
+
buildRequirementList() {
|
|
893
|
+
const map = /* @__PURE__ */ new Map();
|
|
894
|
+
for (const requirement of this.staticRequirements) map.set(requirement.id, requirement);
|
|
895
|
+
return map;
|
|
896
|
+
}
|
|
897
|
+
};
|
|
898
|
+
//#endregion
|
|
899
|
+
//#region src/events/create.ts
|
|
900
|
+
/**
|
|
901
|
+
* Create a new event stream from a producer function.
|
|
902
|
+
*
|
|
903
|
+
* The producer receives an observer and should call `next()` to emit values,
|
|
904
|
+
* `error()` to signal an error, and `complete()` to signal completion.
|
|
905
|
+
* It may return a teardown function that will be called on unsubscribe.
|
|
906
|
+
*/
|
|
907
|
+
function createEventStream(producer) {
|
|
908
|
+
return new RxEventStream(producer);
|
|
909
|
+
}
|
|
910
|
+
function createEventSubject() {
|
|
911
|
+
return new RxEventSubject();
|
|
912
|
+
}
|
|
913
|
+
function createEventReplaySubject(bufferSize = Infinity) {
|
|
914
|
+
return new RxEventReplaySubject(bufferSize);
|
|
915
|
+
}
|
|
916
|
+
function createEmptyEventStream() {
|
|
917
|
+
return RxEventStream.fromObservableInput(EMPTY);
|
|
918
|
+
}
|
|
919
|
+
function createNeverEventStream() {
|
|
920
|
+
return RxEventStream.fromObservableInput(NEVER);
|
|
921
|
+
}
|
|
922
|
+
//#endregion
|
|
923
|
+
//#region src/events/error.ts
|
|
924
|
+
function isClientErrorEvent(event) {
|
|
925
|
+
if (typeof event !== "object" || event === null) return false;
|
|
926
|
+
if ("error" in event && event.error instanceof ClientError) return true;
|
|
927
|
+
return "payload" in event && typeof event.payload === "object" && event.payload !== null && "error" in event.payload && event.payload.error instanceof ClientError;
|
|
928
|
+
}
|
|
929
|
+
//#endregion
|
|
930
|
+
//#region src/events/interop.ts
|
|
931
|
+
function toEventStream(input) {
|
|
932
|
+
if (isEventStreamTrait(input)) return input;
|
|
933
|
+
return RxEventStream.fromObservableInput(from(input));
|
|
934
|
+
}
|
|
935
|
+
//#endregion
|
|
936
|
+
//#region src/identity/schemas.ts
|
|
937
|
+
const IdentityPrincipalSchema = type({
|
|
938
|
+
subject: "string > 0",
|
|
939
|
+
"displayName?": "string | null | undefined",
|
|
940
|
+
"picture?": "string | null | undefined",
|
|
941
|
+
"issuer?": "string | null | undefined",
|
|
942
|
+
"claims?": "object | null | undefined"
|
|
943
|
+
}).pipe((input) => ({
|
|
944
|
+
subject: input.subject,
|
|
945
|
+
displayName: typeof input.displayName === "string" && input.displayName.trim().length > 0 ? input.displayName : input.subject,
|
|
946
|
+
picture: input.picture ?? void 0,
|
|
947
|
+
issuer: input.issuer ?? void 0,
|
|
948
|
+
claims: input.claims ?? void 0
|
|
949
|
+
}));
|
|
950
|
+
const IdentityPrincipalWireSchema = type({
|
|
951
|
+
subject: "string > 0",
|
|
952
|
+
"display_name?": "string | null | undefined",
|
|
953
|
+
"picture?": "string | null | undefined",
|
|
954
|
+
"issuer?": "string | null | undefined",
|
|
955
|
+
"claims?": "object | null | undefined"
|
|
956
|
+
}).pipe((input) => ({
|
|
957
|
+
subject: input.subject,
|
|
958
|
+
displayName: typeof input.display_name === "string" && input.display_name.trim().length > 0 ? input.display_name : input.subject,
|
|
959
|
+
picture: input.picture ?? void 0,
|
|
960
|
+
issuer: input.issuer ?? void 0,
|
|
961
|
+
claims: input.claims ?? void 0
|
|
962
|
+
}));
|
|
963
|
+
//#endregion
|
|
964
|
+
//#region src/identity/parsers.ts
|
|
965
|
+
function throwIdentityPrincipalParseError(options) {
|
|
966
|
+
throw new ClientError({
|
|
967
|
+
kind: ClientErrorKind.Protocol,
|
|
968
|
+
code: options.code,
|
|
969
|
+
message: `${options.messagePrefix}: ${formatValidationFailure(options.failure) ?? "schema validation failed"}.`,
|
|
970
|
+
source: "identity",
|
|
971
|
+
cause: options.failure.issues
|
|
972
|
+
});
|
|
973
|
+
}
|
|
974
|
+
function parseIdentityPrincipal(input) {
|
|
975
|
+
const result = validateWithSchemaSync(IdentityPrincipalSchema, input);
|
|
976
|
+
if (result.success) return result.value;
|
|
977
|
+
throwIdentityPrincipalParseError({
|
|
978
|
+
code: "identity.invalid_principal",
|
|
979
|
+
messagePrefix: "Identity principal payload is invalid",
|
|
980
|
+
failure: result
|
|
981
|
+
});
|
|
982
|
+
}
|
|
983
|
+
function parseIdentityPrincipalWire(input) {
|
|
984
|
+
const result = validateWithSchemaSync(IdentityPrincipalWireSchema, input);
|
|
985
|
+
if (result.success) return result.value;
|
|
986
|
+
throwIdentityPrincipalParseError({
|
|
987
|
+
code: "identity.invalid_principal_wire",
|
|
988
|
+
messagePrefix: "Identity principal wire payload is invalid",
|
|
989
|
+
failure: result
|
|
990
|
+
});
|
|
991
|
+
}
|
|
992
|
+
function projectIdentityPrincipal(options) {
|
|
993
|
+
const principal = options.principal;
|
|
994
|
+
const subject = principal?.subject ?? options.fallbackSubject ?? "context.anonymous";
|
|
995
|
+
return {
|
|
996
|
+
subject,
|
|
997
|
+
displayName: principal?.displayName?.trim() || options.fallbackDisplayName || subject,
|
|
998
|
+
picture: principal?.picture,
|
|
999
|
+
issuer: principal?.issuer ?? options.fallbackIssuer,
|
|
1000
|
+
claims: principal?.claims ?? options.fallbackClaims
|
|
437
1001
|
};
|
|
1002
|
+
}
|
|
1003
|
+
//#endregion
|
|
1004
|
+
//#region src/protocol/jwt/error.ts
|
|
1005
|
+
const JwtDecodeErrorCode = {
|
|
1006
|
+
InvalidFormat: "protocol.jwt.invalid_format",
|
|
1007
|
+
InvalidPayload: "protocol.jwt.invalid_payload",
|
|
1008
|
+
InvalidClaim: "protocol.jwt.invalid_claim"
|
|
1009
|
+
};
|
|
1010
|
+
var JwtDecodeError = class extends ClientError {
|
|
1011
|
+
code;
|
|
1012
|
+
constructor(options) {
|
|
1013
|
+
super({
|
|
1014
|
+
kind: ClientErrorKind.Protocol,
|
|
1015
|
+
code: options.code,
|
|
1016
|
+
message: options.message,
|
|
1017
|
+
source: "protocol.jwt",
|
|
1018
|
+
cause: options.cause
|
|
1019
|
+
});
|
|
1020
|
+
this.name = "JwtDecodeError";
|
|
1021
|
+
this.code = options.code;
|
|
1022
|
+
}
|
|
1023
|
+
};
|
|
1024
|
+
//#endregion
|
|
1025
|
+
//#region src/protocol/jwt/decode.ts
|
|
1026
|
+
function decodeJwtPayload(jwt, options = {}) {
|
|
1027
|
+
const label = options.label ?? "JWT";
|
|
1028
|
+
const parts = jwt.split(".");
|
|
1029
|
+
if (parts.length !== 3) throw new JwtDecodeError({
|
|
1030
|
+
code: JwtDecodeErrorCode.InvalidFormat,
|
|
1031
|
+
message: `${label} must use compact JWS serialization`
|
|
1032
|
+
});
|
|
1033
|
+
const claims = parseBase64UrlJsonObject(parts[1], `${label} payload`);
|
|
1034
|
+
validateRegisteredClaimTypes(claims, label);
|
|
1035
|
+
return claims;
|
|
1036
|
+
}
|
|
1037
|
+
function parseBase64UrlJsonObject(value, label) {
|
|
1038
|
+
let parsed;
|
|
1039
|
+
try {
|
|
1040
|
+
parsed = JSON.parse(decodeBase64UrlUtf8(value));
|
|
1041
|
+
} catch (cause) {
|
|
1042
|
+
throw new JwtDecodeError({
|
|
1043
|
+
code: JwtDecodeErrorCode.InvalidPayload,
|
|
1044
|
+
message: `${label} must be base64url-encoded JSON`,
|
|
1045
|
+
cause
|
|
1046
|
+
});
|
|
1047
|
+
}
|
|
1048
|
+
if (!isJsonObject(parsed)) throw new JwtDecodeError({
|
|
1049
|
+
code: JwtDecodeErrorCode.InvalidPayload,
|
|
1050
|
+
message: `${label} must be a JSON object`
|
|
1051
|
+
});
|
|
1052
|
+
return parsed;
|
|
1053
|
+
}
|
|
1054
|
+
function decodeBase64UrlUtf8(value) {
|
|
1055
|
+
const base64 = value.replace(/-/g, "+").replace(/_/g, "/");
|
|
1056
|
+
const padded = base64 + "=".repeat((4 - base64.length % 4) % 4);
|
|
1057
|
+
const binary = atob(padded);
|
|
1058
|
+
const bytes = Uint8Array.from(binary, (char) => char.charCodeAt(0));
|
|
1059
|
+
return new TextDecoder().decode(bytes);
|
|
1060
|
+
}
|
|
1061
|
+
function validateRegisteredClaimTypes(claims, label) {
|
|
1062
|
+
if (claims.exp !== void 0 && typeof claims.exp !== "number") throw new JwtDecodeError({
|
|
1063
|
+
code: JwtDecodeErrorCode.InvalidClaim,
|
|
1064
|
+
message: `${label} "exp" claim must be a number`
|
|
1065
|
+
});
|
|
1066
|
+
if (claims.iat !== void 0 && typeof claims.iat !== "number") throw new JwtDecodeError({
|
|
1067
|
+
code: JwtDecodeErrorCode.InvalidClaim,
|
|
1068
|
+
message: `${label} "iat" claim must be a number`
|
|
1069
|
+
});
|
|
1070
|
+
if (claims.nbf !== void 0 && typeof claims.nbf !== "number") throw new JwtDecodeError({
|
|
1071
|
+
code: JwtDecodeErrorCode.InvalidClaim,
|
|
1072
|
+
message: `${label} "nbf" claim must be a number`
|
|
1073
|
+
});
|
|
1074
|
+
if (claims.iss !== void 0 && typeof claims.iss !== "string") throw new JwtDecodeError({
|
|
1075
|
+
code: JwtDecodeErrorCode.InvalidClaim,
|
|
1076
|
+
message: `${label} "iss" claim must be a string`
|
|
1077
|
+
});
|
|
1078
|
+
if (claims.aud !== void 0 && typeof claims.aud !== "string" && !isStringArray(claims.aud)) throw new JwtDecodeError({
|
|
1079
|
+
code: JwtDecodeErrorCode.InvalidClaim,
|
|
1080
|
+
message: `${label} "aud" claim must be a string or string array`
|
|
1081
|
+
});
|
|
1082
|
+
}
|
|
1083
|
+
function isJsonObject(value) {
|
|
1084
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1085
|
+
}
|
|
1086
|
+
function isStringArray(value) {
|
|
1087
|
+
return Array.isArray(value) && value.every((item) => typeof item === "string");
|
|
1088
|
+
}
|
|
1089
|
+
//#endregion
|
|
1090
|
+
//#region src/scheduling/duration.ts
|
|
1091
|
+
/**
|
|
1092
|
+
* Parse a human-readable duration string (for example `5m` or `300s`) into
|
|
1093
|
+
* milliseconds.
|
|
1094
|
+
*/
|
|
1095
|
+
function parseDurationToMs(duration) {
|
|
1096
|
+
const match = duration.match(/^(\d+(?:\.\d+)?)\s*(s|ms|m|h)$/);
|
|
1097
|
+
if (!match) return 0;
|
|
1098
|
+
const value = Number(match[1]);
|
|
1099
|
+
switch (match[2]) {
|
|
1100
|
+
case "ms": return value;
|
|
1101
|
+
case "s": return value * 1e3;
|
|
1102
|
+
case "m": return value * 60 * 1e3;
|
|
1103
|
+
case "h": return value * 60 * 60 * 1e3;
|
|
1104
|
+
default: return 0;
|
|
1105
|
+
}
|
|
1106
|
+
}
|
|
1107
|
+
//#endregion
|
|
1108
|
+
//#region src/storage/json-codec.ts
|
|
1109
|
+
/** Default JSON codec. */
|
|
1110
|
+
function createJsonCodec() {
|
|
438
1111
|
return {
|
|
439
|
-
|
|
440
|
-
|
|
1112
|
+
encode(value) {
|
|
1113
|
+
return JSON.stringify(value);
|
|
1114
|
+
},
|
|
1115
|
+
decode(raw) {
|
|
1116
|
+
return JSON.parse(raw);
|
|
1117
|
+
}
|
|
441
1118
|
};
|
|
442
1119
|
}
|
|
1120
|
+
//#endregion
|
|
1121
|
+
//#region src/storage/ephemeral-flow-store.ts
|
|
1122
|
+
function resolveStorageKey(keyPrefix, key) {
|
|
1123
|
+
return keyPrefix.length > 0 ? `${keyPrefix}:${key}` : key;
|
|
1124
|
+
}
|
|
1125
|
+
function requireRecordStoreTake(store) {
|
|
1126
|
+
if (!store.take) throw new ClientError({
|
|
1127
|
+
kind: ClientErrorKind.Configuration,
|
|
1128
|
+
code: "storage.ephemeral.take_unavailable",
|
|
1129
|
+
message: "Ephemeral flow stores require StorageTrait.take() for atomic single-consume semantics",
|
|
1130
|
+
source: "storage.ephemeral"
|
|
1131
|
+
});
|
|
1132
|
+
return store.take.bind(store);
|
|
1133
|
+
}
|
|
1134
|
+
async function executeStorageOperation(operation) {
|
|
1135
|
+
try {
|
|
1136
|
+
return await operation();
|
|
1137
|
+
} catch (error) {
|
|
1138
|
+
if (error instanceof ClientError) throw error;
|
|
1139
|
+
throw new ClientError({
|
|
1140
|
+
kind: ClientErrorKind.Storage,
|
|
1141
|
+
code: "storage.ephemeral.io_failed",
|
|
1142
|
+
message: "The ephemeral flow store operation failed",
|
|
1143
|
+
source: "storage.ephemeral",
|
|
1144
|
+
cause: error
|
|
1145
|
+
});
|
|
1146
|
+
}
|
|
1147
|
+
}
|
|
1148
|
+
function decodeStoredValue(codec, value) {
|
|
1149
|
+
try {
|
|
1150
|
+
return codec.decode(value);
|
|
1151
|
+
} catch (error) {
|
|
1152
|
+
throw new ClientError({
|
|
1153
|
+
kind: ClientErrorKind.Protocol,
|
|
1154
|
+
code: "storage.ephemeral.invalid_payload",
|
|
1155
|
+
message: "The ephemeral flow store payload is invalid",
|
|
1156
|
+
source: "storage.ephemeral",
|
|
1157
|
+
cause: error
|
|
1158
|
+
});
|
|
1159
|
+
}
|
|
1160
|
+
}
|
|
443
1161
|
/**
|
|
444
|
-
*
|
|
1162
|
+
* Create a typed ephemeral flow-state store backed by a low-level `StorageTrait`.
|
|
445
1163
|
*
|
|
446
|
-
*
|
|
447
|
-
*
|
|
1164
|
+
* Intended for short-lived browser/session coordination state such as pending
|
|
1165
|
+
* redirects or callback fragments.
|
|
448
1166
|
*/
|
|
449
|
-
function
|
|
450
|
-
const
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
}
|
|
1167
|
+
function createEphemeralFlowStore(options) {
|
|
1168
|
+
const codec = options.codec ?? createJsonCodec();
|
|
1169
|
+
const storeTake = requireRecordStoreTake(options.store);
|
|
1170
|
+
async function load() {
|
|
1171
|
+
const raw = await executeStorageOperation(() => options.store.get(options.key));
|
|
1172
|
+
return raw === null ? null : decodeStoredValue(codec, raw);
|
|
1173
|
+
}
|
|
1174
|
+
async function save(value) {
|
|
1175
|
+
await executeStorageOperation(() => options.store.set(options.key, codec.encode(value)));
|
|
1176
|
+
}
|
|
1177
|
+
async function consume() {
|
|
1178
|
+
const raw = await executeStorageOperation(() => storeTake(options.key));
|
|
1179
|
+
return raw === null ? null : decodeStoredValue(codec, raw);
|
|
1180
|
+
}
|
|
1181
|
+
async function clear() {
|
|
1182
|
+
await executeStorageOperation(() => options.store.remove(options.key));
|
|
1183
|
+
}
|
|
456
1184
|
return {
|
|
457
|
-
|
|
458
|
-
|
|
1185
|
+
load,
|
|
1186
|
+
save,
|
|
1187
|
+
consume,
|
|
1188
|
+
clear
|
|
459
1189
|
};
|
|
460
1190
|
}
|
|
461
1191
|
/**
|
|
462
|
-
* Create a
|
|
463
|
-
*
|
|
464
|
-
*
|
|
465
|
-
* This is useful for SDK-internal schemas where pulling in zod/valibot
|
|
466
|
-
* would be excessive. For adopter-facing schemas, prefer a real validation
|
|
467
|
-
* library.
|
|
468
|
-
*
|
|
469
|
-
* @example
|
|
470
|
-
* ```ts
|
|
471
|
-
* import { createSchema, validateWithSchema } from "@securitydept/client";
|
|
472
|
-
*
|
|
473
|
-
* const NameSchema = createSchema<unknown, { name: string }>({
|
|
474
|
-
* validate(input) {
|
|
475
|
-
* if (typeof input === "object" && input !== null && "name" in input &&
|
|
476
|
-
* typeof (input as any).name === "string") {
|
|
477
|
-
* return { value: { name: (input as any).name } };
|
|
478
|
-
* }
|
|
479
|
-
* return { issues: [{ message: "Expected object with string 'name'" }] };
|
|
480
|
-
* },
|
|
481
|
-
* });
|
|
1192
|
+
* Create a typed keyed ephemeral flow-state store backed by a low-level
|
|
1193
|
+
* `StorageTrait`.
|
|
482
1194
|
*
|
|
483
|
-
*
|
|
484
|
-
*
|
|
1195
|
+
* Intended for short-lived browser/session coordination state where multiple
|
|
1196
|
+
* pending records must coexist and be consumed independently.
|
|
1197
|
+
*/
|
|
1198
|
+
function createKeyedEphemeralFlowStore(options) {
|
|
1199
|
+
const codec = options.codec ?? createJsonCodec();
|
|
1200
|
+
const storeTake = requireRecordStoreTake(options.store);
|
|
1201
|
+
async function load(key) {
|
|
1202
|
+
const raw = await executeStorageOperation(() => options.store.get(resolveStorageKey(options.keyPrefix, key)));
|
|
1203
|
+
return raw === null ? null : decodeStoredValue(codec, raw);
|
|
1204
|
+
}
|
|
1205
|
+
async function save(key, value) {
|
|
1206
|
+
await executeStorageOperation(() => options.store.set(resolveStorageKey(options.keyPrefix, key), codec.encode(value)));
|
|
1207
|
+
}
|
|
1208
|
+
async function take(key) {
|
|
1209
|
+
const raw = await executeStorageOperation(() => storeTake(resolveStorageKey(options.keyPrefix, key)));
|
|
1210
|
+
return raw === null ? null : decodeStoredValue(codec, raw);
|
|
1211
|
+
}
|
|
1212
|
+
async function clear(key) {
|
|
1213
|
+
await executeStorageOperation(() => options.store.remove(resolveStorageKey(options.keyPrefix, key)));
|
|
1214
|
+
}
|
|
1215
|
+
return {
|
|
1216
|
+
load,
|
|
1217
|
+
save,
|
|
1218
|
+
take,
|
|
1219
|
+
clear
|
|
1220
|
+
};
|
|
1221
|
+
}
|
|
1222
|
+
//#endregion
|
|
1223
|
+
//#region src/struct/async-lock.ts
|
|
1224
|
+
const OnceAsyncLockState = {
|
|
1225
|
+
Init: "init",
|
|
1226
|
+
Running: "running",
|
|
1227
|
+
Success: "success",
|
|
1228
|
+
Error: "error"
|
|
1229
|
+
};
|
|
1230
|
+
function createOnceAsyncLockCallable(fn) {
|
|
1231
|
+
const internalStateSignal = createSignal({ state: OnceAsyncLockState.Init });
|
|
1232
|
+
const coreFn = async function(...args) {
|
|
1233
|
+
const internalState = internalStateSignal.get();
|
|
1234
|
+
if (internalState.state === OnceAsyncLockState.Running) return internalState.promise;
|
|
1235
|
+
if (internalState.state === OnceAsyncLockState.Success) return internalState.data;
|
|
1236
|
+
let resolvePromise;
|
|
1237
|
+
let rejectPromise;
|
|
1238
|
+
const promise = new Promise((res, rej) => {
|
|
1239
|
+
resolvePromise = res;
|
|
1240
|
+
rejectPromise = rej;
|
|
1241
|
+
});
|
|
1242
|
+
promise.catch(() => void 0);
|
|
1243
|
+
internalStateSignal.set({
|
|
1244
|
+
state: OnceAsyncLockState.Running,
|
|
1245
|
+
promise
|
|
1246
|
+
});
|
|
1247
|
+
try {
|
|
1248
|
+
const result = await fn.apply(this, args);
|
|
1249
|
+
internalStateSignal.set({
|
|
1250
|
+
state: OnceAsyncLockState.Success,
|
|
1251
|
+
data: result
|
|
1252
|
+
});
|
|
1253
|
+
resolvePromise(result);
|
|
1254
|
+
return result;
|
|
1255
|
+
} catch (err) {
|
|
1256
|
+
internalStateSignal.set({
|
|
1257
|
+
state: OnceAsyncLockState.Error,
|
|
1258
|
+
error: err
|
|
1259
|
+
});
|
|
1260
|
+
rejectPromise(err);
|
|
1261
|
+
throw err;
|
|
1262
|
+
}
|
|
1263
|
+
};
|
|
1264
|
+
return new Proxy(coreFn, {
|
|
1265
|
+
get(target, prop, receiver) {
|
|
1266
|
+
const internalState = internalStateSignal.get();
|
|
1267
|
+
if (prop in internalState) return Reflect.get(internalState, prop);
|
|
1268
|
+
if (prop === "get" || prop === "watchStream" || prop === SYMBOL_OBSERVABLE) {
|
|
1269
|
+
const value = Reflect.get(internalStateSignal, prop, internalStateSignal);
|
|
1270
|
+
return typeof value === "function" ? value.bind(internalStateSignal) : value;
|
|
1271
|
+
}
|
|
1272
|
+
return Reflect.get(target, prop, receiver);
|
|
1273
|
+
},
|
|
1274
|
+
set() {
|
|
1275
|
+
return false;
|
|
1276
|
+
}
|
|
1277
|
+
});
|
|
1278
|
+
}
|
|
1279
|
+
//#endregion
|
|
1280
|
+
//#region src/transport/url.ts
|
|
1281
|
+
/**
|
|
1282
|
+
* Returns `true` for loopback HTTP URLs that browsers and local tooling often
|
|
1283
|
+
* permit during development flows.
|
|
485
1284
|
*/
|
|
486
|
-
function
|
|
487
|
-
return
|
|
488
|
-
version: 1,
|
|
489
|
-
vendor: "securitydept",
|
|
490
|
-
validate: options.validate
|
|
491
|
-
} };
|
|
1285
|
+
function isLoopbackHttpUrl(url) {
|
|
1286
|
+
return url.protocol === "http:" && (url.hostname === "localhost" || url.hostname === "127.0.0.1" || url.hostname === "::1" || url.hostname === "[::1]");
|
|
492
1287
|
}
|
|
493
1288
|
//#endregion
|
|
494
|
-
export { ClientError, ClientErrorKind, ClientErrorSource, ErrorPresentationTone, EventSourceKind, FetchTransportRedirectKind,
|
|
1289
|
+
export { Base64CompatErrorCode, BaseRequirementPlanner, BaseURIStringSchema, CLIENT_ERROR_SPAN_ATTRIBUTE_PROVIDER_ID, ClientError, ClientErrorKind, ClientErrorSource, ConsoleTracingSubscriber, ENVIRONMENT_TOKEN, ErrorPresentationTone, EventSourceKind, FetchTransportRedirectKind, IDLE_CALLBACK_TRAIT_TOKEN, INJECTOR_TOKEN, IdentityPrincipalSchema, IdentityPrincipalWireSchema, JwtDecodeError, JwtDecodeErrorCode, MergeRequirementPlanner, OnceAsyncLockState, OperationSpan, OperationTraceEventType, PAGE_LIFECYCLE_TRAIT_TOKEN, PERSISTENT_STORAGE_TRAIT_TOKEN, POPUP_TRAIT_TOKEN, PipelineOutcome, PlanStatus, PopupAttachFailureReason, PopupClientWindowHandle, PopupErrorCode, PopupServerWindowHandle, REALM_STORAGE_TRAIT_TOKEN, REQUIREMENT_PLANNER_HOST, ROUTER_TRAIT_TOKEN, RequirementPlannerError, RequirementPlannerHost, RequirementsComposition, ResolutionStatus, ResourceError, ResourceErrorCode, ResourceSnapshotUpdateKind, ResourceStatus, RouteCompositionRequirementPlanner, RouterNavigationIntent, RouterNavigationMode, SECURITYDEPT_COMPAT_FRAGMENT_VERSION, SECURITYDEPT_ROUTE_METADATA_KEY, SESSION_STORAGE_TRAIT_TOKEN, SPAN_TRAIT_TOKEN, SYMBOL_ASYNC_DISPOSE, SYMBOL_DISPOSABLE_STACK, SYMBOL_DISPOSE, SYMBOL_OBSERVABLE, SecurityDeptOptional, SecuritydeptDestroyRef, SecuritydeptInjectionToken, SecuritydeptInjector, SimpleDisposableStack, SpanSharedAttributeName, StaticAttrsAuthRequirement, StaticRequirementPlanner, StdDisposableStack, StorageChangeEventOrigin, TIME_TRAIT_TOKEN, TRACING_SPAN_ATTRIBUTE_PROVIDER_ID, TRACING_TRAIT_TOKEN, TRANSPORT_TRAIT_TOKEN, TraceTimelineStore, TracingLevel, TransportErrorCode, UriParseError, UriReferenceString, UriReferenceStringSchema, UriRelativeString, UriRelativeStringSchema, UriString, UriStringSchema, UserRecovery, abortSignalToCancellationToken, abortSignalToEventStream, appendOrReplaceCompatFragment, cancellationTokenToAbortSignal, createAuthorizationInterceptedFetch, createBaseTransportForStdFetch, createCancellationTokenSource, createComputed, createConsoleTracingSubscriber, createDisposableStack, createEmptyEventStream, createEphemeralFlowStore, createEventReplaySubject, createEventStream, createEventSubject, createFoundationEnvironment, createInMemoryRecordStore, createJsonCodec, createJsonRpcClient, createJsonRpcServer, createJsonRpcServerAndClient, createKeyedEphemeralFlowStore, createLinkedCancellationToken, createNeverEventStream, createOnceAsyncLockCallable, createProviderIfTokenMissing, createResource, createRootSpan, createSecuritydeptDestroyRef, createSignal, createTimeForStd, createTraceTimelineStore, createTracing, decodeBase64ToUint8Array, decodeJwtPayload, defaultSelectCandidate, defineInstrumentMethodDecorator, describeError, encodeUint8ArrayToBase64, flattenResourceSnapshot, formatClientErrorContext, formatValidationFailure, getSecuritydeptProviderToken, inject, injectDisposableStackFrom, injectRequirementPlannerHost, isCancellationTokenTrait, isClientErrorEvent, isCompatFragmentBlock, isInteropObservableTrait, isLoopbackHttpUrl, isRouteBehaviourContextExtra, isRouteStateSnapshotTrait, mapResource, normalizeAbortError, notMissingProvider, parseCompatFragment, parseDurationToMs, parseIdentityPrincipal, parseIdentityPrincipalWire, projectIdentityPrincipal, promisesToRacedAsyncGenerator, provideRequirementPlannerHost, readErrorPresentationDescriptor, readPopupErrorPresentationDescriptor, readSecuritydeptRouteMetadata, readonlySignal, reduceResourceSnapshot, resolveEffectiveRequirements, resourceFromSnapshots, runInInjectionContext, runOperation, takeCompatFragment, takeCompatFragmentFromRouter, throwValidationClientError, toEventStream, tryInjectInInjectionContext, validateTraitInput, validateWithSchema, validateWithSchemaSync, whenResourceSnapshotValue, withDisposableStack, writeSecuritydeptRouteMetadata };
|
|
495
1290
|
|
|
496
1291
|
//# sourceMappingURL=index.mjs.map
|