@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,631 +0,0 @@
|
|
|
1
|
-
//#region src/errors/types.ts
|
|
2
|
-
/** Recovery actions the user might take. Aligned with server-side `UserRecovery`. */
|
|
3
|
-
const UserRecovery = {
|
|
4
|
-
None: "none",
|
|
5
|
-
Retry: "retry",
|
|
6
|
-
RestartFlow: "restart_flow",
|
|
7
|
-
Reauthenticate: "reauthenticate",
|
|
8
|
-
ContactSupport: "contact_support"
|
|
9
|
-
};
|
|
10
|
-
const ErrorPresentationTone = {
|
|
11
|
-
Neutral: "neutral",
|
|
12
|
-
Warning: "warning",
|
|
13
|
-
Danger: "danger"
|
|
14
|
-
};
|
|
15
|
-
/** Machine-facing error kind discriminator. */
|
|
16
|
-
const ClientErrorKind = {
|
|
17
|
-
Authorization: "authorization",
|
|
18
|
-
Transport: "transport",
|
|
19
|
-
Server: "server",
|
|
20
|
-
Protocol: "protocol",
|
|
21
|
-
Presentation: "presentation",
|
|
22
|
-
Validation: "validation",
|
|
23
|
-
Storage: "storage",
|
|
24
|
-
Scheduler: "scheduler",
|
|
25
|
-
Configuration: "configuration",
|
|
26
|
-
Unauthenticated: "unauthenticated",
|
|
27
|
-
Unauthorized: "unauthorized",
|
|
28
|
-
RedirectRequired: "redirect_required",
|
|
29
|
-
Cancelled: "cancelled",
|
|
30
|
-
Timeout: "timeout",
|
|
31
|
-
Internal: "internal"
|
|
32
|
-
};
|
|
33
|
-
/** Stable source vocabulary for common client error producers. */
|
|
34
|
-
const ClientErrorSource = {
|
|
35
|
-
Transport: "transport",
|
|
36
|
-
Server: "server",
|
|
37
|
-
ClientRuntime: "client_runtime"
|
|
38
|
-
};
|
|
39
|
-
//#endregion
|
|
40
|
-
//#region src/errors/client-error.ts
|
|
41
|
-
function mapServerErrorKind(kind, status) {
|
|
42
|
-
switch (kind) {
|
|
43
|
-
case "unauthenticated": return ClientErrorKind.Unauthenticated;
|
|
44
|
-
case "unauthorized": return ClientErrorKind.Unauthorized;
|
|
45
|
-
case "unavailable":
|
|
46
|
-
case "internal": return ClientErrorKind.Server;
|
|
47
|
-
case "invalid_request":
|
|
48
|
-
case "conflict": return ClientErrorKind.Protocol;
|
|
49
|
-
default: return status === 401 ? ClientErrorKind.Unauthenticated : status === 403 ? ClientErrorKind.Unauthorized : status >= 500 ? ClientErrorKind.Server : ClientErrorKind.Protocol;
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
function readServerErrorBody(body) {
|
|
53
|
-
if (!body || typeof body !== "object") return void 0;
|
|
54
|
-
const record = body;
|
|
55
|
-
const error = record.error && typeof record.error === "object" ? record.error : record;
|
|
56
|
-
return {
|
|
57
|
-
kind: typeof error.kind === "string" ? error.kind : void 0,
|
|
58
|
-
code: typeof error.code === "string" ? error.code : void 0,
|
|
59
|
-
message: typeof error.message === "string" ? error.message : void 0,
|
|
60
|
-
recovery: typeof error.recovery === "string" ? error.recovery : void 0,
|
|
61
|
-
presentation: error.presentation && typeof error.presentation === "object" ? {
|
|
62
|
-
code: typeof error.presentation.code === "string" ? error.presentation.code : void 0,
|
|
63
|
-
message: typeof error.presentation.message === "string" ? error.presentation.message : void 0,
|
|
64
|
-
recovery: typeof error.presentation.recovery === "string" ? error.presentation.recovery : void 0
|
|
65
|
-
} : void 0
|
|
66
|
-
};
|
|
67
|
-
}
|
|
68
|
-
/**
|
|
69
|
-
* Base client error carrying both machine-facing context and an optional
|
|
70
|
-
* user-facing presentation layer.
|
|
71
|
-
*
|
|
72
|
-
* Top-level `code` and `recovery` provide stable machine contracts for
|
|
73
|
-
* policy decisions without requiring callers to unwrap `presentation`.
|
|
74
|
-
*/
|
|
75
|
-
var ClientError = class ClientError extends Error {
|
|
76
|
-
kind;
|
|
77
|
-
/**
|
|
78
|
-
* Stable machine-readable error code.
|
|
79
|
-
* Matches `presentation.code` when present, otherwise a default
|
|
80
|
-
* derived from `kind`.
|
|
81
|
-
*/
|
|
82
|
-
code;
|
|
83
|
-
/** Recovery hint at the machine level. */
|
|
84
|
-
recovery;
|
|
85
|
-
/** Whether this error is safe to retry. */
|
|
86
|
-
retryable;
|
|
87
|
-
/** Structured user-facing error presentation from the server. */
|
|
88
|
-
presentation;
|
|
89
|
-
/** Source subsystem or component that produced the error. */
|
|
90
|
-
source;
|
|
91
|
-
constructor(options) {
|
|
92
|
-
super(options.message, { cause: options.cause });
|
|
93
|
-
this.name = "ClientError";
|
|
94
|
-
this.kind = options.kind;
|
|
95
|
-
this.code = options.code ?? options.presentation?.code ?? `client.${options.kind}`;
|
|
96
|
-
this.recovery = options.recovery ?? options.presentation?.recovery ?? UserRecovery.None;
|
|
97
|
-
this.retryable = options.retryable ?? this.recovery === UserRecovery.Retry;
|
|
98
|
-
this.presentation = options.presentation;
|
|
99
|
-
this.source = options.source;
|
|
100
|
-
}
|
|
101
|
-
/** Create a `ClientError` from a server error response body. */
|
|
102
|
-
static fromServerError(body, overrides) {
|
|
103
|
-
const rawPresentation = body.presentation;
|
|
104
|
-
const presentation = (rawPresentation?.code ?? body.code) && (rawPresentation?.message ?? body.message) ? {
|
|
105
|
-
code: rawPresentation?.code ?? body.code ?? "unknown_server_error",
|
|
106
|
-
message: rawPresentation?.message ?? body.message ?? "Unknown server error",
|
|
107
|
-
recovery: rawPresentation?.recovery ?? body.recovery ?? UserRecovery.None
|
|
108
|
-
} : void 0;
|
|
109
|
-
return new ClientError({
|
|
110
|
-
kind: overrides?.kind ?? mapServerErrorKind(body.kind, 400),
|
|
111
|
-
message: presentation?.message ?? body.message ?? "Unknown server error",
|
|
112
|
-
presentation,
|
|
113
|
-
source: overrides?.source
|
|
114
|
-
});
|
|
115
|
-
}
|
|
116
|
-
/**
|
|
117
|
-
* Create a `ClientError` from an HTTP response status and optional body.
|
|
118
|
-
* Used when a non-success status is unexpected.
|
|
119
|
-
*/
|
|
120
|
-
static fromHttpResponse(status, body) {
|
|
121
|
-
const serverBody = readServerErrorBody(body);
|
|
122
|
-
const kind = mapServerErrorKind(serverBody?.kind, status);
|
|
123
|
-
const source = status >= 500 ? ClientErrorSource.Server : ClientErrorSource.ClientRuntime;
|
|
124
|
-
if (serverBody?.code && serverBody?.message) return ClientError.fromServerError(serverBody, {
|
|
125
|
-
kind,
|
|
126
|
-
source
|
|
127
|
-
});
|
|
128
|
-
const recovery = kind === ClientErrorKind.Unauthenticated ? UserRecovery.Reauthenticate : status >= 500 ? UserRecovery.Retry : UserRecovery.None;
|
|
129
|
-
return new ClientError({
|
|
130
|
-
kind,
|
|
131
|
-
message: serverBody?.message ?? `HTTP ${status}`,
|
|
132
|
-
code: serverBody?.code ?? `http.${status}`,
|
|
133
|
-
recovery,
|
|
134
|
-
retryable: status >= 500,
|
|
135
|
-
source
|
|
136
|
-
});
|
|
137
|
-
}
|
|
138
|
-
};
|
|
139
|
-
//#endregion
|
|
140
|
-
//#region src/logging/types.ts
|
|
141
|
-
const LogLevel = {
|
|
142
|
-
Debug: "debug",
|
|
143
|
-
Info: "info",
|
|
144
|
-
Warn: "warn",
|
|
145
|
-
Error: "error"
|
|
146
|
-
};
|
|
147
|
-
const OperationTraceEventType = {
|
|
148
|
-
Started: "operation.started",
|
|
149
|
-
Event: "operation.event",
|
|
150
|
-
Error: "operation.error",
|
|
151
|
-
Ended: "operation.ended"
|
|
152
|
-
};
|
|
153
|
-
//#endregion
|
|
154
|
-
//#region src/logging/operation-tracer.ts
|
|
155
|
-
const defaultClock = { now: () => Date.now() };
|
|
156
|
-
function createDefaultOperationId() {
|
|
157
|
-
return `op_${Math.random().toString(36).slice(2, 10)}`;
|
|
158
|
-
}
|
|
159
|
-
var DefaultOperationScope = class {
|
|
160
|
-
id;
|
|
161
|
-
_attributes;
|
|
162
|
-
_ended = false;
|
|
163
|
-
constructor(_name, _clock, _traceSink, _logger, _scope, _source, idFactory, attributes) {
|
|
164
|
-
this._name = _name;
|
|
165
|
-
this._clock = _clock;
|
|
166
|
-
this._traceSink = _traceSink;
|
|
167
|
-
this._logger = _logger;
|
|
168
|
-
this._scope = _scope;
|
|
169
|
-
this._source = _source;
|
|
170
|
-
this.id = idFactory();
|
|
171
|
-
this._attributes = { ...attributes ?? {} };
|
|
172
|
-
this._recordTrace(OperationTraceEventType.Started, {
|
|
173
|
-
operationName: this._name,
|
|
174
|
-
...this._attributes
|
|
175
|
-
});
|
|
176
|
-
}
|
|
177
|
-
addEvent(type, attributes) {
|
|
178
|
-
this._recordTrace(OperationTraceEventType.Event, {
|
|
179
|
-
operationName: this._name,
|
|
180
|
-
eventType: type,
|
|
181
|
-
...this._attributes,
|
|
182
|
-
...attributes ?? {}
|
|
183
|
-
});
|
|
184
|
-
}
|
|
185
|
-
setAttribute(key, value) {
|
|
186
|
-
this._attributes[key] = value;
|
|
187
|
-
}
|
|
188
|
-
recordError(error, attributes) {
|
|
189
|
-
const errorAttributes = describeError(error);
|
|
190
|
-
this._recordTrace(OperationTraceEventType.Error, {
|
|
191
|
-
operationName: this._name,
|
|
192
|
-
...this._attributes,
|
|
193
|
-
...errorAttributes,
|
|
194
|
-
...attributes ?? {}
|
|
195
|
-
});
|
|
196
|
-
this._logger?.log({
|
|
197
|
-
level: LogLevel.Error,
|
|
198
|
-
message: `Operation failed: ${this._name}`,
|
|
199
|
-
scope: this._scope,
|
|
200
|
-
attributes: {
|
|
201
|
-
operationId: this.id,
|
|
202
|
-
operationName: this._name,
|
|
203
|
-
...this._attributes,
|
|
204
|
-
...errorAttributes,
|
|
205
|
-
...attributes ?? {}
|
|
206
|
-
},
|
|
207
|
-
error,
|
|
208
|
-
at: this._clock.now()
|
|
209
|
-
});
|
|
210
|
-
}
|
|
211
|
-
end(attributes) {
|
|
212
|
-
if (this._ended) return;
|
|
213
|
-
this._ended = true;
|
|
214
|
-
this._recordTrace(OperationTraceEventType.Ended, {
|
|
215
|
-
operationName: this._name,
|
|
216
|
-
...this._attributes,
|
|
217
|
-
...attributes ?? {}
|
|
218
|
-
});
|
|
219
|
-
}
|
|
220
|
-
_recordTrace(type, attributes) {
|
|
221
|
-
this._traceSink?.record({
|
|
222
|
-
type,
|
|
223
|
-
at: this._clock.now(),
|
|
224
|
-
scope: this._scope,
|
|
225
|
-
source: this._source,
|
|
226
|
-
operationId: this.id,
|
|
227
|
-
attributes
|
|
228
|
-
});
|
|
229
|
-
}
|
|
230
|
-
};
|
|
231
|
-
function createOperationTracer(options = {}) {
|
|
232
|
-
const clock = options.clock ?? defaultClock;
|
|
233
|
-
const idFactory = options.idFactory ?? createDefaultOperationId;
|
|
234
|
-
return { startOperation(name, attributes) {
|
|
235
|
-
return new DefaultOperationScope(name, clock, options.traceSink, options.logger, options.scope, options.source, idFactory, attributes);
|
|
236
|
-
} };
|
|
237
|
-
}
|
|
238
|
-
function describeError(error) {
|
|
239
|
-
if (typeof error === "object" && error !== null && "name" in error && "message" in error) {
|
|
240
|
-
const genericError = error;
|
|
241
|
-
return {
|
|
242
|
-
errorName: genericError.name,
|
|
243
|
-
errorMessage: genericError.message
|
|
244
|
-
};
|
|
245
|
-
}
|
|
246
|
-
return { errorValue: String(error) };
|
|
247
|
-
}
|
|
248
|
-
//#endregion
|
|
249
|
-
//#region src/scheduling/default-clock.ts
|
|
250
|
-
/** Default clock backed by `Date.now()`. */
|
|
251
|
-
function createDefaultClock() {
|
|
252
|
-
return { now() {
|
|
253
|
-
return Date.now();
|
|
254
|
-
} };
|
|
255
|
-
}
|
|
256
|
-
//#endregion
|
|
257
|
-
//#region src/scheduling/default-scheduler.ts
|
|
258
|
-
/** Default scheduler backed by platform `setTimeout`. */
|
|
259
|
-
function createDefaultScheduler() {
|
|
260
|
-
return { setTimeout(delayMs, fn) {
|
|
261
|
-
const id = globalThis.setTimeout(fn, delayMs);
|
|
262
|
-
return { cancel() {
|
|
263
|
-
globalThis.clearTimeout(id);
|
|
264
|
-
} };
|
|
265
|
-
} };
|
|
266
|
-
}
|
|
267
|
-
//#endregion
|
|
268
|
-
//#region src/runtime/create-runtime.ts
|
|
269
|
-
/**
|
|
270
|
-
* Create a `ClientRuntime` with non-host-specific defaults filled in for
|
|
271
|
-
* convenience.
|
|
272
|
-
*
|
|
273
|
-
* Host-specific capabilities such as browser `fetch` should be supplied
|
|
274
|
-
* explicitly or composed via adapter-specific helpers such as
|
|
275
|
-
* `@securitydept/client/web`.
|
|
276
|
-
*/
|
|
277
|
-
function createRuntime(overrides) {
|
|
278
|
-
const clock = overrides.clock ?? createDefaultClock();
|
|
279
|
-
const traceSink = overrides.traceSink;
|
|
280
|
-
const logger = overrides.logger;
|
|
281
|
-
return {
|
|
282
|
-
transport: overrides.transport,
|
|
283
|
-
scheduler: overrides.scheduler ?? createDefaultScheduler(),
|
|
284
|
-
clock,
|
|
285
|
-
logger,
|
|
286
|
-
traceSink,
|
|
287
|
-
operationTracer: overrides.operationTracer ?? createOperationTracer({
|
|
288
|
-
clock,
|
|
289
|
-
logger,
|
|
290
|
-
traceSink
|
|
291
|
-
}),
|
|
292
|
-
persistentStore: overrides.persistentStore,
|
|
293
|
-
sessionStore: overrides.sessionStore
|
|
294
|
-
};
|
|
295
|
-
}
|
|
296
|
-
//#endregion
|
|
297
|
-
//#region src/scheduling/helpers.ts
|
|
298
|
-
const PromiseSettlementKind = {
|
|
299
|
-
Fulfilled: "fulfilled",
|
|
300
|
-
Rejected: "rejected"
|
|
301
|
-
};
|
|
302
|
-
/**
|
|
303
|
-
* Schedule a one-shot callback after a delay.
|
|
304
|
-
*
|
|
305
|
-
* Returns a {@link CancelableHandle} that can cancel the pending timer.
|
|
306
|
-
*
|
|
307
|
-
* @example
|
|
308
|
-
* ```ts
|
|
309
|
-
* const handle = timer({
|
|
310
|
-
* scheduler: runtime.scheduler,
|
|
311
|
-
* delayMs: 5000,
|
|
312
|
-
* callback: () => console.log("fired"),
|
|
313
|
-
* });
|
|
314
|
-
* // Cancel before it fires:
|
|
315
|
-
* handle.cancel();
|
|
316
|
-
* ```
|
|
317
|
-
*/
|
|
318
|
-
function timer(options) {
|
|
319
|
-
return options.scheduler.setTimeout(options.delayMs, options.callback);
|
|
320
|
-
}
|
|
321
|
-
/**
|
|
322
|
-
* Schedule a repeating callback at a fixed interval.
|
|
323
|
-
*
|
|
324
|
-
* Built on top of `Scheduler.setTimeout` so it works with deterministic
|
|
325
|
-
* test schedulers. Returns a {@link CancelableHandle} to stop the interval.
|
|
326
|
-
*
|
|
327
|
-
* @example
|
|
328
|
-
* ```ts
|
|
329
|
-
* const handle = interval({
|
|
330
|
-
* scheduler: runtime.scheduler,
|
|
331
|
-
* periodMs: 30_000,
|
|
332
|
-
* callback: () => refreshTokens(),
|
|
333
|
-
* });
|
|
334
|
-
* // Stop:
|
|
335
|
-
* handle.cancel();
|
|
336
|
-
* ```
|
|
337
|
-
*/
|
|
338
|
-
function interval(options) {
|
|
339
|
-
let canceled = false;
|
|
340
|
-
let currentHandle = null;
|
|
341
|
-
function tick() {
|
|
342
|
-
if (canceled) return;
|
|
343
|
-
options.callback();
|
|
344
|
-
scheduleNext();
|
|
345
|
-
}
|
|
346
|
-
function scheduleNext() {
|
|
347
|
-
if (canceled) return;
|
|
348
|
-
currentHandle = options.scheduler.setTimeout(options.periodMs, tick);
|
|
349
|
-
}
|
|
350
|
-
scheduleNext();
|
|
351
|
-
return { cancel() {
|
|
352
|
-
canceled = true;
|
|
353
|
-
currentHandle?.cancel();
|
|
354
|
-
currentHandle = null;
|
|
355
|
-
} };
|
|
356
|
-
}
|
|
357
|
-
/**
|
|
358
|
-
* Schedule a callback at a specific wall-clock time.
|
|
359
|
-
*
|
|
360
|
-
* Computes the delay from `clock.now()` to `atMs` and delegates to
|
|
361
|
-
* `Scheduler.setTimeout`. If the target time is already in the past,
|
|
362
|
-
* the callback fires on the next scheduler tick (delay 0).
|
|
363
|
-
*
|
|
364
|
-
* @example
|
|
365
|
-
* ```ts
|
|
366
|
-
* const handle = scheduleAt({
|
|
367
|
-
* scheduler: runtime.scheduler,
|
|
368
|
-
* clock: runtime.clock,
|
|
369
|
-
* atMs: tokenExpiresAtMs - 30_000,
|
|
370
|
-
* callback: () => refreshToken(),
|
|
371
|
-
* });
|
|
372
|
-
* ```
|
|
373
|
-
*/
|
|
374
|
-
function scheduleAt(options) {
|
|
375
|
-
const delay = Math.max(0, options.atMs - options.clock.now());
|
|
376
|
-
return options.scheduler.setTimeout(delay, options.callback);
|
|
377
|
-
}
|
|
378
|
-
/**
|
|
379
|
-
* Adapt an SDK signal into the shared {@link Subscription} callback model.
|
|
380
|
-
*
|
|
381
|
-
* @example
|
|
382
|
-
* ```ts
|
|
383
|
-
* const sub = fromSignal({
|
|
384
|
-
* signal: authState,
|
|
385
|
-
* callback: (snapshot) => console.log(snapshot),
|
|
386
|
-
* });
|
|
387
|
-
* sub.unsubscribe();
|
|
388
|
-
* ```
|
|
389
|
-
*/
|
|
390
|
-
function fromSignal(options) {
|
|
391
|
-
if (options.emitInitialValue) options.callback(options.signal.get());
|
|
392
|
-
const unsubscribe = options.signal.subscribe(() => {
|
|
393
|
-
options.callback(options.signal.get());
|
|
394
|
-
});
|
|
395
|
-
return { unsubscribe() {
|
|
396
|
-
unsubscribe();
|
|
397
|
-
} };
|
|
398
|
-
}
|
|
399
|
-
/**
|
|
400
|
-
* Adapt a promise settlement into the shared {@link Subscription} callback model.
|
|
401
|
-
*
|
|
402
|
-
* This helper is intentionally thin: it reports one settlement and lets the
|
|
403
|
-
* consumer decide how to model pending/fulfilled/error state.
|
|
404
|
-
*
|
|
405
|
-
* @example
|
|
406
|
-
* ```ts
|
|
407
|
-
* const sub = fromPromise({
|
|
408
|
-
* promise: fetchConfig(),
|
|
409
|
-
* callback: (settlement) => {
|
|
410
|
-
* if (settlement.kind === PromiseSettlementKind.Fulfilled) {
|
|
411
|
-
* console.log(settlement.value);
|
|
412
|
-
* }
|
|
413
|
-
* },
|
|
414
|
-
* });
|
|
415
|
-
* sub.unsubscribe();
|
|
416
|
-
* ```
|
|
417
|
-
*/
|
|
418
|
-
function fromPromise(options) {
|
|
419
|
-
let active = true;
|
|
420
|
-
Promise.resolve(options.promise).then((value) => {
|
|
421
|
-
if (!active) return;
|
|
422
|
-
options.callback({
|
|
423
|
-
kind: PromiseSettlementKind.Fulfilled,
|
|
424
|
-
value
|
|
425
|
-
});
|
|
426
|
-
}, (reason) => {
|
|
427
|
-
if (!active) return;
|
|
428
|
-
options.callback({
|
|
429
|
-
kind: PromiseSettlementKind.Rejected,
|
|
430
|
-
reason
|
|
431
|
-
});
|
|
432
|
-
});
|
|
433
|
-
return { unsubscribe() {
|
|
434
|
-
active = false;
|
|
435
|
-
} };
|
|
436
|
-
}
|
|
437
|
-
/**
|
|
438
|
-
* Adapt an arbitrary add/remove event pattern into a {@link Subscription}.
|
|
439
|
-
*
|
|
440
|
-
* This is a thin bridge between imperative event APIs (e.g. `addEventListener`
|
|
441
|
-
* / `removeEventListener`) and the SDK's subscription model.
|
|
442
|
-
*
|
|
443
|
-
* @example
|
|
444
|
-
* ```ts
|
|
445
|
-
* const sub = fromEventPattern<Event>({
|
|
446
|
-
* addHandler: (h) => document.addEventListener("visibilitychange", h),
|
|
447
|
-
* removeHandler: (h) => document.removeEventListener("visibilitychange", h),
|
|
448
|
-
* callback: () => onVisibilityChange(),
|
|
449
|
-
* });
|
|
450
|
-
* // Cleanup:
|
|
451
|
-
* sub.unsubscribe();
|
|
452
|
-
* ```
|
|
453
|
-
*/
|
|
454
|
-
function fromEventPattern(options) {
|
|
455
|
-
const handler = (value) => {
|
|
456
|
-
options.callback(value);
|
|
457
|
-
};
|
|
458
|
-
options.addHandler(handler);
|
|
459
|
-
return { unsubscribe() {
|
|
460
|
-
options.removeHandler(handler);
|
|
461
|
-
} };
|
|
462
|
-
}
|
|
463
|
-
//#endregion
|
|
464
|
-
//#region src/web/input-sources.ts
|
|
465
|
-
/**
|
|
466
|
-
* Adapt a browser AbortSignal into the shared Subscription model.
|
|
467
|
-
*/
|
|
468
|
-
function fromAbortSignal(options) {
|
|
469
|
-
const signal = options.signal;
|
|
470
|
-
if (!signal) return { unsubscribe() {} };
|
|
471
|
-
if (options.emitIfAborted && signal.aborted) options.callback(signal.reason);
|
|
472
|
-
return fromEventPattern({
|
|
473
|
-
addHandler: (handler) => {
|
|
474
|
-
signal.addEventListener("abort", handler);
|
|
475
|
-
},
|
|
476
|
-
removeHandler: (handler) => {
|
|
477
|
-
signal.removeEventListener("abort", handler);
|
|
478
|
-
},
|
|
479
|
-
callback: () => {
|
|
480
|
-
options.callback(signal.reason);
|
|
481
|
-
}
|
|
482
|
-
});
|
|
483
|
-
}
|
|
484
|
-
/**
|
|
485
|
-
* Adapt browser `storage` events into the shared Subscription model.
|
|
486
|
-
*/
|
|
487
|
-
function fromStorageEvent(options) {
|
|
488
|
-
const target = options.target ?? globalThis;
|
|
489
|
-
return fromEventPattern({
|
|
490
|
-
addHandler: (handler) => {
|
|
491
|
-
target.addEventListener("storage", handler);
|
|
492
|
-
},
|
|
493
|
-
removeHandler: (handler) => {
|
|
494
|
-
target.removeEventListener("storage", handler);
|
|
495
|
-
},
|
|
496
|
-
callback: (event) => {
|
|
497
|
-
options.callback(event);
|
|
498
|
-
}
|
|
499
|
-
});
|
|
500
|
-
}
|
|
501
|
-
//#endregion
|
|
502
|
-
//#region src/web/cancellation.ts
|
|
503
|
-
/**
|
|
504
|
-
* Bridge a web `AbortSignal` back into the foundation cancellation contract.
|
|
505
|
-
*
|
|
506
|
-
* This is the canonical consumer-side path for browser hosts that receive an
|
|
507
|
-
* `AbortSignal` from framework/runtime APIs (for example React Query queryFns)
|
|
508
|
-
* but need to call SDK surfaces that accept `CancellationTokenTrait`.
|
|
509
|
-
*/
|
|
510
|
-
function createCancellationTokenFromAbortSignal(signal) {
|
|
511
|
-
if (!signal) return;
|
|
512
|
-
return {
|
|
513
|
-
get isCancellationRequested() {
|
|
514
|
-
return signal.aborted;
|
|
515
|
-
},
|
|
516
|
-
get reason() {
|
|
517
|
-
return signal.reason;
|
|
518
|
-
},
|
|
519
|
-
onCancellationRequested(listener) {
|
|
520
|
-
const subscription = fromAbortSignal({
|
|
521
|
-
signal,
|
|
522
|
-
callback: listener,
|
|
523
|
-
emitIfAborted: true
|
|
524
|
-
});
|
|
525
|
-
return { dispose() {
|
|
526
|
-
subscription.unsubscribe();
|
|
527
|
-
} };
|
|
528
|
-
},
|
|
529
|
-
throwIfCancellationRequested() {
|
|
530
|
-
if (signal.aborted) throw new ClientError({
|
|
531
|
-
kind: ClientErrorKind.Cancelled,
|
|
532
|
-
message: "Request was cancelled via AbortSignal",
|
|
533
|
-
code: "client.cancelled",
|
|
534
|
-
source: ClientErrorSource.Transport,
|
|
535
|
-
cause: signal.reason
|
|
536
|
-
});
|
|
537
|
-
}
|
|
538
|
-
};
|
|
539
|
-
}
|
|
540
|
-
/**
|
|
541
|
-
* Bridge foundation cancellation to web `AbortSignal` without exposing
|
|
542
|
-
* `AbortSignal` in core contracts.
|
|
543
|
-
*/
|
|
544
|
-
function createAbortSignalBridge(token) {
|
|
545
|
-
if (!token) return {
|
|
546
|
-
signal: void 0,
|
|
547
|
-
dispose() {}
|
|
548
|
-
};
|
|
549
|
-
const controller = new AbortController();
|
|
550
|
-
let subscription = token.onCancellationRequested((reason) => {
|
|
551
|
-
controller.abort(reason);
|
|
552
|
-
});
|
|
553
|
-
if (token.isCancellationRequested) controller.abort(token.reason);
|
|
554
|
-
return {
|
|
555
|
-
signal: controller.signal,
|
|
556
|
-
dispose() {
|
|
557
|
-
subscription?.dispose();
|
|
558
|
-
subscription = null;
|
|
559
|
-
}
|
|
560
|
-
};
|
|
561
|
-
}
|
|
562
|
-
function normalizeAbortError(token, error) {
|
|
563
|
-
if (!isAbortError(error) && !token?.isCancellationRequested) return error;
|
|
564
|
-
const reason = token?.reason;
|
|
565
|
-
if (reason instanceof ClientError) return reason;
|
|
566
|
-
if (reason instanceof Error) return new ClientError({
|
|
567
|
-
kind: ClientErrorKind.Cancelled,
|
|
568
|
-
message: reason.message,
|
|
569
|
-
code: "client.cancelled",
|
|
570
|
-
source: ClientErrorSource.Transport,
|
|
571
|
-
cause: reason
|
|
572
|
-
});
|
|
573
|
-
return new ClientError({
|
|
574
|
-
kind: ClientErrorKind.Cancelled,
|
|
575
|
-
message: "HTTP request was cancelled",
|
|
576
|
-
code: "client.cancelled",
|
|
577
|
-
source: ClientErrorSource.Transport,
|
|
578
|
-
cause: reason ?? error
|
|
579
|
-
});
|
|
580
|
-
}
|
|
581
|
-
function isAbortError(error) {
|
|
582
|
-
return typeof error === "object" && error !== null && "name" in error && error.name === "AbortError";
|
|
583
|
-
}
|
|
584
|
-
//#endregion
|
|
585
|
-
//#region src/transport/fetch-transport.ts
|
|
586
|
-
const FetchTransportRedirectKind = {
|
|
587
|
-
Follow: "follow",
|
|
588
|
-
Manual: "manual"
|
|
589
|
-
};
|
|
590
|
-
/**
|
|
591
|
-
* Default `HttpTransport` backed by the global `fetch` API.
|
|
592
|
-
*
|
|
593
|
-
* The caller is responsible for ensuring `fetch` is available in the runtime.
|
|
594
|
-
* No polyfill is injected — see the polyfill strategy in the design guide.
|
|
595
|
-
*/
|
|
596
|
-
function createFetchTransport(options = {}) {
|
|
597
|
-
const redirect = options.redirect ?? FetchTransportRedirectKind.Manual;
|
|
598
|
-
return { async execute(request) {
|
|
599
|
-
const abortBridge = createAbortSignalBridge(request.cancellationToken);
|
|
600
|
-
const init = {
|
|
601
|
-
method: request.method,
|
|
602
|
-
headers: request.headers,
|
|
603
|
-
redirect,
|
|
604
|
-
signal: abortBridge.signal
|
|
605
|
-
};
|
|
606
|
-
if (request.body !== void 0 && request.method !== "GET" && request.method !== "HEAD") init.body = typeof request.body === "string" ? request.body : JSON.stringify(request.body);
|
|
607
|
-
try {
|
|
608
|
-
const res = await fetch(request.url, init);
|
|
609
|
-
const responseHeaders = {};
|
|
610
|
-
res.headers.forEach((value, key) => {
|
|
611
|
-
responseHeaders[key] = value;
|
|
612
|
-
});
|
|
613
|
-
let body;
|
|
614
|
-
if (res.headers.get("content-type")?.includes("application/json")) body = await res.json();
|
|
615
|
-
else if (res.status !== 302 && res.status !== 303 && res.status !== 301) body = await res.text();
|
|
616
|
-
return {
|
|
617
|
-
status: res.status,
|
|
618
|
-
headers: responseHeaders,
|
|
619
|
-
body
|
|
620
|
-
};
|
|
621
|
-
} catch (error) {
|
|
622
|
-
throw normalizeAbortError(request.cancellationToken, error);
|
|
623
|
-
} finally {
|
|
624
|
-
abortBridge.dispose();
|
|
625
|
-
}
|
|
626
|
-
} };
|
|
627
|
-
}
|
|
628
|
-
//#endregion
|
|
629
|
-
export { ClientErrorSource as C, ClientErrorKind as S, UserRecovery as T, createDefaultClock as _, normalizeAbortError as a, OperationTraceEventType as b, PromiseSettlementKind as c, fromSignal as d, interval as f, createDefaultScheduler as g, createRuntime as h, createCancellationTokenFromAbortSignal as i, fromEventPattern as l, timer as m, createFetchTransport as n, fromAbortSignal as o, scheduleAt as p, createAbortSignalBridge as r, fromStorageEvent as s, FetchTransportRedirectKind as t, fromPromise as u, createOperationTracer as v, ErrorPresentationTone as w, ClientError as x, LogLevel as y };
|
|
630
|
-
|
|
631
|
-
//# sourceMappingURL=fetch-transport-DtnSRWAH.mjs.map
|