@finueva/auth 0.18.0 → 0.19.0
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 +48 -25
- package/dist/device.d.ts +22 -2
- package/dist/device.js +746 -368
- package/dist/index.d.ts +2 -2
- package/dist/index.js +917 -38
- package/dist/server.d.ts +6 -2
- package/dist/server.js +1915 -1828
- package/dist/types-BEgD_Js1.d.ts +591 -0
- package/package.json +1 -1
- package/dist/types-CrdIcEJ3.d.ts +0 -351
package/dist/device.js
CHANGED
|
@@ -198,347 +198,31 @@ const messages = {
|
|
|
198
198
|
platform_target_unavailable: "The platform administration target is unavailable.",
|
|
199
199
|
platform_quorum_unavailable: "Platform administration quorum is unavailable.",
|
|
200
200
|
platform_recovery_required: "Platform administration requires separate recovery.",
|
|
201
|
-
identity_authority_unavailable: "Authentication is temporarily unavailable."
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
expiresAt: new Date(startedAt + value.expiresIn * 1e3)
|
|
227
|
-
};
|
|
228
|
-
}
|
|
229
|
-
function createUserApiCredentialCache(issue, now) {
|
|
230
|
-
let generation = 0;
|
|
231
|
-
let cached;
|
|
232
|
-
let pending;
|
|
233
|
-
const copy = (value) => ({
|
|
234
|
-
...value,
|
|
235
|
-
expiresAt: new Date(value.expiresAt)
|
|
236
|
-
});
|
|
237
|
-
return {
|
|
238
|
-
hasAuthority: () => Boolean(cached || pending),
|
|
239
|
-
clear() {
|
|
240
|
-
generation += 1;
|
|
241
|
-
cached = void 0;
|
|
242
|
-
pending = void 0;
|
|
243
|
-
},
|
|
244
|
-
async get(input) {
|
|
245
|
-
const applicationId = userApiApplication(input);
|
|
246
|
-
if (pending) {
|
|
247
|
-
if (pending.applicationId !== applicationId) throw new AuthError("state_conflict", 409);
|
|
248
|
-
return copy(await pending.request);
|
|
249
|
-
}
|
|
250
|
-
const startedAt = now();
|
|
251
|
-
if (!input.forceRefresh && cached?.applicationId === applicationId && cached.expiresAt - startedAt > 12e4) return {
|
|
252
|
-
tokenType: "Bearer",
|
|
253
|
-
token: cached.token,
|
|
254
|
-
expiresAt: new Date(cached.expiresAt)
|
|
255
|
-
};
|
|
256
|
-
cached = void 0;
|
|
257
|
-
const epoch = generation;
|
|
258
|
-
const request = (async () => {
|
|
259
|
-
const value = normalizeUserApiCredential(await issue(applicationId), startedAt);
|
|
260
|
-
if (epoch !== generation) throw new AuthError("state_conflict", 409);
|
|
261
|
-
if (now() < startedAt || value.expiresAt.getTime() <= now()) throw new AuthError("authentication_required", 401);
|
|
262
|
-
cached = {
|
|
263
|
-
applicationId,
|
|
264
|
-
token: value.token,
|
|
265
|
-
expiresAt: value.expiresAt.getTime()
|
|
266
|
-
};
|
|
267
|
-
return value;
|
|
268
|
-
})().finally(() => {
|
|
269
|
-
if (pending?.request === request) pending = void 0;
|
|
270
|
-
});
|
|
271
|
-
pending = {
|
|
272
|
-
applicationId,
|
|
273
|
-
request
|
|
274
|
-
};
|
|
275
|
-
return copy(await request);
|
|
276
|
-
}
|
|
277
|
-
};
|
|
278
|
-
}
|
|
279
|
-
//#endregion
|
|
280
|
-
//#region ../../node_modules/.pnpm/destr@2.0.5/node_modules/destr/dist/index.mjs
|
|
281
|
-
const suspectProtoRx = /"(?:_|\\u0{2}5[Ff]){2}(?:p|\\u0{2}70)(?:r|\\u0{2}72)(?:o|\\u0{2}6[Ff])(?:t|\\u0{2}74)(?:o|\\u0{2}6[Ff])(?:_|\\u0{2}5[Ff]){2}"\s*:/;
|
|
282
|
-
const suspectConstructorRx = /"(?:c|\\u0063)(?:o|\\u006[Ff])(?:n|\\u006[Ee])(?:s|\\u0073)(?:t|\\u0074)(?:r|\\u0072)(?:u|\\u0075)(?:c|\\u0063)(?:t|\\u0074)(?:o|\\u006[Ff])(?:r|\\u0072)"\s*:/;
|
|
283
|
-
const JsonSigRx = /^\s*["[{]|^\s*-?\d{1,16}(\.\d{1,17})?([Ee][+-]?\d+)?\s*$/;
|
|
284
|
-
function jsonParseTransform(key, value) {
|
|
285
|
-
if (key === "__proto__" || key === "constructor" && value && typeof value === "object" && "prototype" in value) {
|
|
286
|
-
warnKeyDropped(key);
|
|
287
|
-
return;
|
|
288
|
-
}
|
|
289
|
-
return value;
|
|
290
|
-
}
|
|
291
|
-
function warnKeyDropped(key) {
|
|
292
|
-
console.warn(`[destr] Dropping "${key}" key to prevent prototype pollution.`);
|
|
293
|
-
}
|
|
294
|
-
function destr(value, options = {}) {
|
|
295
|
-
if (typeof value !== "string") return value;
|
|
296
|
-
if (value[0] === "\"" && value[value.length - 1] === "\"" && value.indexOf("\\") === -1) return value.slice(1, -1);
|
|
297
|
-
const _value = value.trim();
|
|
298
|
-
if (_value.length <= 9) switch (_value.toLowerCase()) {
|
|
299
|
-
case "true": return true;
|
|
300
|
-
case "false": return false;
|
|
301
|
-
case "undefined": return;
|
|
302
|
-
case "null": return null;
|
|
303
|
-
case "nan": return NaN;
|
|
304
|
-
case "infinity": return Number.POSITIVE_INFINITY;
|
|
305
|
-
case "-infinity": return Number.NEGATIVE_INFINITY;
|
|
306
|
-
}
|
|
307
|
-
if (!JsonSigRx.test(value)) {
|
|
308
|
-
if (options.strict) throw new SyntaxError("[destr] Invalid JSON");
|
|
309
|
-
return value;
|
|
310
|
-
}
|
|
311
|
-
try {
|
|
312
|
-
if (suspectProtoRx.test(value) || suspectConstructorRx.test(value)) {
|
|
313
|
-
if (options.strict) throw new Error("[destr] Possible prototype pollution");
|
|
314
|
-
return JSON.parse(value, jsonParseTransform);
|
|
315
|
-
}
|
|
316
|
-
return JSON.parse(value);
|
|
317
|
-
} catch (error) {
|
|
318
|
-
if (options.strict) throw error;
|
|
319
|
-
return value;
|
|
320
|
-
}
|
|
321
|
-
}
|
|
322
|
-
//#endregion
|
|
323
|
-
//#region ../../node_modules/.pnpm/ofetch@1.5.1/node_modules/ofetch/dist/shared/ofetch.CWycOUEr.mjs
|
|
324
|
-
var FetchError = class extends Error {
|
|
325
|
-
constructor(message, opts) {
|
|
326
|
-
super(message, opts);
|
|
327
|
-
this.name = "FetchError";
|
|
328
|
-
if (opts?.cause && !this.cause) this.cause = opts.cause;
|
|
329
|
-
}
|
|
330
|
-
};
|
|
331
|
-
function createFetchError(ctx) {
|
|
332
|
-
const errorMessage = ctx.error?.message || ctx.error?.toString() || "";
|
|
333
|
-
const method = ctx.request?.method || ctx.options?.method || "GET";
|
|
334
|
-
const url = ctx.request?.url || String(ctx.request) || "/";
|
|
335
|
-
const fetchError = new FetchError(`${`[${method}] ${JSON.stringify(url)}`}: ${ctx.response ? `${ctx.response.status} ${ctx.response.statusText}` : "<no response>"}${errorMessage ? ` ${errorMessage}` : ""}`, ctx.error ? { cause: ctx.error } : void 0);
|
|
336
|
-
for (const key of [
|
|
337
|
-
"request",
|
|
338
|
-
"options",
|
|
339
|
-
"response"
|
|
340
|
-
]) Object.defineProperty(fetchError, key, { get() {
|
|
341
|
-
return ctx[key];
|
|
342
|
-
} });
|
|
343
|
-
for (const [key, refKey] of [
|
|
344
|
-
["data", "_data"],
|
|
345
|
-
["status", "status"],
|
|
346
|
-
["statusCode", "status"],
|
|
347
|
-
["statusText", "statusText"],
|
|
348
|
-
["statusMessage", "statusText"]
|
|
349
|
-
]) Object.defineProperty(fetchError, key, { get() {
|
|
350
|
-
return ctx.response && ctx.response[refKey];
|
|
351
|
-
} });
|
|
352
|
-
return fetchError;
|
|
353
|
-
}
|
|
354
|
-
const payloadMethods = new Set(Object.freeze([
|
|
355
|
-
"PATCH",
|
|
356
|
-
"POST",
|
|
357
|
-
"PUT",
|
|
358
|
-
"DELETE"
|
|
359
|
-
]));
|
|
360
|
-
function isPayloadMethod(method = "GET") {
|
|
361
|
-
return payloadMethods.has(method.toUpperCase());
|
|
362
|
-
}
|
|
363
|
-
function isJSONSerializable(value) {
|
|
364
|
-
if (value === void 0) return false;
|
|
365
|
-
const t = typeof value;
|
|
366
|
-
if (t === "string" || t === "number" || t === "boolean" || t === null) return true;
|
|
367
|
-
if (t !== "object") return false;
|
|
368
|
-
if (Array.isArray(value)) return true;
|
|
369
|
-
if (value.buffer) return false;
|
|
370
|
-
if (value instanceof FormData || value instanceof URLSearchParams) return false;
|
|
371
|
-
return value.constructor && value.constructor.name === "Object" || typeof value.toJSON === "function";
|
|
372
|
-
}
|
|
373
|
-
const textTypes = new Set([
|
|
374
|
-
"image/svg",
|
|
375
|
-
"application/xml",
|
|
376
|
-
"application/xhtml",
|
|
377
|
-
"application/html"
|
|
378
|
-
]);
|
|
379
|
-
const JSON_RE = /^application\/(?:[\w!#$%&*.^`~-]*\+)?json(;.+)?$/i;
|
|
380
|
-
function detectResponseType(_contentType = "") {
|
|
381
|
-
if (!_contentType) return "json";
|
|
382
|
-
const contentType = _contentType.split(";").shift() || "";
|
|
383
|
-
if (JSON_RE.test(contentType)) return "json";
|
|
384
|
-
if (contentType === "text/event-stream") return "stream";
|
|
385
|
-
if (textTypes.has(contentType) || contentType.startsWith("text/")) return "text";
|
|
386
|
-
return "blob";
|
|
387
|
-
}
|
|
388
|
-
function resolveFetchOptions(request, input, defaults, Headers) {
|
|
389
|
-
const headers = mergeHeaders(input?.headers ?? request?.headers, defaults?.headers, Headers);
|
|
390
|
-
let query;
|
|
391
|
-
if (defaults?.query || defaults?.params || input?.params || input?.query) query = {
|
|
392
|
-
...defaults?.params,
|
|
393
|
-
...defaults?.query,
|
|
394
|
-
...input?.params,
|
|
395
|
-
...input?.query
|
|
396
|
-
};
|
|
397
|
-
return {
|
|
398
|
-
...defaults,
|
|
399
|
-
...input,
|
|
400
|
-
query,
|
|
401
|
-
params: query,
|
|
402
|
-
headers
|
|
403
|
-
};
|
|
404
|
-
}
|
|
405
|
-
function mergeHeaders(input, defaults, Headers) {
|
|
406
|
-
if (!defaults) return new Headers(input);
|
|
407
|
-
const headers = new Headers(defaults);
|
|
408
|
-
if (input) for (const [key, value] of Symbol.iterator in input || Array.isArray(input) ? input : new Headers(input)) headers.set(key, value);
|
|
409
|
-
return headers;
|
|
410
|
-
}
|
|
411
|
-
async function callHooks(context, hooks) {
|
|
412
|
-
if (hooks) if (Array.isArray(hooks)) for (const hook of hooks) await hook(context);
|
|
413
|
-
else await hooks(context);
|
|
414
|
-
}
|
|
415
|
-
const retryStatusCodes = new Set([
|
|
416
|
-
408,
|
|
417
|
-
409,
|
|
418
|
-
425,
|
|
419
|
-
429,
|
|
420
|
-
500,
|
|
421
|
-
502,
|
|
422
|
-
503,
|
|
423
|
-
504
|
|
424
|
-
]);
|
|
425
|
-
const nullBodyResponses = new Set([
|
|
426
|
-
101,
|
|
427
|
-
204,
|
|
428
|
-
205,
|
|
429
|
-
304
|
|
430
|
-
]);
|
|
431
|
-
function createFetch(globalOptions = {}) {
|
|
432
|
-
const { fetch = globalThis.fetch, Headers = globalThis.Headers, AbortController = globalThis.AbortController } = globalOptions;
|
|
433
|
-
async function onError(context) {
|
|
434
|
-
const isAbort = context.error && context.error.name === "AbortError" && !context.options.timeout || false;
|
|
435
|
-
if (context.options.retry !== false && !isAbort) {
|
|
436
|
-
let retries;
|
|
437
|
-
if (typeof context.options.retry === "number") retries = context.options.retry;
|
|
438
|
-
else retries = isPayloadMethod(context.options.method) ? 0 : 1;
|
|
439
|
-
const responseCode = context.response && context.response.status || 500;
|
|
440
|
-
if (retries > 0 && (Array.isArray(context.options.retryStatusCodes) ? context.options.retryStatusCodes.includes(responseCode) : retryStatusCodes.has(responseCode))) {
|
|
441
|
-
const retryDelay = typeof context.options.retryDelay === "function" ? context.options.retryDelay(context) : context.options.retryDelay || 0;
|
|
442
|
-
if (retryDelay > 0) await new Promise((resolve) => setTimeout(resolve, retryDelay));
|
|
443
|
-
return $fetchRaw(context.request, {
|
|
444
|
-
...context.options,
|
|
445
|
-
retry: retries - 1
|
|
446
|
-
});
|
|
447
|
-
}
|
|
448
|
-
}
|
|
449
|
-
const error = createFetchError(context);
|
|
450
|
-
if (Error.captureStackTrace) Error.captureStackTrace(error, $fetchRaw);
|
|
451
|
-
throw error;
|
|
452
|
-
}
|
|
453
|
-
const $fetchRaw = async function $fetchRaw2(_request, _options = {}) {
|
|
454
|
-
const context = {
|
|
455
|
-
request: _request,
|
|
456
|
-
options: resolveFetchOptions(_request, _options, globalOptions.defaults, Headers),
|
|
457
|
-
response: void 0,
|
|
458
|
-
error: void 0
|
|
459
|
-
};
|
|
460
|
-
if (context.options.method) context.options.method = context.options.method.toUpperCase();
|
|
461
|
-
if (context.options.onRequest) {
|
|
462
|
-
await callHooks(context, context.options.onRequest);
|
|
463
|
-
if (!(context.options.headers instanceof Headers)) context.options.headers = new Headers(context.options.headers || {});
|
|
464
|
-
}
|
|
465
|
-
if (typeof context.request === "string") {
|
|
466
|
-
if (context.options.baseURL) context.request = withBase(context.request, context.options.baseURL);
|
|
467
|
-
if (context.options.query) {
|
|
468
|
-
context.request = withQuery(context.request, context.options.query);
|
|
469
|
-
delete context.options.query;
|
|
470
|
-
}
|
|
471
|
-
if ("query" in context.options) delete context.options.query;
|
|
472
|
-
if ("params" in context.options) delete context.options.params;
|
|
473
|
-
}
|
|
474
|
-
if (context.options.body && isPayloadMethod(context.options.method)) {
|
|
475
|
-
if (isJSONSerializable(context.options.body)) {
|
|
476
|
-
const contentType = context.options.headers.get("content-type");
|
|
477
|
-
if (typeof context.options.body !== "string") context.options.body = contentType === "application/x-www-form-urlencoded" ? new URLSearchParams(context.options.body).toString() : JSON.stringify(context.options.body);
|
|
478
|
-
if (!contentType) context.options.headers.set("content-type", "application/json");
|
|
479
|
-
if (!context.options.headers.has("accept")) context.options.headers.set("accept", "application/json");
|
|
480
|
-
} else if ("pipeTo" in context.options.body && typeof context.options.body.pipeTo === "function" || typeof context.options.body.pipe === "function") {
|
|
481
|
-
if (!("duplex" in context.options)) context.options.duplex = "half";
|
|
482
|
-
}
|
|
483
|
-
}
|
|
484
|
-
let abortTimeout;
|
|
485
|
-
if (!context.options.signal && context.options.timeout) {
|
|
486
|
-
const controller = new AbortController();
|
|
487
|
-
abortTimeout = setTimeout(() => {
|
|
488
|
-
const error = new Error("[TimeoutError]: The operation was aborted due to timeout");
|
|
489
|
-
error.name = "TimeoutError";
|
|
490
|
-
error.code = 23;
|
|
491
|
-
controller.abort(error);
|
|
492
|
-
}, context.options.timeout);
|
|
493
|
-
context.options.signal = controller.signal;
|
|
494
|
-
}
|
|
495
|
-
try {
|
|
496
|
-
context.response = await fetch(context.request, context.options);
|
|
497
|
-
} catch (error) {
|
|
498
|
-
context.error = error;
|
|
499
|
-
if (context.options.onRequestError) await callHooks(context, context.options.onRequestError);
|
|
500
|
-
return await onError(context);
|
|
501
|
-
} finally {
|
|
502
|
-
if (abortTimeout) clearTimeout(abortTimeout);
|
|
503
|
-
}
|
|
504
|
-
if ((context.response.body || context.response._bodyInit) && !nullBodyResponses.has(context.response.status) && context.options.method !== "HEAD") {
|
|
505
|
-
const responseType = (context.options.parseResponse ? "json" : context.options.responseType) || detectResponseType(context.response.headers.get("content-type") || "");
|
|
506
|
-
switch (responseType) {
|
|
507
|
-
case "json": {
|
|
508
|
-
const data = await context.response.text();
|
|
509
|
-
const parseFunction = context.options.parseResponse || destr;
|
|
510
|
-
context.response._data = parseFunction(data);
|
|
511
|
-
break;
|
|
512
|
-
}
|
|
513
|
-
case "stream":
|
|
514
|
-
context.response._data = context.response.body || context.response._bodyInit;
|
|
515
|
-
break;
|
|
516
|
-
default: context.response._data = await context.response[responseType]();
|
|
517
|
-
}
|
|
518
|
-
}
|
|
519
|
-
if (context.options.onResponse) await callHooks(context, context.options.onResponse);
|
|
520
|
-
if (!context.options.ignoreResponseError && context.response.status >= 400 && context.response.status < 600) {
|
|
521
|
-
if (context.options.onResponseError) await callHooks(context, context.options.onResponseError);
|
|
522
|
-
return await onError(context);
|
|
523
|
-
}
|
|
524
|
-
return context.response;
|
|
525
|
-
};
|
|
526
|
-
const $fetch = async function $fetch2(request, options) {
|
|
527
|
-
return (await $fetchRaw(request, options))._data;
|
|
528
|
-
};
|
|
529
|
-
$fetch.raw = $fetchRaw;
|
|
530
|
-
$fetch.native = (...args) => fetch(...args);
|
|
531
|
-
$fetch.create = (defaultOptions = {}, customGlobalOptions = {}) => createFetch({
|
|
532
|
-
...globalOptions,
|
|
533
|
-
...customGlobalOptions,
|
|
534
|
-
defaults: {
|
|
535
|
-
...globalOptions.defaults,
|
|
536
|
-
...customGlobalOptions.defaults,
|
|
537
|
-
...defaultOptions
|
|
538
|
-
}
|
|
539
|
-
});
|
|
540
|
-
return $fetch;
|
|
541
|
-
}
|
|
201
|
+
identity_authority_unavailable: "Authentication is temporarily unavailable.",
|
|
202
|
+
two_factor_required: "A second authentication factor is required.",
|
|
203
|
+
two_factor_code_invalid: "The verification code is invalid.",
|
|
204
|
+
two_factor_challenge_expired: "The second-factor challenge has ended. Sign in again.",
|
|
205
|
+
two_factor_locked: "Second-factor verification is temporarily locked.",
|
|
206
|
+
recent_sign_in_required: "A recent sign-in is required.",
|
|
207
|
+
enterprise_recovery_required: "Enterprise administration evidence requires operator recovery.",
|
|
208
|
+
recent_authentication_required: "A ready recent-authentication action is required.",
|
|
209
|
+
organization_closure_confirmation_mismatch: "The confirmation does not match the organization.",
|
|
210
|
+
organization_closure_cancellation_ended: "The closure cancellation period has ended.",
|
|
211
|
+
ceremony_return_refused: "The return address is not registered for this application.",
|
|
212
|
+
password_sign_in_required: "A password sign-in method is required for this passkey change."
|
|
213
|
+
};
|
|
214
|
+
var AuthError = class extends Error {
|
|
215
|
+
code;
|
|
216
|
+
status;
|
|
217
|
+
retryAfterSeconds;
|
|
218
|
+
constructor(code, status, retryAfterSeconds) {
|
|
219
|
+
super(messages[code]);
|
|
220
|
+
this.name = "AuthError";
|
|
221
|
+
this.code = code;
|
|
222
|
+
this.status = status;
|
|
223
|
+
this.retryAfterSeconds = retryAfterSeconds;
|
|
224
|
+
}
|
|
225
|
+
};
|
|
542
226
|
//#endregion
|
|
543
227
|
//#region src/shared.ts
|
|
544
228
|
const DRIVE_CREDENTIAL_LIFETIME_SECONDS = 840;
|
|
@@ -654,7 +338,7 @@ function normalizeIdInput(value) {
|
|
|
654
338
|
return value;
|
|
655
339
|
}
|
|
656
340
|
function normalizeOrganization(value) {
|
|
657
|
-
exact(value, [
|
|
341
|
+
exact$2(value, [
|
|
658
342
|
"capabilities",
|
|
659
343
|
"id",
|
|
660
344
|
"lifecycle",
|
|
@@ -664,7 +348,7 @@ function normalizeOrganization(value) {
|
|
|
664
348
|
"slug"
|
|
665
349
|
]);
|
|
666
350
|
if (!isId(value.id) || !boundedString(value.name, 255) || !boundedString(value.slug, 255) || value.lifecycle !== "ordinary" && value.lifecycle !== "managed" || !role(value.role) || !isObject(value.capabilities)) throw authorityUnavailable();
|
|
667
|
-
exact(value.capabilities, [
|
|
351
|
+
exact$2(value.capabilities, [
|
|
668
352
|
"readInvitations",
|
|
669
353
|
"readMembers",
|
|
670
354
|
"readTeams"
|
|
@@ -726,7 +410,7 @@ function normalizeOrganizationCreationInput(name, slug, idempotencyKey) {
|
|
|
726
410
|
};
|
|
727
411
|
}
|
|
728
412
|
function normalizeCreatedOrganization(value) {
|
|
729
|
-
exact(value, [
|
|
413
|
+
exact$2(value, [
|
|
730
414
|
"id",
|
|
731
415
|
"name",
|
|
732
416
|
"slug"
|
|
@@ -746,7 +430,7 @@ function normalizeOrganizationTeamCreationInput(name, idempotencyKey) {
|
|
|
746
430
|
};
|
|
747
431
|
}
|
|
748
432
|
function normalizeCreatedOrganizationTeam(value) {
|
|
749
|
-
exact(value, ["id", "name"]);
|
|
433
|
+
exact$2(value, ["id", "name"]);
|
|
750
434
|
if (!isId(value.id) || !boundedString(value.name, 255)) throw authorityUnavailable();
|
|
751
435
|
return {
|
|
752
436
|
id: value.id,
|
|
@@ -773,7 +457,7 @@ function normalizeOrganizationMemberInvitationCreationInput(value) {
|
|
|
773
457
|
};
|
|
774
458
|
}
|
|
775
459
|
function normalizeCreatedOrganizationMemberInvitation(value) {
|
|
776
|
-
exact(value, ["expiresAt", "id"]);
|
|
460
|
+
exact$2(value, ["expiresAt", "id"]);
|
|
777
461
|
if (!isId(value.id)) throw authorityUnavailable();
|
|
778
462
|
return {
|
|
779
463
|
id: value.id,
|
|
@@ -781,7 +465,7 @@ function normalizeCreatedOrganizationMemberInvitation(value) {
|
|
|
781
465
|
};
|
|
782
466
|
}
|
|
783
467
|
function normalizeOrganizations(value) {
|
|
784
|
-
exact(value, ["nextCursor", "organizations"]);
|
|
468
|
+
exact$2(value, ["nextCursor", "organizations"]);
|
|
785
469
|
if (!Array.isArray(value.organizations) || value.organizations.length > 100) throw authorityUnavailable();
|
|
786
470
|
return {
|
|
787
471
|
organizations: unique(value.organizations.map(normalizeOrganization), (item) => item.id),
|
|
@@ -789,11 +473,11 @@ function normalizeOrganizations(value) {
|
|
|
789
473
|
};
|
|
790
474
|
}
|
|
791
475
|
function normalizeOrganizationMembers(value) {
|
|
792
|
-
exact(value, ["members", "nextCursor"]);
|
|
476
|
+
exact$2(value, ["members", "nextCursor"]);
|
|
793
477
|
if (!Array.isArray(value.members) || value.members.length > 100) throw authorityUnavailable();
|
|
794
478
|
return {
|
|
795
479
|
members: unique(value.members.map((member) => {
|
|
796
|
-
exact(member, [
|
|
480
|
+
exact$2(member, [
|
|
797
481
|
"email",
|
|
798
482
|
"id",
|
|
799
483
|
"image",
|
|
@@ -822,11 +506,11 @@ function normalizeOrganizationMembers(value) {
|
|
|
822
506
|
};
|
|
823
507
|
}
|
|
824
508
|
function normalizeOrganizationTeams(value) {
|
|
825
|
-
exact(value, ["nextCursor", "teams"]);
|
|
509
|
+
exact$2(value, ["nextCursor", "teams"]);
|
|
826
510
|
if (!Array.isArray(value.teams) || value.teams.length > 100) throw authorityUnavailable();
|
|
827
511
|
return {
|
|
828
512
|
teams: unique(value.teams.map((team) => {
|
|
829
|
-
exact(team, [
|
|
513
|
+
exact$2(team, [
|
|
830
514
|
"category",
|
|
831
515
|
"createdAt",
|
|
832
516
|
"id",
|
|
@@ -844,7 +528,7 @@ function normalizeOrganizationTeams(value) {
|
|
|
844
528
|
};
|
|
845
529
|
}
|
|
846
530
|
function normalizeOrganizationTeamMembers(value) {
|
|
847
|
-
exact(value, ["memberIds", "nextCursor"]);
|
|
531
|
+
exact$2(value, ["memberIds", "nextCursor"]);
|
|
848
532
|
if (!Array.isArray(value.memberIds) || value.memberIds.length > 100) throw authorityUnavailable();
|
|
849
533
|
return {
|
|
850
534
|
memberIds: unique(value.memberIds.map((item) => normalizeResponseId(item)), (item) => item),
|
|
@@ -852,7 +536,7 @@ function normalizeOrganizationTeamMembers(value) {
|
|
|
852
536
|
};
|
|
853
537
|
}
|
|
854
538
|
function normalizeOrganizationInvitation(value) {
|
|
855
|
-
exact(value, [
|
|
539
|
+
exact$2(value, [
|
|
856
540
|
"createdAt",
|
|
857
541
|
"email",
|
|
858
542
|
"expiresAt",
|
|
@@ -863,7 +547,7 @@ function normalizeOrganizationInvitation(value) {
|
|
|
863
547
|
"teamIds"
|
|
864
548
|
]);
|
|
865
549
|
if (!isId(value.id) || typeof value.email !== "string" || value.email.length > 320 || !email.test(value.email) || !role(value.role) || value.status !== "pending" || !Array.isArray(value.teamIds) || value.teamIds.length > 100 || !isObject(value.inviter)) throw authorityUnavailable();
|
|
866
|
-
exact(value.inviter, ["membershipId", "name"]);
|
|
550
|
+
exact$2(value.inviter, ["membershipId", "name"]);
|
|
867
551
|
if (!isId(value.inviter.membershipId) || !boundedString(value.inviter.name, 255)) throw authorityUnavailable();
|
|
868
552
|
return {
|
|
869
553
|
id: value.id,
|
|
@@ -880,7 +564,7 @@ function normalizeOrganizationInvitation(value) {
|
|
|
880
564
|
};
|
|
881
565
|
}
|
|
882
566
|
function normalizeOrganizationInvitations(value) {
|
|
883
|
-
exact(value, ["invitations", "nextCursor"]);
|
|
567
|
+
exact$2(value, ["invitations", "nextCursor"]);
|
|
884
568
|
if (!Array.isArray(value.invitations) || value.invitations.length > 100) throw authorityUnavailable();
|
|
885
569
|
return {
|
|
886
570
|
invitations: unique(value.invitations.map(normalizeOrganizationInvitation), (item) => item.id),
|
|
@@ -888,7 +572,7 @@ function normalizeOrganizationInvitations(value) {
|
|
|
888
572
|
};
|
|
889
573
|
}
|
|
890
574
|
function normalizeReceivedInvitation(value) {
|
|
891
|
-
exact(value, [
|
|
575
|
+
exact$2(value, [
|
|
892
576
|
"expiresAt",
|
|
893
577
|
"id",
|
|
894
578
|
"inviterName",
|
|
@@ -897,7 +581,7 @@ function normalizeReceivedInvitation(value) {
|
|
|
897
581
|
"teams"
|
|
898
582
|
]);
|
|
899
583
|
if (!isId(value.id) || !boundedString(value.inviterName, 255) || !role(value.role) || !Array.isArray(value.teams) || value.teams.length > 100 || !isObject(value.organization)) throw authorityUnavailable();
|
|
900
|
-
exact(value.organization, [
|
|
584
|
+
exact$2(value.organization, [
|
|
901
585
|
"id",
|
|
902
586
|
"logo",
|
|
903
587
|
"name",
|
|
@@ -914,7 +598,7 @@ function normalizeReceivedInvitation(value) {
|
|
|
914
598
|
},
|
|
915
599
|
role: value.role,
|
|
916
600
|
teams: unique(value.teams.map((team) => {
|
|
917
|
-
exact(team, ["id", "name"]);
|
|
601
|
+
exact$2(team, ["id", "name"]);
|
|
918
602
|
if (!isId(team.id) || !boundedString(team.name, 255)) throw authorityUnavailable();
|
|
919
603
|
return {
|
|
920
604
|
id: team.id,
|
|
@@ -926,7 +610,7 @@ function normalizeReceivedInvitation(value) {
|
|
|
926
610
|
};
|
|
927
611
|
}
|
|
928
612
|
function normalizeReceivedInvitations(value) {
|
|
929
|
-
exact(value, ["invitations", "nextCursor"]);
|
|
613
|
+
exact$2(value, ["invitations", "nextCursor"]);
|
|
930
614
|
if (!Array.isArray(value.invitations) || value.invitations.length > 100) throw authorityUnavailable();
|
|
931
615
|
return {
|
|
932
616
|
invitations: unique(value.invitations.map(normalizeReceivedInvitation), (item) => item.id),
|
|
@@ -984,8 +668,35 @@ function fromOrganizationMutationAuthorityError(value, status, retryAfter) {
|
|
|
984
668
|
if (status === 403 && code === "REQUEST_ORIGIN_DENIED") return new AuthError("request_origin_denied", 403);
|
|
985
669
|
return fromOrganizationReadAuthorityError(value, status);
|
|
986
670
|
}
|
|
671
|
+
function normalizeOrganizationClosureStartInput(value) {
|
|
672
|
+
if (!isObject(value) || Object.keys(value).sort().join(",") !== "confirmationName,idempotencyKey") throw new TypeError("organization closure input is invalid");
|
|
673
|
+
if (!boundedString(value.confirmationName, 255)) throw new TypeError("confirmationName is invalid");
|
|
674
|
+
return {
|
|
675
|
+
confirmationName: value.confirmationName,
|
|
676
|
+
idempotencyKey: normalizeAuthorityIdempotencyKey(value.idempotencyKey)
|
|
677
|
+
};
|
|
678
|
+
}
|
|
679
|
+
function normalizeOrganizationClosureCancelInput(value) {
|
|
680
|
+
if (!isObject(value) || Object.keys(value).join(",") !== "idempotencyKey") throw new TypeError("organization closure cancellation input is invalid");
|
|
681
|
+
return { idempotencyKey: normalizeAuthorityIdempotencyKey(value.idempotencyKey) };
|
|
682
|
+
}
|
|
683
|
+
function normalizeOrganizationOwnershipTransferInput(value) {
|
|
684
|
+
if (!isObject(value) || Object.keys(value).sort().join(",") !== "expectedActorAuthorityRevision,expectedOutgoingOwnerAuthorityRevision,expectedSuccessorAuthorityRevision,idempotencyKey,outgoingOwnerMembershipId,outgoingOwnerRole,successorMembershipId") throw new TypeError("organization ownership transfer input is invalid");
|
|
685
|
+
if (!isId(value.outgoingOwnerMembershipId) || !isId(value.successorMembershipId)) throw new TypeError("ownership transfer membership is invalid");
|
|
686
|
+
if (value.outgoingOwnerMembershipId === value.successorMembershipId) throw new TypeError("ownership transfer memberships must differ");
|
|
687
|
+
if (value.outgoingOwnerRole !== "admin" && value.outgoingOwnerRole !== "member") throw new TypeError("outgoingOwnerRole is invalid");
|
|
688
|
+
return {
|
|
689
|
+
outgoingOwnerMembershipId: value.outgoingOwnerMembershipId,
|
|
690
|
+
successorMembershipId: value.successorMembershipId,
|
|
691
|
+
outgoingOwnerRole: value.outgoingOwnerRole,
|
|
692
|
+
expectedActorAuthorityRevision: normalizeAuthorityRevision(value.expectedActorAuthorityRevision, "expectedActorAuthorityRevision"),
|
|
693
|
+
expectedOutgoingOwnerAuthorityRevision: normalizeAuthorityRevision(value.expectedOutgoingOwnerAuthorityRevision, "expectedOutgoingOwnerAuthorityRevision", true),
|
|
694
|
+
expectedSuccessorAuthorityRevision: normalizeAuthorityRevision(value.expectedSuccessorAuthorityRevision, "expectedSuccessorAuthorityRevision", true),
|
|
695
|
+
idempotencyKey: normalizeAuthorityIdempotencyKey(value.idempotencyKey)
|
|
696
|
+
};
|
|
697
|
+
}
|
|
987
698
|
function normalizeOrganizationMemberAuthority(value, organizationId, memberId) {
|
|
988
|
-
exact(value, [
|
|
699
|
+
exact$2(value, [
|
|
989
700
|
"organizationId",
|
|
990
701
|
"actor",
|
|
991
702
|
"target"
|
|
@@ -1003,7 +714,7 @@ function normalizeOrganizationMemberAuthority(value, organizationId, memberId) {
|
|
|
1003
714
|
};
|
|
1004
715
|
}
|
|
1005
716
|
function normalizeOrganizationAuthorityMemberOutcome(value, includesStatus = false) {
|
|
1006
|
-
exact(value, [
|
|
717
|
+
exact$2(value, [
|
|
1007
718
|
"memberId",
|
|
1008
719
|
"manualRole",
|
|
1009
720
|
"role",
|
|
@@ -1018,10 +729,18 @@ function normalizeOrganizationAuthorityMemberOutcome(value, includesStatus = fal
|
|
|
1018
729
|
authorityRevision: normalizeAuthorityResultRevision(value.authorityRevision)
|
|
1019
730
|
};
|
|
1020
731
|
}
|
|
732
|
+
function normalizeAuthorityRevision(value, name, incremented = false) {
|
|
733
|
+
if (!Number.isSafeInteger(value) || value < 0 || value >= Number.MAX_SAFE_INTEGER - (incremented ? 1 : 0)) throw new TypeError(`${name} is invalid`);
|
|
734
|
+
return value;
|
|
735
|
+
}
|
|
1021
736
|
function normalizeAuthorityResultRevision(value) {
|
|
1022
737
|
if (!Number.isSafeInteger(value) || value < 0 || value >= Number.MAX_SAFE_INTEGER) throw authorityUnavailable();
|
|
1023
738
|
return value;
|
|
1024
739
|
}
|
|
740
|
+
function normalizeAuthorityIdempotencyKey(value) {
|
|
741
|
+
if (typeof value !== "string" || !/^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$/.test(value)) throw new TypeError("idempotencyKey is invalid");
|
|
742
|
+
return value;
|
|
743
|
+
}
|
|
1025
744
|
function mapError(code, status) {
|
|
1026
745
|
if (code === "authentication_required") return {
|
|
1027
746
|
code,
|
|
@@ -1096,7 +815,7 @@ function normalizeProfileImage(value) {
|
|
|
1096
815
|
function isId(value) {
|
|
1097
816
|
return typeof value === "string" && id.test(value);
|
|
1098
817
|
}
|
|
1099
|
-
function exact(value, keys) {
|
|
818
|
+
function exact$2(value, keys) {
|
|
1100
819
|
if (!isObject(value) || Object.keys(value).sort().join(",") !== [...keys].sort().join(",")) throw authorityUnavailable();
|
|
1101
820
|
}
|
|
1102
821
|
function boundedString(value, maximum) {
|
|
@@ -1132,12 +851,361 @@ function normalizeResponseId(value) {
|
|
|
1132
851
|
if (!isId(value)) throw authorityUnavailable();
|
|
1133
852
|
return value;
|
|
1134
853
|
}
|
|
1135
|
-
function unique(items, key) {
|
|
1136
|
-
if (new Set(items.map(key)).size !== items.length) throw authorityUnavailable();
|
|
1137
|
-
return items;
|
|
854
|
+
function unique(items, key) {
|
|
855
|
+
if (new Set(items.map(key)).size !== items.length) throw authorityUnavailable();
|
|
856
|
+
return items;
|
|
857
|
+
}
|
|
858
|
+
function credentialSessionId(token) {
|
|
859
|
+
const parts = token.split(".");
|
|
860
|
+
if (parts.length !== 3 || !/^[A-Za-z0-9_-]+$/.test(parts[1])) return void 0;
|
|
861
|
+
try {
|
|
862
|
+
const base64 = parts[1].replaceAll("-", "+").replaceAll("_", "/");
|
|
863
|
+
const decoded = atob(base64.padEnd(base64.length + (4 - base64.length % 4) % 4, "="));
|
|
864
|
+
const payload = JSON.parse(decoded);
|
|
865
|
+
return isObject(payload) && typeof payload.sid === "string" && payload.sid.length > 0 ? payload.sid : void 0;
|
|
866
|
+
} catch {
|
|
867
|
+
return;
|
|
868
|
+
}
|
|
869
|
+
}
|
|
870
|
+
function isObject(value) {
|
|
871
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
872
|
+
}
|
|
873
|
+
//#endregion
|
|
874
|
+
//#region src/user-api/credential.ts
|
|
875
|
+
function userApiApplication(input) {
|
|
876
|
+
if (!input || typeof input.applicationId !== "string" || !/^[A-Za-z0-9_-]{1,128}$(?![\s\S])/.test(input.applicationId) || input.forceRefresh !== void 0 && typeof input.forceRefresh !== "boolean") throw new TypeError("User API credential input is invalid");
|
|
877
|
+
return input.applicationId;
|
|
878
|
+
}
|
|
879
|
+
function normalizeUserApiCredential(value, startedAt) {
|
|
880
|
+
if (!value || typeof value !== "object" || Array.isArray(value) || !("tokenType" in value) || value.tokenType !== "Bearer" || !("token" in value) || typeof value.token !== "string" || value.token.length + 7 > 16 * 1024 || !/^[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+$/.test(value.token) || !("expiresIn" in value) || typeof value.expiresIn !== "number" || !Number.isInteger(value.expiresIn) || value.expiresIn < 1 || value.expiresIn > 840 || Object.keys(value).sort().join(",") !== "expiresIn,token,tokenType") throw new AuthError("identity_authority_unavailable", 503);
|
|
881
|
+
return {
|
|
882
|
+
tokenType: "Bearer",
|
|
883
|
+
token: value.token,
|
|
884
|
+
expiresAt: new Date(startedAt + value.expiresIn * 1e3)
|
|
885
|
+
};
|
|
886
|
+
}
|
|
887
|
+
function createUserApiCredentialCache(issue, now, currentSessionId = () => void 0) {
|
|
888
|
+
let generation = 0;
|
|
889
|
+
let cached;
|
|
890
|
+
let pending;
|
|
891
|
+
const copy = (value) => ({
|
|
892
|
+
...value,
|
|
893
|
+
expiresAt: new Date(value.expiresAt)
|
|
894
|
+
});
|
|
895
|
+
return {
|
|
896
|
+
hasAuthority: () => Boolean(cached || pending),
|
|
897
|
+
retainSession(sessionId) {
|
|
898
|
+
if (cached?.sessionId === sessionId && !pending) return;
|
|
899
|
+
generation += 1;
|
|
900
|
+
cached = void 0;
|
|
901
|
+
pending = void 0;
|
|
902
|
+
},
|
|
903
|
+
clear() {
|
|
904
|
+
generation += 1;
|
|
905
|
+
cached = void 0;
|
|
906
|
+
pending = void 0;
|
|
907
|
+
},
|
|
908
|
+
async get(input) {
|
|
909
|
+
const applicationId = userApiApplication(input);
|
|
910
|
+
if (pending) {
|
|
911
|
+
if (pending.applicationId !== applicationId) throw new AuthError("state_conflict", 409);
|
|
912
|
+
return copy(await pending.request);
|
|
913
|
+
}
|
|
914
|
+
const startedAt = now();
|
|
915
|
+
if (!input.forceRefresh && cached?.applicationId === applicationId && cached.expiresAt - startedAt > 12e4) return {
|
|
916
|
+
tokenType: "Bearer",
|
|
917
|
+
token: cached.token,
|
|
918
|
+
expiresAt: new Date(cached.expiresAt)
|
|
919
|
+
};
|
|
920
|
+
cached = void 0;
|
|
921
|
+
const epoch = generation;
|
|
922
|
+
const request = (async () => {
|
|
923
|
+
const value = normalizeUserApiCredential(await issue(applicationId), startedAt);
|
|
924
|
+
if (epoch !== generation) throw new AuthError("state_conflict", 409);
|
|
925
|
+
if (now() < startedAt || value.expiresAt.getTime() <= now()) throw new AuthError("authentication_required", 401);
|
|
926
|
+
const sessionId = credentialSessionId(value.token);
|
|
927
|
+
const observed = currentSessionId();
|
|
928
|
+
if (observed !== void 0 && sessionId !== void 0 && sessionId !== observed) throw new AuthError("authentication_required", 401);
|
|
929
|
+
cached = {
|
|
930
|
+
applicationId,
|
|
931
|
+
token: value.token,
|
|
932
|
+
expiresAt: value.expiresAt.getTime(),
|
|
933
|
+
sessionId
|
|
934
|
+
};
|
|
935
|
+
return value;
|
|
936
|
+
})().finally(() => {
|
|
937
|
+
if (pending?.request === request) pending = void 0;
|
|
938
|
+
});
|
|
939
|
+
pending = {
|
|
940
|
+
applicationId,
|
|
941
|
+
request
|
|
942
|
+
};
|
|
943
|
+
return copy(await request);
|
|
944
|
+
}
|
|
945
|
+
};
|
|
946
|
+
}
|
|
947
|
+
//#endregion
|
|
948
|
+
//#region ../../node_modules/.pnpm/destr@2.0.5/node_modules/destr/dist/index.mjs
|
|
949
|
+
const suspectProtoRx = /"(?:_|\\u0{2}5[Ff]){2}(?:p|\\u0{2}70)(?:r|\\u0{2}72)(?:o|\\u0{2}6[Ff])(?:t|\\u0{2}74)(?:o|\\u0{2}6[Ff])(?:_|\\u0{2}5[Ff]){2}"\s*:/;
|
|
950
|
+
const suspectConstructorRx = /"(?:c|\\u0063)(?:o|\\u006[Ff])(?:n|\\u006[Ee])(?:s|\\u0073)(?:t|\\u0074)(?:r|\\u0072)(?:u|\\u0075)(?:c|\\u0063)(?:t|\\u0074)(?:o|\\u006[Ff])(?:r|\\u0072)"\s*:/;
|
|
951
|
+
const JsonSigRx = /^\s*["[{]|^\s*-?\d{1,16}(\.\d{1,17})?([Ee][+-]?\d+)?\s*$/;
|
|
952
|
+
function jsonParseTransform(key, value) {
|
|
953
|
+
if (key === "__proto__" || key === "constructor" && value && typeof value === "object" && "prototype" in value) {
|
|
954
|
+
warnKeyDropped(key);
|
|
955
|
+
return;
|
|
956
|
+
}
|
|
957
|
+
return value;
|
|
958
|
+
}
|
|
959
|
+
function warnKeyDropped(key) {
|
|
960
|
+
console.warn(`[destr] Dropping "${key}" key to prevent prototype pollution.`);
|
|
961
|
+
}
|
|
962
|
+
function destr(value, options = {}) {
|
|
963
|
+
if (typeof value !== "string") return value;
|
|
964
|
+
if (value[0] === "\"" && value[value.length - 1] === "\"" && value.indexOf("\\") === -1) return value.slice(1, -1);
|
|
965
|
+
const _value = value.trim();
|
|
966
|
+
if (_value.length <= 9) switch (_value.toLowerCase()) {
|
|
967
|
+
case "true": return true;
|
|
968
|
+
case "false": return false;
|
|
969
|
+
case "undefined": return;
|
|
970
|
+
case "null": return null;
|
|
971
|
+
case "nan": return NaN;
|
|
972
|
+
case "infinity": return Number.POSITIVE_INFINITY;
|
|
973
|
+
case "-infinity": return Number.NEGATIVE_INFINITY;
|
|
974
|
+
}
|
|
975
|
+
if (!JsonSigRx.test(value)) {
|
|
976
|
+
if (options.strict) throw new SyntaxError("[destr] Invalid JSON");
|
|
977
|
+
return value;
|
|
978
|
+
}
|
|
979
|
+
try {
|
|
980
|
+
if (suspectProtoRx.test(value) || suspectConstructorRx.test(value)) {
|
|
981
|
+
if (options.strict) throw new Error("[destr] Possible prototype pollution");
|
|
982
|
+
return JSON.parse(value, jsonParseTransform);
|
|
983
|
+
}
|
|
984
|
+
return JSON.parse(value);
|
|
985
|
+
} catch (error) {
|
|
986
|
+
if (options.strict) throw error;
|
|
987
|
+
return value;
|
|
988
|
+
}
|
|
989
|
+
}
|
|
990
|
+
//#endregion
|
|
991
|
+
//#region ../../node_modules/.pnpm/ofetch@1.5.1/node_modules/ofetch/dist/shared/ofetch.CWycOUEr.mjs
|
|
992
|
+
var FetchError = class extends Error {
|
|
993
|
+
constructor(message, opts) {
|
|
994
|
+
super(message, opts);
|
|
995
|
+
this.name = "FetchError";
|
|
996
|
+
if (opts?.cause && !this.cause) this.cause = opts.cause;
|
|
997
|
+
}
|
|
998
|
+
};
|
|
999
|
+
function createFetchError(ctx) {
|
|
1000
|
+
const errorMessage = ctx.error?.message || ctx.error?.toString() || "";
|
|
1001
|
+
const method = ctx.request?.method || ctx.options?.method || "GET";
|
|
1002
|
+
const url = ctx.request?.url || String(ctx.request) || "/";
|
|
1003
|
+
const fetchError = new FetchError(`${`[${method}] ${JSON.stringify(url)}`}: ${ctx.response ? `${ctx.response.status} ${ctx.response.statusText}` : "<no response>"}${errorMessage ? ` ${errorMessage}` : ""}`, ctx.error ? { cause: ctx.error } : void 0);
|
|
1004
|
+
for (const key of [
|
|
1005
|
+
"request",
|
|
1006
|
+
"options",
|
|
1007
|
+
"response"
|
|
1008
|
+
]) Object.defineProperty(fetchError, key, { get() {
|
|
1009
|
+
return ctx[key];
|
|
1010
|
+
} });
|
|
1011
|
+
for (const [key, refKey] of [
|
|
1012
|
+
["data", "_data"],
|
|
1013
|
+
["status", "status"],
|
|
1014
|
+
["statusCode", "status"],
|
|
1015
|
+
["statusText", "statusText"],
|
|
1016
|
+
["statusMessage", "statusText"]
|
|
1017
|
+
]) Object.defineProperty(fetchError, key, { get() {
|
|
1018
|
+
return ctx.response && ctx.response[refKey];
|
|
1019
|
+
} });
|
|
1020
|
+
return fetchError;
|
|
1021
|
+
}
|
|
1022
|
+
const payloadMethods = new Set(Object.freeze([
|
|
1023
|
+
"PATCH",
|
|
1024
|
+
"POST",
|
|
1025
|
+
"PUT",
|
|
1026
|
+
"DELETE"
|
|
1027
|
+
]));
|
|
1028
|
+
function isPayloadMethod(method = "GET") {
|
|
1029
|
+
return payloadMethods.has(method.toUpperCase());
|
|
1030
|
+
}
|
|
1031
|
+
function isJSONSerializable(value) {
|
|
1032
|
+
if (value === void 0) return false;
|
|
1033
|
+
const t = typeof value;
|
|
1034
|
+
if (t === "string" || t === "number" || t === "boolean" || t === null) return true;
|
|
1035
|
+
if (t !== "object") return false;
|
|
1036
|
+
if (Array.isArray(value)) return true;
|
|
1037
|
+
if (value.buffer) return false;
|
|
1038
|
+
if (value instanceof FormData || value instanceof URLSearchParams) return false;
|
|
1039
|
+
return value.constructor && value.constructor.name === "Object" || typeof value.toJSON === "function";
|
|
1040
|
+
}
|
|
1041
|
+
const textTypes = new Set([
|
|
1042
|
+
"image/svg",
|
|
1043
|
+
"application/xml",
|
|
1044
|
+
"application/xhtml",
|
|
1045
|
+
"application/html"
|
|
1046
|
+
]);
|
|
1047
|
+
const JSON_RE = /^application\/(?:[\w!#$%&*.^`~-]*\+)?json(;.+)?$/i;
|
|
1048
|
+
function detectResponseType(_contentType = "") {
|
|
1049
|
+
if (!_contentType) return "json";
|
|
1050
|
+
const contentType = _contentType.split(";").shift() || "";
|
|
1051
|
+
if (JSON_RE.test(contentType)) return "json";
|
|
1052
|
+
if (contentType === "text/event-stream") return "stream";
|
|
1053
|
+
if (textTypes.has(contentType) || contentType.startsWith("text/")) return "text";
|
|
1054
|
+
return "blob";
|
|
1055
|
+
}
|
|
1056
|
+
function resolveFetchOptions(request, input, defaults, Headers) {
|
|
1057
|
+
const headers = mergeHeaders(input?.headers ?? request?.headers, defaults?.headers, Headers);
|
|
1058
|
+
let query;
|
|
1059
|
+
if (defaults?.query || defaults?.params || input?.params || input?.query) query = {
|
|
1060
|
+
...defaults?.params,
|
|
1061
|
+
...defaults?.query,
|
|
1062
|
+
...input?.params,
|
|
1063
|
+
...input?.query
|
|
1064
|
+
};
|
|
1065
|
+
return {
|
|
1066
|
+
...defaults,
|
|
1067
|
+
...input,
|
|
1068
|
+
query,
|
|
1069
|
+
params: query,
|
|
1070
|
+
headers
|
|
1071
|
+
};
|
|
1072
|
+
}
|
|
1073
|
+
function mergeHeaders(input, defaults, Headers) {
|
|
1074
|
+
if (!defaults) return new Headers(input);
|
|
1075
|
+
const headers = new Headers(defaults);
|
|
1076
|
+
if (input) for (const [key, value] of Symbol.iterator in input || Array.isArray(input) ? input : new Headers(input)) headers.set(key, value);
|
|
1077
|
+
return headers;
|
|
1078
|
+
}
|
|
1079
|
+
async function callHooks(context, hooks) {
|
|
1080
|
+
if (hooks) if (Array.isArray(hooks)) for (const hook of hooks) await hook(context);
|
|
1081
|
+
else await hooks(context);
|
|
1138
1082
|
}
|
|
1139
|
-
|
|
1140
|
-
|
|
1083
|
+
const retryStatusCodes = new Set([
|
|
1084
|
+
408,
|
|
1085
|
+
409,
|
|
1086
|
+
425,
|
|
1087
|
+
429,
|
|
1088
|
+
500,
|
|
1089
|
+
502,
|
|
1090
|
+
503,
|
|
1091
|
+
504
|
|
1092
|
+
]);
|
|
1093
|
+
const nullBodyResponses = new Set([
|
|
1094
|
+
101,
|
|
1095
|
+
204,
|
|
1096
|
+
205,
|
|
1097
|
+
304
|
|
1098
|
+
]);
|
|
1099
|
+
function createFetch(globalOptions = {}) {
|
|
1100
|
+
const { fetch = globalThis.fetch, Headers = globalThis.Headers, AbortController = globalThis.AbortController } = globalOptions;
|
|
1101
|
+
async function onError(context) {
|
|
1102
|
+
const isAbort = context.error && context.error.name === "AbortError" && !context.options.timeout || false;
|
|
1103
|
+
if (context.options.retry !== false && !isAbort) {
|
|
1104
|
+
let retries;
|
|
1105
|
+
if (typeof context.options.retry === "number") retries = context.options.retry;
|
|
1106
|
+
else retries = isPayloadMethod(context.options.method) ? 0 : 1;
|
|
1107
|
+
const responseCode = context.response && context.response.status || 500;
|
|
1108
|
+
if (retries > 0 && (Array.isArray(context.options.retryStatusCodes) ? context.options.retryStatusCodes.includes(responseCode) : retryStatusCodes.has(responseCode))) {
|
|
1109
|
+
const retryDelay = typeof context.options.retryDelay === "function" ? context.options.retryDelay(context) : context.options.retryDelay || 0;
|
|
1110
|
+
if (retryDelay > 0) await new Promise((resolve) => setTimeout(resolve, retryDelay));
|
|
1111
|
+
return $fetchRaw(context.request, {
|
|
1112
|
+
...context.options,
|
|
1113
|
+
retry: retries - 1
|
|
1114
|
+
});
|
|
1115
|
+
}
|
|
1116
|
+
}
|
|
1117
|
+
const error = createFetchError(context);
|
|
1118
|
+
if (Error.captureStackTrace) Error.captureStackTrace(error, $fetchRaw);
|
|
1119
|
+
throw error;
|
|
1120
|
+
}
|
|
1121
|
+
const $fetchRaw = async function $fetchRaw2(_request, _options = {}) {
|
|
1122
|
+
const context = {
|
|
1123
|
+
request: _request,
|
|
1124
|
+
options: resolveFetchOptions(_request, _options, globalOptions.defaults, Headers),
|
|
1125
|
+
response: void 0,
|
|
1126
|
+
error: void 0
|
|
1127
|
+
};
|
|
1128
|
+
if (context.options.method) context.options.method = context.options.method.toUpperCase();
|
|
1129
|
+
if (context.options.onRequest) {
|
|
1130
|
+
await callHooks(context, context.options.onRequest);
|
|
1131
|
+
if (!(context.options.headers instanceof Headers)) context.options.headers = new Headers(context.options.headers || {});
|
|
1132
|
+
}
|
|
1133
|
+
if (typeof context.request === "string") {
|
|
1134
|
+
if (context.options.baseURL) context.request = withBase(context.request, context.options.baseURL);
|
|
1135
|
+
if (context.options.query) {
|
|
1136
|
+
context.request = withQuery(context.request, context.options.query);
|
|
1137
|
+
delete context.options.query;
|
|
1138
|
+
}
|
|
1139
|
+
if ("query" in context.options) delete context.options.query;
|
|
1140
|
+
if ("params" in context.options) delete context.options.params;
|
|
1141
|
+
}
|
|
1142
|
+
if (context.options.body && isPayloadMethod(context.options.method)) {
|
|
1143
|
+
if (isJSONSerializable(context.options.body)) {
|
|
1144
|
+
const contentType = context.options.headers.get("content-type");
|
|
1145
|
+
if (typeof context.options.body !== "string") context.options.body = contentType === "application/x-www-form-urlencoded" ? new URLSearchParams(context.options.body).toString() : JSON.stringify(context.options.body);
|
|
1146
|
+
if (!contentType) context.options.headers.set("content-type", "application/json");
|
|
1147
|
+
if (!context.options.headers.has("accept")) context.options.headers.set("accept", "application/json");
|
|
1148
|
+
} else if ("pipeTo" in context.options.body && typeof context.options.body.pipeTo === "function" || typeof context.options.body.pipe === "function") {
|
|
1149
|
+
if (!("duplex" in context.options)) context.options.duplex = "half";
|
|
1150
|
+
}
|
|
1151
|
+
}
|
|
1152
|
+
let abortTimeout;
|
|
1153
|
+
if (!context.options.signal && context.options.timeout) {
|
|
1154
|
+
const controller = new AbortController();
|
|
1155
|
+
abortTimeout = setTimeout(() => {
|
|
1156
|
+
const error = new Error("[TimeoutError]: The operation was aborted due to timeout");
|
|
1157
|
+
error.name = "TimeoutError";
|
|
1158
|
+
error.code = 23;
|
|
1159
|
+
controller.abort(error);
|
|
1160
|
+
}, context.options.timeout);
|
|
1161
|
+
context.options.signal = controller.signal;
|
|
1162
|
+
}
|
|
1163
|
+
try {
|
|
1164
|
+
context.response = await fetch(context.request, context.options);
|
|
1165
|
+
} catch (error) {
|
|
1166
|
+
context.error = error;
|
|
1167
|
+
if (context.options.onRequestError) await callHooks(context, context.options.onRequestError);
|
|
1168
|
+
return await onError(context);
|
|
1169
|
+
} finally {
|
|
1170
|
+
if (abortTimeout) clearTimeout(abortTimeout);
|
|
1171
|
+
}
|
|
1172
|
+
if ((context.response.body || context.response._bodyInit) && !nullBodyResponses.has(context.response.status) && context.options.method !== "HEAD") {
|
|
1173
|
+
const responseType = (context.options.parseResponse ? "json" : context.options.responseType) || detectResponseType(context.response.headers.get("content-type") || "");
|
|
1174
|
+
switch (responseType) {
|
|
1175
|
+
case "json": {
|
|
1176
|
+
const data = await context.response.text();
|
|
1177
|
+
const parseFunction = context.options.parseResponse || destr;
|
|
1178
|
+
context.response._data = parseFunction(data);
|
|
1179
|
+
break;
|
|
1180
|
+
}
|
|
1181
|
+
case "stream":
|
|
1182
|
+
context.response._data = context.response.body || context.response._bodyInit;
|
|
1183
|
+
break;
|
|
1184
|
+
default: context.response._data = await context.response[responseType]();
|
|
1185
|
+
}
|
|
1186
|
+
}
|
|
1187
|
+
if (context.options.onResponse) await callHooks(context, context.options.onResponse);
|
|
1188
|
+
if (!context.options.ignoreResponseError && context.response.status >= 400 && context.response.status < 600) {
|
|
1189
|
+
if (context.options.onResponseError) await callHooks(context, context.options.onResponseError);
|
|
1190
|
+
return await onError(context);
|
|
1191
|
+
}
|
|
1192
|
+
return context.response;
|
|
1193
|
+
};
|
|
1194
|
+
const $fetch = async function $fetch2(request, options) {
|
|
1195
|
+
return (await $fetchRaw(request, options))._data;
|
|
1196
|
+
};
|
|
1197
|
+
$fetch.raw = $fetchRaw;
|
|
1198
|
+
$fetch.native = (...args) => fetch(...args);
|
|
1199
|
+
$fetch.create = (defaultOptions = {}, customGlobalOptions = {}) => createFetch({
|
|
1200
|
+
...globalOptions,
|
|
1201
|
+
...customGlobalOptions,
|
|
1202
|
+
defaults: {
|
|
1203
|
+
...globalOptions.defaults,
|
|
1204
|
+
...customGlobalOptions.defaults,
|
|
1205
|
+
...defaultOptions
|
|
1206
|
+
}
|
|
1207
|
+
});
|
|
1208
|
+
return $fetch;
|
|
1141
1209
|
}
|
|
1142
1210
|
//#endregion
|
|
1143
1211
|
//#region src/http.ts
|
|
@@ -1208,6 +1276,237 @@ async function readJson(response, maximum = MAX_RESPONSE_BYTES) {
|
|
|
1208
1276
|
}
|
|
1209
1277
|
}
|
|
1210
1278
|
//#endregion
|
|
1279
|
+
//#region src/two-factor.ts
|
|
1280
|
+
function isTwoFactorChallenge(value) {
|
|
1281
|
+
return isObject(value) && value.twoFactorRedirect === true;
|
|
1282
|
+
}
|
|
1283
|
+
function normalizeTwoFactorStatus(value) {
|
|
1284
|
+
if (value === null) throw new AuthError("authentication_required", 401);
|
|
1285
|
+
if (!isObject(value) || !isObject(value.user) || typeof value.user.twoFactorEnabled !== "boolean") throw authorityUnavailable();
|
|
1286
|
+
return { enabled: value.user.twoFactorEnabled };
|
|
1287
|
+
}
|
|
1288
|
+
//#endregion
|
|
1289
|
+
//#region src/sessions.ts
|
|
1290
|
+
const idPattern$1 = /^[A-Za-z0-9_-]{1,128}$(?![\s\S])/;
|
|
1291
|
+
const MAX_SESSIONS = 50;
|
|
1292
|
+
const itemKeys$1 = [
|
|
1293
|
+
"createdAt",
|
|
1294
|
+
"current",
|
|
1295
|
+
"expiresAt",
|
|
1296
|
+
"id",
|
|
1297
|
+
"ipAddress",
|
|
1298
|
+
"updatedAt",
|
|
1299
|
+
"userAgent"
|
|
1300
|
+
];
|
|
1301
|
+
function exact$1(value, keys) {
|
|
1302
|
+
return isObject(value) && Object.keys(value).length === keys.length && keys.every((key) => Object.hasOwn(value, key));
|
|
1303
|
+
}
|
|
1304
|
+
function date$1(value) {
|
|
1305
|
+
if (typeof value !== "string") throw authorityUnavailable();
|
|
1306
|
+
const parsed = new Date(value);
|
|
1307
|
+
if (!Number.isFinite(parsed.getTime()) || parsed.toISOString() !== value) throw authorityUnavailable();
|
|
1308
|
+
return parsed;
|
|
1309
|
+
}
|
|
1310
|
+
function text(value, maximum) {
|
|
1311
|
+
if (value === null) return null;
|
|
1312
|
+
if (typeof value !== "string" || value.length === 0 || value.length > maximum || /[^\x20-\x7e]/.test(value)) throw authorityUnavailable();
|
|
1313
|
+
return value;
|
|
1314
|
+
}
|
|
1315
|
+
function normalizeSessionId(value) {
|
|
1316
|
+
if (typeof value !== "string" || !idPattern$1.test(value)) throw new TypeError("sessionId is invalid");
|
|
1317
|
+
return value;
|
|
1318
|
+
}
|
|
1319
|
+
function normalizeSessionSummary(value) {
|
|
1320
|
+
if (!exact$1(value, itemKeys$1) || typeof value.id !== "string" || !idPattern$1.test(value.id)) throw authorityUnavailable();
|
|
1321
|
+
if (typeof value.current !== "boolean") throw authorityUnavailable();
|
|
1322
|
+
return {
|
|
1323
|
+
id: value.id,
|
|
1324
|
+
current: value.current,
|
|
1325
|
+
createdAt: date$1(value.createdAt),
|
|
1326
|
+
updatedAt: date$1(value.updatedAt),
|
|
1327
|
+
expiresAt: date$1(value.expiresAt),
|
|
1328
|
+
userAgent: text(value.userAgent, 512),
|
|
1329
|
+
ipAddress: text(value.ipAddress, 64)
|
|
1330
|
+
};
|
|
1331
|
+
}
|
|
1332
|
+
function normalizeSessionInventory(value) {
|
|
1333
|
+
if (!exact$1(value, ["sessions", "truncated"]) || !Array.isArray(value.sessions) || value.sessions.length > MAX_SESSIONS || typeof value.truncated !== "boolean") throw authorityUnavailable();
|
|
1334
|
+
const sessions = value.sessions.map(normalizeSessionSummary);
|
|
1335
|
+
if (new Set(sessions.map((session) => session.id)).size !== sessions.length) throw authorityUnavailable();
|
|
1336
|
+
if (sessions.filter((session) => session.current).length !== 1) throw authorityUnavailable();
|
|
1337
|
+
return {
|
|
1338
|
+
sessions,
|
|
1339
|
+
truncated: value.truncated
|
|
1340
|
+
};
|
|
1341
|
+
}
|
|
1342
|
+
function normalizeSessionRevocation(value) {
|
|
1343
|
+
if (!exact$1(value, ["status"]) || value.status !== "revoked") throw authorityUnavailable();
|
|
1344
|
+
}
|
|
1345
|
+
function normalizeOtherSessionRevocation(value) {
|
|
1346
|
+
if (!exact$1(value, ["revoked"]) || !Number.isSafeInteger(value.revoked) || value.revoked < 0) throw authorityUnavailable();
|
|
1347
|
+
return { revoked: value.revoked };
|
|
1348
|
+
}
|
|
1349
|
+
function fromSessionInventoryError(_value, status, retryAfter) {
|
|
1350
|
+
if (status === 400) return new AuthError("invalid_request", 400);
|
|
1351
|
+
if (status === 401) return new AuthError("authentication_required", 401);
|
|
1352
|
+
if (status === 403) return new AuthError("request_origin_denied", 403);
|
|
1353
|
+
if (status === 404 || status === 409) return new AuthError("state_conflict", 409);
|
|
1354
|
+
if (status === 429) return new AuthError("auth_request_rate_limited", 429, parseRetryAfter(retryAfter));
|
|
1355
|
+
return authorityUnavailable();
|
|
1356
|
+
}
|
|
1357
|
+
//#endregion
|
|
1358
|
+
//#region src/passkeys.ts
|
|
1359
|
+
const idPattern = /^[A-Za-z0-9_-]{1,128}$(?![\s\S])/;
|
|
1360
|
+
const MAX_PASSKEYS = 50;
|
|
1361
|
+
const MAX_RETURN_BYTES = 2048;
|
|
1362
|
+
const PASSKEY_NAME_MAX_LENGTH = 64;
|
|
1363
|
+
const itemKeys = [
|
|
1364
|
+
"backedUp",
|
|
1365
|
+
"createdAt",
|
|
1366
|
+
"deviceType",
|
|
1367
|
+
"id",
|
|
1368
|
+
"name"
|
|
1369
|
+
];
|
|
1370
|
+
function exact(value, keys) {
|
|
1371
|
+
return isObject(value) && Object.keys(value).length === keys.length && keys.every((key) => Object.hasOwn(value, key));
|
|
1372
|
+
}
|
|
1373
|
+
function date(value) {
|
|
1374
|
+
if (typeof value !== "string") throw authorityUnavailable();
|
|
1375
|
+
const parsed = new Date(value);
|
|
1376
|
+
if (!Number.isFinite(parsed.getTime()) || parsed.toISOString() !== value) throw authorityUnavailable();
|
|
1377
|
+
return parsed;
|
|
1378
|
+
}
|
|
1379
|
+
function returnInput(value) {
|
|
1380
|
+
if (!isObject(value)) throw new TypeError("ceremony input is invalid");
|
|
1381
|
+
const { applicationId, returnTo } = value;
|
|
1382
|
+
if (typeof applicationId !== "string" || !idPattern.test(applicationId)) throw new TypeError("applicationId is invalid");
|
|
1383
|
+
if (typeof returnTo !== "string" || new TextEncoder().encode(returnTo).byteLength > MAX_RETURN_BYTES || !URL.canParse(returnTo) || new URL(returnTo).toString() !== returnTo) throw new TypeError("returnTo is invalid");
|
|
1384
|
+
return {
|
|
1385
|
+
applicationId,
|
|
1386
|
+
returnTo
|
|
1387
|
+
};
|
|
1388
|
+
}
|
|
1389
|
+
function normalizeCeremonyHandoffInput(value) {
|
|
1390
|
+
const base = returnInput(value);
|
|
1391
|
+
const input = value;
|
|
1392
|
+
switch (input.purpose) {
|
|
1393
|
+
case "passkey_enrollment": return {
|
|
1394
|
+
purpose: input.purpose,
|
|
1395
|
+
...base
|
|
1396
|
+
};
|
|
1397
|
+
case "passkey_removal": return {
|
|
1398
|
+
purpose: input.purpose,
|
|
1399
|
+
...base,
|
|
1400
|
+
passkeyId: normalizePasskeyId(input.passkeyId)
|
|
1401
|
+
};
|
|
1402
|
+
case "recent_authentication": {
|
|
1403
|
+
const request = input.request;
|
|
1404
|
+
if (!isObject(request)) throw new TypeError("request is invalid");
|
|
1405
|
+
const organizationId = normalizeIdInput(request.organizationId);
|
|
1406
|
+
if (request.action === "organization_ownership_transfer") {
|
|
1407
|
+
const { action: _action, organizationId: _organizationId, ...transfer } = request;
|
|
1408
|
+
return {
|
|
1409
|
+
purpose: input.purpose,
|
|
1410
|
+
...base,
|
|
1411
|
+
request: {
|
|
1412
|
+
action: request.action,
|
|
1413
|
+
organizationId,
|
|
1414
|
+
...normalizeOrganizationOwnershipTransferInput(transfer)
|
|
1415
|
+
}
|
|
1416
|
+
};
|
|
1417
|
+
}
|
|
1418
|
+
if (request.action === "organization_closure_start") {
|
|
1419
|
+
const { action: _action, organizationId: _organizationId, ...closure } = request;
|
|
1420
|
+
return {
|
|
1421
|
+
purpose: input.purpose,
|
|
1422
|
+
...base,
|
|
1423
|
+
request: {
|
|
1424
|
+
action: request.action,
|
|
1425
|
+
organizationId,
|
|
1426
|
+
...normalizeOrganizationClosureStartInput(closure)
|
|
1427
|
+
}
|
|
1428
|
+
};
|
|
1429
|
+
}
|
|
1430
|
+
if (request.action === "organization_closure_cancel") {
|
|
1431
|
+
const { action: _action, organizationId: _organizationId, ...closure } = request;
|
|
1432
|
+
return {
|
|
1433
|
+
purpose: input.purpose,
|
|
1434
|
+
...base,
|
|
1435
|
+
request: {
|
|
1436
|
+
action: request.action,
|
|
1437
|
+
organizationId,
|
|
1438
|
+
...normalizeOrganizationClosureCancelInput(closure)
|
|
1439
|
+
}
|
|
1440
|
+
};
|
|
1441
|
+
}
|
|
1442
|
+
throw new TypeError("request action is invalid");
|
|
1443
|
+
}
|
|
1444
|
+
default: throw new TypeError("purpose is invalid");
|
|
1445
|
+
}
|
|
1446
|
+
}
|
|
1447
|
+
function normalizeCeremonyHandoff(value) {
|
|
1448
|
+
if (!exact(value, ["expiresAt", "url"]) || typeof value.url !== "string") throw authorityUnavailable();
|
|
1449
|
+
let url;
|
|
1450
|
+
try {
|
|
1451
|
+
url = new URL(value.url);
|
|
1452
|
+
} catch {
|
|
1453
|
+
throw authorityUnavailable();
|
|
1454
|
+
}
|
|
1455
|
+
const local = url.hostname === "localhost" || url.hostname.endsWith(".localhost");
|
|
1456
|
+
if (url.protocol !== "https:" && !(local && url.protocol === "http:") || url.username || url.password || url.pathname !== "/api/v1/auth/ceremony/start" || url.search || !/^#code=[A-Za-z0-9_-]{43}$/.test(url.hash)) throw authorityUnavailable();
|
|
1457
|
+
return {
|
|
1458
|
+
url: url.toString(),
|
|
1459
|
+
expiresAt: date(value.expiresAt)
|
|
1460
|
+
};
|
|
1461
|
+
}
|
|
1462
|
+
function normalizePasskeyId(value) {
|
|
1463
|
+
if (typeof value !== "string" || !idPattern.test(value)) throw new TypeError("passkeyId is invalid");
|
|
1464
|
+
return value;
|
|
1465
|
+
}
|
|
1466
|
+
function normalizePasskeyName(value) {
|
|
1467
|
+
if (typeof value !== "string") throw new TypeError("name is invalid");
|
|
1468
|
+
const name = value.trim();
|
|
1469
|
+
if (!name || name.length > PASSKEY_NAME_MAX_LENGTH || /[\p{Cc}\p{Cf}]/u.test(name)) throw new TypeError("name is invalid");
|
|
1470
|
+
return name;
|
|
1471
|
+
}
|
|
1472
|
+
function normalizePasskeySummary(value) {
|
|
1473
|
+
if (!exact(value, itemKeys) || typeof value.id !== "string" || !idPattern.test(value.id)) throw authorityUnavailable();
|
|
1474
|
+
if (value.name !== null && (typeof value.name !== "string" || value.name.length > PASSKEY_NAME_MAX_LENGTH)) throw authorityUnavailable();
|
|
1475
|
+
if (value.deviceType !== "singleDevice" && value.deviceType !== "multiDevice") throw authorityUnavailable();
|
|
1476
|
+
if (typeof value.backedUp !== "boolean") throw authorityUnavailable();
|
|
1477
|
+
return {
|
|
1478
|
+
id: value.id,
|
|
1479
|
+
name: value.name,
|
|
1480
|
+
createdAt: value.createdAt === null ? null : date(value.createdAt),
|
|
1481
|
+
deviceType: value.deviceType,
|
|
1482
|
+
backedUp: value.backedUp
|
|
1483
|
+
};
|
|
1484
|
+
}
|
|
1485
|
+
function normalizePasskeyInventory(value) {
|
|
1486
|
+
if (!exact(value, ["passkeys", "truncated"]) || !Array.isArray(value.passkeys) || value.passkeys.length > MAX_PASSKEYS || typeof value.truncated !== "boolean") throw authorityUnavailable();
|
|
1487
|
+
const passkeys = value.passkeys.map(normalizePasskeySummary);
|
|
1488
|
+
if (new Set(passkeys.map((passkey) => passkey.id)).size !== passkeys.length) throw authorityUnavailable();
|
|
1489
|
+
return {
|
|
1490
|
+
passkeys,
|
|
1491
|
+
truncated: value.truncated
|
|
1492
|
+
};
|
|
1493
|
+
}
|
|
1494
|
+
function normalizePasskeyRename(value) {
|
|
1495
|
+
if (!exact(value, ["status"]) || value.status !== "renamed") throw authorityUnavailable();
|
|
1496
|
+
}
|
|
1497
|
+
function fromCeremonyHandoffError(value, status, retryAfter) {
|
|
1498
|
+
const code = isObject(value) ? value.code : void 0;
|
|
1499
|
+
if (status === 400 && code === "RETURN_ADDRESS_REFUSED") return new AuthError("ceremony_return_refused", 400);
|
|
1500
|
+
if (status === 400) return new AuthError("invalid_request", 400);
|
|
1501
|
+
if (status === 401) return new AuthError("authentication_required", 401);
|
|
1502
|
+
if (status === 403) return new AuthError("request_origin_denied", 403);
|
|
1503
|
+
if (status === 404) return new AuthError("state_conflict", 409);
|
|
1504
|
+
if (status === 409 && code === "PASSWORD_REQUIRED") return new AuthError("password_sign_in_required", 409);
|
|
1505
|
+
if (status === 409) return new AuthError("state_conflict", 409);
|
|
1506
|
+
if (status === 429) return new AuthError("auth_request_rate_limited", 429, parseRetryAfter(retryAfter));
|
|
1507
|
+
return authorityUnavailable();
|
|
1508
|
+
}
|
|
1509
|
+
//#endregion
|
|
1211
1510
|
//#region src/device.ts
|
|
1212
1511
|
const DEVICE_SCOPE = "openid";
|
|
1213
1512
|
const GRANT_TYPE = "urn:ietf:params:oauth:grant-type:device_code";
|
|
@@ -1416,6 +1715,34 @@ function createDeviceAuth(options) {
|
|
|
1416
1715
|
mapError: fromAccountAuthorityError
|
|
1417
1716
|
});
|
|
1418
1717
|
}
|
|
1718
|
+
async function sessionInventoryRequest(method, path, normalize) {
|
|
1719
|
+
const current = await readToken();
|
|
1720
|
+
if (!current) throw new AuthError("authentication_required", 401);
|
|
1721
|
+
return normalize((await requestJsonResponse(joinURL(authOrigin, "api/v1/auth/sessions", path), {
|
|
1722
|
+
fetch: requestFetch,
|
|
1723
|
+
timeoutMs,
|
|
1724
|
+
method,
|
|
1725
|
+
credentials: "omit",
|
|
1726
|
+
headers: { authorization: `Bearer ${current.accessToken}` },
|
|
1727
|
+
mapError: fromSessionInventoryError
|
|
1728
|
+
})).value);
|
|
1729
|
+
}
|
|
1730
|
+
async function ceremonyRequest(method, path, body, normalize) {
|
|
1731
|
+
const current = await readToken();
|
|
1732
|
+
if (!current) throw new AuthError("authentication_required", 401);
|
|
1733
|
+
return normalize((await requestJsonResponse(joinURL(authOrigin, "api/v1/auth", path), {
|
|
1734
|
+
fetch: requestFetch,
|
|
1735
|
+
timeoutMs,
|
|
1736
|
+
method,
|
|
1737
|
+
credentials: "omit",
|
|
1738
|
+
headers: {
|
|
1739
|
+
authorization: `Bearer ${current.accessToken}`,
|
|
1740
|
+
...body ? { "content-type": "application/json" } : {}
|
|
1741
|
+
},
|
|
1742
|
+
...body ? { body } : {},
|
|
1743
|
+
mapError: fromCeremonyHandoffError
|
|
1744
|
+
})).value);
|
|
1745
|
+
}
|
|
1419
1746
|
async function revoke(path) {
|
|
1420
1747
|
const current = await readToken();
|
|
1421
1748
|
if (!current) return;
|
|
@@ -1818,9 +2145,60 @@ function createDeviceAuth(options) {
|
|
|
1818
2145
|
}
|
|
1819
2146
|
return serializeAuthority(async () => {
|
|
1820
2147
|
const previous = await readToken();
|
|
1821
|
-
|
|
2148
|
+
const response = await accountRequest("sign-in/email", body);
|
|
2149
|
+
if (isTwoFactorChallenge(response.value)) throw new AuthError("two_factor_required", 401);
|
|
2150
|
+
return replaceIssuedResponse(response.value, previous);
|
|
1822
2151
|
}, true);
|
|
1823
2152
|
},
|
|
2153
|
+
listSessions() {
|
|
2154
|
+
return serializeAuthority(() => sessionInventoryRequest("GET", "", normalizeSessionInventory));
|
|
2155
|
+
},
|
|
2156
|
+
revokeSession(sessionId) {
|
|
2157
|
+
let id;
|
|
2158
|
+
try {
|
|
2159
|
+
id = normalizeSessionId(sessionId);
|
|
2160
|
+
} catch (error) {
|
|
2161
|
+
return Promise.reject(error);
|
|
2162
|
+
}
|
|
2163
|
+
return serializeAuthority(async () => {
|
|
2164
|
+
await sessionInventoryRequest("POST", `${id}/revoke`, normalizeSessionRevocation);
|
|
2165
|
+
});
|
|
2166
|
+
},
|
|
2167
|
+
revokeOtherSessions() {
|
|
2168
|
+
return serializeAuthority(() => sessionInventoryRequest("POST", "revoke-others", normalizeOtherSessionRevocation));
|
|
2169
|
+
},
|
|
2170
|
+
createCeremonyHandoff(input) {
|
|
2171
|
+
let body;
|
|
2172
|
+
try {
|
|
2173
|
+
body = normalizeCeremonyHandoffInput(input);
|
|
2174
|
+
} catch (error) {
|
|
2175
|
+
return Promise.reject(error);
|
|
2176
|
+
}
|
|
2177
|
+
return serializeAuthority(() => ceremonyRequest("POST", "ceremony-handoffs", body, normalizeCeremonyHandoff));
|
|
2178
|
+
},
|
|
2179
|
+
listPasskeys() {
|
|
2180
|
+
return serializeAuthority(() => ceremonyRequest("GET", "passkeys", void 0, normalizePasskeyInventory));
|
|
2181
|
+
},
|
|
2182
|
+
renamePasskey(passkeyId, name) {
|
|
2183
|
+
let path;
|
|
2184
|
+
let body;
|
|
2185
|
+
try {
|
|
2186
|
+
path = `passkeys/${normalizePasskeyId(passkeyId)}/name`;
|
|
2187
|
+
body = { name: normalizePasskeyName(name) };
|
|
2188
|
+
} catch (error) {
|
|
2189
|
+
return Promise.reject(error);
|
|
2190
|
+
}
|
|
2191
|
+
return serializeAuthority(async () => {
|
|
2192
|
+
await ceremonyRequest("POST", path, body, normalizePasskeyRename);
|
|
2193
|
+
});
|
|
2194
|
+
},
|
|
2195
|
+
getTwoFactorStatus() {
|
|
2196
|
+
return serializeAuthority(async () => {
|
|
2197
|
+
const current = await readToken();
|
|
2198
|
+
if (!current) throw new AuthError("authentication_required", 401);
|
|
2199
|
+
return normalizeTwoFactorStatus((await authenticated("get-session", current)).value);
|
|
2200
|
+
});
|
|
2201
|
+
},
|
|
1824
2202
|
signInWithSocialIdToken(input) {
|
|
1825
2203
|
let body;
|
|
1826
2204
|
try {
|