@finueva/auth 0.10.1 → 0.11.1
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 +83 -16
- package/THIRD_PARTY_NOTICES.md +26 -0
- package/dist/device.d.ts +1 -1
- package/dist/device.js +3 -0
- package/dist/index.d.ts +2 -2
- package/dist/index.js +1035 -8
- package/dist/server.d.ts +1 -1
- package/dist/server.js +3 -0
- package/dist/{types-Byw9JQwL.d.ts → types--G_Gwf2r.d.ts} +78 -3
- package/package.json +4 -2
package/dist/index.js
CHANGED
|
@@ -383,6 +383,109 @@ function parseJSON(value, options = { strict: true }) {
|
|
|
383
383
|
return betterJSONParse(value, options);
|
|
384
384
|
}
|
|
385
385
|
//#endregion
|
|
386
|
+
//#region ../../node_modules/.pnpm/better-auth@1.6.22_drizzle-kit@0.31.10_drizzle-orm@0.45.2_@libsql+client@0.17.4_kysely@_fc032d4b6d0d0a5be5267474da10b212/node_modules/better-auth/dist/client/query.mjs
|
|
387
|
+
const isServer$1 = () => typeof window === "undefined";
|
|
388
|
+
function isAuthQueryStateEqual(a, b) {
|
|
389
|
+
return isJsonEqual(a.data, b.data) && a.error === b.error && a.isPending === b.isPending && a.isRefetching === b.isRefetching && a.refetch === b.refetch;
|
|
390
|
+
}
|
|
391
|
+
const useAuthQuery = (initializedAtom, path, $fetch, options) => {
|
|
392
|
+
const value = atom({
|
|
393
|
+
data: null,
|
|
394
|
+
error: null,
|
|
395
|
+
isPending: true,
|
|
396
|
+
isRefetching: false,
|
|
397
|
+
refetch: (queryParams) => fn(queryParams)
|
|
398
|
+
});
|
|
399
|
+
withEquality(value, isAuthQueryStateEqual);
|
|
400
|
+
const fn = async (queryParams) => {
|
|
401
|
+
return new Promise((resolve) => {
|
|
402
|
+
const opts = typeof options === "function" ? options({
|
|
403
|
+
data: value.get().data,
|
|
404
|
+
error: value.get().error,
|
|
405
|
+
isPending: value.get().isPending
|
|
406
|
+
}) : options;
|
|
407
|
+
$fetch(path, {
|
|
408
|
+
...opts,
|
|
409
|
+
query: {
|
|
410
|
+
...opts?.query,
|
|
411
|
+
...queryParams?.query
|
|
412
|
+
},
|
|
413
|
+
async onSuccess(context) {
|
|
414
|
+
const current = value.get();
|
|
415
|
+
const stableData = current.data != null && context.data != null && isJsonEqual(current.data, context.data) ? current.data : context.data;
|
|
416
|
+
value.set({
|
|
417
|
+
data: stableData,
|
|
418
|
+
error: null,
|
|
419
|
+
isPending: false,
|
|
420
|
+
isRefetching: false,
|
|
421
|
+
refetch: value.value.refetch
|
|
422
|
+
});
|
|
423
|
+
await opts?.onSuccess?.(context);
|
|
424
|
+
},
|
|
425
|
+
async onError(context) {
|
|
426
|
+
const { request } = context;
|
|
427
|
+
const retryAttempts = typeof request.retry === "number" ? request.retry : request.retry?.attempts;
|
|
428
|
+
const retryAttempt = request.retryAttempt || 0;
|
|
429
|
+
if (retryAttempts && retryAttempt < retryAttempts) return;
|
|
430
|
+
const isUnauthorized = context.error.status === 401;
|
|
431
|
+
value.set({
|
|
432
|
+
error: context.error,
|
|
433
|
+
data: isUnauthorized ? null : value.get().data,
|
|
434
|
+
isPending: false,
|
|
435
|
+
isRefetching: false,
|
|
436
|
+
refetch: value.value.refetch
|
|
437
|
+
});
|
|
438
|
+
await opts?.onError?.(context);
|
|
439
|
+
},
|
|
440
|
+
async onRequest(context) {
|
|
441
|
+
const currentValue = value.get();
|
|
442
|
+
value.set({
|
|
443
|
+
isPending: currentValue.data === null,
|
|
444
|
+
data: currentValue.data,
|
|
445
|
+
error: null,
|
|
446
|
+
isRefetching: true,
|
|
447
|
+
refetch: value.value.refetch
|
|
448
|
+
});
|
|
449
|
+
await opts?.onRequest?.(context);
|
|
450
|
+
}
|
|
451
|
+
}).catch((error) => {
|
|
452
|
+
value.set({
|
|
453
|
+
error,
|
|
454
|
+
data: value.get().data,
|
|
455
|
+
isPending: false,
|
|
456
|
+
isRefetching: false,
|
|
457
|
+
refetch: value.value.refetch
|
|
458
|
+
});
|
|
459
|
+
}).finally(() => {
|
|
460
|
+
resolve(void 0);
|
|
461
|
+
});
|
|
462
|
+
});
|
|
463
|
+
};
|
|
464
|
+
initializedAtom = Array.isArray(initializedAtom) ? initializedAtom : [initializedAtom];
|
|
465
|
+
let isInitialized = false;
|
|
466
|
+
const cleanups = [];
|
|
467
|
+
for (const initAtom of initializedAtom) {
|
|
468
|
+
const unbind = initAtom.subscribe(async () => {
|
|
469
|
+
if (isServer$1()) return;
|
|
470
|
+
if (isInitialized) await fn();
|
|
471
|
+
else onMount(value, () => {
|
|
472
|
+
const timeoutId = setTimeout(async () => {
|
|
473
|
+
if (!isInitialized) {
|
|
474
|
+
isInitialized = true;
|
|
475
|
+
await fn();
|
|
476
|
+
}
|
|
477
|
+
}, 0);
|
|
478
|
+
return () => {
|
|
479
|
+
for (const u of cleanups) u();
|
|
480
|
+
clearTimeout(timeoutId);
|
|
481
|
+
};
|
|
482
|
+
});
|
|
483
|
+
});
|
|
484
|
+
cleanups.push(unbind);
|
|
485
|
+
}
|
|
486
|
+
return value;
|
|
487
|
+
};
|
|
488
|
+
//#endregion
|
|
386
489
|
//#region ../../node_modules/.pnpm/better-auth@1.6.22_drizzle-kit@0.31.10_drizzle-orm@0.45.2_@libsql+client@0.17.4_kysely@_fc032d4b6d0d0a5be5267474da10b212/node_modules/better-auth/dist/client/session-refresh.mjs
|
|
387
490
|
const now = () => Math.floor(Date.now() / 1e3);
|
|
388
491
|
const FOCUS_REFETCH_RATE_LIMIT_SECONDS = 5;
|
|
@@ -564,6 +667,15 @@ Object.freeze({
|
|
|
564
667
|
}
|
|
565
668
|
});
|
|
566
669
|
//#endregion
|
|
670
|
+
//#region ../../node_modules/.pnpm/@better-auth+core@1.6.22_@better-auth+utils@0.4.2_@better-fetch+fetch@1.3.1_better-call_17975d57218030f5a353914665f207d6/node_modules/@better-auth/core/dist/utils/error-codes.mjs
|
|
671
|
+
function defineErrorCodes(codes) {
|
|
672
|
+
return Object.fromEntries(Object.entries(codes).map(([key, value]) => [key, {
|
|
673
|
+
code: key,
|
|
674
|
+
message: value,
|
|
675
|
+
toString: () => key
|
|
676
|
+
}]));
|
|
677
|
+
}
|
|
678
|
+
//#endregion
|
|
567
679
|
//#region ../../node_modules/.pnpm/better-call@1.3.7_zod@4.4.3/node_modules/better-call/dist/error.mjs
|
|
568
680
|
function isErrorStackTraceLimitWritable() {
|
|
569
681
|
const desc = Object.getOwnPropertyDescriptor(Error, "stackTraceLimit");
|
|
@@ -1635,7 +1747,551 @@ function createAuthClient$1(options) {
|
|
|
1635
1747
|
}, $fetch, pluginPathMethods, pluginsAtoms, atomListeners);
|
|
1636
1748
|
}
|
|
1637
1749
|
//#endregion
|
|
1638
|
-
//#region ../../node_modules/.pnpm/@
|
|
1750
|
+
//#region ../../node_modules/.pnpm/@better-auth+passkey@1.6.22_@better-auth+core@1.6.22_@better-auth+utils@0.4.2_@better-f_9dcb641568b0468b4b3f2fd37291240f/node_modules/@better-auth/passkey/dist/version-uW-pDlTC.mjs
|
|
1751
|
+
const PASSKEY_ERROR_CODES = defineErrorCodes({
|
|
1752
|
+
CHALLENGE_NOT_FOUND: "Challenge not found",
|
|
1753
|
+
YOU_ARE_NOT_ALLOWED_TO_REGISTER_THIS_PASSKEY: "You are not allowed to register this passkey",
|
|
1754
|
+
FAILED_TO_VERIFY_REGISTRATION: "Failed to verify registration",
|
|
1755
|
+
PASSKEY_NOT_FOUND: "Passkey not found",
|
|
1756
|
+
AUTHENTICATION_FAILED: "Authentication failed",
|
|
1757
|
+
UNABLE_TO_CREATE_SESSION: "Unable to create session",
|
|
1758
|
+
FAILED_TO_UPDATE_PASSKEY: "Failed to update passkey",
|
|
1759
|
+
PREVIOUSLY_REGISTERED: "Previously registered",
|
|
1760
|
+
REGISTRATION_CANCELLED: "Registration cancelled",
|
|
1761
|
+
AUTH_CANCELLED: "Auth cancelled",
|
|
1762
|
+
UNKNOWN_ERROR: "Unknown error",
|
|
1763
|
+
SESSION_REQUIRED: "Passkey registration requires an authenticated session",
|
|
1764
|
+
RESOLVE_USER_REQUIRED: "Passkey registration requires either an authenticated session or a resolveUser callback when requireSession is false",
|
|
1765
|
+
RESOLVED_USER_INVALID: "Resolved user is invalid"
|
|
1766
|
+
});
|
|
1767
|
+
const PACKAGE_VERSION = "1.6.22";
|
|
1768
|
+
//#endregion
|
|
1769
|
+
//#region ../../node_modules/.pnpm/@simplewebauthn+browser@13.3.0/node_modules/@simplewebauthn/browser/esm/helpers/bufferToBase64URLString.js
|
|
1770
|
+
function bufferToBase64URLString(buffer) {
|
|
1771
|
+
const bytes = new Uint8Array(buffer);
|
|
1772
|
+
let str = "";
|
|
1773
|
+
for (const charCode of bytes) str += String.fromCharCode(charCode);
|
|
1774
|
+
return btoa(str).replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, "");
|
|
1775
|
+
}
|
|
1776
|
+
//#endregion
|
|
1777
|
+
//#region ../../node_modules/.pnpm/@simplewebauthn+browser@13.3.0/node_modules/@simplewebauthn/browser/esm/helpers/base64URLStringToBuffer.js
|
|
1778
|
+
function base64URLStringToBuffer(base64URLString) {
|
|
1779
|
+
const base64 = base64URLString.replace(/-/g, "+").replace(/_/g, "/");
|
|
1780
|
+
const padLength = (4 - base64.length % 4) % 4;
|
|
1781
|
+
const padded = base64.padEnd(base64.length + padLength, "=");
|
|
1782
|
+
const binary = atob(padded);
|
|
1783
|
+
const buffer = new ArrayBuffer(binary.length);
|
|
1784
|
+
const bytes = new Uint8Array(buffer);
|
|
1785
|
+
for (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i);
|
|
1786
|
+
return buffer;
|
|
1787
|
+
}
|
|
1788
|
+
//#endregion
|
|
1789
|
+
//#region ../../node_modules/.pnpm/@simplewebauthn+browser@13.3.0/node_modules/@simplewebauthn/browser/esm/helpers/browserSupportsWebAuthn.js
|
|
1790
|
+
function browserSupportsWebAuthn() {
|
|
1791
|
+
return _browserSupportsWebAuthnInternals.stubThis(globalThis?.PublicKeyCredential !== void 0 && typeof globalThis.PublicKeyCredential === "function");
|
|
1792
|
+
}
|
|
1793
|
+
const _browserSupportsWebAuthnInternals = { stubThis: (value) => value };
|
|
1794
|
+
//#endregion
|
|
1795
|
+
//#region ../../node_modules/.pnpm/@simplewebauthn+browser@13.3.0/node_modules/@simplewebauthn/browser/esm/helpers/toPublicKeyCredentialDescriptor.js
|
|
1796
|
+
function toPublicKeyCredentialDescriptor(descriptor) {
|
|
1797
|
+
const { id } = descriptor;
|
|
1798
|
+
return {
|
|
1799
|
+
...descriptor,
|
|
1800
|
+
id: base64URLStringToBuffer(id),
|
|
1801
|
+
transports: descriptor.transports
|
|
1802
|
+
};
|
|
1803
|
+
}
|
|
1804
|
+
//#endregion
|
|
1805
|
+
//#region ../../node_modules/.pnpm/@simplewebauthn+browser@13.3.0/node_modules/@simplewebauthn/browser/esm/helpers/isValidDomain.js
|
|
1806
|
+
function isValidDomain(hostname) {
|
|
1807
|
+
return hostname === "localhost" || /^((xn--[a-z0-9-]+|[a-z0-9]+(-[a-z0-9]+)*)\.)+([a-z]{2,}|xn--[a-z0-9-]+)$/i.test(hostname);
|
|
1808
|
+
}
|
|
1809
|
+
//#endregion
|
|
1810
|
+
//#region ../../node_modules/.pnpm/@simplewebauthn+browser@13.3.0/node_modules/@simplewebauthn/browser/esm/helpers/webAuthnError.js
|
|
1811
|
+
var WebAuthnError = class extends Error {
|
|
1812
|
+
constructor({ message, code, cause, name }) {
|
|
1813
|
+
super(message, { cause });
|
|
1814
|
+
Object.defineProperty(this, "code", {
|
|
1815
|
+
enumerable: true,
|
|
1816
|
+
configurable: true,
|
|
1817
|
+
writable: true,
|
|
1818
|
+
value: void 0
|
|
1819
|
+
});
|
|
1820
|
+
this.name = name ?? cause.name;
|
|
1821
|
+
this.code = code;
|
|
1822
|
+
}
|
|
1823
|
+
};
|
|
1824
|
+
//#endregion
|
|
1825
|
+
//#region ../../node_modules/.pnpm/@simplewebauthn+browser@13.3.0/node_modules/@simplewebauthn/browser/esm/helpers/identifyRegistrationError.js
|
|
1826
|
+
function identifyRegistrationError({ error, options }) {
|
|
1827
|
+
const { publicKey } = options;
|
|
1828
|
+
if (!publicKey) throw Error("options was missing required publicKey property");
|
|
1829
|
+
if (error.name === "AbortError") {
|
|
1830
|
+
if (options.signal instanceof AbortSignal) return new WebAuthnError({
|
|
1831
|
+
message: "Registration ceremony was sent an abort signal",
|
|
1832
|
+
code: "ERROR_CEREMONY_ABORTED",
|
|
1833
|
+
cause: error
|
|
1834
|
+
});
|
|
1835
|
+
} else if (error.name === "ConstraintError") {
|
|
1836
|
+
if (publicKey.authenticatorSelection?.requireResidentKey === true) return new WebAuthnError({
|
|
1837
|
+
message: "Discoverable credentials were required but no available authenticator supported it",
|
|
1838
|
+
code: "ERROR_AUTHENTICATOR_MISSING_DISCOVERABLE_CREDENTIAL_SUPPORT",
|
|
1839
|
+
cause: error
|
|
1840
|
+
});
|
|
1841
|
+
else if (options.mediation === "conditional" && publicKey.authenticatorSelection?.userVerification === "required") return new WebAuthnError({
|
|
1842
|
+
message: "User verification was required during automatic registration but it could not be performed",
|
|
1843
|
+
code: "ERROR_AUTO_REGISTER_USER_VERIFICATION_FAILURE",
|
|
1844
|
+
cause: error
|
|
1845
|
+
});
|
|
1846
|
+
else if (publicKey.authenticatorSelection?.userVerification === "required") return new WebAuthnError({
|
|
1847
|
+
message: "User verification was required but no available authenticator supported it",
|
|
1848
|
+
code: "ERROR_AUTHENTICATOR_MISSING_USER_VERIFICATION_SUPPORT",
|
|
1849
|
+
cause: error
|
|
1850
|
+
});
|
|
1851
|
+
} else if (error.name === "InvalidStateError") return new WebAuthnError({
|
|
1852
|
+
message: "The authenticator was previously registered",
|
|
1853
|
+
code: "ERROR_AUTHENTICATOR_PREVIOUSLY_REGISTERED",
|
|
1854
|
+
cause: error
|
|
1855
|
+
});
|
|
1856
|
+
else if (error.name === "NotAllowedError") return new WebAuthnError({
|
|
1857
|
+
message: error.message,
|
|
1858
|
+
code: "ERROR_PASSTHROUGH_SEE_CAUSE_PROPERTY",
|
|
1859
|
+
cause: error
|
|
1860
|
+
});
|
|
1861
|
+
else if (error.name === "NotSupportedError") {
|
|
1862
|
+
if (publicKey.pubKeyCredParams.filter((param) => param.type === "public-key").length === 0) return new WebAuthnError({
|
|
1863
|
+
message: "No entry in pubKeyCredParams was of type \"public-key\"",
|
|
1864
|
+
code: "ERROR_MALFORMED_PUBKEYCREDPARAMS",
|
|
1865
|
+
cause: error
|
|
1866
|
+
});
|
|
1867
|
+
return new WebAuthnError({
|
|
1868
|
+
message: "No available authenticator supported any of the specified pubKeyCredParams algorithms",
|
|
1869
|
+
code: "ERROR_AUTHENTICATOR_NO_SUPPORTED_PUBKEYCREDPARAMS_ALG",
|
|
1870
|
+
cause: error
|
|
1871
|
+
});
|
|
1872
|
+
} else if (error.name === "SecurityError") {
|
|
1873
|
+
const effectiveDomain = globalThis.location.hostname;
|
|
1874
|
+
if (!isValidDomain(effectiveDomain)) return new WebAuthnError({
|
|
1875
|
+
message: `${globalThis.location.hostname} is an invalid domain`,
|
|
1876
|
+
code: "ERROR_INVALID_DOMAIN",
|
|
1877
|
+
cause: error
|
|
1878
|
+
});
|
|
1879
|
+
else if (publicKey.rp.id !== effectiveDomain) return new WebAuthnError({
|
|
1880
|
+
message: `The RP ID "${publicKey.rp.id}" is invalid for this domain`,
|
|
1881
|
+
code: "ERROR_INVALID_RP_ID",
|
|
1882
|
+
cause: error
|
|
1883
|
+
});
|
|
1884
|
+
} else if (error.name === "TypeError") {
|
|
1885
|
+
if (publicKey.user.id.byteLength < 1 || publicKey.user.id.byteLength > 64) return new WebAuthnError({
|
|
1886
|
+
message: "User ID was not between 1 and 64 characters",
|
|
1887
|
+
code: "ERROR_INVALID_USER_ID_LENGTH",
|
|
1888
|
+
cause: error
|
|
1889
|
+
});
|
|
1890
|
+
} else if (error.name === "UnknownError") return new WebAuthnError({
|
|
1891
|
+
message: "The authenticator was unable to process the specified options, or could not create a new credential",
|
|
1892
|
+
code: "ERROR_AUTHENTICATOR_GENERAL_ERROR",
|
|
1893
|
+
cause: error
|
|
1894
|
+
});
|
|
1895
|
+
return error;
|
|
1896
|
+
}
|
|
1897
|
+
//#endregion
|
|
1898
|
+
//#region ../../node_modules/.pnpm/@simplewebauthn+browser@13.3.0/node_modules/@simplewebauthn/browser/esm/helpers/webAuthnAbortService.js
|
|
1899
|
+
var BaseWebAuthnAbortService = class {
|
|
1900
|
+
constructor() {
|
|
1901
|
+
Object.defineProperty(this, "controller", {
|
|
1902
|
+
enumerable: true,
|
|
1903
|
+
configurable: true,
|
|
1904
|
+
writable: true,
|
|
1905
|
+
value: void 0
|
|
1906
|
+
});
|
|
1907
|
+
}
|
|
1908
|
+
createNewAbortSignal() {
|
|
1909
|
+
if (this.controller) {
|
|
1910
|
+
const abortError = new Error("Cancelling existing WebAuthn API call for new one");
|
|
1911
|
+
abortError.name = "AbortError";
|
|
1912
|
+
this.controller.abort(abortError);
|
|
1913
|
+
}
|
|
1914
|
+
const newController = new AbortController();
|
|
1915
|
+
this.controller = newController;
|
|
1916
|
+
return newController.signal;
|
|
1917
|
+
}
|
|
1918
|
+
cancelCeremony() {
|
|
1919
|
+
if (this.controller) {
|
|
1920
|
+
const abortError = new Error("Manually cancelling existing WebAuthn API call");
|
|
1921
|
+
abortError.name = "AbortError";
|
|
1922
|
+
this.controller.abort(abortError);
|
|
1923
|
+
this.controller = void 0;
|
|
1924
|
+
}
|
|
1925
|
+
}
|
|
1926
|
+
};
|
|
1927
|
+
const WebAuthnAbortService = new BaseWebAuthnAbortService();
|
|
1928
|
+
//#endregion
|
|
1929
|
+
//#region ../../node_modules/.pnpm/@simplewebauthn+browser@13.3.0/node_modules/@simplewebauthn/browser/esm/helpers/toAuthenticatorAttachment.js
|
|
1930
|
+
const attachments = ["cross-platform", "platform"];
|
|
1931
|
+
function toAuthenticatorAttachment(attachment) {
|
|
1932
|
+
if (!attachment) return;
|
|
1933
|
+
if (attachments.indexOf(attachment) < 0) return;
|
|
1934
|
+
return attachment;
|
|
1935
|
+
}
|
|
1936
|
+
//#endregion
|
|
1937
|
+
//#region ../../node_modules/.pnpm/@simplewebauthn+browser@13.3.0/node_modules/@simplewebauthn/browser/esm/methods/startRegistration.js
|
|
1938
|
+
async function startRegistration(options) {
|
|
1939
|
+
if (!options.optionsJSON && options.challenge) {
|
|
1940
|
+
console.warn("startRegistration() was not called correctly. It will try to continue with the provided options, but this call should be refactored to use the expected call structure instead. See https://simplewebauthn.dev/docs/packages/browser#typeerror-cannot-read-properties-of-undefined-reading-challenge for more information.");
|
|
1941
|
+
options = { optionsJSON: options };
|
|
1942
|
+
}
|
|
1943
|
+
const { optionsJSON, useAutoRegister = false } = options;
|
|
1944
|
+
if (!browserSupportsWebAuthn()) throw new Error("WebAuthn is not supported in this browser");
|
|
1945
|
+
const publicKey = {
|
|
1946
|
+
...optionsJSON,
|
|
1947
|
+
challenge: base64URLStringToBuffer(optionsJSON.challenge),
|
|
1948
|
+
user: {
|
|
1949
|
+
...optionsJSON.user,
|
|
1950
|
+
id: base64URLStringToBuffer(optionsJSON.user.id)
|
|
1951
|
+
},
|
|
1952
|
+
excludeCredentials: optionsJSON.excludeCredentials?.map(toPublicKeyCredentialDescriptor)
|
|
1953
|
+
};
|
|
1954
|
+
const createOptions = {};
|
|
1955
|
+
if (useAutoRegister) createOptions.mediation = "conditional";
|
|
1956
|
+
createOptions.publicKey = publicKey;
|
|
1957
|
+
createOptions.signal = WebAuthnAbortService.createNewAbortSignal();
|
|
1958
|
+
let credential;
|
|
1959
|
+
try {
|
|
1960
|
+
credential = await navigator.credentials.create(createOptions);
|
|
1961
|
+
} catch (err) {
|
|
1962
|
+
throw identifyRegistrationError({
|
|
1963
|
+
error: err,
|
|
1964
|
+
options: createOptions
|
|
1965
|
+
});
|
|
1966
|
+
}
|
|
1967
|
+
if (!credential) throw new Error("Registration was not completed");
|
|
1968
|
+
const { id, rawId, response, type } = credential;
|
|
1969
|
+
let transports = void 0;
|
|
1970
|
+
if (typeof response.getTransports === "function") transports = response.getTransports();
|
|
1971
|
+
let responsePublicKeyAlgorithm = void 0;
|
|
1972
|
+
if (typeof response.getPublicKeyAlgorithm === "function") try {
|
|
1973
|
+
responsePublicKeyAlgorithm = response.getPublicKeyAlgorithm();
|
|
1974
|
+
} catch (error) {
|
|
1975
|
+
warnOnBrokenImplementation("getPublicKeyAlgorithm()", error);
|
|
1976
|
+
}
|
|
1977
|
+
let responsePublicKey = void 0;
|
|
1978
|
+
if (typeof response.getPublicKey === "function") try {
|
|
1979
|
+
const _publicKey = response.getPublicKey();
|
|
1980
|
+
if (_publicKey !== null) responsePublicKey = bufferToBase64URLString(_publicKey);
|
|
1981
|
+
} catch (error) {
|
|
1982
|
+
warnOnBrokenImplementation("getPublicKey()", error);
|
|
1983
|
+
}
|
|
1984
|
+
let responseAuthenticatorData;
|
|
1985
|
+
if (typeof response.getAuthenticatorData === "function") try {
|
|
1986
|
+
responseAuthenticatorData = bufferToBase64URLString(response.getAuthenticatorData());
|
|
1987
|
+
} catch (error) {
|
|
1988
|
+
warnOnBrokenImplementation("getAuthenticatorData()", error);
|
|
1989
|
+
}
|
|
1990
|
+
return {
|
|
1991
|
+
id,
|
|
1992
|
+
rawId: bufferToBase64URLString(rawId),
|
|
1993
|
+
response: {
|
|
1994
|
+
attestationObject: bufferToBase64URLString(response.attestationObject),
|
|
1995
|
+
clientDataJSON: bufferToBase64URLString(response.clientDataJSON),
|
|
1996
|
+
transports,
|
|
1997
|
+
publicKeyAlgorithm: responsePublicKeyAlgorithm,
|
|
1998
|
+
publicKey: responsePublicKey,
|
|
1999
|
+
authenticatorData: responseAuthenticatorData
|
|
2000
|
+
},
|
|
2001
|
+
type,
|
|
2002
|
+
clientExtensionResults: credential.getClientExtensionResults(),
|
|
2003
|
+
authenticatorAttachment: toAuthenticatorAttachment(credential.authenticatorAttachment)
|
|
2004
|
+
};
|
|
2005
|
+
}
|
|
2006
|
+
function warnOnBrokenImplementation(methodName, cause) {
|
|
2007
|
+
console.warn(`The browser extension that intercepted this WebAuthn API call incorrectly implemented ${methodName}. You should report this error to them.\n`, cause);
|
|
2008
|
+
}
|
|
2009
|
+
//#endregion
|
|
2010
|
+
//#region ../../node_modules/.pnpm/@simplewebauthn+browser@13.3.0/node_modules/@simplewebauthn/browser/esm/helpers/browserSupportsWebAuthnAutofill.js
|
|
2011
|
+
function browserSupportsWebAuthnAutofill() {
|
|
2012
|
+
if (!browserSupportsWebAuthn()) return _browserSupportsWebAuthnAutofillInternals.stubThis(new Promise((resolve) => resolve(false)));
|
|
2013
|
+
const globalPublicKeyCredential = globalThis.PublicKeyCredential;
|
|
2014
|
+
if (globalPublicKeyCredential?.isConditionalMediationAvailable === void 0) return _browserSupportsWebAuthnAutofillInternals.stubThis(new Promise((resolve) => resolve(false)));
|
|
2015
|
+
return _browserSupportsWebAuthnAutofillInternals.stubThis(globalPublicKeyCredential.isConditionalMediationAvailable());
|
|
2016
|
+
}
|
|
2017
|
+
const _browserSupportsWebAuthnAutofillInternals = { stubThis: (value) => value };
|
|
2018
|
+
//#endregion
|
|
2019
|
+
//#region ../../node_modules/.pnpm/@simplewebauthn+browser@13.3.0/node_modules/@simplewebauthn/browser/esm/helpers/identifyAuthenticationError.js
|
|
2020
|
+
function identifyAuthenticationError({ error, options }) {
|
|
2021
|
+
const { publicKey } = options;
|
|
2022
|
+
if (!publicKey) throw Error("options was missing required publicKey property");
|
|
2023
|
+
if (error.name === "AbortError") {
|
|
2024
|
+
if (options.signal instanceof AbortSignal) return new WebAuthnError({
|
|
2025
|
+
message: "Authentication ceremony was sent an abort signal",
|
|
2026
|
+
code: "ERROR_CEREMONY_ABORTED",
|
|
2027
|
+
cause: error
|
|
2028
|
+
});
|
|
2029
|
+
} else if (error.name === "NotAllowedError") return new WebAuthnError({
|
|
2030
|
+
message: error.message,
|
|
2031
|
+
code: "ERROR_PASSTHROUGH_SEE_CAUSE_PROPERTY",
|
|
2032
|
+
cause: error
|
|
2033
|
+
});
|
|
2034
|
+
else if (error.name === "SecurityError") {
|
|
2035
|
+
const effectiveDomain = globalThis.location.hostname;
|
|
2036
|
+
if (!isValidDomain(effectiveDomain)) return new WebAuthnError({
|
|
2037
|
+
message: `${globalThis.location.hostname} is an invalid domain`,
|
|
2038
|
+
code: "ERROR_INVALID_DOMAIN",
|
|
2039
|
+
cause: error
|
|
2040
|
+
});
|
|
2041
|
+
else if (publicKey.rpId !== effectiveDomain) return new WebAuthnError({
|
|
2042
|
+
message: `The RP ID "${publicKey.rpId}" is invalid for this domain`,
|
|
2043
|
+
code: "ERROR_INVALID_RP_ID",
|
|
2044
|
+
cause: error
|
|
2045
|
+
});
|
|
2046
|
+
} else if (error.name === "UnknownError") return new WebAuthnError({
|
|
2047
|
+
message: "The authenticator was unable to process the specified options, or could not create a new assertion signature",
|
|
2048
|
+
code: "ERROR_AUTHENTICATOR_GENERAL_ERROR",
|
|
2049
|
+
cause: error
|
|
2050
|
+
});
|
|
2051
|
+
return error;
|
|
2052
|
+
}
|
|
2053
|
+
//#endregion
|
|
2054
|
+
//#region ../../node_modules/.pnpm/@simplewebauthn+browser@13.3.0/node_modules/@simplewebauthn/browser/esm/methods/startAuthentication.js
|
|
2055
|
+
async function startAuthentication(options) {
|
|
2056
|
+
if (!options.optionsJSON && options.challenge) {
|
|
2057
|
+
console.warn("startAuthentication() was not called correctly. It will try to continue with the provided options, but this call should be refactored to use the expected call structure instead. See https://simplewebauthn.dev/docs/packages/browser#typeerror-cannot-read-properties-of-undefined-reading-challenge for more information.");
|
|
2058
|
+
options = { optionsJSON: options };
|
|
2059
|
+
}
|
|
2060
|
+
const { optionsJSON, useBrowserAutofill = false, verifyBrowserAutofillInput = true } = options;
|
|
2061
|
+
if (!browserSupportsWebAuthn()) throw new Error("WebAuthn is not supported in this browser");
|
|
2062
|
+
let allowCredentials;
|
|
2063
|
+
if (optionsJSON.allowCredentials?.length !== 0) allowCredentials = optionsJSON.allowCredentials?.map(toPublicKeyCredentialDescriptor);
|
|
2064
|
+
const publicKey = {
|
|
2065
|
+
...optionsJSON,
|
|
2066
|
+
challenge: base64URLStringToBuffer(optionsJSON.challenge),
|
|
2067
|
+
allowCredentials
|
|
2068
|
+
};
|
|
2069
|
+
const getOptions = {};
|
|
2070
|
+
if (useBrowserAutofill) {
|
|
2071
|
+
if (!await browserSupportsWebAuthnAutofill()) throw Error("Browser does not support WebAuthn autofill");
|
|
2072
|
+
if (document.querySelectorAll("input[autocomplete$='webauthn']").length < 1 && verifyBrowserAutofillInput) throw Error("No <input> with \"webauthn\" as the only or last value in its `autocomplete` attribute was detected");
|
|
2073
|
+
getOptions.mediation = "conditional";
|
|
2074
|
+
publicKey.allowCredentials = [];
|
|
2075
|
+
}
|
|
2076
|
+
getOptions.publicKey = publicKey;
|
|
2077
|
+
getOptions.signal = WebAuthnAbortService.createNewAbortSignal();
|
|
2078
|
+
let credential;
|
|
2079
|
+
try {
|
|
2080
|
+
credential = await navigator.credentials.get(getOptions);
|
|
2081
|
+
} catch (err) {
|
|
2082
|
+
throw identifyAuthenticationError({
|
|
2083
|
+
error: err,
|
|
2084
|
+
options: getOptions
|
|
2085
|
+
});
|
|
2086
|
+
}
|
|
2087
|
+
if (!credential) throw new Error("Authentication was not completed");
|
|
2088
|
+
const { id, rawId, response, type } = credential;
|
|
2089
|
+
let userHandle = void 0;
|
|
2090
|
+
if (response.userHandle) userHandle = bufferToBase64URLString(response.userHandle);
|
|
2091
|
+
return {
|
|
2092
|
+
id,
|
|
2093
|
+
rawId: bufferToBase64URLString(rawId),
|
|
2094
|
+
response: {
|
|
2095
|
+
authenticatorData: bufferToBase64URLString(response.authenticatorData),
|
|
2096
|
+
clientDataJSON: bufferToBase64URLString(response.clientDataJSON),
|
|
2097
|
+
signature: bufferToBase64URLString(response.signature),
|
|
2098
|
+
userHandle
|
|
2099
|
+
},
|
|
2100
|
+
type,
|
|
2101
|
+
clientExtensionResults: credential.getClientExtensionResults(),
|
|
2102
|
+
authenticatorAttachment: toAuthenticatorAttachment(credential.authenticatorAttachment)
|
|
2103
|
+
};
|
|
2104
|
+
}
|
|
2105
|
+
//#endregion
|
|
2106
|
+
//#region ../../node_modules/.pnpm/@better-auth+passkey@1.6.22_@better-auth+core@1.6.22_@better-auth+utils@0.4.2_@better-f_9dcb641568b0468b4b3f2fd37291240f/node_modules/@better-auth/passkey/dist/client.mjs
|
|
2107
|
+
const getPasskeyActions = ($fetch, { $listPasskeys, $store }) => {
|
|
2108
|
+
const signInPasskey = async (opts, options) => {
|
|
2109
|
+
const response = await $fetch("/passkey/generate-authenticate-options", {
|
|
2110
|
+
method: "GET",
|
|
2111
|
+
throw: false
|
|
2112
|
+
});
|
|
2113
|
+
if (!response.data) return response;
|
|
2114
|
+
const mergedExtensions = response.data.extensions || opts?.extensions ? {
|
|
2115
|
+
...response.data.extensions || {},
|
|
2116
|
+
...opts?.extensions || {}
|
|
2117
|
+
} : void 0;
|
|
2118
|
+
let res;
|
|
2119
|
+
try {
|
|
2120
|
+
res = await startAuthentication({
|
|
2121
|
+
optionsJSON: {
|
|
2122
|
+
...response.data,
|
|
2123
|
+
extensions: mergedExtensions
|
|
2124
|
+
},
|
|
2125
|
+
useBrowserAutofill: opts?.autoFill
|
|
2126
|
+
});
|
|
2127
|
+
} catch (err) {
|
|
2128
|
+
return {
|
|
2129
|
+
data: null,
|
|
2130
|
+
error: {
|
|
2131
|
+
code: err instanceof WebAuthnError ? err.code : "AUTH_CANCELLED",
|
|
2132
|
+
message: PASSKEY_ERROR_CODES.AUTH_CANCELLED.message,
|
|
2133
|
+
status: 400,
|
|
2134
|
+
statusText: "BAD_REQUEST"
|
|
2135
|
+
}
|
|
2136
|
+
};
|
|
2137
|
+
}
|
|
2138
|
+
try {
|
|
2139
|
+
const { clientExtensionResults, ...responseBody } = res;
|
|
2140
|
+
const verified = await $fetch("/passkey/verify-authentication", {
|
|
2141
|
+
body: { response: responseBody },
|
|
2142
|
+
...opts?.fetchOptions,
|
|
2143
|
+
...options,
|
|
2144
|
+
method: "POST",
|
|
2145
|
+
throw: false
|
|
2146
|
+
});
|
|
2147
|
+
$listPasskeys.set(Math.random());
|
|
2148
|
+
$store.notify("$sessionSignal");
|
|
2149
|
+
if (opts?.returnWebAuthnResponse) return {
|
|
2150
|
+
...verified,
|
|
2151
|
+
webauthn: {
|
|
2152
|
+
response: res,
|
|
2153
|
+
clientExtensionResults
|
|
2154
|
+
}
|
|
2155
|
+
};
|
|
2156
|
+
return verified;
|
|
2157
|
+
} catch (err) {
|
|
2158
|
+
console.error(`[Better Auth] Error verifying passkey`, err);
|
|
2159
|
+
return {
|
|
2160
|
+
data: null,
|
|
2161
|
+
error: {
|
|
2162
|
+
code: "AUTH_CANCELLED",
|
|
2163
|
+
message: PASSKEY_ERROR_CODES.AUTH_CANCELLED.message,
|
|
2164
|
+
status: 400,
|
|
2165
|
+
statusText: "BAD_REQUEST"
|
|
2166
|
+
}
|
|
2167
|
+
};
|
|
2168
|
+
}
|
|
2169
|
+
};
|
|
2170
|
+
const registerPasskey = async (opts, fetchOpts) => {
|
|
2171
|
+
const options = await $fetch("/passkey/generate-register-options", {
|
|
2172
|
+
method: "GET",
|
|
2173
|
+
query: {
|
|
2174
|
+
...opts?.authenticatorAttachment && { authenticatorAttachment: opts.authenticatorAttachment },
|
|
2175
|
+
...opts?.name && { name: opts.name },
|
|
2176
|
+
...opts?.context && { context: opts.context }
|
|
2177
|
+
},
|
|
2178
|
+
throw: false
|
|
2179
|
+
});
|
|
2180
|
+
if (!options.data) return options;
|
|
2181
|
+
try {
|
|
2182
|
+
const mergedExtensions = options.data.extensions || opts?.extensions ? {
|
|
2183
|
+
...options.data.extensions || {},
|
|
2184
|
+
...opts?.extensions || {}
|
|
2185
|
+
} : void 0;
|
|
2186
|
+
const res = await startRegistration({
|
|
2187
|
+
optionsJSON: {
|
|
2188
|
+
...options.data,
|
|
2189
|
+
extensions: mergedExtensions
|
|
2190
|
+
},
|
|
2191
|
+
useAutoRegister: opts?.useAutoRegister
|
|
2192
|
+
});
|
|
2193
|
+
const { clientExtensionResults, ...responseBody } = res;
|
|
2194
|
+
const verified = await $fetch("/passkey/verify-registration", {
|
|
2195
|
+
...opts?.fetchOptions,
|
|
2196
|
+
...fetchOpts,
|
|
2197
|
+
body: {
|
|
2198
|
+
response: responseBody,
|
|
2199
|
+
name: opts?.name
|
|
2200
|
+
},
|
|
2201
|
+
method: "POST",
|
|
2202
|
+
throw: false
|
|
2203
|
+
});
|
|
2204
|
+
if (!verified.data) return verified;
|
|
2205
|
+
$listPasskeys.set(Math.random());
|
|
2206
|
+
if (opts?.returnWebAuthnResponse) return {
|
|
2207
|
+
...verified,
|
|
2208
|
+
webauthn: {
|
|
2209
|
+
response: res,
|
|
2210
|
+
clientExtensionResults
|
|
2211
|
+
}
|
|
2212
|
+
};
|
|
2213
|
+
return verified;
|
|
2214
|
+
} catch (e) {
|
|
2215
|
+
if (e instanceof WebAuthnError) {
|
|
2216
|
+
if (e.code === "ERROR_AUTHENTICATOR_PREVIOUSLY_REGISTERED") return {
|
|
2217
|
+
data: null,
|
|
2218
|
+
error: {
|
|
2219
|
+
code: e.code,
|
|
2220
|
+
message: PASSKEY_ERROR_CODES.PREVIOUSLY_REGISTERED.message,
|
|
2221
|
+
status: 400,
|
|
2222
|
+
statusText: "BAD_REQUEST"
|
|
2223
|
+
}
|
|
2224
|
+
};
|
|
2225
|
+
if (e.code === "ERROR_CEREMONY_ABORTED") return {
|
|
2226
|
+
data: null,
|
|
2227
|
+
error: {
|
|
2228
|
+
code: e.code,
|
|
2229
|
+
message: PASSKEY_ERROR_CODES.REGISTRATION_CANCELLED.message,
|
|
2230
|
+
status: 400,
|
|
2231
|
+
statusText: "BAD_REQUEST"
|
|
2232
|
+
}
|
|
2233
|
+
};
|
|
2234
|
+
return {
|
|
2235
|
+
data: null,
|
|
2236
|
+
error: {
|
|
2237
|
+
code: e.code,
|
|
2238
|
+
message: e.message,
|
|
2239
|
+
status: 400,
|
|
2240
|
+
statusText: "BAD_REQUEST"
|
|
2241
|
+
}
|
|
2242
|
+
};
|
|
2243
|
+
}
|
|
2244
|
+
return {
|
|
2245
|
+
data: null,
|
|
2246
|
+
error: {
|
|
2247
|
+
code: "UNKNOWN_ERROR",
|
|
2248
|
+
message: e instanceof Error ? e.message : PASSKEY_ERROR_CODES.UNKNOWN_ERROR.message,
|
|
2249
|
+
status: 500,
|
|
2250
|
+
statusText: "INTERNAL_SERVER_ERROR"
|
|
2251
|
+
}
|
|
2252
|
+
};
|
|
2253
|
+
}
|
|
2254
|
+
};
|
|
2255
|
+
return {
|
|
2256
|
+
signIn: { passkey: signInPasskey },
|
|
2257
|
+
passkey: { addPasskey: registerPasskey },
|
|
2258
|
+
$Infer: {}
|
|
2259
|
+
};
|
|
2260
|
+
};
|
|
2261
|
+
const passkeyClient = () => {
|
|
2262
|
+
const $listPasskeys = atom();
|
|
2263
|
+
return {
|
|
2264
|
+
id: "passkey",
|
|
2265
|
+
version: PACKAGE_VERSION,
|
|
2266
|
+
$InferServerPlugin: {},
|
|
2267
|
+
getActions: ($fetch, $store) => getPasskeyActions($fetch, {
|
|
2268
|
+
$listPasskeys,
|
|
2269
|
+
$store
|
|
2270
|
+
}),
|
|
2271
|
+
getAtoms($fetch) {
|
|
2272
|
+
return {
|
|
2273
|
+
listPasskeys: useAuthQuery($listPasskeys, "/passkey/list-user-passkeys", $fetch, { method: "GET" }),
|
|
2274
|
+
$listPasskeys
|
|
2275
|
+
};
|
|
2276
|
+
},
|
|
2277
|
+
pathMethods: {
|
|
2278
|
+
"/passkey/register": "POST",
|
|
2279
|
+
"/passkey/authenticate": "POST"
|
|
2280
|
+
},
|
|
2281
|
+
atomListeners: [{
|
|
2282
|
+
matcher(path) {
|
|
2283
|
+
return path === "/passkey/verify-registration" || path === "/passkey/delete-passkey" || path === "/passkey/update-passkey" || path === "/sign-out";
|
|
2284
|
+
},
|
|
2285
|
+
signal: "$listPasskeys"
|
|
2286
|
+
}, {
|
|
2287
|
+
matcher: (path) => path === "/passkey/verify-authentication",
|
|
2288
|
+
signal: "$sessionSignal"
|
|
2289
|
+
}],
|
|
2290
|
+
$ERROR_CODES: PASSKEY_ERROR_CODES
|
|
2291
|
+
};
|
|
2292
|
+
};
|
|
2293
|
+
//#endregion
|
|
2294
|
+
//#region ../../node_modules/.pnpm/@chiballc+utils@2.5.1_@hono+zod-openapi@1.5.1_hono@4.13.0_zod@4.4.3__hono@4.13.0_magic-_dfcdb59639d9fe73412dad0223379a88/node_modules/@chiballc/utils/dist/index.mjs
|
|
1639
2295
|
function isPromise(arg) {
|
|
1640
2296
|
return arg && typeof arg.then === "function";
|
|
1641
2297
|
}
|
|
@@ -1895,6 +2551,9 @@ const messages = {
|
|
|
1895
2551
|
auth_request_rate_limited: "Authentication requests are temporarily limited.",
|
|
1896
2552
|
state_conflict: "The authentication state conflicts with the request.",
|
|
1897
2553
|
access_denied: "Access is denied.",
|
|
2554
|
+
platform_target_unavailable: "The platform administration target is unavailable.",
|
|
2555
|
+
platform_quorum_unavailable: "Platform administration quorum is unavailable.",
|
|
2556
|
+
platform_recovery_required: "Platform administration requires separate recovery.",
|
|
1898
2557
|
identity_authority_unavailable: "Authentication is temporarily unavailable."
|
|
1899
2558
|
};
|
|
1900
2559
|
var AuthError = class extends Error {
|
|
@@ -2639,6 +3298,187 @@ function fromOrganizationMutationAuthorityError(value, status, retryAfter) {
|
|
|
2639
3298
|
if (status === 403 && code === "REQUEST_ORIGIN_DENIED") return new AuthError("request_origin_denied", 403);
|
|
2640
3299
|
return fromOrganizationReadAuthorityError(value, status);
|
|
2641
3300
|
}
|
|
3301
|
+
function normalizePlatformRoleChangeRecentAuthenticationInput(value) {
|
|
3302
|
+
if (!isObject(value) || Object.keys(value).sort().join(",") !== "changeReference,expectedGlobalRevision,expectedTargetRevision,idempotencyKey,reasonCategory,requestedRoles,targetUserId") throw new TypeError("recent authentication input is invalid");
|
|
3303
|
+
if (!isId(value.targetUserId)) throw new TypeError("targetUserId is invalid");
|
|
3304
|
+
if (!Array.isArray(value.requestedRoles) || value.requestedRoles.length < 1 || value.requestedRoles.length > 2 || value.requestedRoles.some((role) => role !== "administrator" && role !== "investigator") || new Set(value.requestedRoles).size !== value.requestedRoles.length) throw new TypeError("requestedRoles is invalid");
|
|
3305
|
+
for (const field of ["expectedTargetRevision", "expectedGlobalRevision"]) if (!Number.isSafeInteger(value[field]) || value[field] < 0 || value[field] >= Number.MAX_SAFE_INTEGER) throw new TypeError(`${field} is invalid`);
|
|
3306
|
+
if (!(typeof value.reasonCategory === "string" && [
|
|
3307
|
+
"initial_bootstrap",
|
|
3308
|
+
"personnel_change",
|
|
3309
|
+
"privilege_review",
|
|
3310
|
+
"quorum_recovery",
|
|
3311
|
+
"security_response"
|
|
3312
|
+
].includes(value.reasonCategory))) throw new TypeError("reasonCategory is invalid");
|
|
3313
|
+
for (const field of ["changeReference", "idempotencyKey"]) if (typeof value[field] !== "string" || !/^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$/.test(value[field])) throw new TypeError(`${field} is invalid`);
|
|
3314
|
+
return {
|
|
3315
|
+
action: "platform_role_change",
|
|
3316
|
+
targetUserId: value.targetUserId,
|
|
3317
|
+
requestedRoles: [...value.requestedRoles].sort(),
|
|
3318
|
+
expectedTargetRevision: value.expectedTargetRevision,
|
|
3319
|
+
expectedGlobalRevision: value.expectedGlobalRevision,
|
|
3320
|
+
reasonCategory: value.reasonCategory,
|
|
3321
|
+
changeReference: value.changeReference,
|
|
3322
|
+
idempotencyKey: value.idempotencyKey
|
|
3323
|
+
};
|
|
3324
|
+
}
|
|
3325
|
+
function normalizeOrganizationManualRoleChangeInput(value) {
|
|
3326
|
+
if (!isObject(value) || Object.keys(value).sort().join(",") !== "expectedActorAuthorityRevision,expectedTargetAuthorityRevision,idempotencyKey,requestedManualRole") throw new TypeError("organization manual role input is invalid");
|
|
3327
|
+
if (value.requestedManualRole !== "owner" && value.requestedManualRole !== "admin" && value.requestedManualRole !== "member") throw new TypeError("requestedManualRole is invalid");
|
|
3328
|
+
const expectedActorAuthorityRevision = normalizeAuthorityRevision(value.expectedActorAuthorityRevision, "expectedActorAuthorityRevision");
|
|
3329
|
+
const expectedTargetAuthorityRevision = normalizeAuthorityRevision(value.expectedTargetAuthorityRevision, "expectedTargetAuthorityRevision", true);
|
|
3330
|
+
return {
|
|
3331
|
+
requestedManualRole: value.requestedManualRole,
|
|
3332
|
+
expectedActorAuthorityRevision,
|
|
3333
|
+
expectedTargetAuthorityRevision,
|
|
3334
|
+
idempotencyKey: normalizeAuthorityIdempotencyKey(value.idempotencyKey)
|
|
3335
|
+
};
|
|
3336
|
+
}
|
|
3337
|
+
function normalizeOrganizationOwnershipTransferInput(value) {
|
|
3338
|
+
if (!isObject(value) || Object.keys(value).sort().join(",") !== "expectedActorAuthorityRevision,expectedOutgoingOwnerAuthorityRevision,expectedSuccessorAuthorityRevision,idempotencyKey,outgoingOwnerMembershipId,outgoingOwnerRole,successorMembershipId") throw new TypeError("organization ownership transfer input is invalid");
|
|
3339
|
+
if (!isId(value.outgoingOwnerMembershipId) || !isId(value.successorMembershipId)) throw new TypeError("ownership transfer membership is invalid");
|
|
3340
|
+
if (value.outgoingOwnerMembershipId === value.successorMembershipId) throw new TypeError("ownership transfer memberships must differ");
|
|
3341
|
+
if (value.outgoingOwnerRole !== "admin" && value.outgoingOwnerRole !== "member") throw new TypeError("outgoingOwnerRole is invalid");
|
|
3342
|
+
return {
|
|
3343
|
+
outgoingOwnerMembershipId: value.outgoingOwnerMembershipId,
|
|
3344
|
+
successorMembershipId: value.successorMembershipId,
|
|
3345
|
+
outgoingOwnerRole: value.outgoingOwnerRole,
|
|
3346
|
+
expectedActorAuthorityRevision: normalizeAuthorityRevision(value.expectedActorAuthorityRevision, "expectedActorAuthorityRevision"),
|
|
3347
|
+
expectedOutgoingOwnerAuthorityRevision: normalizeAuthorityRevision(value.expectedOutgoingOwnerAuthorityRevision, "expectedOutgoingOwnerAuthorityRevision", true),
|
|
3348
|
+
expectedSuccessorAuthorityRevision: normalizeAuthorityRevision(value.expectedSuccessorAuthorityRevision, "expectedSuccessorAuthorityRevision", true),
|
|
3349
|
+
idempotencyKey: normalizeAuthorityIdempotencyKey(value.idempotencyKey)
|
|
3350
|
+
};
|
|
3351
|
+
}
|
|
3352
|
+
function normalizeOrganizationManualRoleChangeResult(value) {
|
|
3353
|
+
exact(value, [
|
|
3354
|
+
"status",
|
|
3355
|
+
"memberId",
|
|
3356
|
+
"manualRole",
|
|
3357
|
+
"role",
|
|
3358
|
+
"authorityRevision"
|
|
3359
|
+
]);
|
|
3360
|
+
if (value.status !== "applied") throw authorityUnavailable();
|
|
3361
|
+
return {
|
|
3362
|
+
status: "applied",
|
|
3363
|
+
...normalizeOrganizationAuthorityMemberOutcome(value, true)
|
|
3364
|
+
};
|
|
3365
|
+
}
|
|
3366
|
+
function normalizeOrganizationOwnershipTransferResult(value) {
|
|
3367
|
+
exact(value, [
|
|
3368
|
+
"status",
|
|
3369
|
+
"outgoingOwner",
|
|
3370
|
+
"successor"
|
|
3371
|
+
]);
|
|
3372
|
+
if (value.status !== "applied") throw authorityUnavailable();
|
|
3373
|
+
return {
|
|
3374
|
+
status: "applied",
|
|
3375
|
+
outgoingOwner: normalizeOrganizationAuthorityMemberOutcome(value.outgoingOwner),
|
|
3376
|
+
successor: normalizeOrganizationAuthorityMemberOutcome(value.successor)
|
|
3377
|
+
};
|
|
3378
|
+
}
|
|
3379
|
+
function normalizeOrganizationAuthorityMemberOutcome(value, includesStatus = false) {
|
|
3380
|
+
exact(value, [
|
|
3381
|
+
"memberId",
|
|
3382
|
+
"manualRole",
|
|
3383
|
+
"role",
|
|
3384
|
+
"authorityRevision",
|
|
3385
|
+
...includesStatus ? ["status"] : []
|
|
3386
|
+
]);
|
|
3387
|
+
if (!isId(value.memberId) || value.manualRole !== "owner" && value.manualRole !== "admin" && value.manualRole !== "member" || value.role !== "owner" && value.role !== "admin" && value.role !== "member") throw authorityUnavailable();
|
|
3388
|
+
return {
|
|
3389
|
+
memberId: value.memberId,
|
|
3390
|
+
manualRole: value.manualRole,
|
|
3391
|
+
role: value.role,
|
|
3392
|
+
authorityRevision: normalizeAuthorityResultRevision(value.authorityRevision)
|
|
3393
|
+
};
|
|
3394
|
+
}
|
|
3395
|
+
function normalizeAuthorityRevision(value, name, incremented = false) {
|
|
3396
|
+
if (!Number.isSafeInteger(value) || value < 0 || value >= Number.MAX_SAFE_INTEGER - (incremented ? 1 : 0)) throw new TypeError(`${name} is invalid`);
|
|
3397
|
+
return value;
|
|
3398
|
+
}
|
|
3399
|
+
function normalizeAuthorityResultRevision(value) {
|
|
3400
|
+
if (!Number.isSafeInteger(value) || value < 0 || value >= Number.MAX_SAFE_INTEGER) throw authorityUnavailable();
|
|
3401
|
+
return value;
|
|
3402
|
+
}
|
|
3403
|
+
function normalizeAuthorityIdempotencyKey(value) {
|
|
3404
|
+
if (typeof value !== "string" || !/^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$/.test(value)) throw new TypeError("idempotencyKey is invalid");
|
|
3405
|
+
return value;
|
|
3406
|
+
}
|
|
3407
|
+
function normalizePlatformBootstrapRoleChangeInput(value) {
|
|
3408
|
+
const request = normalizePlatformRoleChangeRecentAuthenticationInput(value);
|
|
3409
|
+
if (request.reasonCategory !== "initial_bootstrap" || !request.requestedRoles.includes("administrator")) throw new TypeError("platform first approval input is invalid");
|
|
3410
|
+
return request;
|
|
3411
|
+
}
|
|
3412
|
+
function normalizePlatformRoleApproval(value) {
|
|
3413
|
+
exact(value, [
|
|
3414
|
+
"status",
|
|
3415
|
+
"targetUserId",
|
|
3416
|
+
"targetRevision",
|
|
3417
|
+
"globalRevision",
|
|
3418
|
+
"roles"
|
|
3419
|
+
]);
|
|
3420
|
+
if (value.status !== "awaiting_second_approval" && value.status !== "applied" || !isId(value.targetUserId)) throw authorityUnavailable();
|
|
3421
|
+
if (!Number.isSafeInteger(value.targetRevision) || value.targetRevision < 0) throw authorityUnavailable();
|
|
3422
|
+
if (!Number.isSafeInteger(value.globalRevision) || value.globalRevision < 0) throw authorityUnavailable();
|
|
3423
|
+
if (!Array.isArray(value.roles) || value.status === "awaiting_second_approval" && value.roles.length !== 0 || value.status === "applied" && !(value.roles.length === 1 && value.roles[0] === "administrator" || value.roles.length === 2 && value.roles[0] === "administrator" && value.roles[1] === "investigator")) throw authorityUnavailable();
|
|
3424
|
+
if (value.status === "applied") return {
|
|
3425
|
+
status: "applied",
|
|
3426
|
+
targetUserId: value.targetUserId,
|
|
3427
|
+
targetRevision: value.targetRevision,
|
|
3428
|
+
globalRevision: value.globalRevision,
|
|
3429
|
+
roles: value.roles
|
|
3430
|
+
};
|
|
3431
|
+
return {
|
|
3432
|
+
status: "awaiting_second_approval",
|
|
3433
|
+
targetUserId: value.targetUserId,
|
|
3434
|
+
targetRevision: value.targetRevision,
|
|
3435
|
+
globalRevision: value.globalRevision,
|
|
3436
|
+
roles: []
|
|
3437
|
+
};
|
|
3438
|
+
}
|
|
3439
|
+
function normalizePlatformStatus(value) {
|
|
3440
|
+
exact(value, [
|
|
3441
|
+
"eligible",
|
|
3442
|
+
"globalRevision",
|
|
3443
|
+
"roles"
|
|
3444
|
+
]);
|
|
3445
|
+
if (typeof value.eligible !== "boolean") throw authorityUnavailable();
|
|
3446
|
+
if (!Number.isSafeInteger(value.globalRevision) || value.globalRevision < 0 || value.globalRevision >= Number.MAX_SAFE_INTEGER) throw authorityUnavailable();
|
|
3447
|
+
if (!Array.isArray(value.roles) || !(value.roles.length === 0 || value.roles.length === 1 && (value.roles[0] === "administrator" || value.roles[0] === "investigator") || value.roles.length === 2 && value.roles[0] === "administrator" && value.roles[1] === "investigator") || !value.eligible && value.roles.length !== 0) throw authorityUnavailable();
|
|
3448
|
+
return {
|
|
3449
|
+
eligible: value.eligible,
|
|
3450
|
+
globalRevision: value.globalRevision,
|
|
3451
|
+
roles: value.roles
|
|
3452
|
+
};
|
|
3453
|
+
}
|
|
3454
|
+
function normalizeRecentAuthenticationStatus(value) {
|
|
3455
|
+
exact(value, ["status"]);
|
|
3456
|
+
if (value.status !== "pending" && value.status !== "ready") throw authorityUnavailable();
|
|
3457
|
+
return { status: value.status };
|
|
3458
|
+
}
|
|
3459
|
+
function fromRecentAuthenticationError(value, status, retryAfter) {
|
|
3460
|
+
if (status === 400 || status === 413 || status === 415) return new AuthError("invalid_request", 400);
|
|
3461
|
+
if (status === 401) return new AuthError("authentication_required", 401);
|
|
3462
|
+
if (status === 403) return new AuthError("request_origin_denied", 403);
|
|
3463
|
+
if (status === 409) return new AuthError("state_conflict", 409);
|
|
3464
|
+
if (status === 429) return new AuthError("auth_request_rate_limited", 429, parseRetryAfter(retryAfter));
|
|
3465
|
+
return authorityUnavailable();
|
|
3466
|
+
}
|
|
3467
|
+
function fromPlatformAdministrationError(value, status, retryAfter) {
|
|
3468
|
+
const code = isObject(value) && typeof value.code === "string" ? value.code : void 0;
|
|
3469
|
+
if (status === 400 && code === "BAD_REQUEST") return new AuthError("invalid_request", 400);
|
|
3470
|
+
if (status === 401 && code === "UNAUTHORIZED") return new AuthError("authentication_required", 401);
|
|
3471
|
+
if (status === 403 && code === "FORBIDDEN") return new AuthError("access_denied", 403);
|
|
3472
|
+
if (status === 404 && code === "NOT_FOUND") return new AuthError("platform_target_unavailable", 404);
|
|
3473
|
+
if (status === 409 && code === "CONFLICT") return new AuthError("state_conflict", 409);
|
|
3474
|
+
if (status === 409 && code === "QUORUM_UNAVAILABLE") return new AuthError("platform_quorum_unavailable", 409);
|
|
3475
|
+
if (status === 413 && code === "REQUEST_TOO_LONG") return new AuthError("invalid_request", 413);
|
|
3476
|
+
if (status === 415 && code === "UNSUPPORTED_MEDIA_TYPE") return new AuthError("invalid_request", 415);
|
|
3477
|
+
if (status === 422 && code === "RECOVERY_REQUIRED") return new AuthError("platform_recovery_required", 422);
|
|
3478
|
+
if (status === 429 && code === "RATE_LIMITED") return new AuthError("auth_request_rate_limited", 429, parseRetryAfter(retryAfter));
|
|
3479
|
+
if (status === 503 && code === "SERVICE_UNAVAILABLE") return authorityUnavailable();
|
|
3480
|
+
return authorityUnavailable();
|
|
3481
|
+
}
|
|
2642
3482
|
function fromInvitationAuthorityError(value, status) {
|
|
2643
3483
|
const code = isObject(value) && typeof value.code === "string" ? value.code : void 0;
|
|
2644
3484
|
if (status === 401 && code === "UNAUTHORIZED") return new AuthError("authentication_required", 401);
|
|
@@ -3580,6 +4420,8 @@ function byteLength(value) {
|
|
|
3580
4420
|
//#endregion
|
|
3581
4421
|
//#region src/client.ts
|
|
3582
4422
|
const REFRESH_WINDOW_MS = 120 * 1e3;
|
|
4423
|
+
const RECENT_AUTHENTICATION_BROWSER_HEADER = "x-finueva-recent-auth-browser";
|
|
4424
|
+
const RECENT_AUTHENTICATION_REQUEST_HEADER = "x-finueva-recent-auth-request";
|
|
3583
4425
|
function createAuthClient(options) {
|
|
3584
4426
|
const authOrigin = normalizeOrigin(options.authOrigin, "authOrigin");
|
|
3585
4427
|
const appOrigin = normalizeOrigin(options.appOrigin, "appOrigin");
|
|
@@ -3596,7 +4438,8 @@ function createAuthClient(options) {
|
|
|
3596
4438
|
credentials: "include",
|
|
3597
4439
|
retry: 0,
|
|
3598
4440
|
timeout: timeoutMs
|
|
3599
|
-
}
|
|
4441
|
+
},
|
|
4442
|
+
plugins: [passkeyClient()]
|
|
3600
4443
|
});
|
|
3601
4444
|
const persistence = createSessionPersistence(options.persistence, authOrigin, now, timeoutMs);
|
|
3602
4445
|
const authStateListeners = new Set();
|
|
@@ -3608,6 +4451,12 @@ function createAuthClient(options) {
|
|
|
3608
4451
|
let selectedWorkspaceKey;
|
|
3609
4452
|
let credentialGeneration = 0;
|
|
3610
4453
|
let authorityGeneration = 0;
|
|
4454
|
+
let platformStatusReadEpoch = 0;
|
|
4455
|
+
let sessionAuthorityEpoch = 0;
|
|
4456
|
+
let sessionAuthorityObserved = false;
|
|
4457
|
+
let recentAuthenticationBrowserToken;
|
|
4458
|
+
let recentAuthenticationStartAttempt;
|
|
4459
|
+
let recentAuthenticationStartRequest;
|
|
3611
4460
|
let sessionReadEpoch = 0;
|
|
3612
4461
|
let activeAccountMutationGeneration;
|
|
3613
4462
|
let invitationAbort;
|
|
@@ -3621,6 +4470,10 @@ function createAuthClient(options) {
|
|
|
3621
4470
|
let signalRefreshPending = false;
|
|
3622
4471
|
let signalRefreshScheduled = false;
|
|
3623
4472
|
let signalRefreshRequest;
|
|
4473
|
+
function advanceAuthorityGeneration() {
|
|
4474
|
+
recentAuthenticationStartAttempt = void 0;
|
|
4475
|
+
return ++authorityGeneration;
|
|
4476
|
+
}
|
|
3624
4477
|
function setAuthState(state) {
|
|
3625
4478
|
authState = state;
|
|
3626
4479
|
for (const listener of authStateListeners) try {
|
|
@@ -3726,7 +4579,11 @@ function createAuthClient(options) {
|
|
|
3726
4579
|
}
|
|
3727
4580
|
function updateSession(session) {
|
|
3728
4581
|
const unboundCredential = !sessionId && (credential || credentialRequests.size > 0);
|
|
4582
|
+
const changedSession = sessionId === void 0 ? !sessionAuthorityObserved || session !== null : !session || session.id !== sessionId || session.user.id !== sessionUserId;
|
|
3729
4583
|
if (!session || unboundCredential || sessionId && (session.id !== sessionId || session.user.id !== sessionUserId)) clearCredential();
|
|
4584
|
+
if (changedSession || recentAuthenticationStartAttempt && (recentAuthenticationStartAttempt.sessionId !== session?.id || recentAuthenticationStartAttempt.userId !== session?.user.id)) recentAuthenticationStartAttempt = void 0;
|
|
4585
|
+
if (changedSession) sessionAuthorityEpoch += 1;
|
|
4586
|
+
sessionAuthorityObserved = true;
|
|
3730
4587
|
sessionId = session?.id;
|
|
3731
4588
|
sessionUserId = session?.user.id;
|
|
3732
4589
|
return session;
|
|
@@ -3755,10 +4612,10 @@ function createAuthClient(options) {
|
|
|
3755
4612
|
}
|
|
3756
4613
|
function signOut() {
|
|
3757
4614
|
if (signOutRequest) return signOutRequest;
|
|
3758
|
-
if (activeAccountMutationGeneration !== void 0) return Promise.reject(new AuthError("state_conflict", 409));
|
|
4615
|
+
if (activeAccountMutationGeneration !== void 0 || recentAuthenticationStartRequest) return Promise.reject(new AuthError("state_conflict", 409));
|
|
3759
4616
|
const pendingInvitation = invitationRequest;
|
|
3760
4617
|
invitationAbort?.abort();
|
|
3761
|
-
const generation =
|
|
4618
|
+
const generation = advanceAuthorityGeneration();
|
|
3762
4619
|
sessionReadEpoch += 1;
|
|
3763
4620
|
clearCredential();
|
|
3764
4621
|
sessionId = void 0;
|
|
@@ -3803,10 +4660,10 @@ function createAuthClient(options) {
|
|
|
3803
4660
|
return request;
|
|
3804
4661
|
}
|
|
3805
4662
|
async function runAccountMutation(operation) {
|
|
3806
|
-
if (signOutRequest || activeAccountMutationGeneration !== void 0) throw new AuthError("state_conflict", 409);
|
|
4663
|
+
if (signOutRequest || activeAccountMutationGeneration !== void 0 || recentAuthenticationStartRequest) throw new AuthError("state_conflict", 409);
|
|
3807
4664
|
const pendingInvitation = invitationRequest;
|
|
3808
4665
|
invitationAbort?.abort();
|
|
3809
|
-
const generation =
|
|
4666
|
+
const generation = advanceAuthorityGeneration();
|
|
3810
4667
|
sessionReadEpoch += 1;
|
|
3811
4668
|
activeAccountMutationGeneration = generation;
|
|
3812
4669
|
clearCredential();
|
|
@@ -3873,8 +4730,138 @@ function createAuthClient(options) {
|
|
|
3873
4730
|
throw error;
|
|
3874
4731
|
}
|
|
3875
4732
|
}
|
|
4733
|
+
function assertRecentAuthenticationOrigin() {
|
|
4734
|
+
if (appOrigin !== authOrigin) throw new TypeError("recent authentication requires the exact Auth Origin");
|
|
4735
|
+
}
|
|
4736
|
+
function assertPlatformAdministrationOrigin() {
|
|
4737
|
+
if (appOrigin !== authOrigin) throw new TypeError("platform administration requires the exact Auth Origin");
|
|
4738
|
+
}
|
|
4739
|
+
async function startRecentAuthentication(body) {
|
|
4740
|
+
assertRecentAuthenticationOrigin();
|
|
4741
|
+
if (signOutRequest || activeAccountMutationGeneration !== void 0 || invitationRequest) throw new AuthError("state_conflict", 409);
|
|
4742
|
+
if (recentAuthenticationStartRequest) throw new AuthError("state_conflict", 409);
|
|
4743
|
+
const generation = authorityGeneration;
|
|
4744
|
+
recentAuthenticationBrowserToken ??= createOpaqueToken();
|
|
4745
|
+
const normalizedInput = JSON.stringify(body);
|
|
4746
|
+
const attempt = recentAuthenticationStartAttempt?.input === normalizedInput ? recentAuthenticationStartAttempt : {
|
|
4747
|
+
input: normalizedInput,
|
|
4748
|
+
requestToken: createOpaqueToken(),
|
|
4749
|
+
sessionId,
|
|
4750
|
+
userId: sessionUserId
|
|
4751
|
+
};
|
|
4752
|
+
recentAuthenticationStartAttempt = attempt;
|
|
4753
|
+
const request = (async () => {
|
|
4754
|
+
try {
|
|
4755
|
+
const value = await requestJson(joinURL(authOrigin, "api/v1/auth/recent-authentication"), {
|
|
4756
|
+
fetch: fetchImpl,
|
|
4757
|
+
timeoutMs,
|
|
4758
|
+
method: "POST",
|
|
4759
|
+
headers: {
|
|
4760
|
+
"content-type": "application/json",
|
|
4761
|
+
[RECENT_AUTHENTICATION_BROWSER_HEADER]: recentAuthenticationBrowserToken,
|
|
4762
|
+
[RECENT_AUTHENTICATION_REQUEST_HEADER]: attempt.requestToken
|
|
4763
|
+
},
|
|
4764
|
+
body,
|
|
4765
|
+
mapError: fromRecentAuthenticationError
|
|
4766
|
+
});
|
|
4767
|
+
if (generation !== authorityGeneration) throw new AuthError("state_conflict", 409);
|
|
4768
|
+
const status = normalizeRecentAuthenticationStatus(value);
|
|
4769
|
+
if (recentAuthenticationStartAttempt === attempt) recentAuthenticationStartAttempt = void 0;
|
|
4770
|
+
return status;
|
|
4771
|
+
} catch (error) {
|
|
4772
|
+
if (recentAuthenticationStartAttempt === attempt && (!(error instanceof AuthError) || error.code !== "identity_authority_unavailable")) recentAuthenticationStartAttempt = void 0;
|
|
4773
|
+
throw error;
|
|
4774
|
+
}
|
|
4775
|
+
})();
|
|
4776
|
+
recentAuthenticationStartRequest = request;
|
|
4777
|
+
try {
|
|
4778
|
+
return await request;
|
|
4779
|
+
} finally {
|
|
4780
|
+
if (recentAuthenticationStartRequest === request) recentAuthenticationStartRequest = void 0;
|
|
4781
|
+
}
|
|
4782
|
+
}
|
|
3876
4783
|
return {
|
|
3877
4784
|
_type: "browser",
|
|
4785
|
+
async getPlatformStatus() {
|
|
4786
|
+
assertPlatformAdministrationOrigin();
|
|
4787
|
+
if (signOutRequest || activeAccountMutationGeneration !== void 0 || invitationRequest) throw new AuthError("state_conflict", 409);
|
|
4788
|
+
const generation = authorityGeneration;
|
|
4789
|
+
const readEpoch = ++platformStatusReadEpoch;
|
|
4790
|
+
const sessionEpoch = sessionAuthorityEpoch;
|
|
4791
|
+
const value = await requestJson(joinURL(authOrigin, "api/v1/auth/platform/status"), {
|
|
4792
|
+
fetch: fetchImpl,
|
|
4793
|
+
timeoutMs,
|
|
4794
|
+
method: "POST",
|
|
4795
|
+
headers: { "content-type": "application/json" },
|
|
4796
|
+
body: {},
|
|
4797
|
+
mapError: fromPlatformAdministrationError
|
|
4798
|
+
});
|
|
4799
|
+
if (generation !== authorityGeneration || readEpoch !== platformStatusReadEpoch || sessionEpoch !== sessionAuthorityEpoch) throw new AuthError("state_conflict", 409);
|
|
4800
|
+
return normalizePlatformStatus(value);
|
|
4801
|
+
},
|
|
4802
|
+
async startPlatformRoleChangeRecentAuthentication(input) {
|
|
4803
|
+
return startRecentAuthentication(normalizePlatformRoleChangeRecentAuthenticationInput(input));
|
|
4804
|
+
},
|
|
4805
|
+
async startOrganizationOwnerRoleChangeRecentAuthentication(organizationId, targetMembershipId, input) {
|
|
4806
|
+
return startRecentAuthentication({
|
|
4807
|
+
action: "organization_owner_role_change",
|
|
4808
|
+
organizationId: normalizeIdInput(organizationId),
|
|
4809
|
+
targetMembershipId: normalizeIdInput(targetMembershipId),
|
|
4810
|
+
...normalizeOrganizationManualRoleChangeInput(input)
|
|
4811
|
+
});
|
|
4812
|
+
},
|
|
4813
|
+
async startOrganizationOwnershipTransferRecentAuthentication(organizationId, input) {
|
|
4814
|
+
return startRecentAuthentication({
|
|
4815
|
+
action: "organization_ownership_transfer",
|
|
4816
|
+
organizationId: normalizeIdInput(organizationId),
|
|
4817
|
+
...normalizeOrganizationOwnershipTransferInput(input)
|
|
4818
|
+
});
|
|
4819
|
+
},
|
|
4820
|
+
async approveBootstrapPlatformRoleChange(input) {
|
|
4821
|
+
assertRecentAuthenticationOrigin();
|
|
4822
|
+
if (signOutRequest || activeAccountMutationGeneration !== void 0 || invitationRequest) throw new AuthError("state_conflict", 409);
|
|
4823
|
+
const body = normalizePlatformBootstrapRoleChangeInput(input);
|
|
4824
|
+
const generation = authorityGeneration;
|
|
4825
|
+
const value = await requestJson(joinURL(authOrigin, "api/v1/auth/platform/role-approvals"), {
|
|
4826
|
+
fetch: fetchImpl,
|
|
4827
|
+
timeoutMs,
|
|
4828
|
+
method: "POST",
|
|
4829
|
+
headers: { "content-type": "application/json" },
|
|
4830
|
+
body,
|
|
4831
|
+
mapError: fromPlatformAdministrationError
|
|
4832
|
+
});
|
|
4833
|
+
if (generation !== authorityGeneration) throw new AuthError("state_conflict", 409);
|
|
4834
|
+
return normalizePlatformRoleApproval(value);
|
|
4835
|
+
},
|
|
4836
|
+
async verifyRecentAuthenticationWithPasskey() {
|
|
4837
|
+
assertRecentAuthenticationOrigin();
|
|
4838
|
+
if (!(await runAccountMutation(async () => {
|
|
4839
|
+
const verification = await betterAuth.signIn.passkey({ autoFill: false });
|
|
4840
|
+
if (verification.error) throw fromRecentAuthenticationError(void 0, verification.error.status);
|
|
4841
|
+
})).session) throw new AuthError("authentication_required", 401);
|
|
4842
|
+
},
|
|
4843
|
+
async addPasskey() {
|
|
4844
|
+
assertRecentAuthenticationOrigin();
|
|
4845
|
+
if (!(await runAccountMutation(async () => {
|
|
4846
|
+
const registration = await betterAuth.passkey.addPasskey({ context: createOpaqueToken() });
|
|
4847
|
+
if (registration.error) throw fromAccountAuthorityError(registration.error, registration.error.status);
|
|
4848
|
+
})).session) throw new AuthError("authentication_required", 401);
|
|
4849
|
+
},
|
|
4850
|
+
async getRecentAuthenticationStatus() {
|
|
4851
|
+
assertRecentAuthenticationOrigin();
|
|
4852
|
+
if (signOutRequest || activeAccountMutationGeneration !== void 0 || invitationRequest) throw new AuthError("state_conflict", 409);
|
|
4853
|
+
const generation = authorityGeneration;
|
|
4854
|
+
const value = await requestJson(joinURL(authOrigin, "api/v1/auth/recent-authentication/status"), {
|
|
4855
|
+
fetch: fetchImpl,
|
|
4856
|
+
timeoutMs,
|
|
4857
|
+
method: "POST",
|
|
4858
|
+
headers: { "content-type": "application/json" },
|
|
4859
|
+
body: {},
|
|
4860
|
+
mapError: fromRecentAuthenticationError
|
|
4861
|
+
});
|
|
4862
|
+
if (generation !== authorityGeneration) throw new AuthError("state_conflict", 409);
|
|
4863
|
+
return normalizeRecentAuthenticationStatus(value);
|
|
4864
|
+
},
|
|
3878
4865
|
acceptInvitation(input) {
|
|
3879
4866
|
let invitation;
|
|
3880
4867
|
try {
|
|
@@ -3882,8 +4869,8 @@ function createAuthClient(options) {
|
|
|
3882
4869
|
} catch (error) {
|
|
3883
4870
|
return Promise.reject(error);
|
|
3884
4871
|
}
|
|
3885
|
-
if (signOutRequest || activeAccountMutationGeneration !== void 0 || invitationRequest) return Promise.reject(new AuthError("state_conflict", 409));
|
|
3886
|
-
const generation =
|
|
4872
|
+
if (signOutRequest || activeAccountMutationGeneration !== void 0 || invitationRequest || recentAuthenticationStartRequest) return Promise.reject(new AuthError("state_conflict", 409));
|
|
4873
|
+
const generation = advanceAuthorityGeneration();
|
|
3887
4874
|
const controller = new AbortController();
|
|
3888
4875
|
clearCredential();
|
|
3889
4876
|
const request = (async () => {
|
|
@@ -3989,6 +4976,39 @@ function createAuthClient(options) {
|
|
|
3989
4976
|
if (generation !== authorityGeneration) throw new AuthError("state_conflict", 409);
|
|
3990
4977
|
return normalizeOrganizationTeamDisplay(value);
|
|
3991
4978
|
},
|
|
4979
|
+
async changeOrganizationMemberManualRole(organizationId, targetMembershipId, input) {
|
|
4980
|
+
const organization = normalizeIdInput(organizationId);
|
|
4981
|
+
const target = normalizeIdInput(targetMembershipId);
|
|
4982
|
+
const body = normalizeOrganizationManualRoleChangeInput(input);
|
|
4983
|
+
if (signOutRequest || activeAccountMutationGeneration !== void 0 || invitationRequest) throw new AuthError("state_conflict", 409);
|
|
4984
|
+
const generation = authorityGeneration;
|
|
4985
|
+
const value = await requestJson(joinURL(authOrigin, "api/v1/auth/organizations", organization, "members", target, "manual-role"), {
|
|
4986
|
+
fetch: fetchImpl,
|
|
4987
|
+
timeoutMs,
|
|
4988
|
+
method: "POST",
|
|
4989
|
+
headers: { "content-type": "application/json" },
|
|
4990
|
+
body,
|
|
4991
|
+
mapError: fromOrganizationMutationAuthorityError
|
|
4992
|
+
});
|
|
4993
|
+
if (generation !== authorityGeneration) throw new AuthError("state_conflict", 409);
|
|
4994
|
+
return normalizeOrganizationManualRoleChangeResult(value);
|
|
4995
|
+
},
|
|
4996
|
+
async transferOrganizationOwnership(organizationId, input) {
|
|
4997
|
+
const organization = normalizeIdInput(organizationId);
|
|
4998
|
+
const body = normalizeOrganizationOwnershipTransferInput(input);
|
|
4999
|
+
if (signOutRequest || activeAccountMutationGeneration !== void 0 || invitationRequest) throw new AuthError("state_conflict", 409);
|
|
5000
|
+
const generation = authorityGeneration;
|
|
5001
|
+
const value = await requestJson(joinURL(authOrigin, "api/v1/auth/organizations", organization, "ownership-transfer"), {
|
|
5002
|
+
fetch: fetchImpl,
|
|
5003
|
+
timeoutMs,
|
|
5004
|
+
method: "POST",
|
|
5005
|
+
headers: { "content-type": "application/json" },
|
|
5006
|
+
body,
|
|
5007
|
+
mapError: fromOrganizationMutationAuthorityError
|
|
5008
|
+
});
|
|
5009
|
+
if (generation !== authorityGeneration) throw new AuthError("state_conflict", 409);
|
|
5010
|
+
return normalizeOrganizationOwnershipTransferResult(value);
|
|
5011
|
+
},
|
|
3992
5012
|
async listOrganizationMembers(organizationId, input) {
|
|
3993
5013
|
return organizationRead(`${normalizeIdInput(organizationId)}/members`, input, normalizeOrganizationMembers);
|
|
3994
5014
|
},
|
|
@@ -4138,5 +5158,12 @@ function createAuthClient(options) {
|
|
|
4138
5158
|
}
|
|
4139
5159
|
};
|
|
4140
5160
|
}
|
|
5161
|
+
function createOpaqueToken() {
|
|
5162
|
+
const bytes = new Uint8Array(32);
|
|
5163
|
+
globalThis.crypto.getRandomValues(bytes);
|
|
5164
|
+
let binary = "";
|
|
5165
|
+
for (const byte of bytes) binary += String.fromCharCode(byte);
|
|
5166
|
+
return globalThis.btoa(binary).replaceAll("+", "-").replaceAll("/", "_").replace(/=+$/, "");
|
|
5167
|
+
}
|
|
4141
5168
|
//#endregion
|
|
4142
5169
|
export { AuthError, createAuthClient };
|