@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/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
- var AuthError = class extends Error {
204
- code;
205
- status;
206
- retryAfterSeconds;
207
- constructor(code, status, retryAfterSeconds) {
208
- super(messages[code]);
209
- this.name = "AuthError";
210
- this.code = code;
211
- this.status = status;
212
- this.retryAfterSeconds = retryAfterSeconds;
213
- }
214
- };
215
- //#endregion
216
- //#region src/user-api/credential.ts
217
- function userApiApplication(input) {
218
- 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");
219
- return input.applicationId;
220
- }
221
- function normalizeUserApiCredential(value, startedAt) {
222
- 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);
223
- return {
224
- tokenType: "Bearer",
225
- token: value.token,
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
- function isObject(value) {
1140
- return typeof value === "object" && value !== null && !Array.isArray(value);
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
- return replaceIssuedResponse((await accountRequest("sign-in/email", body)).value, previous);
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 {