@faable/auth-js 1.9.0 → 1.9.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/dist/main.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"main.js","sources":["../../node_modules/tslib/tslib.es6.js","../../../src/lib/version.ts","../../../src/BaseLog.ts","../../../src/Base.ts","../../../src/lib/globals.ts","../../../src/lib/fetch.ts","../../../src/FaableAuthApi.ts","../../../src/lib/auth_helpers.ts","../../../src/lib/storage_helpers.ts","../../../src/lib/pkce_storage.ts","../../../src/lib/helpers.ts","../../../src/lib/broadcast_sync.ts","../../../src/lib/constants.ts","../../../src/lib/errors.ts","../../../src/lib/helpers/window.ts","../../../src/lib/jwt.ts","../../../src/lib/nextjs.ts","../../../src/lib/session_helpers.ts","../../../src/lib/storage/cookie_helpers.ts","../../../src/lib/storage/cookie-storage.ts","../../../src/lib/storage/local-storage.ts","../../../src/lib/url_helpers.ts","../../../src/lock/locks.ts","../../../src/lock/Lock.ts","../../../src/FaableAuthClient.ts","../../../src/utils.ts","../../../src/lib/with_timeout.ts","../../../src/createClient.ts","../../../src/lib/types.ts"],"sourcesContent":["/******************************************************************************\r\nCopyright (c) Microsoft Corporation.\r\n\r\nPermission to use, copy, modify, and/or distribute this software for any\r\npurpose with or without fee is hereby granted.\r\n\r\nTHE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH\r\nREGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY\r\nAND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,\r\nINDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM\r\nLOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR\r\nOTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR\r\nPERFORMANCE OF THIS SOFTWARE.\r\n***************************************************************************** */\r\n/* global Reflect, Promise, SuppressedError, Symbol, Iterator */\r\n\r\nvar extendStatics = function(d, b) {\r\n extendStatics = Object.setPrototypeOf ||\r\n ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||\r\n function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };\r\n return extendStatics(d, b);\r\n};\r\n\r\nexport function __extends(d, b) {\r\n if (typeof b !== \"function\" && b !== null)\r\n throw new TypeError(\"Class extends value \" + String(b) + \" is not a constructor or null\");\r\n extendStatics(d, b);\r\n function __() { this.constructor = d; }\r\n d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());\r\n}\r\n\r\nexport var __assign = function() {\r\n __assign = Object.assign || function __assign(t) {\r\n for (var s, i = 1, n = arguments.length; i < n; i++) {\r\n s = arguments[i];\r\n for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p];\r\n }\r\n return t;\r\n }\r\n return __assign.apply(this, arguments);\r\n}\r\n\r\nexport function __rest(s, e) {\r\n var t = {};\r\n for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)\r\n t[p] = s[p];\r\n if (s != null && typeof Object.getOwnPropertySymbols === \"function\")\r\n for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {\r\n if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))\r\n t[p[i]] = s[p[i]];\r\n }\r\n return t;\r\n}\r\n\r\nexport function __decorate(decorators, target, key, desc) {\r\n var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;\r\n if (typeof Reflect === \"object\" && typeof Reflect.decorate === \"function\") r = Reflect.decorate(decorators, target, key, desc);\r\n else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;\r\n return c > 3 && r && Object.defineProperty(target, key, r), r;\r\n}\r\n\r\nexport function __param(paramIndex, decorator) {\r\n return function (target, key) { decorator(target, key, paramIndex); }\r\n}\r\n\r\nexport function __esDecorate(ctor, descriptorIn, decorators, contextIn, initializers, extraInitializers) {\r\n function accept(f) { if (f !== void 0 && typeof f !== \"function\") throw new TypeError(\"Function expected\"); return f; }\r\n var kind = contextIn.kind, key = kind === \"getter\" ? \"get\" : kind === \"setter\" ? \"set\" : \"value\";\r\n var target = !descriptorIn && ctor ? contextIn[\"static\"] ? ctor : ctor.prototype : null;\r\n var descriptor = descriptorIn || (target ? Object.getOwnPropertyDescriptor(target, contextIn.name) : {});\r\n var _, done = false;\r\n for (var i = decorators.length - 1; i >= 0; i--) {\r\n var context = {};\r\n for (var p in contextIn) context[p] = p === \"access\" ? {} : contextIn[p];\r\n for (var p in contextIn.access) context.access[p] = contextIn.access[p];\r\n context.addInitializer = function (f) { if (done) throw new TypeError(\"Cannot add initializers after decoration has completed\"); extraInitializers.push(accept(f || null)); };\r\n var result = (0, decorators[i])(kind === \"accessor\" ? { get: descriptor.get, set: descriptor.set } : descriptor[key], context);\r\n if (kind === \"accessor\") {\r\n if (result === void 0) continue;\r\n if (result === null || typeof result !== \"object\") throw new TypeError(\"Object expected\");\r\n if (_ = accept(result.get)) descriptor.get = _;\r\n if (_ = accept(result.set)) descriptor.set = _;\r\n if (_ = accept(result.init)) initializers.unshift(_);\r\n }\r\n else if (_ = accept(result)) {\r\n if (kind === \"field\") initializers.unshift(_);\r\n else descriptor[key] = _;\r\n }\r\n }\r\n if (target) Object.defineProperty(target, contextIn.name, descriptor);\r\n done = true;\r\n};\r\n\r\nexport function __runInitializers(thisArg, initializers, value) {\r\n var useValue = arguments.length > 2;\r\n for (var i = 0; i < initializers.length; i++) {\r\n value = useValue ? initializers[i].call(thisArg, value) : initializers[i].call(thisArg);\r\n }\r\n return useValue ? value : void 0;\r\n};\r\n\r\nexport function __propKey(x) {\r\n return typeof x === \"symbol\" ? x : \"\".concat(x);\r\n};\r\n\r\nexport function __setFunctionName(f, name, prefix) {\r\n if (typeof name === \"symbol\") name = name.description ? \"[\".concat(name.description, \"]\") : \"\";\r\n return Object.defineProperty(f, \"name\", { configurable: true, value: prefix ? \"\".concat(prefix, \" \", name) : name });\r\n};\r\n\r\nexport function __metadata(metadataKey, metadataValue) {\r\n if (typeof Reflect === \"object\" && typeof Reflect.metadata === \"function\") return Reflect.metadata(metadataKey, metadataValue);\r\n}\r\n\r\nexport function __awaiter(thisArg, _arguments, P, generator) {\r\n function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }\r\n return new (P || (P = Promise))(function (resolve, reject) {\r\n function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }\r\n function rejected(value) { try { step(generator[\"throw\"](value)); } catch (e) { reject(e); } }\r\n function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }\r\n step((generator = generator.apply(thisArg, _arguments || [])).next());\r\n });\r\n}\r\n\r\nexport function __generator(thisArg, body) {\r\n var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === \"function\" ? Iterator : Object).prototype);\r\n return g.next = verb(0), g[\"throw\"] = verb(1), g[\"return\"] = verb(2), typeof Symbol === \"function\" && (g[Symbol.iterator] = function() { return this; }), g;\r\n function verb(n) { return function (v) { return step([n, v]); }; }\r\n function step(op) {\r\n if (f) throw new TypeError(\"Generator is already executing.\");\r\n while (g && (g = 0, op[0] && (_ = 0)), _) try {\r\n if (f = 1, y && (t = op[0] & 2 ? y[\"return\"] : op[0] ? y[\"throw\"] || ((t = y[\"return\"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;\r\n if (y = 0, t) op = [op[0] & 2, t.value];\r\n switch (op[0]) {\r\n case 0: case 1: t = op; break;\r\n case 4: _.label++; return { value: op[1], done: false };\r\n case 5: _.label++; y = op[1]; op = [0]; continue;\r\n case 7: op = _.ops.pop(); _.trys.pop(); continue;\r\n default:\r\n if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }\r\n if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }\r\n if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }\r\n if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }\r\n if (t[2]) _.ops.pop();\r\n _.trys.pop(); continue;\r\n }\r\n op = body.call(thisArg, _);\r\n } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }\r\n if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };\r\n }\r\n}\r\n\r\nexport var __createBinding = Object.create ? (function(o, m, k, k2) {\r\n if (k2 === undefined) k2 = k;\r\n var desc = Object.getOwnPropertyDescriptor(m, k);\r\n if (!desc || (\"get\" in desc ? !m.__esModule : desc.writable || desc.configurable)) {\r\n desc = { enumerable: true, get: function() { return m[k]; } };\r\n }\r\n Object.defineProperty(o, k2, desc);\r\n}) : (function(o, m, k, k2) {\r\n if (k2 === undefined) k2 = k;\r\n o[k2] = m[k];\r\n});\r\n\r\nexport function __exportStar(m, o) {\r\n for (var p in m) if (p !== \"default\" && !Object.prototype.hasOwnProperty.call(o, p)) __createBinding(o, m, p);\r\n}\r\n\r\nexport function __values(o) {\r\n var s = typeof Symbol === \"function\" && Symbol.iterator, m = s && o[s], i = 0;\r\n if (m) return m.call(o);\r\n if (o && typeof o.length === \"number\") return {\r\n next: function () {\r\n if (o && i >= o.length) o = void 0;\r\n return { value: o && o[i++], done: !o };\r\n }\r\n };\r\n throw new TypeError(s ? \"Object is not iterable.\" : \"Symbol.iterator is not defined.\");\r\n}\r\n\r\nexport function __read(o, n) {\r\n var m = typeof Symbol === \"function\" && o[Symbol.iterator];\r\n if (!m) return o;\r\n var i = m.call(o), r, ar = [], e;\r\n try {\r\n while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);\r\n }\r\n catch (error) { e = { error: error }; }\r\n finally {\r\n try {\r\n if (r && !r.done && (m = i[\"return\"])) m.call(i);\r\n }\r\n finally { if (e) throw e.error; }\r\n }\r\n return ar;\r\n}\r\n\r\n/** @deprecated */\r\nexport function __spread() {\r\n for (var ar = [], i = 0; i < arguments.length; i++)\r\n ar = ar.concat(__read(arguments[i]));\r\n return ar;\r\n}\r\n\r\n/** @deprecated */\r\nexport function __spreadArrays() {\r\n for (var s = 0, i = 0, il = arguments.length; i < il; i++) s += arguments[i].length;\r\n for (var r = Array(s), k = 0, i = 0; i < il; i++)\r\n for (var a = arguments[i], j = 0, jl = a.length; j < jl; j++, k++)\r\n r[k] = a[j];\r\n return r;\r\n}\r\n\r\nexport function __spreadArray(to, from, pack) {\r\n if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {\r\n if (ar || !(i in from)) {\r\n if (!ar) ar = Array.prototype.slice.call(from, 0, i);\r\n ar[i] = from[i];\r\n }\r\n }\r\n return to.concat(ar || Array.prototype.slice.call(from));\r\n}\r\n\r\nexport function __await(v) {\r\n return this instanceof __await ? (this.v = v, this) : new __await(v);\r\n}\r\n\r\nexport function __asyncGenerator(thisArg, _arguments, generator) {\r\n if (!Symbol.asyncIterator) throw new TypeError(\"Symbol.asyncIterator is not defined.\");\r\n var g = generator.apply(thisArg, _arguments || []), i, q = [];\r\n return i = Object.create((typeof AsyncIterator === \"function\" ? AsyncIterator : Object).prototype), verb(\"next\"), verb(\"throw\"), verb(\"return\", awaitReturn), i[Symbol.asyncIterator] = function () { return this; }, i;\r\n function awaitReturn(f) { return function (v) { return Promise.resolve(v).then(f, reject); }; }\r\n function verb(n, f) { if (g[n]) { i[n] = function (v) { return new Promise(function (a, b) { q.push([n, v, a, b]) > 1 || resume(n, v); }); }; if (f) i[n] = f(i[n]); } }\r\n function resume(n, v) { try { step(g[n](v)); } catch (e) { settle(q[0][3], e); } }\r\n function step(r) { r.value instanceof __await ? Promise.resolve(r.value.v).then(fulfill, reject) : settle(q[0][2], r); }\r\n function fulfill(value) { resume(\"next\", value); }\r\n function reject(value) { resume(\"throw\", value); }\r\n function settle(f, v) { if (f(v), q.shift(), q.length) resume(q[0][0], q[0][1]); }\r\n}\r\n\r\nexport function __asyncDelegator(o) {\r\n var i, p;\r\n return i = {}, verb(\"next\"), verb(\"throw\", function (e) { throw e; }), verb(\"return\"), i[Symbol.iterator] = function () { return this; }, i;\r\n function verb(n, f) { i[n] = o[n] ? function (v) { return (p = !p) ? { value: __await(o[n](v)), done: false } : f ? f(v) : v; } : f; }\r\n}\r\n\r\nexport function __asyncValues(o) {\r\n if (!Symbol.asyncIterator) throw new TypeError(\"Symbol.asyncIterator is not defined.\");\r\n var m = o[Symbol.asyncIterator], i;\r\n return m ? m.call(o) : (o = typeof __values === \"function\" ? __values(o) : o[Symbol.iterator](), i = {}, verb(\"next\"), verb(\"throw\"), verb(\"return\"), i[Symbol.asyncIterator] = function () { return this; }, i);\r\n function verb(n) { i[n] = o[n] && function (v) { return new Promise(function (resolve, reject) { v = o[n](v), settle(resolve, reject, v.done, v.value); }); }; }\r\n function settle(resolve, reject, d, v) { Promise.resolve(v).then(function(v) { resolve({ value: v, done: d }); }, reject); }\r\n}\r\n\r\nexport function __makeTemplateObject(cooked, raw) {\r\n if (Object.defineProperty) { Object.defineProperty(cooked, \"raw\", { value: raw }); } else { cooked.raw = raw; }\r\n return cooked;\r\n};\r\n\r\nvar __setModuleDefault = Object.create ? (function(o, v) {\r\n Object.defineProperty(o, \"default\", { enumerable: true, value: v });\r\n}) : function(o, v) {\r\n o[\"default\"] = v;\r\n};\r\n\r\nvar ownKeys = function(o) {\r\n ownKeys = Object.getOwnPropertyNames || function (o) {\r\n var ar = [];\r\n for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;\r\n return ar;\r\n };\r\n return ownKeys(o);\r\n};\r\n\r\nexport function __importStar(mod) {\r\n if (mod && mod.__esModule) return mod;\r\n var result = {};\r\n if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== \"default\") __createBinding(result, mod, k[i]);\r\n __setModuleDefault(result, mod);\r\n return result;\r\n}\r\n\r\nexport function __importDefault(mod) {\r\n return (mod && mod.__esModule) ? mod : { default: mod };\r\n}\r\n\r\nexport function __classPrivateFieldGet(receiver, state, kind, f) {\r\n if (kind === \"a\" && !f) throw new TypeError(\"Private accessor was defined without a getter\");\r\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError(\"Cannot read private member from an object whose class did not declare it\");\r\n return kind === \"m\" ? f : kind === \"a\" ? f.call(receiver) : f ? f.value : state.get(receiver);\r\n}\r\n\r\nexport function __classPrivateFieldSet(receiver, state, value, kind, f) {\r\n if (kind === \"m\") throw new TypeError(\"Private method is not writable\");\r\n if (kind === \"a\" && !f) throw new TypeError(\"Private accessor was defined without a setter\");\r\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError(\"Cannot write private member to an object whose class did not declare it\");\r\n return (kind === \"a\" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;\r\n}\r\n\r\nexport function __classPrivateFieldIn(state, receiver) {\r\n if (receiver === null || (typeof receiver !== \"object\" && typeof receiver !== \"function\")) throw new TypeError(\"Cannot use 'in' operator on non-object\");\r\n return typeof state === \"function\" ? receiver === state : state.has(receiver);\r\n}\r\n\r\nexport function __addDisposableResource(env, value, async) {\r\n if (value !== null && value !== void 0) {\r\n if (typeof value !== \"object\" && typeof value !== \"function\") throw new TypeError(\"Object expected.\");\r\n var dispose, inner;\r\n if (async) {\r\n if (!Symbol.asyncDispose) throw new TypeError(\"Symbol.asyncDispose is not defined.\");\r\n dispose = value[Symbol.asyncDispose];\r\n }\r\n if (dispose === void 0) {\r\n if (!Symbol.dispose) throw new TypeError(\"Symbol.dispose is not defined.\");\r\n dispose = value[Symbol.dispose];\r\n if (async) inner = dispose;\r\n }\r\n if (typeof dispose !== \"function\") throw new TypeError(\"Object not disposable.\");\r\n if (inner) dispose = function() { try { inner.call(this); } catch (e) { return Promise.reject(e); } };\r\n env.stack.push({ value: value, dispose: dispose, async: async });\r\n }\r\n else if (async) {\r\n env.stack.push({ async: true });\r\n }\r\n return value;\r\n\r\n}\r\n\r\nvar _SuppressedError = typeof SuppressedError === \"function\" ? SuppressedError : function (error, suppressed, message) {\r\n var e = new Error(message);\r\n return e.name = \"SuppressedError\", e.error = error, e.suppressed = suppressed, e;\r\n};\r\n\r\nexport function __disposeResources(env) {\r\n function fail(e) {\r\n env.error = env.hasError ? new _SuppressedError(e, env.error, \"An error was suppressed during disposal.\") : e;\r\n env.hasError = true;\r\n }\r\n var r, s = 0;\r\n function next() {\r\n while (r = env.stack.pop()) {\r\n try {\r\n if (!r.async && s === 1) return s = 0, env.stack.push(r), Promise.resolve().then(next);\r\n if (r.dispose) {\r\n var result = r.dispose.call(r.value);\r\n if (r.async) return s |= 2, Promise.resolve(result).then(next, function(e) { fail(e); return next(); });\r\n }\r\n else s |= 1;\r\n }\r\n catch (e) {\r\n fail(e);\r\n }\r\n }\r\n if (s === 1) return env.hasError ? Promise.reject(env.error) : Promise.resolve();\r\n if (env.hasError) throw env.error;\r\n }\r\n return next();\r\n}\r\n\r\nexport function __rewriteRelativeImportExtension(path, preserveJsx) {\r\n if (typeof path === \"string\" && /^\\.\\.?\\//.test(path)) {\r\n return path.replace(/\\.(tsx)$|((?:\\.d)?)((?:\\.[^./]+?)?)\\.([cm]?)ts$/i, function (m, tsx, d, ext, cm) {\r\n return tsx ? preserveJsx ? \".jsx\" : \".js\" : d && (!ext || !cm) ? m : (d + ext + \".\" + cm.toLowerCase() + \"js\");\r\n });\r\n }\r\n return path;\r\n}\r\n\r\nexport default {\r\n __extends: __extends,\r\n __assign: __assign,\r\n __rest: __rest,\r\n __decorate: __decorate,\r\n __param: __param,\r\n __esDecorate: __esDecorate,\r\n __runInitializers: __runInitializers,\r\n __propKey: __propKey,\r\n __setFunctionName: __setFunctionName,\r\n __metadata: __metadata,\r\n __awaiter: __awaiter,\r\n __generator: __generator,\r\n __createBinding: __createBinding,\r\n __exportStar: __exportStar,\r\n __values: __values,\r\n __read: __read,\r\n __spread: __spread,\r\n __spreadArrays: __spreadArrays,\r\n __spreadArray: __spreadArray,\r\n __await: __await,\r\n __asyncGenerator: __asyncGenerator,\r\n __asyncDelegator: __asyncDelegator,\r\n __asyncValues: __asyncValues,\r\n __makeTemplateObject: __makeTemplateObject,\r\n __importStar: __importStar,\r\n __importDefault: __importDefault,\r\n __classPrivateFieldGet: __classPrivateFieldGet,\r\n __classPrivateFieldSet: __classPrivateFieldSet,\r\n __classPrivateFieldIn: __classPrivateFieldIn,\r\n __addDisposableResource: __addDisposableResource,\r\n __disposeResources: __disposeResources,\r\n __rewriteRelativeImportExtension: __rewriteRelativeImportExtension,\r\n};\r\n","// Will be overwriten by .github/workflows/release.yml\nexport const version = '0.0.0'\n","import { version } from './lib/version'\n\nexport type BaseLogOptions = {\n debug?: boolean | ((message: string, ...args: any[]) => void)\n}\n\nexport abstract class BaseLog {\n protected logDebugMessages: boolean\n protected logger: (message: string, ...args: any[]) => void = console.log\n\n constructor(config: BaseLogOptions = {}) {\n this.logDebugMessages = !!config.debug\n if (typeof config.debug === 'function') {\n this.logger = config.debug\n }\n }\n\n protected extraPrint?(): string\n\n protected _debug(...args: any[]) {\n if (this.logDebugMessages) {\n const extra = this.extraPrint ? this.extraPrint() : ''\n this.logger(\n `FaableAuth@${extra} (${version}) ${new Date().toISOString()}`,\n ...args\n )\n }\n\n return this\n }\n}\n","import { BaseLog, BaseLogOptions } from './BaseLog'\n\nexport abstract class Base extends BaseLog {\n private static nextInstanceID = 0\n private instanceID: number\n\n constructor(config: BaseLogOptions = {}) {\n super(config)\n this.instanceID = Base.nextInstanceID\n Base.nextInstanceID += 1\n }\n\n /** @hidden */\n extraPrint() {\n return this.instanceID.toString()\n }\n}\n","const win: (Window & typeof globalThis) | undefined =\n typeof window !== 'undefined' ? window : undefined\n\nconst global: typeof globalThis | undefined =\n typeof globalThis !== 'undefined' ? globalThis : win\nexport const document = global?.document as Document\n\nexport { win as window }\n\nexport const fetch = (global as any).fetch as typeof globalThis.fetch\n","import { fetch } from './globals'\nimport { version } from './version'\n\nexport type JsonResponse<T = any> = {\n data: T | null\n error?: any\n}\n\ntype RequestInitWithToken = RequestInit & {\n token: string\n raw: boolean\n}\n\nconst headers = (init: Partial<RequestInitWithToken> = {}) => {\n // Identify ourselves as a first-party client so the auth server can tell\n // auth-js (browser OAuth SDK) traffic apart from the dashboard, the\n // management SDK, or third-party integrations. Format: `<name>/<version>`\n // (version injected at release time).\n let headers: Record<string, string> = {\n 'x-faable-client': `auth-js/${version}`\n }\n if (init?.token) {\n headers = { ...headers, Authorization: `Bearer ${init?.token}` }\n }\n return {\n ...init?.headers,\n ...headers\n }\n}\n\nconst _handleRes = async (\n res: Response,\n options: Partial<RequestInitWithToken> = {}\n) => {\n const body = options.raw ? await res.text() : await res.json()\n if (res.status >= 300) {\n return {\n data: body,\n error: options.raw ? JSON.parse(body)?.message : body?.message\n }\n }\n return { data: body, error: null }\n}\n\nexport const _post = async <T>(\n url: string,\n data: object,\n options: Partial<RequestInitWithToken> = {}\n): Promise<JsonResponse<T>> => {\n try {\n const res = await fetch(url, {\n method: 'POST',\n body: JSON.stringify(data),\n headers: { ...headers(options), 'Content-Type': 'application/json' }\n })\n\n return await _handleRes(res, options)\n } catch (e) {\n return { data: null, error: e }\n }\n}\n\nexport const _get = async <T>(\n url: string,\n options: Partial<RequestInitWithToken> = {}\n): Promise<JsonResponse<T>> => {\n try {\n const res = await fetch(url, {\n ...options,\n method: 'GET',\n headers: headers(options)\n })\n\n return await _handleRes(res, options)\n } catch (e) {\n return { data: null, error: e }\n }\n}\n","import { BaseLog, BaseLogOptions } from './BaseLog'\nimport { AuthError } from './lib/errors'\nimport { _get } from './lib/fetch'\n\nexport default class FaableAuthApi extends BaseLog {\n constructor(\n public base_url: string,\n config: BaseLogOptions\n ) {\n super(config)\n }\n protected extraPrint(): string {\n return 'api'\n }\n\n async signOut(params: {\n client_id: string\n returnTo?: string\n }): Promise<{ data: null; error: AuthError | null }> {\n const url = `${this.base_url}/logout?${new URLSearchParams(params)}`\n this._debug(`requesting ${url}`)\n const res = await _get(url)\n this._debug(res)\n if (res.error) {\n return { error: res.error, data: null }\n } else {\n return { error: null, data: null }\n }\n }\n}\n","/**\n * Picks the OAuth `response_type` for an authorize request.\n *\n * Browsers default to the authorization code flow (PKCE); non-browser\n * environments default to the implicit token flow. A caller-provided\n * value always wins.\n */\nexport const resolveResponseType = (\n options: { response_type?: string },\n isBrowserEnv: boolean\n): string => options.response_type || (isBrowserEnv ? 'code' : 'token')\n\n/**\n * Renders an HTML form returned by the authorization server and submits it,\n * triggering the browser navigation that completes the username/password\n * login flow.\n */\nexport const buildAndSubmitForm = (formHtml: string, doc: Document): void => {\n const div = doc.createElement('div')\n div.innerHTML = formHtml\n const form = doc.body.appendChild(div).children[0] as\n | HTMLFormElement\n | undefined\n if (!form) {\n throw new Error('Auth response did not contain a submittable form')\n }\n form.submit()\n}\n","import { SupportedStorage } from './types'\n\n// Storage helpers\nexport const setItemAsync = async (\n storage: SupportedStorage,\n key: string,\n data: any\n): Promise<void> => {\n await storage.setItem(key, JSON.stringify(data))\n}\n\nexport const getItemAsync = async (\n storage: SupportedStorage,\n key: string\n): Promise<unknown> => {\n const value = await storage.getItem(key)\n\n if (!value) {\n return null\n }\n\n try {\n return JSON.parse(value)\n } catch {\n return value\n }\n}\n","import { getItemAsync, setItemAsync } from './storage_helpers'\nimport type { SupportedStorage } from './types'\n\nexport const CODE_VERIFIER_TTL_MS = 10 * 60 * 1000\n\ntype StoredCodeVerifier = {\n verifier: string\n createdAt: number\n redirectType?: string\n returnTo?: string\n}\n\ntype LoadedCodeVerifier = {\n verifier: string\n redirectType?: string\n returnTo?: string\n}\n\nconst isStoredCodeVerifier = (value: unknown): value is StoredCodeVerifier =>\n typeof value === 'object' &&\n value !== null &&\n typeof (value as StoredCodeVerifier).verifier === 'string' &&\n typeof (value as StoredCodeVerifier).createdAt === 'number'\n\nexport const saveCodeVerifier = async (\n storage: SupportedStorage,\n key: string,\n {\n verifier,\n redirectType,\n returnTo,\n now = Date.now()\n }: {\n verifier: string\n redirectType?: string\n returnTo?: string\n now?: number\n }\n): Promise<void> => {\n const payload: StoredCodeVerifier = { verifier, createdAt: now }\n if (redirectType) {\n payload.redirectType = redirectType\n }\n if (returnTo) {\n payload.returnTo = returnTo\n }\n await setItemAsync(storage, key, payload)\n}\n\nexport const loadCodeVerifier = async (\n storage: SupportedStorage,\n key: string,\n { now = Date.now() }: { now?: number } = {}\n): Promise<LoadedCodeVerifier | null> => {\n const raw = await getItemAsync(storage, key)\n if (!isStoredCodeVerifier(raw)) {\n return null\n }\n\n if (now - raw.createdAt > CODE_VERIFIER_TTL_MS) {\n await storage.removeItem(key)\n return null\n }\n\n const loaded: LoadedCodeVerifier = { verifier: raw.verifier }\n if (raw.redirectType) {\n loaded.redirectType = raw.redirectType\n }\n if (raw.returnTo) {\n loaded.returnTo = raw.returnTo\n }\n return loaded\n}\n","import { JsonResponse } from './fetch'\nimport { saveCodeVerifier } from './pkce_storage'\nimport { AuthResponse, SupportedStorage, User } from './types'\n\nfunction dec2hex(dec: number) {\n return ('0' + dec.toString(16)).substr(-2)\n}\n\nexport function decodeBase64URL(value: string): string {\n const key =\n 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/='\n let base64 = ''\n let chr1, chr2, chr3\n let enc1, enc2, enc3, enc4\n let i = 0\n value = value.replace('-', '+').replace('_', '/')\n\n while (i < value.length) {\n enc1 = key.indexOf(value.charAt(i++))\n enc2 = key.indexOf(value.charAt(i++))\n enc3 = key.indexOf(value.charAt(i++))\n enc4 = key.indexOf(value.charAt(i++))\n chr1 = (enc1 << 2) | (enc2 >> 4)\n chr2 = ((enc2 & 15) << 4) | (enc3 >> 2)\n chr3 = ((enc3 & 3) << 6) | enc4\n base64 = base64 + String.fromCharCode(chr1)\n\n if (enc3 != 64 && chr2 != 0) {\n base64 = base64 + String.fromCharCode(chr2)\n }\n if (enc4 != 64 && chr3 != 0) {\n base64 = base64 + String.fromCharCode(chr3)\n }\n }\n return base64\n}\n\nexport function generatePKCEVerifier() {\n if (\n typeof crypto === 'undefined' ||\n typeof crypto.getRandomValues !== 'function'\n ) {\n throw new Error(\n 'Web Crypto API is required to generate a PKCE code verifier'\n )\n }\n const verifierLength = 56\n const array = new Uint32Array(verifierLength)\n crypto.getRandomValues(array)\n return Array.from(array, dec2hex).join('')\n}\n\nasync function sha256(randomString: string) {\n const encoder = new TextEncoder()\n const encodedData = encoder.encode(randomString)\n const hash = await crypto.subtle.digest('SHA-256', encodedData)\n const bytes = new Uint8Array(hash)\n\n return Array.from(bytes)\n .map(c => String.fromCharCode(c))\n .join('')\n}\n\nfunction base64urlencode(str: string) {\n return btoa(str).replace(/\\+/g, '-').replace(/\\//g, '_').replace(/=+$/, '')\n}\n\nexport async function generatePKCEChallenge(verifier: string) {\n const hasCryptoSupport =\n typeof crypto !== 'undefined' &&\n typeof crypto.subtle !== 'undefined' &&\n typeof TextEncoder !== 'undefined'\n\n if (!hasCryptoSupport) {\n console.warn(\n 'WebCrypto API is not supported. Code challenge method will default to use plain instead of sha256.'\n )\n return verifier\n }\n const hashed = await sha256(verifier)\n return base64urlencode(hashed)\n}\n\nexport async function getCodeChallengeAndMethod(\n storage: SupportedStorage,\n storageKey: string,\n isPasswordRecovery = false,\n returnTo?: string\n) {\n const codeVerifier = generatePKCEVerifier()\n await saveCodeVerifier(storage, `${storageKey}-code-verifier`, {\n verifier: codeVerifier,\n redirectType: isPasswordRecovery ? 'PASSWORD_RECOVERY' : undefined,\n returnTo\n })\n const codeChallenge = await generatePKCEChallenge(codeVerifier)\n const codeChallengeMethod = codeVerifier === codeChallenge ? 'plain' : 'S256'\n return [codeChallenge, codeChallengeMethod]\n}\n\nexport const isBrowser = () => typeof document !== 'undefined'\n\nconst localStorageWriteTests = {\n tested: false,\n writable: false\n}\n\n/**\n * Checks whether localStorage is supported on this browser.\n */\nexport const supportsLocalStorage = () => {\n if (!isBrowser()) {\n return false\n }\n\n try {\n if (typeof globalThis.localStorage !== 'object') {\n return false\n }\n } catch (_e) {\n // DOM exception when accessing `localStorage`\n return false\n }\n\n if (localStorageWriteTests.tested) {\n return localStorageWriteTests.writable\n }\n\n const randomKey = `lswt-${Math.random()}${Math.random()}`\n\n try {\n globalThis.localStorage.setItem(randomKey, randomKey)\n globalThis.localStorage.removeItem(randomKey)\n\n localStorageWriteTests.tested = true\n localStorageWriteTests.writable = true\n } catch (_e) {\n // localStorage can't be written to\n // https://www.chromium.org/for-testers/bug-reporting-guidelines/uncaught-securityerror-failed-to-read-the-localstorage-property-from-window-access-is-denied-for-this-document\n\n localStorageWriteTests.tested = true\n localStorageWriteTests.writable = false\n }\n\n return localStorageWriteTests.writable\n}\n\nexport function uuid() {\n return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {\n const r = (Math.random() * 16) | 0,\n v = c == 'x' ? r : (r & 0x3) | 0x8\n return v.toString(16)\n })\n}\n\nexport type RawAuthResponse = {\n expires_at: number\n expires_in: number\n user: User\n access_token: string\n refresh_token: string\n token_type: string\n}\n/**\n * hasSession checks if the response object contains a valid session\n * @param data A response object\n * @returns true if a session is in the response\n */\nfunction hasSession(data: Partial<RawAuthResponse>): data is RawAuthResponse {\n return !!data.access_token && !!data.refresh_token && !!data.expires_in\n}\n\nexport function expiresAt(expiresIn: number) {\n const timeNow = Math.round(Date.now() / 1000)\n return timeNow + expiresIn\n}\n\nexport function _sessionResponse({\n data\n}: JsonResponse<Partial<RawAuthResponse>>): AuthResponse {\n let session = null\n if (!data) throw new Error('Bad session response')\n if (hasSession(data)) {\n session = { ...data }\n if (!data.expires_at && data.expires_in) {\n session.expires_at = expiresAt(data.expires_in)\n }\n }\n\n const user: User = data.user ?? (data as User)\n return { data: { session, user }, error: null }\n}\n\n/**\n * A deferred represents some asynchronous work that is not yet finished, which\n * may or may not culminate in a value.\n * Taken from: https://github.com/mike-north/types/blob/master/src/async.ts\n */\nexport class Deferred<T = any> {\n public static promiseConstructor: PromiseConstructor = Promise\n\n public readonly promise!: PromiseLike<T>\n\n public readonly resolve!: (value?: T | PromiseLike<T>) => void\n\n public readonly reject!: (reason?: any) => any\n\n public constructor() {\n ;(this as any).promise = new Deferred.promiseConstructor((res, rej) => {\n ;(this as any).resolve = res\n ;(this as any).reject = rej\n })\n }\n}\n\n/**\n * Converts the provided async function into a retryable function. Each result\n * or thrown error is sent to the isRetryable function which should return true\n * if the function should run again.\n */\nexport function retryable<T>(\n fn: (attempt: number) => Promise<T>,\n isRetryable: (attempt: number, error: any | null, result?: T) => boolean\n): Promise<T> {\n const promise = new Promise<T>((accept, reject) => {\n ;(async () => {\n for (let attempt = 0; attempt < Infinity; attempt++) {\n try {\n const result = await fn(attempt)\n\n if (!isRetryable(attempt, null, result)) {\n accept(result)\n return\n }\n } catch (e: any) {\n if (!isRetryable(attempt, e)) {\n reject(e)\n return\n }\n }\n }\n })()\n })\n\n return promise\n}\n\n/**\n * Creates a promise that resolves to null after some time.\n */\nexport async function sleep(time: number): Promise<null> {\n return new Promise(accept => {\n setTimeout(() => accept(null), time)\n })\n}\n\nexport const checkExpiresInTime = ({\n expires_in,\n expires_at,\n refreshTick\n}: {\n expires_in: string\n expires_at?: string\n refreshTick: number\n}) => {\n const timeNow = Math.round(Date.now() / 1000)\n const expiresIn = parseInt(expires_in)\n let expiresAt = timeNow + expiresIn\n\n if (expires_at) {\n expiresAt = parseInt(expires_at)\n }\n\n const actuallyExpiresIn = expiresAt - timeNow\n if (actuallyExpiresIn * 1000 <= refreshTick) {\n console.warn(\n `@faable/auth-js: Session as retrieved from URL expires in ${actuallyExpiresIn}s, should have been closer to ${expiresIn}s`\n )\n }\n\n const issuedAt = expiresAt - expiresIn\n if (timeNow - issuedAt >= 120) {\n console.warn(\n '@faable/auth-js: Session as retrieved from URL was issued over 120s ago, URL could be stale',\n issuedAt,\n expiresAt,\n timeNow\n )\n } else if (timeNow - issuedAt < 0) {\n console.warn(\n '@faable/auth-js: Session as retrieved from URL was issued in the future? Check the device clok for skew',\n issuedAt,\n expiresAt,\n timeNow\n )\n }\n\n return { expiresIn, expiresAt }\n}\n","import { uuid } from './helpers'\nimport type { AuthChangeEvent, Session, Subscription } from './types'\n\ntype Listener = (\n event: AuthChangeEvent,\n session: Session | null\n) => void | Promise<void>\n\ntype DebugFn = (message: string, ...args: unknown[]) => void\n\nconst hasBroadcastChannel = (): boolean =>\n typeof globalThis !== 'undefined' &&\n typeof (globalThis as { BroadcastChannel?: unknown }).BroadcastChannel ===\n 'function'\n\n/**\n * Wraps a BroadcastChannel plus an in-process subscriber registry so the\n * auth client can fan out state changes to local subscribers and other tabs\n * in one call. Cross-tab messages are delivered to local subscribers but\n * NOT re-broadcast, to avoid echo loops.\n */\nexport class BroadcastSync {\n private channel: BroadcastChannel | null = null\n private subscribers = new Map<string, Subscription>()\n\n constructor(\n channelName: string,\n private debug: DebugFn\n ) {\n if (!hasBroadcastChannel() || !channelName) return\n try {\n this.channel = new globalThis.BroadcastChannel(channelName)\n this.channel.addEventListener('message', async event => {\n this.debug(\n 'broadcast_sync: received notification from another tab',\n event\n )\n await this.dispatch(event.data.event, event.data.session, false)\n })\n } catch (err) {\n console.error(\n 'Failed to create BroadcastChannel; cross-tab sync disabled',\n err\n )\n }\n }\n\n subscribe(callback: Listener): { subscription: Subscription } {\n const id = uuid()\n const subscription: Subscription = {\n id,\n callback,\n unsubscribe: () => {\n this.subscribers.delete(id)\n }\n }\n this.subscribers.set(id, subscription)\n return { subscription }\n }\n\n async notify(\n event: AuthChangeEvent,\n session: Session | null,\n broadcast = true\n ): Promise<void> {\n if (broadcast && this.channel) {\n this.channel.postMessage({ event, session })\n }\n await this.dispatch(event, session, broadcast)\n }\n\n private async dispatch(\n event: AuthChangeEvent,\n session: Session | null,\n _broadcast: boolean\n ): Promise<void> {\n const errors: unknown[] = []\n const tasks = Array.from(this.subscribers.values()).map(async sub => {\n try {\n await sub.callback(event, session)\n } catch (err) {\n errors.push(err)\n }\n })\n await Promise.all(tasks)\n if (errors.length > 0) {\n for (let i = 0; i < errors.length; i += 1) {\n console.error(errors[i])\n }\n throw errors[0]\n }\n }\n\n close(): void {\n this.subscribers.clear()\n try {\n this.channel?.close()\n } catch {\n // ignore — channel may already be closed\n }\n this.channel = null\n }\n}\n","export const STORAGE_KEY = 'faableauth'\nexport const EXPIRY_MARGIN = 10 // in seconds\n\nexport const API_VERSION_HEADER_NAME = 'X-Faableauth-Api-Version'\nexport const API_VERSIONS = {\n '2024-01-01': {\n timestamp: Date.parse('2024-01-01T00:00:00.0Z'),\n name: '2024-01-01'\n }\n}\n","/**\n * Known error codes. Note that the server may also return other error codes\n * not included in this list (if the client library is older than the version\n * on the server).\n */\nexport type ErrorCode =\n | 'unexpected_failure'\n | 'validation_failed'\n | 'bad_json'\n | 'email_exists'\n | 'phone_exists'\n | 'bad_jwt'\n | 'not_admin'\n | 'no_authorization'\n | 'user_not_found'\n | 'session_not_found'\n | 'flow_state_not_found'\n | 'flow_state_expired'\n | 'signup_disabled'\n | 'user_banned'\n | 'provider_email_needs_verification'\n | 'invite_not_found'\n | 'bad_oauth_state'\n | 'bad_oauth_callback'\n | 'oauth_provider_not_supported'\n | 'unexpected_audience'\n | 'single_identity_not_deletable'\n | 'email_conflict_identity_not_deletable'\n | 'identity_already_exists'\n | 'email_provider_disabled'\n | 'phone_provider_disabled'\n | 'too_many_enrolled_mfa_factors'\n | 'mfa_factor_name_conflict'\n | 'mfa_factor_not_found'\n | 'mfa_ip_address_mismatch'\n | 'mfa_challenge_expired'\n | 'mfa_verification_failed'\n | 'mfa_verification_rejected'\n | 'insufficient_aal'\n | 'captcha_failed'\n | 'saml_provider_disabled'\n | 'manual_linking_disabled'\n | 'sms_send_failed'\n | 'email_not_confirmed'\n | 'phone_not_confirmed'\n | 'reauth_nonce_missing'\n | 'saml_relay_state_not_found'\n | 'saml_relay_state_expired'\n | 'saml_idp_not_found'\n | 'saml_assertion_no_user_id'\n | 'saml_assertion_no_email'\n | 'user_already_exists'\n | 'sso_provider_not_found'\n | 'saml_metadata_fetch_failed'\n | 'saml_idp_already_exists'\n | 'sso_domain_already_exists'\n | 'saml_entity_id_mismatch'\n | 'conflict'\n | 'provider_disabled'\n | 'user_sso_managed'\n | 'reauthentication_needed'\n | 'same_password'\n | 'reauthentication_not_valid'\n | 'otp_expired'\n | 'otp_disabled'\n | 'identity_not_found'\n | 'weak_password'\n | 'over_request_rate_limit'\n | 'over_email_send_rate_limit'\n | 'over_sms_send_rate_limit'\n | 'bad_code_verifier'\n\nexport class AuthError extends Error {\n /**\n * Error code associated with the error. Most errors coming from\n * HTTP responses will have a code, though some errors that occur\n * before a response is received will not have one present. In that\n * case {@link AuthError.status} will also be undefined.\n */\n code: ErrorCode | string | undefined\n\n /** HTTP status code that caused the error. */\n status: number | undefined\n\n protected __isAuthError = true\n\n constructor(message: string, status?: number, code?: string) {\n super(message)\n this.name = 'AuthError'\n this.status = status\n this.code = code\n }\n}\n\nexport class CustomAuthError extends AuthError {\n name: string\n status: number\n\n constructor(\n message: string,\n name: string,\n status: number,\n code: string | undefined\n ) {\n super(message, status, code)\n this.name = name\n this.status = status\n }\n}\n\nexport class AuthSessionMissingError extends CustomAuthError {\n constructor() {\n super('Auth session missing!', 'AuthSessionMissingError', 400, undefined)\n }\n}\n\nexport function isAuthError(error: unknown): error is AuthError {\n return typeof error === 'object' && error !== null && '__isAuthError' in error\n}\n\nexport class AuthApiError extends AuthError {\n status: number\n\n constructor(message: string, status: number, code: string | undefined) {\n super(message, status, code)\n this.name = 'AuthApiError'\n this.status = status\n this.code = code\n }\n}\n\nexport function isAuthApiError(error: unknown): error is AuthApiError {\n return isAuthError(error) && error.name === 'AuthApiError'\n}\n\nexport class AuthImplicitGrantRedirectError extends CustomAuthError {\n details: { error: string; code: string } | null = null\n constructor(\n message: string,\n details: { error: string; code: string } | null = null\n ) {\n super(message, 'AuthImplicitGrantRedirectError', 500, undefined)\n this.details = details\n }\n\n toJSON() {\n return {\n name: this.name,\n message: this.message,\n status: this.status,\n details: this.details\n }\n }\n}\n\nexport class AuthPKCEGrantCodeExchangeError extends CustomAuthError {\n details: { error: string; code: string } | null = null\n\n constructor(\n message: string,\n details: { error: string; code: string } | null = null\n ) {\n super(message, 'AuthPKCEGrantCodeExchangeError', 500, undefined)\n this.details = details\n }\n\n toJSON() {\n return {\n name: this.name,\n message: this.message,\n status: this.status,\n details: this.details\n }\n }\n}\n\nexport class AuthUnknownError extends AuthError {\n originalError: unknown\n\n constructor(message: string, originalError: unknown) {\n super(message)\n this.name = 'AuthUnknownError'\n this.originalError = originalError\n }\n}\n\nexport class AuthInvalidTokenResponseError extends CustomAuthError {\n constructor() {\n super(\n 'Auth session or user missing',\n 'AuthInvalidTokenResponseError',\n 500,\n undefined\n )\n }\n}\n\nexport class AuthRetryableFetchError extends CustomAuthError {\n constructor(message: string, status: number) {\n super(message, 'AuthRetryableFetchError', status, undefined)\n }\n}\n\nexport function isAuthRetryableFetchError(\n error: unknown\n): error is AuthRetryableFetchError {\n return isAuthError(error) && error.name === 'AuthRetryableFetchError'\n}\n","import { window } from '../globals'\n\nfunction redirect(url: string) {\n getWindow().location = url as any\n}\n\nfunction getDocument() {\n return getWindow().document\n}\n\nfunction getWindow() {\n if (!window) throw new Error('No window in environment')\n return window\n}\n\nexport const windowHelpers = {\n redirect: redirect,\n getDocument: getDocument,\n getWindow: getWindow\n}\n","import { decodeBase64URL } from './helpers'\n\n/**\n * @ignore\n */\nexport interface JWTVerifyOptions {\n iss: string\n aud: string\n id_token: string\n nonce?: string\n leeway?: number\n max_age?: number\n organizationId?: string\n now?: number\n}\n\nexport interface IdToken {\n __raw: string\n name?: string\n given_name?: string\n family_name?: string\n middle_name?: string\n nickname?: string\n preferred_username?: string\n profile?: string\n picture?: string\n website?: string\n email?: string\n email_verified?: boolean\n gender?: string\n birthdate?: string\n zoneinfo?: string\n locale?: string\n phone_number?: string\n phone_number_verified?: boolean\n address?: string\n updated_at?: string\n iss?: string\n aud?: string\n exp?: number\n nbf?: number\n iat?: number\n jti?: string\n azp?: string\n nonce?: string\n auth_time?: string\n at_hash?: string\n c_hash?: string\n acr?: string\n amr?: string\n sub_jwk?: string\n cnf?: string\n sid?: string\n org_id?: string\n [key: string]: any\n}\n\nconst isNumber = (n: any) => typeof n === 'number'\n\nexport function decodeJWTPayload(token: string) {\n // Regex checks for base64url format\n const base64UrlRegex =\n /^([a-z0-9_-]{4})*($|[a-z0-9_-]{3}=?$|[a-z0-9_-]{2}(==)?$)$/i\n\n const parts = token.split('.')\n\n if (parts.length !== 3) {\n throw new Error('JWT is not valid: not a JWT structure')\n }\n\n if (!base64UrlRegex.test(parts[1])) {\n throw new Error('JWT is not valid: payload is not in base64url format')\n }\n\n const base64Url = parts[1]\n return JSON.parse(decodeBase64URL(base64Url))\n}\n\n/**\n * Derives a session's expiry from a redirect that may omit the OIDC envelope\n * (`expires_in` / `token_type`). Some flows hand the tokens back in the query\n * string with only the token pair; in that case we trust the access token's\n * own `exp` claim. An explicit `expires_at` (in seconds) wins when provided.\n *\n * @param accessToken The access token JWT to read `exp` from.\n * @param expiresAt Optional explicit absolute expiry (seconds since epoch).\n * @param now Current time in seconds (injectable for tests).\n * @returns Absolute `expiresAt` and relative `expiresIn`, both in seconds.\n */\nexport function expiryFromAccessToken(\n accessToken: string,\n expiresAt?: string | number,\n now: number = Date.now() / 1000\n): { expiresAt: number; expiresIn: number } {\n const payload = decodeJWTPayload(accessToken)\n const resolvedExpiresAt =\n expiresAt != null && expiresAt !== ''\n ? Number(expiresAt)\n : (payload.exp ?? now)\n return { expiresAt: resolvedExpiresAt, expiresIn: resolvedExpiresAt - now }\n}\n\nexport const verify = (options: JWTVerifyOptions) => {\n if (!options.id_token) {\n throw new Error('ID token is required but missing')\n }\n\n const decoded = decodeJWTPayload(options.id_token)\n\n if (!decoded.claims.iss) {\n throw new Error(\n 'Issuer (iss) claim must be a string present in the ID token'\n )\n }\n\n if (decoded.claims.iss !== options.iss) {\n throw new Error(\n `Issuer (iss) claim mismatch in the ID token; expected \"${options.iss}\", found \"${decoded.claims.iss}\"`\n )\n }\n\n if (!decoded.user.sub) {\n throw new Error(\n 'Subject (sub) claim must be a string present in the ID token'\n )\n }\n\n if (decoded.header.alg !== 'RS256') {\n throw new Error(\n `Signature algorithm of \"${decoded.header.alg}\" is not supported. Expected the ID token to be signed with \"RS256\".`\n )\n }\n\n if (\n !decoded.claims.aud ||\n !(\n typeof decoded.claims.aud === 'string' ||\n Array.isArray(decoded.claims.aud)\n )\n ) {\n throw new Error(\n 'Audience (aud) claim must be a string or array of strings present in the ID token'\n )\n }\n if (Array.isArray(decoded.claims.aud)) {\n if (!decoded.claims.aud.includes(options.aud)) {\n throw new Error(\n `Audience (aud) claim mismatch in the ID token; expected \"${\n options.aud\n }\" but was not one of \"${decoded.claims.aud.join(', ')}\"`\n )\n }\n if (decoded.claims.aud.length > 1) {\n if (!decoded.claims.azp) {\n throw new Error(\n 'Authorized Party (azp) claim must be a string present in the ID token when Audience (aud) claim has multiple values'\n )\n }\n if (decoded.claims.azp !== options.aud) {\n throw new Error(\n `Authorized Party (azp) claim mismatch in the ID token; expected \"${options.aud}\", found \"${decoded.claims.azp}\"`\n )\n }\n }\n } else if (decoded.claims.aud !== options.aud) {\n throw new Error(\n `Audience (aud) claim mismatch in the ID token; expected \"${options.aud}\" but found \"${decoded.claims.aud}\"`\n )\n }\n if (options.nonce) {\n if (!decoded.claims.nonce) {\n throw new Error(\n 'Nonce (nonce) claim must be a string present in the ID token'\n )\n }\n if (decoded.claims.nonce !== options.nonce) {\n throw new Error(\n `Nonce (nonce) claim mismatch in the ID token; expected \"${options.nonce}\", found \"${decoded.claims.nonce}\"`\n )\n }\n }\n\n if (options.max_age && !isNumber(decoded.claims.auth_time)) {\n throw new Error(\n 'Authentication Time (auth_time) claim must be a number present in the ID token when Max Age (max_age) is specified'\n )\n }\n\n /* c8 ignore next 5 */\n if (decoded.claims.exp == null || !isNumber(decoded.claims.exp)) {\n throw new Error(\n 'Expiration Time (exp) claim must be a number present in the ID token'\n )\n }\n if (!isNumber(decoded.claims.iat)) {\n throw new Error(\n 'Issued At (iat) claim must be a number present in the ID token'\n )\n }\n\n const leeway = options.leeway || 60\n const now = new Date(options.now || Date.now())\n const expDate = new Date(0)\n\n expDate.setUTCSeconds(decoded.claims.exp + leeway)\n\n if (now > expDate) {\n throw new Error(\n `Expiration Time (exp) claim error in the ID token; current time (${now}) is after expiration time (${expDate})`\n )\n }\n\n if (decoded.claims.nbf != null && isNumber(decoded.claims.nbf)) {\n const nbfDate = new Date(0)\n nbfDate.setUTCSeconds(decoded.claims.nbf - leeway)\n if (now < nbfDate) {\n throw new Error(\n `Not Before time (nbf) claim in the ID token indicates that this token can't be used just yet. Current time (${now}) is before ${nbfDate}`\n )\n }\n }\n\n if (decoded.claims.auth_time != null && isNumber(decoded.claims.auth_time)) {\n const authTimeDate = new Date(0)\n authTimeDate.setUTCSeconds(\n parseInt(decoded.claims.auth_time) + (options.max_age as number) + leeway\n )\n\n if (now > authTimeDate) {\n throw new Error(\n `Authentication Time (auth_time) claim in the ID token indicates that too much time has passed since the last end-user authentication. Current time (${now}) is after last auth at ${authTimeDate}`\n )\n }\n }\n\n if (options.organizationId) {\n if (!decoded.claims.org_id) {\n throw new Error(\n 'Organization ID (org_id) claim must be a string present in the ID token'\n )\n } else if (options.organizationId !== decoded.claims.org_id) {\n throw new Error(\n `Organization ID (org_id) claim mismatch in the ID token; expected \"${options.organizationId}\", found \"${decoded.claims.org_id}\"`\n )\n }\n }\n\n return decoded\n}\n","import { STORAGE_KEY } from './constants'\nimport { Session } from './types'\n\n/**\n * Reads the persisted session from cookies on the server.\n *\n * Pair this with the cookie storage adapter on the client: when the browser\n * stores its session under the cookie shared with the server, the same\n * `clientId` lets the server reconstruct it. Mirrors how the browser\n * adapter builds the storage key and reassembles chunked cookies, so no\n * extra wiring is required.\n *\n * @param cookiesStore Either the result of `cookies()` from `next/headers`,\n * or any plain `{ name: value }` map. Adapters with a `get(name)` method\n * are detected automatically.\n * @param options `{ clientId, storageKey? }`. `storageKey` defaults to the\n * library's built-in prefix — only set it when you customized\n * `storageKey` in `createClient`.\n * @returns The decoded {@link Session} or `null` when the cookie is absent\n * or malformed.\n * @example\n * ```ts\n * // app/page.tsx\n * import { cookies } from 'next/headers'\n * import { getSessionFromCookies } from '@faable/auth-js'\n *\n * export default async function Page() {\n * const session = getSessionFromCookies(cookies(), {\n * clientId: '<client_id>'\n * })\n * if (!session) return <SignIn />\n * return <Dashboard user={session.user} />\n * }\n * ```\n * @see {@link https://faable.com/docs/auth/quickstart/nextjs | Next.js Quickstart}\n */\nexport const getSessionFromCookies = (\n cookiesStore: any,\n options: { clientId: string; storageKey?: string }\n): Session | null => {\n const key = `${options.storageKey ?? STORAGE_KEY}-${options.clientId}`\n\n const cookieValue = readCookieValue(cookiesStore, key)\n if (!cookieValue) return null\n\n try {\n return JSON.parse(decodeURIComponent(cookieValue))\n } catch (e) {\n console.error('Failed to parse session from cookie', e)\n return null\n }\n}\n\n/**\n * Reads `key` (or its `<key>.0`, `<key>.1`, … chunks) out of either a Next.js\n * `cookies()` object or a plain `{ name: value }` map, mirroring how the\n * browser adapter writes them.\n */\nconst readCookieValue = (cookiesStore: any, key: string): string | null => {\n if (!cookiesStore) return null\n\n const readOne =\n typeof cookiesStore.get === 'function'\n ? (name: string) => cookiesStore.get(name)?.value\n : (name: string) => cookiesStore[name]\n\n const single = readOne(key)\n if (single) return single\n\n const chunks: string[] = []\n for (let i = 0; ; i++) {\n const value = readOne(`${key}.${i}`)\n if (!value) break\n chunks.push(value)\n }\n return chunks.length ? chunks.join('') : null\n}\n","import type { Session } from './types'\n\n/**\n * Type guard for a stored session blob — checks the presence of the fields\n * the client needs to consider the value usable. Does not validate the\n * cryptographic signature of the access/refresh tokens.\n */\nexport const isValidSession = (value: unknown): value is Session =>\n typeof value === 'object' &&\n value !== null &&\n 'access_token' in value &&\n 'refresh_token' in value &&\n 'expires_at' in value\n","export interface CookieAttributes {\n domain?: string\n path?: string\n sameSite?: 'Lax' | 'Strict' | 'None'\n secure?: boolean\n maxAge?: number\n}\n\n/**\n * Parses a raw cookie string (the shape of `document.cookie`) into a Map of\n * decoded name → value. Splitting happens BEFORE decoding so encoded `;` and\n * `=` characters inside a value don't break the parser.\n */\nexport const parseCookies = (cookieString: string): Map<string, string> => {\n const out = new Map<string, string>()\n if (!cookieString) return out\n\n for (const rawPair of cookieString.split(';')) {\n const pair = rawPair.trim()\n if (!pair) continue\n const eq = pair.indexOf('=')\n if (eq < 0) continue\n const name = decodeMaybe(pair.slice(0, eq).trim())\n const value = decodeMaybe(pair.slice(eq + 1).trim())\n if (name) out.set(name, value)\n }\n return out\n}\n\nconst decodeMaybe = (input: string): string => {\n try {\n return decodeURIComponent(input)\n } catch {\n return input\n }\n}\n\n/**\n * Builds a `name=value; Attr=...` string suitable for assignment to\n * `document.cookie`. Encodes name and value per RFC 6265 and forces `Secure`\n * when `SameSite=None` (browsers reject the cookie otherwise).\n */\nexport const serializeCookie = (\n name: string,\n value: string,\n attrs: CookieAttributes\n): string => {\n let out = `${encodeURIComponent(name)}=${encodeURIComponent(value)}`\n\n if (attrs.maxAge !== undefined) out += `; Max-Age=${attrs.maxAge}`\n if (attrs.domain) out += `; Domain=${attrs.domain}`\n if (attrs.path) out += `; Path=${attrs.path}`\n if (attrs.sameSite) out += `; SameSite=${attrs.sameSite}`\n\n // `SameSite=None` only works with Secure; emit Secure even if the caller\n // forgot it so the browser doesn't silently drop the cookie.\n const needsSecure = attrs.secure === true || attrs.sameSite === 'None'\n if (needsSecure) out += '; Secure'\n\n return out\n}\n\n/**\n * Builds the cookie string that clears `name`. Browsers will only remove a\n * cookie when the deletion attributes (Domain, Path, SameSite, Secure) match\n * those used at write time, so we mirror them here.\n */\nexport const serializeCookieRemoval = (\n name: string,\n attrs: CookieAttributes\n): string =>\n serializeCookie(name, '', {\n domain: attrs.domain,\n path: attrs.path,\n sameSite: attrs.sameSite,\n secure: attrs.secure,\n maxAge: 0\n })\n","import { isBrowser } from '../helpers'\nimport { SupportedStorage } from '../types'\nimport {\n CookieAttributes,\n parseCookies,\n serializeCookie,\n serializeCookieRemoval\n} from './cookie_helpers'\n\nexport type CookieOptions = CookieAttributes\n\n/**\n * Document-like surface the cookie adapter needs. Accepting a minimal shape\n * (instead of the full DOM `Document`) keeps the adapter testable without\n * jsdom and works in any environment that exposes a `cookie` property.\n */\nexport interface CookieJar {\n cookie: string\n}\n\n/** Default cookie lifetime when the caller doesn't override `maxAge`. */\nconst DEFAULT_COOKIE_MAX_AGE_SECONDS = 30 * 24 * 60 * 60\n\n/**\n * Maximum raw bytes we put in a single cookie value before splitting. Browsers\n * cap individual cookies at ~4096 bytes including name + attributes; after\n * URL-encoding (typical ratio ~1.1x for JSON sessions) and the attribute tail\n * (`Max-Age=…; Path=/; SameSite=Lax; …`) this leaves enough headroom even for\n * the longest realistic cookie names.\n */\nconst MAX_CHUNK_SIZE = 3200\n\nconst chunkKey = (key: string, idx: number): string => `${key}.${idx}`\n\n/**\n * Returns the chunk keys for `key` in numeric order. A \"chunk key\" is one\n * shaped like `<key>.<integer>`; foreign cookies that happen to share the\n * prefix (e.g. `key-suffix`) are ignored thanks to the dot + digits check.\n */\nconst collectChunkKeys = (\n parsed: Map<string, string>,\n key: string\n): string[] => {\n const prefix = `${key}.`\n const found: { name: string; idx: number }[] = []\n parsed.forEach((_value, name) => {\n if (!name.startsWith(prefix)) return\n const tail = name.slice(prefix.length)\n if (!/^\\d+$/.test(tail)) return\n found.push({ name, idx: Number(tail) })\n })\n found.sort((a, b) => a.idx - b.idx)\n return found.map(c => c.name)\n}\n\n/**\n * Reads `key` from the parsed cookie map. Prefers a single un-chunked cookie\n * (back-compat with sessions written by earlier SDK versions); falls back to\n * concatenating numbered chunks. Returns null when nothing is found.\n */\nexport const readChunkedCookieValue = (\n parsed: Map<string, string>,\n key: string\n): string | null => {\n const single = parsed.get(key)\n if (single !== undefined) return single\n const chunkNames = collectChunkKeys(parsed, key)\n if (chunkNames.length === 0) return null\n return chunkNames.map(name => parsed.get(name) as string).join('')\n}\n\n/**\n * Storage adapter that persists the session in `document.cookie`.\n *\n * Pick this adapter when you need SSR (server reads the cookie on every\n * request) or want to scope storage with `Secure`, `SameSite`, or `Domain`.\n * The simplest way to enable it is `createClient({ storage: 'cookie' })` or\n * by passing `cookieOptions` — the SDK calls this factory internally.\n *\n * Defaults applied to every cookie: `Path=/`, `SameSite=Lax`, `Secure` on\n * HTTPS, 30-day `Max-Age`. Override any of them through `options`. Values\n * larger than the per-cookie browser limit (~4 KB) are transparently split\n * across numbered chunks (`<key>.0`, `<key>.1`, …) and re-assembled on read.\n *\n * @param options Attribute overrides for every written cookie.\n * @param jar Document-like object whose `cookie` property is read/written.\n * Defaults to `document` in browsers and `null` (no-op) on the server —\n * only override for tests.\n * @returns A {@link SupportedStorage} ready to pass to {@link createClient}.\n * @example\n * ```ts\n * import { createClient } from '@faable/auth-js'\n *\n * export const auth = createClient({\n * domain: '<faableauth_domain>',\n * clientId: '<client_id>',\n * storage: 'cookie',\n * cookieOptions: { domain: '.example.com' }\n * })\n * ```\n * @see {@link https://faable.com/docs/auth/quickstart/nextjs | Next.js Quickstart}\n */\nexport const cookieStorageAdapter = (\n options: CookieOptions = {},\n jar: CookieJar | null = isBrowser() ? document : null\n): SupportedStorage => {\n const attrs: CookieAttributes = {\n path: '/',\n sameSite: 'Lax',\n secure: isBrowser() && window.location.protocol === 'https:',\n maxAge: DEFAULT_COOKIE_MAX_AGE_SECONDS,\n ...options\n }\n\n return {\n getItem: (key: string) => {\n if (!jar) return null\n const parsed = parseCookies(jar.cookie)\n return readChunkedCookieValue(parsed, key)\n },\n\n setItem: (key: string, value: string) => {\n if (!jar) return\n const parsed = parseCookies(jar.cookie)\n\n if (value.length <= MAX_CHUNK_SIZE) {\n // Single cookie path. Wipe any stale chunks left from a prior large\n // value so a subsequent `getItem` doesn't reassemble garbage.\n for (const name of collectChunkKeys(parsed, key)) {\n jar.cookie = serializeCookieRemoval(name, attrs)\n }\n jar.cookie = serializeCookie(key, value, attrs)\n return\n }\n\n // Chunked path. Drop a stale single (if any) and any chunks that fall\n // beyond the new count; the surviving chunk indices get overwritten by\n // the loop below.\n if (parsed.has(key)) {\n jar.cookie = serializeCookieRemoval(key, attrs)\n }\n const newCount = Math.ceil(value.length / MAX_CHUNK_SIZE)\n for (const name of collectChunkKeys(parsed, key)) {\n const idx = Number(name.slice(key.length + 1))\n if (idx >= newCount) {\n jar.cookie = serializeCookieRemoval(name, attrs)\n }\n }\n for (let pos = 0, i = 0; pos < value.length; pos += MAX_CHUNK_SIZE, i++) {\n const slice = value.slice(pos, pos + MAX_CHUNK_SIZE)\n jar.cookie = serializeCookie(chunkKey(key, i), slice, attrs)\n }\n },\n\n removeItem: (key: string) => {\n if (!jar) return\n // Always emit the single removal so the call mirrors a `Set-Cookie:\n // key=; Max-Age=0` (browsers no-op on absent cookies) and additionally\n // clear every chunk we can see.\n const parsed = parseCookies(jar.cookie)\n jar.cookie = serializeCookieRemoval(key, attrs)\n for (const name of collectChunkKeys(parsed, key)) {\n jar.cookie = serializeCookieRemoval(name, attrs)\n }\n }\n }\n}\n","import { supportsLocalStorage } from '../helpers'\nimport { SupportedStorage } from '../types'\n\n/**\n * Provides safe access to the globalThis.localStorage property.\n */\nexport const localStorageAdapter: SupportedStorage = {\n getItem: key => {\n if (!supportsLocalStorage()) {\n return null\n }\n\n return globalThis.localStorage.getItem(key)\n },\n setItem: (key, value) => {\n if (!supportsLocalStorage()) {\n return\n }\n\n globalThis.localStorage.setItem(key, value)\n },\n removeItem: key => {\n if (!supportsLocalStorage()) {\n return\n }\n\n globalThis.localStorage.removeItem(key)\n }\n}\n\n/**\n * Returns a localStorage-like object that stores the key-value pairs in\n * memory.\n */\nexport function memoryLocalStorageAdapter(\n store: { [key: string]: string } = {}\n): SupportedStorage {\n return {\n getItem: key => {\n return store[key] || null\n },\n\n setItem: (key, value) => {\n store[key] = value\n },\n\n removeItem: key => {\n delete store[key]\n }\n }\n}\n","/**\n * Extracts parameters encoded in the URL both in the query and fragment.\n */\nexport function parseParametersFromURL(href: string = '') {\n const result: { [parameter: string]: string } = {}\n\n const url = new URL(href)\n\n if (url.hash && url.hash[0] === '#') {\n try {\n const hashSearchParams = new URLSearchParams(url.hash.substring(1))\n hashSearchParams.forEach((value, key) => {\n result[key] = value\n })\n } catch (_e) {\n // hash is not a query string\n }\n }\n\n // search parameters take precedence over hash parameters\n url.searchParams.forEach((value, key) => {\n result[key] = value\n })\n\n return result\n}\n\nexport const clearURLParameters = (delete_params: string[] = []) => {\n const url = new URL(window.location.href)\n\n delete_params.forEach(param => {\n url.searchParams.delete(param)\n })\n\n url.hash = ''\n\n window.history.replaceState(window.history.state, '', url.toString())\n}\n","import { supportsLocalStorage } from '../lib/helpers'\n\n/**\n * Provide your own global lock implementation instead of the default\n * implementation. The function should acquire a lock for the duration of the\n * `fn` async function, such that no other client instances will be able to\n * hold it at the same time.\n *\n * @experimental\n *\n * @param name Name of the lock to be acquired.\n * @param acquireTimeout If negative, no timeout should occur. If positive it\n * should throw an Error with an `isAcquireTimeout`\n * property set to true if the operation fails to be\n * acquired after this much time (ms).\n * @param fn The operation to execute when the lock is acquired.\n */\nexport type LockFunc = <R>(\n name: string,\n acquireTimeout: number,\n fn: () => Promise<R>\n) => Promise<R>\n\n/**\n * @experimental\n */\nexport const internals = {\n /**\n * @experimental\n */\n debug: !!(\n globalThis &&\n supportsLocalStorage() &&\n globalThis.localStorage &&\n globalThis.localStorage.getItem('faable.auth.locks.debug') === 'true'\n )\n}\n\n/**\n * An error thrown when a lock cannot be acquired after some amount of time.\n *\n * Use the {@link #isAcquireTimeout} property instead of checking with `instanceof`.\n */\nexport abstract class LockAcquireTimeoutError extends Error {\n public readonly isAcquireTimeout = true\n\n constructor(message: string) {\n super(message)\n }\n}\n\nexport class NavigatorLockAcquireTimeoutError extends LockAcquireTimeoutError {}\n\n/**\n * Implements a global exclusive lock using the Navigator LockManager API. It\n * is available on all browsers released after 2022-03-15 with Safari being the\n * last one to release support. If the API is not available, this function will\n * throw. Make sure you check availability before passing this lock to the\n * client.\n *\n * You can turn on debugging by setting the `faable.auth.locks.debug`\n * local storage item to `true`.\n *\n * Internals:\n *\n * Since the LockManager API does not preserve stack traces for the async\n * function passed in the `request` method, a trick is used where acquiring the\n * lock releases a previously started promise to run the operation in the `fn`\n * function. The lock waits for that promise to finish (with or without error),\n * while the function will finally wait for the result anyway.\n *\n * @param name Name of the lock to be acquired.\n * @param acquireTimeout If negative, no timeout. If 0 an error is thrown if\n * the lock can't be acquired without waiting. If positive, the lock acquire\n * will time out after so many milliseconds. An error is\n * a timeout if it has `isAcquireTimeout` set to true.\n * @param fn The operation to run once the lock is acquired.\n */\nexport async function navigatorLock<R>(\n name: string,\n acquireTimeout: number,\n fn: () => Promise<R>\n): Promise<R> {\n if (internals.debug) {\n console.log(\n '@faable/auth-js: navigatorLock: acquire lock',\n name,\n acquireTimeout\n )\n }\n\n const abortController = new globalThis.AbortController()\n\n if (acquireTimeout > 0) {\n setTimeout(() => {\n abortController.abort()\n if (internals.debug) {\n console.log('@faable/auth-js: navigatorLock acquire timed out', name)\n }\n }, acquireTimeout)\n }\n\n // MDN article: https://developer.mozilla.org/en-US/docs/Web/API/LockManager/request\n\n return await globalThis.navigator.locks.request(\n name,\n acquireTimeout === 0\n ? {\n mode: 'exclusive',\n ifAvailable: true\n }\n : {\n mode: 'exclusive',\n signal: abortController.signal\n },\n async lock => {\n if (lock) {\n if (internals.debug) {\n console.log(\n '@faable/auth-js: navigatorLock: acquired',\n name,\n lock.name\n )\n }\n\n try {\n return await fn()\n } finally {\n if (internals.debug) {\n console.log(\n '@faable/auth-js: navigatorLock: released',\n name,\n lock.name\n )\n }\n }\n } else {\n if (acquireTimeout === 0) {\n if (internals.debug) {\n console.log(\n '@faable/auth-js: navigatorLock: not immediately available',\n name\n )\n }\n\n throw new NavigatorLockAcquireTimeoutError(\n `Acquiring an exclusive Navigator LockManager lock \"${name}\" immediately failed`\n )\n } else {\n if (internals.debug) {\n try {\n const result = await globalThis.navigator.locks.query()\n\n console.log(\n '@faable/auth-js: Navigator LockManager state',\n JSON.stringify(result, null, ' ')\n )\n } catch (e: any) {\n console.warn(\n '@faable/auth-js: Error when querying Navigator LockManager state',\n e\n )\n }\n }\n\n // Browser is not following the Navigator LockManager spec, it\n // returned a null lock when we didn't use ifAvailable. So we can\n // pretend the lock is acquired in the name of backward compatibility\n // and user experience and just run the function.\n console.warn(\n '@faable/auth-js: Navigator LockManager returned a null lock when using #request without ifAvailable set to true, it appears this browser is not following the LockManager spec https://developer.mozilla.org/en-US/docs/Web/API/LockManager/request'\n )\n\n return await fn()\n }\n }\n }\n )\n}\n\nexport async function lockNoOp<R>(\n name: string,\n acquireTimeout: number,\n fn: () => Promise<R>\n): Promise<R> {\n return await fn()\n}\n","import { Base } from '../Base'\nimport { BaseLogOptions } from '../BaseLog'\nimport { LockFunc, lockNoOp } from './locks'\n\ntype LockOptions = {\n storageKey: string\n lock?: LockFunc\n} & BaseLogOptions\n\nexport class Lock extends Base {\n protected lock: LockFunc\n lockAcquired = false\n protected pendingInLock: Promise<any>[] = []\n\n protected storageKey: string\n\n constructor(options: LockOptions) {\n super({ debug: options.debug })\n this.lock = options.lock || lockNoOp\n this.storageKey = options.storageKey\n }\n\n /**\n * Acquires a global lock based on the storage key.\n */\n async _acquireLock<R>(\n acquireTimeout: number,\n fn: () => Promise<R>\n ): Promise<R> {\n this._debug('#_acquireLock', 'begin', acquireTimeout)\n\n try {\n if (this.lockAcquired) {\n const last = this.pendingInLock.length\n ? this.pendingInLock[this.pendingInLock.length - 1]\n : Promise.resolve()\n\n const result = (async () => {\n await last\n return await fn()\n })()\n\n this.pendingInLock.push(\n (async () => {\n try {\n await result\n } catch (_e) {\n // we just care if it finished\n }\n })()\n )\n\n return result\n }\n\n return await this.lock(\n `lock:${this.storageKey}`,\n acquireTimeout,\n async () => {\n this._debug(\n '#_acquireLock',\n 'lock acquired for storage key',\n this.storageKey\n )\n\n try {\n this.lockAcquired = true\n\n const result = fn()\n\n this.pendingInLock.push(\n (async () => {\n try {\n await result\n } catch (_e) {\n // we just care if it finished\n }\n })()\n )\n\n await result\n\n // keep draining the queue until there's nothing to wait on\n while (this.pendingInLock.length) {\n const waitOn = [...this.pendingInLock]\n\n await Promise.all(waitOn)\n\n this.pendingInLock.splice(0, waitOn.length)\n }\n\n return await result\n } finally {\n this._debug(\n '#_acquireLock',\n 'lock released for storage key',\n this.storageKey\n )\n\n this.lockAcquired = false\n }\n }\n )\n } finally {\n this._debug('#_acquireLock', 'end')\n }\n }\n}\n","import { Base } from './Base'\nimport FaableAuthApi from './FaableAuthApi'\nimport { buildAndSubmitForm, resolveResponseType } from './lib/auth_helpers'\nimport { BroadcastSync } from './lib/broadcast_sync'\nimport { EXPIRY_MARGIN, STORAGE_KEY } from './lib/constants'\nimport {\n AuthApiError,\n AuthError,\n AuthImplicitGrantRedirectError,\n AuthInvalidTokenResponseError,\n AuthPKCEGrantCodeExchangeError,\n AuthSessionMissingError,\n AuthUnknownError,\n isAuthApiError,\n isAuthError,\n isAuthRetryableFetchError\n} from './lib/errors'\nimport { _get, _post } from './lib/fetch'\nimport { document, window } from './lib/globals'\nimport {\n Deferred,\n RawAuthResponse,\n _sessionResponse,\n checkExpiresInTime,\n getCodeChallengeAndMethod,\n isBrowser,\n retryable,\n sleep\n} from './lib/helpers'\nimport { windowHelpers } from './lib/helpers/window'\nimport { decodeJWTPayload, expiryFromAccessToken } from './lib/jwt'\nimport { getSessionFromCookies } from './lib/nextjs'\nimport { loadCodeVerifier } from './lib/pkce_storage'\nimport { isValidSession } from './lib/session_helpers'\nimport { cookieStorageAdapter } from './lib/storage/cookie-storage'\nimport { localStorageAdapter } from './lib/storage/local-storage'\nimport { getItemAsync, setItemAsync } from './lib/storage_helpers'\nimport {\n AuthFlowType,\n CallRefreshTokenResult,\n InitializeResult,\n OAuthResponse,\n SignInWithOAuthConnection,\n Subscription,\n SupportedStorage,\n User\n} from './lib/types'\nimport {\n AuthChangeEvent,\n AuthResponse,\n FaableAuthClientConfig\n} from './lib/types'\nimport { Session, SignOut } from './lib/types'\nimport { clearURLParameters, parseParametersFromURL } from './lib/url_helpers'\nimport { withTimeout } from './lib/with_timeout'\nimport { Lock } from './lock/Lock'\nimport { LockAcquireTimeoutError } from './lock/locks'\nimport { getDomain, getTokenIssuer } from './utils'\n\nexport { cookieStorageAdapter, getSessionFromCookies }\n\n/** Current session will be checked for refresh at this interval. */\nconst AUTO_REFRESH_TICK_DURATION = 30 * 1000\n\n/**\n * A token refresh will be attempted this many ticks before the current session expires. */\nconst AUTO_REFRESH_TICK_THRESHOLD = 3\n\n/** Hard upper bound for a single refresh-token call before it's aborted. */\nconst REFRESH_TIMEOUT_MS = 30 * 1000\n\nconst resolveStorage = (config: FaableAuthClientConfig): SupportedStorage => {\n const { storage, cookieOptions } = config\n if (storage === 'cookie' || cookieOptions) {\n return cookieStorageAdapter(cookieOptions)\n }\n if (storage === 'localStorage' || storage === undefined) {\n return localStorageAdapter\n }\n return storage\n}\n\n/**\n * The main entry point of the SDK: an isomorphic client bound to a Faable\n * Auth tenant that drives every authentication flow.\n *\n * Prefer creating it through the {@link createClient} factory in app code.\n * Once instantiated it begins loading its session in the background, so you\n * can subscribe to {@link FaableAuthClient.onAuthStateChange | auth-state\n * changes} and trigger sign-ins right away. The most common starting points\n * are the {@link FaableAuthClient.signInWithOauthConnection | sign-in}\n * methods and {@link FaableAuthClient.getSession | getSession}.\n *\n * @category Getting started\n * @see {@link https://faable.com/docs/auth/get-started | Get Started with Faable Auth}\n */\nexport class FaableAuthClient extends Base {\n domainUrl: string\n tokenIssuer: string\n redirectUri: string\n scope?: string\n audience?: string\n sessionCheckExpiryDays: number\n\n protected initializePromise: Promise<InitializeResult> | null = null\n protected _lastInitializeResult: InitializeResult | null = null\n protected detectSessionInUrl = true\n\n protected storageKey: string\n\n protected clientId: string\n protected storage: SupportedStorage\n protected api: FaableAuthApi\n\n protected autoRefreshToken: boolean\n protected autoRefreshTicker: ReturnType<typeof setInterval> | null = null\n protected visibilityChangedCallback: (() => Promise<any>) | null = null\n\n protected refreshingDeferred: Deferred<CallRefreshTokenResult> | null = null\n\n /**\n * Cross-tab broadcaster + local subscriber registry for state changes.\n */\n protected broadcastSync: BroadcastSync\n protected _session: Session | null = null\n\n /**\n * Initiation flow to use when redirecting to /authorize. Defaults to\n * PKCE in browsers (recommended for SPAs) and implicit otherwise.\n * Distinct from the callback-side flow which is detected from URL params.\n */\n protected flowType: AuthFlowType\n\n protected lock: Lock\n\n /**\n * Creates a new authentication client bound to a Faable Auth tenant.\n *\n * The constructor kicks off {@link FaableAuthClient.initialize} in the\n * background; you do not need to await anything before calling other methods.\n * Prefer the {@link createClient} factory in app code — it has the same\n * effect with less ceremony.\n *\n * @param config Tenant settings. `domain` and `clientId` are required and\n * throw synchronously when missing.\n * @example\n * ```ts\n * const auth = new FaableAuthClient({\n * domain: '<faableauth_domain>',\n * clientId: '<client_id>',\n * redirectUri: window.location.origin\n * })\n * ```\n * @see {@link https://faable.com/docs/auth/get-started | Get Started with Faable Auth}\n * @see {@link https://faable.com/docs/auth/clients | Clients}\n * @category Getting started\n */\n constructor(config: FaableAuthClientConfig) {\n const debug = config?.debug || false\n super({ debug })\n\n this.sessionCheckExpiryDays = 1\n this.redirectUri = config?.redirectUri || ''\n if (!config?.domain) {\n throw new Error('Missing domain')\n }\n this.domainUrl = getDomain(config.domain)\n\n this.tokenIssuer = getTokenIssuer('', this.domainUrl)\n if (!config.clientId) {\n throw new Error('Missing clientId')\n }\n this.clientId = config.clientId\n this.audience = config.audience\n\n this.api = new FaableAuthApi(this.domainUrl, { debug })\n\n // Storage key\n const key_prefix = config?.storageKey || STORAGE_KEY\n this.storageKey = `${key_prefix}-${this.clientId}`\n\n this.storage = resolveStorage(config)\n\n this.lock = new Lock({\n lock: config.lock,\n storageKey: this.storageKey,\n debug: config.debug\n })\n\n this.broadcastSync = new BroadcastSync(\n isBrowser() ? this.storageKey : '',\n (msg, ...args) => this._debug(msg, ...args)\n )\n\n this.flowType = config.flowType ?? (isBrowser() ? 'pkce' : 'implicit')\n\n this.autoRefreshToken = true\n\n this.initialize()\n }\n\n /**\n * Cached session value last persisted by the client.\n *\n * This is a synchronous accessor that returns whatever the client has\n * already loaded into memory. It can lag behind storage (for example,\n * across tabs before the broadcast event arrives) and never triggers a\n * refresh. Prefer {@link FaableAuthClient.getSession} when you need an\n * authoritative value, especially on the server.\n *\n * @returns The cached {@link Session} or `null` if no user is signed in.\n * @see {@link https://faable.com/docs/auth/oidc/userinfo | UserInfo}\n * @category Sessions\n */\n get session() {\n return this._session\n }\n\n /**\n * Initializes the client session either from the URL or from storage.\n *\n * Automatically called once from the constructor and idempotent — extra\n * calls return the same in-flight promise. Call it explicitly when you\n * need to await an OAuth, magic link, or password-recovery redirect to\n * finish processing so you can surface any returned error.\n *\n * @returns A promise that resolves to `{ error }` — non-null when the URL\n * carried a failure or storage was corrupt; never throws.\n * @example\n * ```ts\n * const { error } = await auth.initialize()\n * if (error) console.error('Auth redirect failed', error)\n * ```\n * @see {@link https://faable.com/docs/auth/oauth-flows/authorization-code | Authorization Code with PKCE}\n * @category Lifecycle\n */\n async initialize(): Promise<InitializeResult> {\n if (this.initializePromise) {\n return await this.initializePromise\n }\n\n this.initializePromise = (async () => {\n return await this.lock._acquireLock(-1, async () => {\n return await this._initialize()\n })\n })()\n\n const result = await this.initializePromise\n this._lastInitializeResult = result\n return result\n }\n\n /**\n * The result of the most recent {@link FaableAuthClient.initialize} run, or\n * `null` while the first one is still in flight.\n *\n * The constructor starts `initialize()` in the background and discards the\n * promise; this accessor lets code that cannot await it (for example a\n * React provider effect) read whether the last OAuth/redirect attempt\n * errored, instead of being stuck with a session that silently stays\n * `null`.\n *\n * @category Lifecycle\n */\n get lastInitializeResult(): InitializeResult | null {\n return this._lastInitializeResult\n }\n\n /**\n * Completes an OAuth / magic-link / password-recovery redirect on your\n * callback route and reports the outcome.\n *\n * The SDK already consumes the URL during the `initialize()` it kicks off\n * from the constructor; this is a thin, discoverable wrapper that awaits\n * that same in-flight run (idempotent) so you can:\n *\n * - redirect **only once** the token exchange has finished, and\n * - surface `error` instead of hanging on a \"Signing you in…\" screen when\n * the exchange fails (e.g. an expired PKCE verifier).\n *\n * It also returns `returnTo` — the app-side destination you optionally\n * passed to `signInWith*({ returnTo })` — so you don't need a side channel\n * (like `sessionStorage`) to remember where to send the user.\n *\n * @example\n * ```ts\n * // app/callback/page.tsx\n * const { error, returnTo } = await auth.handleRedirectCallback()\n * if (error) showError(error.message)\n * else router.replace(returnTo ?? '/')\n * ```\n * @see {@link FaableAuthClient.initialize}\n * @category Lifecycle\n */\n async handleRedirectCallback(): Promise<InitializeResult> {\n return await this.initialize()\n }\n\n /**\n * IMPORTANT:\n * 1. Never throw in this method, as it is called from the constructor\n * 2. Never return a session from this method as it would be cached over\n * the whole lifetime of the client\n */\n private async _initialize(): Promise<InitializeResult> {\n try {\n const flow = await this._detectFlowType()\n\n this._debug('#_initialize()', 'begin', 'flow_type', flow)\n\n // if exists any flow, process the session\n if (flow) {\n const { data, error } = await this._getSessionFromURL(flow)\n if (error) {\n this._debug(\n '#_initialize()',\n 'error detecting session from URL',\n error\n )\n\n // hacky workaround to keep the existing session if there's an error returned from identity linking\n // TODO: once error codes are ready, we should match against it instead of the message\n if (\n error?.message === 'Identity is already linked' ||\n error?.message === 'Identity is already linked to another user'\n ) {\n return { error }\n }\n\n // failed login attempt via url,\n // remove old session as in verifyOtp, signUp and signInWith*\n await this._removeSession()\n\n return { error }\n }\n\n const { session, redirectType, returnTo, is_new_user } = data\n\n this._debug(\n '#_initialize()',\n 'detected session in URL',\n session,\n 'redirect type',\n redirectType\n )\n\n await this._saveSession(session)\n\n setTimeout(async () => {\n if (redirectType === 'recovery') {\n await this._notifyAllSubscribers('PASSWORD_RECOVERY', session)\n } else {\n await this._notifyAllSubscribers('SIGNED_IN', session)\n }\n }, 0)\n\n return { error: null, redirectType, returnTo, is_new_user }\n }\n // no login attempt via callback url try to recover session from storage\n await this._recoverAndRefresh()\n return { error: null }\n } catch (error) {\n if (isAuthError(error)) {\n return { error }\n }\n\n return {\n error: new AuthUnknownError(\n 'Unexpected error during initialization',\n error\n )\n }\n } finally {\n await this._handleVisibilityChange()\n this._debug('#_initialize()', 'end')\n }\n }\n\n /**\n * Gets the session data from a URL string\n */\n private async _getSessionFromURL(flow: AuthFlowType): Promise<\n | {\n data: {\n session: Session\n redirectType: string | null\n returnTo: string | null\n is_new_user: boolean\n }\n error: null\n }\n | {\n data: {\n session: null\n redirectType: null\n returnTo: null\n is_new_user: false\n }\n error: AuthError\n }\n > {\n try {\n const params = parseParametersFromURL(window?.location.href)\n // The auth server appends `?signup=true` to the callback when the login\n // just created a new account (social/OAuth only). Surface it so the app\n // can branch into onboarding; strip it from the URL alongside the tokens.\n const is_new_user = params.signup === 'true'\n if (flow == 'pkce') {\n if (!params.code) {\n throw new AuthPKCEGrantCodeExchangeError('No code detected.')\n }\n\n const { data, error } = await this._exchangeCodeForSession(params.code)\n if (error) throw error\n\n // Remove code (and the signup marker) from URL\n clearURLParameters(['code', 'signup'])\n\n return {\n data: {\n session: data.session,\n redirectType: data.redirectType,\n returnTo: data.returnTo,\n is_new_user\n },\n error: null\n }\n }\n\n if (params.error || params.error_description || params.error_code) {\n throw new AuthImplicitGrantRedirectError(\n params.error_description ||\n 'Error in URL with unspecified error_description',\n {\n error: params.error || 'unspecified_error',\n code: params.error_code || 'unspecified_code'\n }\n )\n }\n\n const {\n provider_token,\n provider_refresh_token,\n access_token,\n refresh_token,\n expires_in,\n expires_at,\n token_type\n } = params\n\n // We only strictly need the token pair. Some flows hand the tokens back\n // in the query string without the full OIDC envelope (`expires_in` /\n // `token_type`); fall back to the access token's own `exp` claim and a\n // `bearer` default instead of rejecting an otherwise-valid callback.\n if (!access_token || !refresh_token) {\n throw new AuthImplicitGrantRedirectError('No session defined in URL')\n }\n\n let expiresAt: number\n let expiresIn: number\n if (expires_in) {\n // Check time is valid\n ;({ expiresAt, expiresIn } = checkExpiresInTime({\n expires_in,\n expires_at,\n refreshTick: AUTO_REFRESH_TICK_DURATION\n }))\n } else {\n ;({ expiresAt, expiresIn } = expiryFromAccessToken(\n access_token,\n expires_at\n ))\n }\n\n const { data: user, error } = await this._getUser(access_token)\n\n if (error || !user) throw error\n\n const session: Session = {\n provider_token,\n provider_refresh_token,\n access_token,\n expires_in: expiresIn,\n expires_at: expiresAt,\n refresh_token,\n token_type: token_type || 'bearer',\n user\n }\n\n // Remove tokens from URL\n clearURLParameters([\n 'access_token',\n 'expires_in',\n 'refresh_token',\n 'token_type',\n 'scope',\n 'signup'\n ])\n this._debug('#_getSessionFromURL()', 'clearing window.location.hash')\n\n return {\n data: {\n session,\n redirectType: params.type,\n returnTo: null,\n is_new_user\n },\n error: null\n }\n } catch (error) {\n this._debug(error)\n if (isAuthError(error)) {\n return {\n data: {\n session: null,\n redirectType: null,\n returnTo: null,\n is_new_user: false\n },\n error\n }\n }\n throw error\n }\n }\n\n private async _exchangeCodeForSession(authCode: string): Promise<\n | {\n data: {\n session: Session\n user: User\n redirectType: string | null\n returnTo: string | null\n }\n error: null\n }\n | {\n data: {\n session: null\n user: null\n redirectType: null\n returnTo: null\n }\n error: AuthError\n }\n > {\n const stored = await loadCodeVerifier(\n this.storage,\n `${this.storageKey}-code-verifier`\n )\n if (!stored) {\n return {\n data: { user: null, session: null, redirectType: null, returnTo: null },\n error: new AuthPKCEGrantCodeExchangeError(\n 'No active PKCE code verifier — the authorization flow has expired or was not started'\n )\n }\n }\n const {\n verifier: codeVerifier,\n redirectType = null,\n returnTo = null\n } = stored\n\n const rawResponse = await _post<Partial<RawAuthResponse>>(\n `${this.domainUrl}/oauth/token`,\n {\n client_id: this.clientId,\n grant_type: 'authorization_code',\n code: authCode,\n code_verifier: codeVerifier,\n ...(this.audience ? { audience: this.audience } : {})\n }\n )\n\n const { data, error } = _sessionResponse(rawResponse)\n\n if (!data) {\n throw new Error('Missing data')\n }\n\n await this.storage.removeItem(`${this.storageKey}-code-verifier`)\n\n if (error) {\n return {\n data: { user: null, session: null, redirectType: null, returnTo: null },\n error\n }\n } else if (!data || !data.session || !data.user) {\n return {\n data: { user: null, session: null, redirectType: null, returnTo: null },\n error: new AuthInvalidTokenResponseError()\n }\n }\n let session = data.session as Session\n if (session) {\n const { data: user, error } = await this._getUser(session.access_token)\n if (error || !user) {\n throw error\n }\n\n session = {\n ...session,\n user\n }\n data.session = session\n\n await this._saveSession(session)\n await this._notifyAllSubscribers('SIGNED_IN', session)\n }\n return {\n data: {\n ...data,\n redirectType: redirectType ?? null,\n returnTo: returnTo ?? null\n } as any,\n error\n }\n }\n\n /**\n * Registers callbacks on the browser / platform, which in-turn run\n * algorithms when the browser window/tab are in foreground. On non-browser\n * platforms it assumes always foreground.\n */\n private async _handleVisibilityChange() {\n this._debug('#_handleVisibilityChange()')\n\n if (!isBrowser() || !window?.addEventListener) {\n if (this.autoRefreshToken) {\n // in non-browser environments the refresh token ticker runs always\n this.startAutoRefresh()\n }\n\n return false\n }\n\n try {\n this.visibilityChangedCallback = async () =>\n await this._onVisibilityChanged(false)\n\n window?.addEventListener(\n 'visibilitychange',\n this.visibilityChangedCallback\n )\n\n // now immediately call the visbility changed callback to setup with the\n // current visbility state\n await this._onVisibilityChanged(true) // initial call\n } catch (error) {\n console.error('_handleVisibilityChange', error)\n }\n }\n\n /**\n * Callback registered with `window.addEventListener('visibilitychange')`.\n */\n private async _onVisibilityChanged(calledFromInitialize: boolean) {\n const methodName = `#_onVisibilityChanged(${calledFromInitialize})`\n this._debug(methodName, 'visibilityState', document.visibilityState)\n\n if (document.visibilityState === 'visible') {\n if (this.autoRefreshToken) {\n // in browser environments the refresh token ticker runs only on focused tabs\n // which prevents race conditions\n this._startAutoRefresh()\n }\n\n if (!calledFromInitialize) {\n // called when the visibility has changed, i.e. the browser\n // transitioned from hidden -> visible so we need to see if the session\n // should be recovered immediately... but to do that we need to acquire\n // the lock first asynchronously\n await this.initializePromise\n\n await this.lock._acquireLock(-1, async () => {\n if (document.visibilityState !== 'visible') {\n this._debug(\n methodName,\n 'acquired the lock to recover the session, but the browser visibilityState is no longer visible, aborting'\n )\n\n // visibility has changed while waiting for the lock, abort\n return\n }\n\n // recover the session\n await this._recoverAndRefresh()\n })\n }\n } else if (document.visibilityState === 'hidden') {\n if (this.autoRefreshToken) {\n this._stopAutoRefresh()\n }\n }\n }\n\n /**\n * Recovers the session from LocalStorage and refreshes\n * Note: this method is async to accommodate for AsyncStorage e.g. in React native.\n */\n private async _recoverAndRefresh() {\n const debugName = '#_recoverAndRefresh()'\n this._debug(debugName, 'begin')\n\n try {\n const currentSession = await getItemAsync(this.storage, this.storageKey)\n this._debug(debugName, 'session from storage', currentSession)\n\n if (!isValidSession(currentSession)) {\n this._debug(debugName, 'session is not valid')\n if (currentSession !== null) {\n await this._removeSession()\n }\n\n return\n }\n\n const timeNow = Math.round(Date.now() / 1000)\n const expiresWithMargin =\n (currentSession.expires_at ?? Infinity) < timeNow + EXPIRY_MARGIN\n\n this._debug(\n debugName,\n `session has${\n expiresWithMargin ? '' : ' not'\n } expired with margin of ${EXPIRY_MARGIN}s`\n )\n\n if (expiresWithMargin) {\n if (this.autoRefreshToken && currentSession.refresh_token) {\n const { error } = await this._callRefreshToken(\n currentSession.refresh_token\n )\n\n if (error) {\n console.error(error)\n\n if (!isAuthRetryableFetchError(error)) {\n this._debug(\n debugName,\n 'refresh failed with a non-retryable error, removing the session',\n error\n )\n await this._removeSession()\n }\n }\n }\n } else {\n // no need to persist currentSession again, as we just loaded it from\n // local storage; persisting it again may overwrite a value saved by\n // another client with access to the same local storage\n this._session = currentSession\n await this._notifyAllSubscribers('SIGNED_IN', currentSession)\n }\n } catch (err) {\n this._debug(debugName, 'error', err)\n\n console.error(err)\n return\n } finally {\n this._debug(debugName, 'end')\n }\n }\n\n /**\n * Removes any registered visibilitychange callback.\n *\n * @see startAutoRefresh\n * @see stopAutoRefresh\n */\n private _removeVisibilityChangedCallback() {\n this._debug('#_removeVisibilityChangedCallback()')\n\n const callback = this.visibilityChangedCallback\n this.visibilityChangedCallback = null\n\n try {\n if (callback && isBrowser() && window?.removeEventListener) {\n window.removeEventListener('visibilitychange', callback)\n }\n } catch (e) {\n console.error('removing visibilitychange callback failed', e)\n }\n }\n\n /**\n * Starts an auto-refresh process in the background. The session is checked\n * every few seconds. Close to the time of expiration a process is started to\n * refresh the session. If refreshing fails it will be retried for as long as\n * necessary.\n *\n * If `autoRefreshToken` is enabled in the client config you don't need to\n * call this function, it will be called for you.\n *\n * On browsers the refresh process works only when the tab/window is in the\n * foreground to conserve resources as well as prevent race conditions and\n * flooding auth with requests. If you call this method any managed\n * visibility change callback will be removed and you must manage visibility\n * changes on your own.\n *\n * On non-browser platforms the refresh process works *continuously* in the\n * background, which may not be desirable. You should hook into your\n * platform's foreground indication mechanism and call these methods\n * appropriately to conserve resources.\n *\n * @example\n * ```ts\n * // React Native / Node: drive the refresh loop on focus events yourself\n * appState.addEventListener('change', state => {\n * if (state === 'active') auth.startAutoRefresh()\n * })\n * ```\n * @see {@link https://faable.com/docs/auth/oauth-flows/refresh-token | Refresh Token}\n * @category Sessions\n */\n async startAutoRefresh() {\n this._removeVisibilityChangedCallback()\n await this._startAutoRefresh()\n }\n\n /**\n * This is the private implementation of {@link #startAutoRefresh}. Use this\n * within the library.\n */\n private async _startAutoRefresh() {\n await this._stopAutoRefresh()\n\n this._debug('#_startAutoRefresh()')\n\n const ticker = setInterval(\n () => this._autoRefreshTokenTick(),\n AUTO_REFRESH_TICK_DURATION\n )\n this.autoRefreshTicker = ticker\n\n if (\n ticker &&\n typeof ticker === 'object' &&\n typeof ticker.unref === 'function'\n ) {\n // ticker is a NodeJS Timeout object that has an `unref` method\n // https://nodejs.org/api/timers.html#timeoutunref\n // When auto refresh is used in NodeJS (like for testing) the\n // `setInterval` is preventing the process from being marked as\n // finished and tests run endlessly. This can be prevented by calling\n // `unref()` on the returned object.\n ticker.unref()\n } else if (\n typeof (globalThis as any).Deno !== 'undefined' &&\n typeof (globalThis as any).Deno.unrefTimer === 'function'\n ) {\n // Same intent as Node's unref(), via the Deno API.\n // https://deno.land/api@latest?unstable&s=Deno.unrefTimer\n ;(globalThis as any).Deno.unrefTimer(ticker)\n }\n\n // run the tick immediately, but in the next pass of the event loop so that\n // #_initialize can be allowed to complete without recursively waiting on\n // itself\n setTimeout(async () => {\n await this.initializePromise\n await this._autoRefreshTokenTick()\n }, 0)\n }\n\n /**\n * This is the private implementation of {@link #stopAutoRefresh}. Use this\n * within the library.\n */\n private async _stopAutoRefresh() {\n this._debug('#_stopAutoRefresh()')\n\n const ticker = this.autoRefreshTicker\n this.autoRefreshTicker = null\n\n if (ticker) {\n clearInterval(ticker)\n }\n }\n\n /**\n * Runs the auto refresh token tick.\n */\n private async _autoRefreshTokenTick() {\n this._debug('#_autoRefreshTokenTick()', 'begin')\n\n try {\n await this.lock._acquireLock(0, async () => {\n try {\n const now = Date.now()\n\n try {\n return await this._useSession(async result => {\n const {\n data: { session }\n } = result\n\n if (!session || !session.refresh_token || !session.expires_at) {\n this._debug('#_autoRefreshTokenTick()', 'no session')\n return\n }\n\n // session will expire in this many ticks (or has already expired if <= 0)\n const expiresInTicks = Math.floor(\n (session.expires_at * 1000 - now) / AUTO_REFRESH_TICK_DURATION\n )\n\n this._debug(\n '#_autoRefreshTokenTick()',\n `access token expires in ${expiresInTicks} ticks, a tick lasts ${AUTO_REFRESH_TICK_DURATION}ms, refresh threshold is ${AUTO_REFRESH_TICK_THRESHOLD} ticks`\n )\n\n if (expiresInTicks <= AUTO_REFRESH_TICK_THRESHOLD) {\n await this._callRefreshToken(session.refresh_token)\n }\n })\n } catch (e: any) {\n console.error(\n 'Auto refresh tick failed with error. This is likely a transient error.',\n e\n )\n }\n } finally {\n this._debug('#_autoRefreshTokenTick()', 'end')\n }\n })\n } catch (e: any) {\n if (e.isAcquireTimeout || e instanceof LockAcquireTimeoutError) {\n this._debug('auto refresh token tick lock not available')\n } else {\n throw e\n }\n }\n }\n\n private async _detectFlowType(): Promise<AuthFlowType | null> {\n const params = parseParametersFromURL(window?.location.href)\n\n const browser = isBrowser()\n\n // PKCE\n if (browser && params.code) {\n return 'pkce'\n }\n\n // Implicit\n if (browser && (params.access_token || params.error_description)) {\n return 'implicit'\n }\n return null\n }\n\n private _scope() {\n return this.scope || 'openid profile email'\n }\n\n private async _getUrlForConnection(\n url: string,\n params: {\n connection?: string\n connection_id?: string\n redirectTo?: string\n returnTo?: string\n scopes?: string\n response_type?: 'code' | 'token'\n queryParams?: { [key: string]: string }\n skipBrowserRedirect?: boolean\n audience?: string\n }\n ) {\n let urlParams: Record<string, any> = params.queryParams || {}\n\n const authorize_params: Record<string, any> = {\n client_id: this.clientId,\n response_type: params.response_type,\n redirect_uri:\n params.redirectTo || this.redirectUri || window?.location.origin,\n scope: params.scopes || this._scope()\n }\n\n if (this.flowType === 'pkce') {\n const [codeChallenge, codeChallengeMethod] =\n await getCodeChallengeAndMethod(\n this.storage,\n this.storageKey,\n false,\n params.returnTo\n )\n\n urlParams = {\n ...urlParams,\n code_challenge: codeChallenge,\n code_challenge_method: codeChallengeMethod\n }\n }\n\n if (params.connection_id) {\n authorize_params.connection_id = params.connection_id\n } else if (params.connection) {\n authorize_params.connection = params.connection\n }\n\n const audience = params.audience ?? this.audience\n if (audience) {\n authorize_params.audience = audience\n }\n\n return `${url}?${new URLSearchParams({\n ...urlParams,\n ...authorize_params\n })}`\n }\n\n /**\n * Starts an OAuth / social login by redirecting the browser to the tenant's\n * `/authorize` endpoint for the chosen connection.\n *\n * In browsers the SDK redirects the current window unless\n * `skipBrowserRedirect` is `true`; the call resolves to the authorization\n * URL so you can drive the navigation yourself. PKCE is used by default in\n * browsers, falling back to the implicit flow elsewhere. Prefer\n * `connection_id` when known — the backend resolves it without an extra\n * lookup; `connection` (by name) is kept for legacy tenants.\n *\n * @example\n * ```ts\n * await auth.signInWithOauthConnection({\n * connection: 'google',\n * redirectTo: 'https://app.example.com/callback'\n * })\n * ```\n * @see {@link https://faable.com/docs/auth/connections | Connections}\n * @see {@link https://faable.com/docs/auth/oauth-flows/authorization-code | Authorization Code with PKCE}\n * @category Sign in\n */\n async signInWithOauthConnection(\n credentials: SignInWithOAuthConnection\n ): Promise<OAuthResponse> {\n return await this._handleConnectionSignIn({\n connection: credentials.connection,\n connection_id: credentials.connection_id,\n redirectTo: credentials?.redirectTo,\n returnTo: credentials?.returnTo,\n scopes: credentials?.scopes,\n queryParams: credentials.queryParams,\n skipBrowserRedirect: credentials.skipBrowserRedirect,\n audience: credentials.audience\n })\n }\n\n /**\n * Signs the user in with a username + password against a database\n * connection on the tenant.\n *\n * The server responds with an HTML form that posts the user back to the\n * tenant's `/login/callback` to complete the OAuth flow; the SDK\n * auto-submits it from the current document. That is why the success path\n * resolves to `{ data: null, error: null }` — the actual session lands on\n * the redirect target, not on this return value. Subscribe with\n * {@link FaableAuthClient.onAuthStateChange} to observe the resulting\n * `SIGNED_IN` event.\n *\n * @example\n * ```ts\n * await auth.signInWithUsernamePassword({\n * username: 'user@example.com',\n * password: '••••••••',\n * redirectTo: 'https://app.example.com/callback'\n * })\n * ```\n * @see {@link https://faable.com/docs/auth/connections | Connections}\n * @category Sign in\n */\n async signInWithUsernamePassword(data: {\n username: string\n password: string\n redirectTo?: string\n state?: string\n audience?: string\n }): Promise<{ data: null; error: AuthError | null }> {\n const audience = data.audience ?? this.audience\n const rawAuthResponse = await _post<string>(\n `${this.domainUrl}/usernamepassword/login`,\n {\n username: data.username,\n password: data.password,\n redirect_uri:\n data.redirectTo || this.redirectUri || window?.location.origin,\n client_id: this.clientId,\n state: data.state,\n ...(audience ? { audience } : {})\n },\n { raw: true }\n )\n\n if (!rawAuthResponse.data || rawAuthResponse.error) {\n return {\n data: null,\n error: new AuthUnknownError(\n rawAuthResponse.error || 'Error in username password login',\n rawAuthResponse.error\n )\n }\n }\n buildAndSubmitForm(rawAuthResponse.data, document)\n return { data: null, error: null }\n }\n\n /**\n * Registers a new user against the tenant's database connection with an\n * email + password, then signs them in — so an email/password signup form\n * can live entirely in the browser with no backend of your own.\n *\n * This calls the public `POST /dbconnections/signup` endpoint (the Faable\n * analogue of Auth0's `/dbconnections/signup`) which creates the user and\n * its credential in one step, then chains\n * {@link FaableAuthClient.signInWithUsernamePassword} to establish the\n * session.\n *\n * **Auto-login navigates the browser.** Like every interactive\n * username/password login in this SDK, the sign-in step submits a form that\n * round-trips through the auth server, so on success the page redirects to\n * your `redirectTo` and the live session is delivered there by\n * {@link FaableAuthClient.initialize} (and a `SIGNED_IN` event). This method\n * only returns synchronously when signup itself fails, or in non-navigating\n * runtimes (e.g. tests).\n *\n * The user is created with `email_verified: false`; any verification /\n * welcome email is driven by the tenant's account settings.\n *\n * @param data The new user's email, password and optional profile fields.\n * @example\n * ```ts\n * const { error } = await auth.signUp({\n * email: 'user@example.com',\n * password: '••••••••',\n * name: 'Ada Lovelace',\n * redirectTo: 'https://app.example.com/callback'\n * })\n * if (error) showError(error.message) // e.g. 'email_taken', 'signup_disabled'\n * // otherwise the browser is already navigating to complete the login\n * ```\n * @see {@link https://faable.com/docs/auth/connections | Connections}\n * @category Sign in\n */\n async signUp(data: {\n email: string\n password: string\n name?: string\n given_name?: string\n family_name?: string\n user_metadata?: Record<string, unknown>\n connection?: string\n redirectTo?: string\n state?: string\n audience?: string\n }): Promise<{ data: null; error: AuthError | null }> {\n if (!data?.email || !data?.password) {\n return {\n data: null,\n error: new AuthUnknownError('email and password are required', null)\n }\n }\n\n const { data: body, error } = await _post(\n `${this.domainUrl}/dbconnections/signup`,\n {\n client_id: this.clientId,\n email: data.email,\n password: data.password,\n ...(data.name ? { name: data.name } : {}),\n ...(data.given_name ? { given_name: data.given_name } : {}),\n ...(data.family_name ? { family_name: data.family_name } : {}),\n ...(data.user_metadata ? { user_metadata: data.user_metadata } : {}),\n ...(data.connection ? { connection: data.connection } : {})\n }\n )\n\n if (error) {\n // `_post` hands back the server's `{ status, message }` body as `data`\n // and its `message` as `error`. Map the HTTP status to a stable\n // ErrorCode so callers can branch without string-matching the message.\n const status = (body as any)?.status as number | undefined\n const code =\n status === 403\n ? 'signup_disabled'\n : status === 409\n ? 'email_exists'\n : undefined\n return {\n data: null,\n error: new AuthApiError(String(error), status ?? 500, code)\n }\n }\n\n // Auto-login through the standard redirect flow (no ROPC grant exists for\n // database connections, so this is the same path a manual login takes).\n return this.signInWithUsernamePassword({\n username: data.email,\n password: data.password,\n redirectTo: data.redirectTo,\n state: data.state,\n audience: data.audience\n })\n }\n\n /**\n * Completes a passwordless login by exchanging an OTP code for a session.\n *\n * Pair this with {@link FaableAuthClient.signInWithPasswordless} called\n * with `type: 'code'`. On success the new session is persisted to storage\n * and a `SIGNED_IN` event is broadcast.\n *\n * @param data The user identifier and the OTP code they received.\n * @example\n * ```ts\n * const { data, error } = await auth.signInWithOtp({\n * username: 'user@example.com',\n * otp: '123456'\n * })\n * ```\n * @see {@link https://faable.com/docs/auth/passwordless | Passwordless Authentication}\n * @category Sign in\n */\n async signInWithOtp(data: {\n username: string\n otp: string\n audience?: string\n }): Promise<AuthResponse> {\n const audience = data.audience ?? this.audience\n const rawResponse = await _post<Partial<RawAuthResponse>>(\n `${this.domainUrl}/oauth/token`,\n {\n client_id: this.clientId,\n grant_type: 'http://auth0.com/oauth/grant-type/passwordless/otp',\n username: data.username,\n otp: data.otp,\n ...(audience ? { audience } : {})\n }\n )\n\n const { data: sessionData, error } = _sessionResponse(rawResponse)\n\n if (error) {\n return { data: { user: null, session: null }, error }\n }\n\n if (!sessionData || !sessionData.session) {\n return {\n data: { user: null, session: null },\n error: new AuthInvalidTokenResponseError()\n }\n }\n\n const session = sessionData.session as Session\n const { data: user, error: userError } = await this._getUser(\n session.access_token\n )\n\n if (userError || !user) {\n return {\n data: { user: null, session: null },\n error:\n userError || new AuthUnknownError('Could not fetch user info', null)\n }\n }\n\n session.user = user\n await this._saveSession(session)\n await this._notifyAllSubscribers('SIGNED_IN', session)\n\n return {\n data: { user: session.user, session },\n error: null\n }\n }\n\n /**\n * Starts a passwordless login flow by emailing the user either an OTP code\n * or a magic link.\n *\n * - `type: 'code'` sends a short code the user pastes into your UI; finish\n * the flow with {@link FaableAuthClient.signInWithOtp}.\n * - `type: 'link'` sends a clickable link that lands on your `redirectUri`\n * with the tokens already attached, processed by\n * {@link FaableAuthClient.initialize} on page load.\n *\n * @param data The user's email and the delivery mechanism.\n * @example\n * ```ts\n * await auth.signInWithPasswordless({\n * email: 'user@example.com',\n * type: 'code'\n * })\n * ```\n * @see {@link https://faable.com/docs/auth/passwordless | Passwordless Authentication}\n * @category Sign in\n */\n async signInWithPasswordless(data: {\n email: string\n type: 'code' | 'link'\n audience?: string\n }): Promise<{ data: any; error: AuthError | null }> {\n const audience = data.audience ?? this.audience\n const response = await _post(`${this.domainUrl}/passwordless/start`, {\n client_id: this.clientId,\n email: data.email,\n send: data.type,\n ...(audience ? { audience } : {})\n })\n\n return { data: response.data, error: response.error }\n }\n\n /**\n * Triggers a \"change your password\" email for a database-connection user.\n *\n * The current session is unaffected — the user clicks the link in the\n * email and completes the reset on the tenant's hosted pages. The promise\n * resolves once the email has been queued.\n *\n * @param params The user's email address.\n * @example\n * ```ts\n * await auth.changePassword({ email: 'user@example.com' })\n * ```\n * @see {@link https://faable.com/docs/auth/connections | Connections}\n * @category Account\n */\n async changePassword(params: {\n email: string\n }): Promise<{ data: unknown; error: AuthError | null }> {\n if (!params?.email) {\n return {\n data: null,\n error: new AuthUnknownError('email is required', null)\n }\n }\n\n const { data, error } = await _post(\n `${this.domainUrl}/dbconnections/change_password`,\n { email: params.email }\n )\n return {\n data: data ?? null,\n error: error ? new AuthUnknownError(String(error), error) : null\n }\n }\n\n /**\n * Starts a verified email change for the currently signed-in user.\n *\n * The user must be authenticated — the call is made with the session's\n * access token, and the auth server only lets a user change their own\n * email. It creates a verification ticket and emails the user; the change\n * is applied only after they click the link, which the server handles and\n * then redirects to `redirect_uri`. The current session is unaffected until\n * then.\n *\n * @param params The new email plus optional verification policy.\n * - `verification_mode`: `'new_only'` verifies just the new address;\n * `'old_and_new'` also requires confirming from the old one. When\n * omitted the account's default policy applies.\n * - `redirect_uri`: where the server sends the user after they verify.\n * @example\n * ```ts\n * const { data, error } = await auth.changeEmail({\n * new_email: 'new@example.com',\n * redirect_uri: 'https://app.example.com/account'\n * })\n * // data: { status: 'verification_sent', ticket_id, verification_mode }\n * ```\n * @see {@link https://faable.com/docs/auth/change-email | Change Email}\n * @category Account\n */\n async changeEmail(params: {\n new_email: string\n verification_mode?: 'new_only' | 'old_and_new'\n redirect_uri?: string\n }): Promise<{ data: unknown; error: AuthError | null }> {\n if (!params?.new_email) {\n return {\n data: null,\n error: new AuthUnknownError('new_email is required', null)\n }\n }\n\n const { data: sessionData, error: sessionError } = await this.getSession()\n const session = sessionData?.session\n if (sessionError || !session) {\n return {\n data: null,\n error: sessionError || new AuthSessionMissingError()\n }\n }\n\n const user_id = session.user?.sub\n if (!user_id) {\n return { data: null, error: new AuthSessionMissingError() }\n }\n\n const { data, error } = await _post(\n `${this.domainUrl}/user/${user_id}/change-email`,\n {\n new_email: params.new_email,\n ...(params.verification_mode\n ? { verification_mode: params.verification_mode }\n : {}),\n ...(params.redirect_uri ? { redirect_uri: params.redirect_uri } : {})\n },\n { token: session.access_token }\n )\n return {\n data: data ?? null,\n error: error ? new AuthUnknownError(String(error), error) : null\n }\n }\n\n /**\n * Builds the tenant's `/authorize` URL without redirecting the browser.\n *\n * Useful when you need to render a login link, open the page in a popup,\n * or hand the URL to a different runtime (e.g. a webview). For the\n * everyday \"click → redirect\" flow use {@link FaableAuthClient.authorize}\n * or {@link FaableAuthClient.signInWithOauthConnection}.\n *\n * The redirect target is resolved with this precedence:\n * `options.redirectTo` → `config.redirectUri` → `window.location.origin`.\n *\n * @returns The fully-qualified authorize URL.\n * @example\n * ```ts\n * const url = auth.buildAuthorizeUrl({\n * connection: 'google',\n * redirectTo: 'https://app.example.com/callback'\n * })\n * window.open(url, 'login', 'popup')\n * ```\n * @see {@link https://faable.com/docs/auth/oauth-flows/authorization-code | Authorization Code with PKCE}\n * @category Authorize URLs\n */\n buildAuthorizeUrl(\n options: {\n connection?: string\n redirectTo?: string\n scope?: string\n response_type?: string\n audience?: string\n } = {}\n ): string {\n const params: Record<string, string | undefined> = {\n client_id: this.clientId,\n redirect_uri:\n options.redirectTo || this.redirectUri || window?.location.origin,\n response_type: resolveResponseType(options, isBrowser()),\n audience: options.audience ?? this.audience,\n scope: options.scope,\n connection: options.connection\n }\n\n const definedParams = Object.fromEntries(\n Object.entries(params).filter(([, value]) => !!value)\n ) as Record<string, string>\n\n return `${this.domainUrl}/authorize?${new URLSearchParams(definedParams).toString()}`\n }\n\n /**\n * Redirects the current window to the tenant's `/authorize` endpoint.\n *\n * Fire-and-forget: there is no return value because the browser navigates\n * away. The session lands back on your `redirectUri`, where\n * {@link FaableAuthClient.initialize} consumes it on the next page load.\n *\n * @example\n * ```ts\n * auth.authorize({\n * response_type: 'code',\n * redirectTo: 'https://app.example.com/callback'\n * })\n * ```\n * @see {@link https://faable.com/docs/auth/oauth-flows/authorization-code | Authorization Code with PKCE}\n * @category Authorize URLs\n */\n authorize(options: {\n redirectTo?: string\n scope?: string\n response_type: string\n audience?: string\n }) {\n const url = this.buildAuthorizeUrl(options)\n windowHelpers.redirect(url)\n }\n\n private async _handleConnectionSignIn(options: {\n connection?: string\n connection_id?: string\n redirectTo?: string\n returnTo?: string\n scopes?: string\n queryParams?: { [key: string]: string }\n skipBrowserRedirect?: boolean\n audience?: string\n }) {\n const url: string = await this._getUrlForConnection(\n `${this.domainUrl}/authorize`,\n {\n response_type: isBrowser() ? 'code' : 'token',\n connection: options.connection,\n connection_id: options.connection_id,\n redirectTo: options.redirectTo,\n returnTo: options.returnTo,\n scopes: options.scopes,\n queryParams: options.queryParams,\n audience: options.audience\n }\n )\n\n this._debug('#_handleConnectionSignIn()', 'options', options, 'url', url)\n\n // try to open on the browser\n if (isBrowser() && !options.skipBrowserRedirect) {\n window?.location.assign(url)\n }\n\n return { data: { url }, error: null }\n }\n\n /**\n * Adopts an externally-provided session into the client.\n *\n * Decodes the access token to find its expiry; refreshes immediately when\n * already expired, otherwise fetches the user info to round-trip the\n * session. Persists the result and broadcasts `SIGNED_IN`. An invalid\n * refresh or access token surfaces as `error` on the returned object.\n *\n * @param currentSession Minimal session shape — an access token and a\n * refresh token. Other fields are recomputed.\n * @example\n * ```ts\n * // After receiving tokens from a custom server-side handoff\n * await auth.setSession({ access_token, refresh_token })\n * ```\n * @see {@link https://faable.com/docs/auth/oidc/userinfo | UserInfo}\n * @category Sessions\n */\n async setSession(currentSession: {\n access_token: string\n refresh_token: string\n }): Promise<AuthResponse> {\n await this.initializePromise\n\n return await this.lock._acquireLock(-1, async () => {\n return await this._setSession(currentSession)\n })\n }\n\n /**\n * Returns the session, refreshing it if necessary.\n *\n * The session returned can be `null` if no user is signed in or the last\n * one has logged out.\n *\n * **IMPORTANT:** This method loads values directly from the storage\n * attached to the client. If that storage is based on request cookies (for\n * example, on the server) the values in it may not be authentic and\n * therefore it's strongly advised against using this method and its\n * results in such circumstances — a warning will be emitted when the\n * storage exposes `isServer: true`. Re-fetch the user with a verified\n * call (or verify the access token yourself) before trusting it.\n *\n * @example\n * ```ts\n * const { data, error } = await auth.getSession()\n * if (data.session) console.log(data.session.user)\n * ```\n * @see {@link https://faable.com/docs/auth/oidc/userinfo | UserInfo}\n * @category Sessions\n */\n async getSession() {\n await this.initializePromise\n\n const result = await this.lock._acquireLock(-1, async () => {\n return this._useSession(async result => {\n return result\n })\n })\n\n return result\n }\n\n /**\n * Use instead of {@link #getSession} inside the library. It is\n * semantically usually what you want, as getting a session involves some\n * processing afterwards that requires only one client operating on the\n * session at once across multiple tabs or processes.\n */\n private async _useSession<R>(\n fn: (\n result:\n | {\n data: {\n session: Session\n }\n error: null\n }\n | {\n data: {\n session: null\n }\n error: AuthError\n }\n | {\n data: {\n session: null\n }\n error: null\n }\n ) => Promise<R>\n ): Promise<R> {\n this._debug('#_useSession', 'begin')\n\n try {\n // the use of __loadSession here is the only correct use of the function!\n const result = await this.__loadSession()\n\n return await fn(result)\n } finally {\n this._debug('#_useSession', 'end')\n }\n }\n\n /**\n * NEVER USE DIRECTLY!\n *\n * Always use {@link #_useSession}.\n */\n private async __loadSession(): Promise<\n | {\n data: {\n session: Session\n }\n error: null\n }\n | {\n data: {\n session: null\n }\n error: AuthError\n }\n | {\n data: {\n session: null\n }\n error: null\n }\n > {\n this._debug('#__loadSession()', 'begin')\n\n if (!this.lock.lockAcquired) {\n this._debug(\n '#__loadSession()',\n 'used outside of an acquired lock!',\n new Error().stack\n )\n }\n\n try {\n let currentSession: Session | null = null\n\n const maybeSession = await getItemAsync(this.storage, this.storageKey)\n\n this._debug('#getSession()', 'session from storage', maybeSession)\n\n if (maybeSession !== null) {\n if (isValidSession(maybeSession)) {\n currentSession = maybeSession\n } else {\n this._debug('#getSession()', 'session from storage is not valid')\n await this._removeSession()\n }\n }\n\n if (!currentSession) {\n return { data: { session: null }, error: null }\n }\n\n const hasExpired = currentSession.expires_at\n ? currentSession.expires_at <= Date.now() / 1000\n : false\n\n this._debug(\n '#__loadSession()',\n `session has${hasExpired ? '' : ' not'} expired`,\n 'expires_at',\n currentSession.expires_at\n )\n\n if (!hasExpired) {\n if (this.storage.isServer) {\n const proxySession: Session = new Proxy(currentSession, {\n get(target: any, prop: string, receiver: any) {\n if (prop === 'user') {\n // only show warning when the user object is being accessed from the server\n console.warn(\n 'Reading `session.user` from a server-side cookie store can be insecure: the value is whatever the cookie contains and has not been verified against Faable Auth. Re-fetch the user with `auth.getUser()` (or verify the access token yourself) before trusting it on the server.'\n )\n }\n return Reflect.get(target, prop, receiver)\n }\n })\n currentSession = proxySession\n }\n\n return { data: { session: currentSession }, error: null }\n }\n\n const { session, error } = await this._callRefreshToken(\n currentSession.refresh_token\n )\n if (error) {\n return { data: { session: null }, error }\n }\n\n return { data: { session }, error: null }\n } finally {\n this._debug('#__loadSession()', 'end')\n }\n }\n\n private async _removeSession() {\n this._debug('#_removeSession()')\n this._session = null\n await this.storage.removeItem(this.storageKey)\n }\n\n protected async _setSession(currentSession: {\n access_token: string\n refresh_token: string\n }): Promise<AuthResponse> {\n try {\n if (!currentSession.access_token || !currentSession.refresh_token) {\n throw new AuthSessionMissingError()\n }\n\n const timeNow = Date.now() / 1000\n let expiresAt = timeNow\n let hasExpired = true\n let session: Session | null = null\n const payload = decodeJWTPayload(currentSession.access_token)\n if (payload.exp) {\n expiresAt = payload.exp\n hasExpired = expiresAt <= timeNow\n }\n\n if (hasExpired) {\n const { session: refreshedSession, error } =\n await this._callRefreshToken(currentSession.refresh_token)\n if (error) {\n return { data: { user: null, session: null }, error: error }\n }\n\n if (!refreshedSession) {\n return { data: { user: null, session: null }, error: null }\n }\n session = refreshedSession\n } else {\n const { data: user, error } = await this._getUser(\n currentSession.access_token\n )\n if (error || !user) {\n throw error\n }\n session = {\n access_token: currentSession.access_token,\n refresh_token: currentSession.refresh_token,\n user,\n token_type: 'bearer',\n expires_in: expiresAt - timeNow,\n expires_at: expiresAt\n }\n await this._saveSession(session)\n await this._notifyAllSubscribers('SIGNED_IN', session)\n }\n\n return { data: { user: session.user, session }, error: null }\n } catch (error) {\n if (isAuthError(error)) {\n return { data: { session: null, user: null }, error }\n }\n\n throw error\n }\n }\n\n /**\n * set currentSession and currentUser\n * process to _startAutoRefreshToken if possible\n */\n private async _saveSession(session: Session) {\n this._debug('#_saveSession()', session)\n this._session = session\n\n await setItemAsync(this.storage, this.storageKey, session)\n }\n\n private async _getUser(access_token: string) {\n if (!access_token) throw new Error('Cannot fetch user without token')\n this._debug('#_getUser() begin')\n const res = await _get<User>(`${this.domainUrl}/me`, {\n token: access_token\n })\n this._debug('#_getUser() end')\n return { data: res.data, error: res.error }\n }\n\n private async _callRefreshToken(refreshToken: string) {\n if (!refreshToken) {\n throw new AuthSessionMissingError()\n }\n\n // refreshing is already in progress\n if (this.refreshingDeferred) {\n return this.refreshingDeferred.promise\n }\n\n const debugName = `#_callRefreshToken(${refreshToken.substring(0, 5)}...)`\n\n this._debug(debugName, 'begin')\n\n try {\n this.refreshingDeferred = new Deferred<CallRefreshTokenResult>()\n\n const { data, error } = await withTimeout(\n this._refreshAccessToken(refreshToken),\n REFRESH_TIMEOUT_MS,\n 'Token refresh timed out'\n )\n if (error) throw error\n if (!data.session) throw new AuthSessionMissingError()\n\n await this._saveSession(data.session)\n await this._notifyAllSubscribers('TOKEN_REFRESHED', data.session)\n\n const result = { session: data.session, error: null }\n\n this.refreshingDeferred.resolve(result)\n\n return result\n } catch (error) {\n this._debug(debugName, 'error', error)\n\n if (isAuthError(error)) {\n const result = { session: null, error }\n\n if (!isAuthRetryableFetchError(error)) {\n await this._removeSession()\n await this._notifyAllSubscribers('SIGNED_OUT', null)\n }\n\n this.refreshingDeferred?.resolve(result)\n\n return result\n }\n\n this.refreshingDeferred?.reject(error)\n throw error\n } finally {\n this.refreshingDeferred = null\n this._debug(debugName, 'end')\n }\n }\n\n /**\n * Generates a new JWT.\n * @param refreshToken A valid refresh token that was returned on login.\n */\n private async _refreshAccessToken(\n refreshToken: string\n ): Promise<AuthResponse> {\n const debugName = `#_refreshAccessToken(${refreshToken.substring(0, 5)}...)`\n this._debug(debugName, 'begin')\n\n try {\n const startedAt = Date.now()\n\n // will attempt to refresh the token with exponential backoff\n\n return await retryable(\n async attempt => {\n if (attempt > 0) {\n await sleep(200 * Math.pow(2, attempt - 1)) // 200, 400, 800, ...\n }\n\n this._debug(debugName, 'refreshing attempt', attempt)\n\n // return await _post(`${this.url}/token?grant_type=refresh_token`, {\n // body: { refresh_token: refreshToken },\n // headers: this.headers,\n // xform: _sessionResponse,\n // });\n const rawResponse = await _post<Partial<RawAuthResponse>>(\n `${this.domainUrl}/oauth/token`,\n {\n client_id: this.clientId,\n grant_type: 'refresh_token',\n refresh_token: refreshToken,\n ...(this.audience ? { audience: this.audience } : {})\n }\n )\n if (rawResponse.error) {\n throw new AuthUnknownError(\n `Refresh token request failed: ${rawResponse.error}`,\n rawResponse.error\n )\n }\n const session_res = _sessionResponse(rawResponse)\n\n if (!session_res.data.session?.access_token) {\n throw new AuthInvalidTokenResponseError()\n }\n const { data: user, error } = await this._getUser(\n session_res.data.session?.access_token\n )\n\n if (error) {\n throw new AuthUnknownError('Could not fetch user info', error)\n }\n if (!user) {\n throw new AuthUnknownError('Refresh response missing user', null)\n }\n\n const x = {\n data: {\n session: {\n ...session_res.data.session,\n user\n },\n user\n },\n error: null\n }\n // this._debug(x);\n return x\n },\n (attempt, error) => {\n const nextBackOffInterval = 200 * Math.pow(2, attempt)\n return (\n error &&\n isAuthRetryableFetchError(error) &&\n // retryable only if the request can be sent before the backoff overflows the tick duration\n Date.now() + nextBackOffInterval - startedAt <\n AUTO_REFRESH_TICK_DURATION\n )\n }\n )\n } catch (error) {\n this._debug(debugName, 'error', error)\n\n if (isAuthError(error)) {\n return { data: { session: null, user: null }, error }\n }\n throw error\n } finally {\n this._debug(debugName, 'end')\n }\n }\n\n private async _notifyAllSubscribers(\n event: AuthChangeEvent,\n session: Session | null,\n broadcast = true\n ) {\n const debugName = `#_notifyAllSubscribers(${event})`\n this._debug(debugName, 'begin', session, `broadcast = ${broadcast}`)\n try {\n await this.broadcastSync.notify(event, session, broadcast)\n } finally {\n this._debug(debugName, 'end')\n }\n }\n\n /**\n * Signs the user out and clears the session from storage.\n *\n * In a browser context this removes the persisted session and broadcasts a\n * `SIGNED_OUT` event to every tab listening on the same `storageKey`. The\n * access token JWT itself remains valid until its `exp` — keep that\n * expiry short.\n *\n * Scopes:\n * - `'global'` (default) — invalidate all refresh tokens for the user\n * - `'local'` — only clear this client's storage\n * - `'others'` — invalidate every refresh token except this device's; no\n * `SIGNED_OUT` event is fired locally\n *\n * @example\n * ```ts\n * await auth.signOut() // global — all sessions for this user\n * await auth.signOut({ scope: 'local' }) // only this device\n * ```\n * @see {@link https://faable.com/docs/auth/oidc/logout | Logout}\n * @category Sign out\n */\n async signOut(\n options: SignOut = { scope: 'global' }\n ): Promise<{ error: AuthError | null }> {\n await this.initializePromise\n\n return await this.lock._acquireLock(-1, async () => {\n return await this._signOut(options)\n })\n }\n\n protected async _signOut(\n { scope }: SignOut = { scope: 'global' }\n ): Promise<{ error: AuthError | null }> {\n return await this._useSession(async result => {\n const { data, error: sessionError } = result\n if (sessionError) {\n return { error: sessionError }\n }\n const accessToken = data.session?.access_token\n if (accessToken) {\n const { error } = await this.api.signOut({\n client_id: this.clientId\n })\n if (error) {\n // ignore 404s since user might not exist anymore\n // ignore 401s since an invalid or expired JWT should sign out the current session\n if (\n !(\n isAuthApiError(error) &&\n (error.status === 404 || error.status === 401)\n )\n ) {\n return { error }\n }\n }\n }\n if (scope !== 'others') {\n await this._removeSession()\n await this.storage.removeItem(`${this.storageKey}-code-verifier`)\n await this._notifyAllSubscribers('SIGNED_OUT', null)\n }\n return { error: null }\n })\n }\n\n /**\n * Subscribes to auth-state changes for this client.\n *\n * The callback fires for `INITIAL_SESSION` once shortly after subscribing\n * (so consumers don't have to special-case \"no event yet\"), and then for\n * every `SIGNED_IN`, `SIGNED_OUT`, `TOKEN_REFRESHED`, `PASSWORD_RECOVERY`,\n * and `USER_UPDATED` event. Events are broadcast across tabs through\n * `BroadcastChannel`, so a sign-in or sign-out in one tab reaches every\n * other tab using the same `storageKey`.\n *\n * @param callback Invoked with the event name and the new session (or\n * `null` on `SIGNED_OUT`). Can return a promise — the SDK awaits it.\n * @returns `{ data: { subscription } }` — call `subscription.unsubscribe()`\n * to stop listening.\n * @example\n * ```ts\n * const { data: { subscription } } = auth.onAuthStateChange((event, session) => {\n * if (event === 'SIGNED_IN') console.log('Welcome', session?.user.email)\n * })\n * // later\n * subscription.unsubscribe()\n * ```\n * @see {@link https://faable.com/docs/auth/get-started | Get Started with Faable Auth}\n * @category Sessions\n */\n onAuthStateChange(\n callback: (\n event: AuthChangeEvent,\n session: Session | null\n ) => void | Promise<void>\n ): {\n data: { subscription: Subscription }\n } {\n const { subscription } = this.broadcastSync.subscribe(callback)\n this._debug(\n '#onAuthStateChange()',\n 'registered callback with id',\n subscription.id\n )\n ;(async () => {\n await this.initializePromise\n await this.lock._acquireLock(-1, async () => {\n this._emitInitialSession(subscription)\n })\n })()\n\n return { data: { subscription } }\n }\n\n private async _emitInitialSession(subscription: Subscription): Promise<void> {\n return await this._useSession(async result => {\n try {\n const {\n data: { session },\n error\n } = result\n if (error) throw error\n\n await subscription.callback('INITIAL_SESSION', session)\n this._debug(\n 'INITIAL_SESSION',\n 'callback id',\n subscription.id,\n 'session',\n session\n )\n } catch (err) {\n await subscription.callback('INITIAL_SESSION', null)\n this._debug(\n 'INITIAL_SESSION',\n 'callback id',\n subscription.id,\n 'error',\n err\n )\n console.error(err)\n }\n })\n }\n\n /**\n * Forces a new session by exchanging a refresh token regardless of expiry.\n *\n * Normally the SDK handles refresh transparently via the auto-refresh\n * ticker; call this only when you need to force an immediate refresh —\n * e.g. right after a server-side action that changed the user's claims.\n * Omit `currentSession` to reuse whatever {@link FaableAuthClient.getSession}\n * returns.\n *\n * @param currentSession Optional session shape carrying the refresh token\n * to exchange. When passed it must include `refresh_token`.\n * @example\n * ```ts\n * const { data, error } = await auth.refreshSession()\n * ```\n * @see {@link https://faable.com/docs/auth/oauth-flows/refresh-token | Refresh Token}\n * @category Sessions\n */\n async refreshSession(currentSession?: {\n refresh_token: string\n }): Promise<AuthResponse> {\n await this.initializePromise\n\n return await this.lock._acquireLock(-1, async () => {\n return await this._refreshSession(currentSession)\n })\n }\n\n protected async _refreshSession(currentSession?: {\n refresh_token: string\n }): Promise<AuthResponse> {\n try {\n return await this._useSession(async result => {\n if (!currentSession) {\n const { data, error } = result\n if (error) {\n throw error\n }\n\n currentSession = data.session ?? undefined\n }\n\n if (!currentSession?.refresh_token) {\n throw new AuthSessionMissingError()\n }\n\n const { session, error } = await this._callRefreshToken(\n currentSession.refresh_token\n )\n if (error) {\n return { data: { user: null, session: null }, error: error }\n }\n\n if (!session) {\n return { data: { user: null, session: null }, error: null }\n }\n\n return { data: { user: (session as any).user, session }, error: null }\n })\n } catch (error) {\n if (isAuthError(error)) {\n return { data: { user: null, session: null }, error }\n }\n\n throw error\n }\n }\n}\n","import { AuthenticationResult } from './lib/types'\n\nexport const parseAuthenticationResult = (\n queryString: string\n): AuthenticationResult => {\n if (queryString.indexOf('#') > -1) {\n queryString = queryString.substring(0, queryString.indexOf('#'))\n }\n\n const searchParams = new URLSearchParams(queryString)\n\n return {\n state: searchParams.get('state')!,\n code: searchParams.get('code') || undefined,\n error: searchParams.get('error') || undefined,\n error_description: searchParams.get('error_description') || undefined\n }\n}\n\nconst stripUndefined = (params: any) => {\n return Object.keys(params)\n .filter(k => typeof params[k] !== 'undefined')\n .reduce((acc, key) => ({ ...acc, [key]: params[key] }), {})\n}\n\nexport const createQueryParams = ({ clientId: client_id, ...params }: any) => {\n return new URLSearchParams(\n stripUndefined({ client_id, ...params })\n ).toString()\n}\n\n/**\n * @ignore\n */\nexport const getTokenIssuer = (\n issuer: string | undefined,\n domainUrl: string\n) => {\n if (issuer) {\n return issuer.startsWith('https://') ? issuer : `https://${issuer}`\n }\n\n return `${domainUrl}`\n}\n\n// Normaliza el `domain` para que dé igual cómo lo pase el usuario: con o sin\n// protocolo, con trailing slash, o incluso con protocolo duplicado (el valor\n// que el dashboard copia ya trae `https://`). Siempre devuelve\n// `<protocol>://<host>` sin barra final.\nexport const getDomain = (domainUrl: string) => {\n const raw = (domainUrl ?? '').trim().replace(/\\/+$/, '')\n // Usuario pasó protocolo (uno o varios, p.ej. \"https://https://x\"):\n // preservar http/https intencionado y descartar duplicados.\n const match = raw.match(/^(https?):\\/\\/(.*)$/i)\n if (match) {\n const host = match[2].replace(/^(https?:\\/\\/)+/i, '')\n return `${match[1].toLowerCase()}://${host}`\n }\n // Sin protocolo: heredar el del documento actual en browser, https fuera de él.\n const protocol =\n typeof location !== 'undefined' && location?.protocol\n ? location.protocol.replace(/:$/, '')\n : 'https'\n return `${protocol}://${raw}`\n}\n\nexport const encode = (value: string) => btoa(value)\nexport const decode = (value: string) => atob(value)\n\n// https://stackoverflow.com/questions/30106476/\nconst decodeB64 = (input: string) =>\n decodeURIComponent(\n atob(input)\n .split('')\n .map(c => {\n return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2)\n })\n .join('')\n )\n\nconst urlEncodeB64 = (input: string) => {\n const b64Chars: { [index: string]: string } = { '+': '-', '/': '_', '=': '' }\n return input.replace(/[+/=]/g, (m: string) => b64Chars[m])\n}\n\nexport const urlDecodeB64 = (input: string) =>\n decodeB64(input.replace(/_/g, '/').replace(/-/g, '+'))\n\nexport const bufferToBase64UrlEncoded = (input: number[] | Uint8Array) => {\n const ie11SafeInput = new Uint8Array(input)\n return urlEncodeB64(\n window.btoa(String.fromCharCode(...Array.from(ie11SafeInput)))\n )\n}\n\nexport const parseNumber = (value: any): number | undefined => {\n if (typeof value !== 'string') {\n return value\n }\n return parseInt(value, 10) || undefined\n}\n\n/**\n * @ignore\n */\nexport const buildIsAuthenticatedCookieName = (clientId: string) =>\n `auth0.${clientId}.is.authenticated`\n","/**\n * Races a promise against a deadline. If `promise` settles first the result\n * passes through; if the deadline elapses first the returned promise rejects\n * with an Error whose message is `timeoutMessage`. The internal timer is\n * cleared once `promise` settles, regardless of outcome.\n */\nexport const withTimeout = <T>(\n promise: Promise<T>,\n timeoutMs: number,\n timeoutMessage: string\n): Promise<T> => {\n let timer: ReturnType<typeof setTimeout> | undefined\n const timeoutPromise = new Promise<T>((_, reject) => {\n timer = setTimeout(() => reject(new Error(timeoutMessage)), timeoutMs)\n })\n return Promise.race([\n promise.finally(() => {\n if (timer !== undefined) clearTimeout(timer)\n }),\n timeoutPromise\n ])\n}\n","import { FaableAuthClient } from './FaableAuthClient'\nimport { FaableAuthClientConfig } from './lib/types'\n\n/**\n * Creates a {@link FaableAuthClient} bound to a Faable Auth tenant.\n *\n * This is the recommended entry point for app code. The returned client\n * begins initializing its session in the background as soon as it's created,\n * so you can start subscribing to events or triggering sign-ins right away.\n *\n * @param config Tenant settings. `domain` and `clientId` are required.\n * @example\n * ```ts\n * import { createClient } from '@faable/auth-js'\n *\n * export const auth = createClient({\n * domain: '<faableauth_domain>',\n * clientId: '<client_id>',\n * redirectUri: window.location.origin\n * })\n * ```\n * @see {@link https://faable.com/docs/auth/get-started | Get Started with Faable Auth}\n * @see {@link https://faable.com/docs/auth/clients | Clients}\n * @category Getting started\n */\nexport const createClient = (config: FaableAuthClientConfig) => {\n return new FaableAuthClient(config)\n}\n","import { BaseLogOptions } from '../BaseLog'\nimport { LockFunc } from '../lock/locks'\nimport { AuthError } from './errors'\n\n/**\n * @ignore\n */\nexport interface AuthenticationResult {\n state: string\n code?: string\n error?: string\n error_description?: string\n}\n\n/**\n * OpenID Connect–style user profile returned by the tenant's userinfo\n * endpoint.\n *\n * Standard OIDC claims are typed explicitly; provider-specific or custom\n * claims (e.g. `org_id`, `roles`) surface through the index signature.\n *\n * @see {@link https://faable.com/docs/auth/oidc/userinfo | UserInfo}\n */\nexport class User {\n name?: string\n profile?: string\n picture?: string\n email?: string\n website?: string\n birthdate?: string\n locale?: string\n sub?: string;\n [key: string]: any\n}\n\n/**\n * The state of the application before the user was redirected to the login page.\n */\nexport type AppState = {\n returnTo?: string\n [key: string]: any\n}\n\nexport interface AuthorizationParams {\n /**\n * - `'page'`: displays the UI with a full page view\n * - `'popup'`: displays the UI with a popup window\n * - `'touch'`: displays the UI in a way that leverages a touch interface\n * - `'wap'`: displays the UI with a \"feature phone\" type interface\n */\n display?: 'page' | 'popup' | 'touch' | 'wap'\n\n /**\n * - `'none'`: do not prompt user for login or consent on reauthentication\n * - `'login'`: prompt user for reauthentication\n * - `'consent'`: prompt user for consent before processing request\n * - `'select_account'`: prompt user to select an account\n */\n prompt?: 'none' | 'login' | 'consent' | 'select_account'\n\n /**\n * Maximum allowable elapsed time (in seconds) since authentication.\n * If the last time the user authenticated is greater than this value,\n * the user must be reauthenticated.\n */\n max_age?: string | number\n\n /**\n * The space-separated list of language tags, ordered by preference.\n * For example: `'fr-CA fr en'`.\n */\n ui_locales?: string\n\n /**\n * Previously issued ID Token.\n */\n id_token_hint?: string\n\n /**\n * Provides a hint to Auth0 as to what flow should be displayed.\n * The default behavior is to show a login page but you can override\n * this by passing 'signup' to show the signup page instead.\n *\n * This only affects the New Universal Login Experience.\n */\n screen_hint?: 'signup' | 'login' | string\n\n /**\n * The user's email address or other identifier. When your app knows\n * which user is trying to authenticate, you can provide this parameter\n * to pre-fill the email box or select the right session for sign-in.\n *\n * This currently only affects the classic Lock experience.\n */\n login_hint?: string\n\n acr_values?: string\n\n /**\n * The default scope to be used on authentication requests.\n *\n * This defaults to `profile email` if not set. If you are setting extra scopes and require\n * `profile` and `email` to be included then you must include them in the provided scope.\n *\n * Note: The `openid` scope is **always applied** regardless of this setting.\n */\n scope?: string\n\n /**\n * The default audience to be used for requesting API access.\n */\n audience?: string\n\n /**\n * The name of the connection configured for your application.\n * If null, it will redirect to the Auth0 Login Page and show\n * the Login Widget.\n */\n connection?: string\n\n /**\n * The Id of an organization to log in to.\n *\n * This will specify an `organization` parameter in your user's login request and will add a step to validate\n * the `org_id` claim in your user's ID Token.\n */\n organization?: string\n\n /**\n * The Id of an invitation to accept. This is available from the user invitation URL that is given when participating in a user invitation flow.\n */\n invitation?: string\n\n /**\n * The default URL where Auth0 will redirect your browser to with\n * the authentication result. It must be whitelisted in\n * the \"Allowed Callback URLs\" field in your Auth0 Application's\n * settings. If not provided here, it should be provided in the other\n * methods that provide authentication.\n */\n redirect_uri?: string\n\n /**\n * If you need to send custom parameters to the Authorization Server,\n * make sure to use the original parameter name.\n */\n [key: string]: any\n}\n\ninterface BaseLoginOptions {\n /**\n * URL parameters that will be sent back to the Authorization Server. This can be known parameters\n * defined by Auth0 or custom parameters that you define.\n */\n authorizationParams?: AuthorizationParams\n}\n\nexport interface RedirectLoginOptions<\n TAppState = any\n> extends BaseLoginOptions {\n /**\n * Used to store state before doing the redirect\n */\n appState?: TAppState\n}\n\nexport interface IdToken {\n __raw: string\n name?: string\n given_name?: string\n family_name?: string\n middle_name?: string\n nickname?: string\n preferred_username?: string\n profile?: string\n picture?: string\n website?: string\n email?: string\n email_verified?: boolean\n gender?: string\n birthdate?: string\n zoneinfo?: string\n locale?: string\n phone_number?: string\n phone_number_verified?: boolean\n address?: string\n updated_at?: string\n iss?: string\n aud?: string\n exp?: number\n nbf?: number\n iat?: number\n jti?: string\n azp?: string\n nonce?: string\n auth_time?: string\n at_hash?: string\n c_hash?: string\n acr?: string\n amr?: string\n sub_jwk?: string\n cnf?: string\n sid?: string\n org_id?: string\n [key: string]: any\n}\n\nexport interface GetTokenSilentlyOptions {\n /**\n * When `off`, ignores the cache and always sends a\n * request to Auth0.\n * When `cache-only`, only reads from the cache and never sends a request to Auth0.\n * Defaults to `on`, where it both reads from the cache and sends a request to Auth0 as needed.\n */\n cacheMode?: 'on' | 'off' | 'cache-only'\n\n /**\n * Parameters that will be sent back to Auth0 as part of a request.\n */\n authorizationParams?: {\n /**\n * There's no actual redirect when getting a token silently,\n * but, according to the spec, a `redirect_uri` param is required.\n * Auth0 uses this parameter to validate that the current `origin`\n * matches the `redirect_uri` `origin` when sending the response.\n * It must be whitelisted in the \"Allowed Web Origins\" in your\n * Auth0 Application's settings.\n */\n redirect_uri?: string\n\n /**\n * The scope that was used in the authentication request\n */\n scope?: string\n\n /**\n * The audience that was used in the authentication request\n */\n audience?: string\n\n /**\n * If you need to send custom parameters to the Authorization Server,\n * make sure to use the original parameter name.\n */\n [key: string]: any\n }\n\n /** A maximum number of seconds to wait before declaring the background /authorize call as failed for timeout\n * Defaults to 60s.\n */\n timeoutInSeconds?: number\n\n /**\n * If true, the full response from the /oauth/token endpoint (or the cache, if the cache was used) is returned\n * (minus `refresh_token` if one was issued). Otherwise, just the access token is returned.\n *\n * The default is `false`.\n */\n detailedResponse?: boolean\n}\n\nexport type GetTokenSilentlyVerboseResponse = Omit<\n TokenEndpointResponse,\n 'refresh_token'\n>\n\nexport type TokenEndpointResponse = {\n id_token: string\n access_token: string\n refresh_token?: string\n expires_in: number\n scope?: string\n}\n\n/**\n * Attribute overrides for the bundled cookie storage adapter.\n *\n * Defaults: `Path=/`, `SameSite=Lax`, `Secure` on HTTPS, `Max-Age` 30 days.\n * Use this to share the session across subdomains or tighten `SameSite`.\n *\n * @see {@link https://faable.com/docs/auth/quickstart/nextjs | Next.js Quickstart}\n */\nexport interface CookieOptions {\n /** (Optional) The domain of the cookie. Use a leading dot to share across subdomains, e.g. `.example.com`. */\n domain?: string\n /** (Optional) The path of the cookie. Defaults to `/`. */\n path?: string\n /** (Optional) The same-site attribute of the cookie. Defaults to `'Lax'`. */\n sameSite?: 'Lax' | 'Strict' | 'None'\n /** (Optional) Whether the cookie should only be sent over HTTPS. Defaults to `true` when the current page is HTTPS. */\n secure?: boolean\n /** (Optional) The maximum age of the cookie in seconds. Defaults to 30 days. */\n maxAge?: number\n}\n\n/**\n * Configuration accepted by {@link createClient} and the\n * `FaableAuthClient` constructor.\n *\n * `domain` and `clientId` are the only required fields. Everything else has\n * sensible defaults — see the individual properties for the specifics.\n *\n * @see {@link https://faable.com/docs/auth/get-started | Get Started with Faable Auth}\n * @see {@link https://faable.com/docs/auth/clients | Clients}\n */\nexport type FaableAuthClientConfig = {\n /** **Required.** Your Faable Auth tenant domain. */\n domain: string\n /** **Required.** Application client ID from the dashboard. */\n clientId: string\n\n // Optional\n /** Space-separated scopes. Defaults to `openid profile email`. */\n scope?: string\n /**\n * Default API audience the access tokens issued for this client should be\n * bound to. Forwarded to `/authorize` and to the `/oauth/token` POST bodies\n * (code exchange, refresh, OTP). `signInWith*` methods accept an `audience`\n * argument to override it per call.\n */\n audience?: string\n /** Default callback URL. Falls back to `window.location.origin`. */\n redirectUri?: string\n authorizationParams?: AuthorizationParams\n cookieDomain?: string\n useRefreshTokens?: boolean\n /** OAuth flow used when initiating sign-in. Defaults to `'pkce'` in browsers and `'implicit'` elsewhere. */\n flowType?: AuthFlowType\n /**\n * Where to keep the session. Pass `'localStorage'` (default) or `'cookie'`\n * for the bundled adapters, or any custom `SupportedStorage` implementation.\n * The cookie adapter ships with sane defaults (`Path=/`, `SameSite=Lax`,\n * auto `Secure` on HTTPS, 30-day `Max-Age`); use `cookieOptions` to override.\n */\n storage?: SupportedStorage | 'cookie' | 'localStorage'\n /** Optional prefix for the storage key. Final key is `${storageKey}-${clientId}`. */\n storageKey?: string\n\n /**\n * (Optional) Overrides for the cookie storage attributes. Setting this also\n * implicitly switches to the cookie adapter, so passing `storage: 'cookie'`\n * is not required when you only want to tweak attributes.\n */\n cookieOptions?: CookieOptions\n\n /**\n * Provide your own locking mechanism based on the environment. By default no locking is done at this time.\n *\n * @experimental\n */\n lock?: LockFunc\n} & BaseLogOptions\n\ntype AnyFunction = (...args: any[]) => any\ntype MaybePromisify<T> = T | Promise<T>\ntype PromisifyMethods<T> = {\n [K in keyof T]: T[K] extends AnyFunction\n ? (...args: Parameters<T[K]>) => MaybePromisify<ReturnType<T[K]>>\n : T[K]\n}\n\n/**\n * Minimal storage contract the SDK relies on. Compatible with `localStorage`,\n * `sessionStorage`, the bundled cookie adapter, and any custom adapter you\n * provide. Methods may return synchronously or asynchronously.\n *\n * @example\n * ```ts\n * const memoryStorage: SupportedStorage = {\n * store: new Map<string, string>(),\n * getItem: k => memoryStorage.store.get(k) ?? null,\n * setItem: (k, v) => void memoryStorage.store.set(k, v),\n * removeItem: k => void memoryStorage.store.delete(k)\n * }\n * ```\n */\nexport type SupportedStorage = PromisifyMethods<\n Pick<Storage, 'getItem' | 'setItem' | 'removeItem'>\n> & {\n /**\n * Set to `true` when the storage medium reads from an untrusted source\n * (e.g. request cookies on the server). Triggers a warning when consumers\n * access `session.user` so they refresh against a verified source instead.\n */\n isServer?: boolean\n}\n\n/**\n * Built-in social OAuth providers. Custom enterprise / SAML / OIDC\n * connections are addressed by their `connection` name or `connection_id`.\n *\n * @see {@link https://faable.com/docs/auth/connections | Connections}\n */\nexport type Provider = 'google' | 'github'\n\n/**\n * OAuth initiation flow.\n *\n * - `'pkce'` — recommended for SPAs / public clients; the SDK stores a code\n * verifier and exchanges the auth code for a session on the callback.\n * - `'implicit'` — tokens are returned directly in the URL fragment.\n *\n * @see {@link https://faable.com/docs/auth/oauth-flows/authorization-code | Authorization Code with PKCE}\n */\nexport type AuthFlowType = 'implicit' | 'pkce'\n\n/**\n * Options accepted by {@link FaableAuthClient.signInWithOauthConnection}.\n *\n * @see {@link https://faable.com/docs/auth/connections | Connections}\n */\nexport type SignInWithOAuthConnection = {\n /**\n * Identifier of the connection to use. Preferred over `connection` when\n * known, as the backend resolves it without additional lookups. If both\n * are provided, `connection_id` wins.\n */\n connection_id?: string\n /** Default connection is used if not setted. Kept for compatibility with tenants using connection names. */\n connection?: string\n /** A URL to send the user to after they are confirmed. */\n redirectTo?: string\n /**\n * App-side destination to return the user to once the callback has been\n * processed. It is stored locally alongside the PKCE verifier (never sent\n * to the server) and surfaced back as `returnTo` on the result of\n * {@link FaableAuthClient.handleRedirectCallback} / {@link FaableAuthClient.initialize}.\n */\n returnTo?: string\n /** A space-separated list of scopes granted to the OAuth application. */\n scopes?: string\n /** An object of query params */\n queryParams?: { [key: string]: string }\n /** If set to true does not immediately redirect the current browser context to visit the OAuth authorization page for the provider. */\n skipBrowserRedirect?: boolean\n /**\n * Override the API audience the issued access token should be bound to.\n * Falls back to `FaableAuthClientConfig.audience` when omitted.\n */\n audience?: string\n}\n\n/**\n * Result of {@link FaableAuthClient.signInWithOauthConnection}. Carries the\n * authorize URL on success (useful when `skipBrowserRedirect: true` so you\n * can drive the navigation yourself) or an {@link AuthError} on failure.\n */\nexport type OAuthResponse =\n | {\n data: {\n url: string\n }\n error: null\n }\n | {\n data: {\n url: null\n }\n error: AuthError\n }\n\n/**\n * A signed-in session as persisted by the client.\n *\n * Use {@link FaableAuthClient.getSession} to obtain the current value; the\n * SDK refreshes it automatically before `expires_at`.\n *\n * @see {@link https://faable.com/docs/auth/oidc/userinfo | UserInfo}\n */\nexport interface Session {\n /**\n * The oauth provider token. If present, this can be used to make external API requests to the oauth provider used.\n */\n provider_token?: string | null\n /**\n * The oauth provider refresh token. If present, this can be used to refresh the provider_token via the oauth provider's API.\n * Not all oauth providers return a provider refresh token. If the provider_refresh_token is missing, please refer to the oauth provider's documentation for information on how to obtain the provider refresh token.\n */\n provider_refresh_token?: string | null\n /**\n * The access token jwt. It is recommended to set the JWT_EXPIRY to a shorter expiry value.\n */\n access_token: string\n /**\n * A one-time used refresh token that never expires.\n */\n refresh_token: string\n /**\n * The number of seconds until the token expires (since it was issued). Returned when a login is confirmed.\n */\n expires_in: number\n /**\n * A timestamp of when the token will expire. Returned when a login is confirmed.\n */\n expires_at?: number\n token_type: string\n user: User\n}\n\n/**\n * Discriminated union returned by every sign-in / set-session / refresh\n * method. Always check `error` first — `data` fields are `null` on failure.\n */\nexport type AuthResponse =\n | {\n data: {\n user: User | null\n session: Session | null\n }\n error: null\n }\n | {\n data: {\n user: null\n session: null\n }\n error: AuthError\n }\n\nexport type AuthChangeEventMFA = 'MFA_CHALLENGE_VERIFIED'\n\n/**\n * Event names delivered to {@link FaableAuthClient.onAuthStateChange}\n * callbacks.\n *\n * - `INITIAL_SESSION` — fired once on subscribe with the currently-loaded session\n * - `SIGNED_IN` — a session was newly stored or adopted\n * - `SIGNED_OUT` — the session was cleared (locally or via global sign-out)\n * - `TOKEN_REFRESHED` — the SDK refreshed the access token in the background\n * - `PASSWORD_RECOVERY` — the user landed back from a password-reset link\n * - `USER_UPDATED` — the user object was reloaded from `/me`\n *\n * @see {@link https://faable.com/docs/auth/get-started | Get Started with Faable Auth}\n */\nexport type AuthChangeEvent =\n | 'INITIAL_SESSION'\n | 'PASSWORD_RECOVERY'\n | 'SIGNED_IN'\n | 'SIGNED_OUT'\n | 'TOKEN_REFRESHED'\n | 'USER_UPDATED'\n | AuthChangeEventMFA\n\n/**\n * Handle returned by {@link FaableAuthClient.onAuthStateChange}.\n *\n * Call `unsubscribe()` to stop receiving events — for example, in a React\n * `useEffect` cleanup.\n */\nexport interface Subscription {\n /** Subscriber UUID assigned by the client. */\n id: string\n /** Invoked every time an auth event happens. */\n callback: (event: AuthChangeEvent, session: Session | null) => void\n /** Call to remove the listener. */\n unsubscribe: () => void\n}\n\n/**\n * Options accepted by {@link FaableAuthClient.signOut}.\n *\n * @see {@link https://faable.com/docs/auth/oidc/logout | Logout}\n */\nexport type SignOut = {\n /**\n * Which sessions to log out.\n *\n * - `'global'` — every refresh token for the user (default)\n * - `'local'` — only this client's storage\n * - `'others'` — every other session except this device's; no\n * `SIGNED_OUT` event is fired locally\n */\n scope?: 'global' | 'local' | 'others'\n}\n\nexport type InitializeResult = {\n error: AuthError | null\n /**\n * Set when a sign-in redirect was consumed from the URL (e.g.\n * `'PASSWORD_RECOVERY'`). Absent when the session was recovered from\n * storage or there was nothing to process.\n */\n redirectType?: string | null\n /**\n * The app-side destination passed as `returnTo` when starting the sign-in,\n * round-tripped through the flow so the callback page can navigate there.\n */\n returnTo?: string | null\n /**\n * `true` when the callback that was just consumed created a brand-new\n * account (the auth server appended `?signup=true` to the redirect). Use it\n * to branch into onboarding / welcome UX or fire a signup analytics event.\n *\n * Only social / OAuth logins signal this today — passwordless and\n * username/password callbacks always report `false`. Absent when no sign-in\n * redirect was consumed (session recovered from storage).\n */\n is_new_user?: boolean\n}\n\nexport type UserResponse =\n | {\n data: {\n user: User\n }\n error: null\n }\n | {\n data: {\n user: null\n }\n error: AuthError\n }\n\nexport type CallRefreshTokenResult =\n | {\n session: Session\n error: null\n }\n | {\n session: null\n error: AuthError\n }\n"],"names":["extendStatics","d","b","Object","setPrototypeOf","__proto__","Array","p","prototype","hasOwnProperty","call","__extends","TypeError","String","__","this","constructor","create","__assign","assign","t","s","i","n","arguments","length","apply","__awaiter","thisArg","_arguments","P","generator","Promise","resolve","reject","fulfilled","value","step","next","e","rejected","result","done","then","__generator","body","f","y","_","label","sent","trys","ops","g","Iterator","verb","Symbol","iterator","v","op","pop","push","__spreadArray","to","from","pack","ar","l","slice","concat","SuppressedError","version","BaseLog","config","logger","console","log","logDebugMessages","debug","_debug","args","_i","extra","extraPrint","Date","toISOString","Base","_super","_this","instanceID","nextInstanceID","toString","win","window","undefined","global","globalThis","document","fetch","headers","init","token","Authorization","_handleRes","res_1","args_1","res","options","raw","text","_a","_c","json","status","data","error","_b","JSON","parse","message","_post","url_1","data_1","url","method","stringify","_get","FaableAuthApi","base_url","signOut","params","URLSearchParams","resolveResponseType","isBrowserEnv","response_type","setItemAsync","storage","key","setItem","getItemAsync","getItem","saveCodeVerifier","verifier","redirectType","returnTo","now","payload","createdAt","_d","loadCodeVerifier","storage_1","key_1","removeItem","loaded","dec2hex","dec","substr","sha256","randomString","encoder","TextEncoder","encodedData","encode","crypto","subtle","digest","hash","bytes","Uint8Array","map","c","fromCharCode","join","generatePKCEChallenge","warn","hashed","str","btoa","replace","getCodeChallengeAndMethod","storageKey_1","storageKey","isPasswordRecovery","codeVerifier","getRandomValues","Error","array","Uint32Array","generatePKCEVerifier","codeChallenge","isBrowser","localStorageWriteTests","tested","writable","supportsLocalStorage","localStorage","_e","randomKey","Math","random","_sessionResponse","expiresIn","session","access_token","refresh_token","expires_in","hasSession","expires_at","round","user","Deferred","promise","promiseConstructor","rej","retryable","fn","isRetryable","accept","attempt","Infinity","e_1","sleep","time","setTimeout","BroadcastSync","channelName","channel","subscribers","Map","BroadcastChannel","addEventListener","event","dispatch","err","subscribe","callback","id","r","subscription","unsubscribe","delete","set","notify","event_1","session_1","broadcast","postMessage","_broadcast","errors","tasks","values","sub","err_1","all","close","clear","STORAGE_KEY","AuthError","code","__isAuthError","name","CustomAuthError","AuthSessionMissingError","isAuthError","AuthApiError","AuthImplicitGrantRedirectError","details","toJSON","AuthPKCEGrantCodeExchangeError","AuthUnknownError","originalError","AuthInvalidTokenResponseError","isAuthRetryableFetchError","getWindow","AuthRetryableFetchError","windowHelpers","redirect","location","getDocument","decodeJWTPayload","parts","split","test","base64Url","chr1","chr2","chr3","enc2","enc3","enc4","base64","indexOf","charAt","decodeBase64URL","getSessionFromCookies","cookiesStore","clientId","cookieValue","readCookieValue","decodeURIComponent","readOne","get","single","chunks","isValidSession","parseCookies","cookieString","out","pair","trim","eq","name_1","decodeMaybe","input","serializeCookie","attrs","encodeURIComponent","maxAge","domain","path","sameSite","secure","serializeCookieRemoval","MAX_CHUNK_SIZE","chunkKey","idx","collectChunkKeys","parsed","prefix","found","forEach","_value","startsWith","tail","Number","sort","a","cookieStorageAdapter","jar","protocol","chunkNames","readChunkedCookieValue","cookie","has","newCount","ceil","name_2","pos","name_3","localStorageAdapter","parseParametersFromURL","href","URL","substring","searchParams","clearURLParameters","delete_params","param","history","replaceState","state","LockAcquireTimeoutError","isAcquireTimeout","lockNoOp","acquireTimeout","NavigatorLockAcquireTimeoutError","Lock","lockAcquired","pendingInLock","lock","_acquireLock","last_1","result_1","result_2","waitOn","splice","AUTO_REFRESH_TICK_DURATION","FaableAuthClient","domainUrl","initializePromise","_lastInitializeResult","detectSessionInUrl","autoRefreshTicker","visibilityChangedCallback","refreshingDeferred","_session","sessionCheckExpiryDays","redirectUri","match","host","toLowerCase","getDomain","tokenIssuer","audience","api","key_prefix","cookieOptions","resolveStorage","broadcastSync","msg","flowType","autoRefreshToken","initialize","defineProperty","_initialize","handleRedirectCallback","_detectFlowType","flow","_getSessionFromURL","_removeSession","redirectType_1","is_new_user","_saveSession","_notifyAllSubscribers","_recoverAndRefresh","error_1","_handleVisibilityChange","signup","_exchangeCodeForSession","error_3","error_description","error_code","provider_token","provider_refresh_token","token_type","expiresAt","refreshTick","timeNow","parseInt","actuallyExpiresIn","issuedAt","checkExpiresInTime","accessToken","resolvedExpiresAt","exp","expiryFromAccessToken","_getUser","type","error_2","authCode","stored","client_id","grant_type","code_verifier","rawResponse","error_4","startAutoRefresh","_onVisibilityChanged","error_5","calledFromInitialize","methodName","visibilityState","_startAutoRefresh","_stopAutoRefresh","debugName","currentSession","expiresWithMargin","_callRefreshToken","_removeVisibilityChangedCallback","removeEventListener","ticker","setInterval","_autoRefreshTokenTick","unref","Deno","unrefTimer","clearInterval","now_1","_useSession","expiresInTicks","floor","e_2","browser","_scope","scope","_getUrlForConnection","urlParams","queryParams","authorize_params","redirect_uri","redirectTo","origin","scopes","codeChallengeMethod","code_challenge","code_challenge_method","connection_id","connection","signInWithOauthConnection","credentials","_handleConnectionSignIn","skipBrowserRedirect","signInWithUsernamePassword","username","password","rawAuthResponse","formHtml","doc","div","createElement","innerHTML","form","appendChild","children","submit","buildAndSubmitForm","signUp","email","given_name","family_name","user_metadata","status_1","signInWithOtp","otp","sessionData","userError","signInWithPasswordless","send","response","changePassword","changeEmail","new_email","getSession","sessionError","user_id","verification_mode","buildAuthorizeUrl","definedParams","fromEntries","entries","filter","authorize","setSession","_setSession","__loadSession","stack","maybeSession","hasExpired","isServer","proxySession","Proxy","target","prop","receiver","Reflect","refreshedSession","error_6","refreshToken","_refreshAccessToken","timeoutMs","timeoutMessage","timeoutPromise","timer","race","finally","clearTimeout","error_7","startedAt_1","pow","session_res","nextBackOffInterval","error_8","session_2","_signOut","isAuthApiError","onAuthStateChange","_emitInitialSession","err_2","refreshSession","_refreshSession","error_10","error_9","createClient","User"],"mappings":"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","x_google_ignoreList":[0]}
1
+ {"version":3,"file":"main.js","sources":["../../node_modules/tslib/tslib.es6.js","../../../src/lib/version.ts","../../../src/BaseLog.ts","../../../src/Base.ts","../../../src/lib/globals.ts","../../../src/lib/fetch.ts","../../../src/FaableAuthApi.ts","../../../src/lib/auth_helpers.ts","../../../src/lib/storage_helpers.ts","../../../src/lib/pkce_storage.ts","../../../src/lib/helpers.ts","../../../src/lib/broadcast_sync.ts","../../../src/lib/constants.ts","../../../src/lib/errors.ts","../../../src/lib/helpers/window.ts","../../../src/lib/jwt.ts","../../../src/lib/nextjs.ts","../../../src/lib/session_helpers.ts","../../../src/lib/storage/cookie_helpers.ts","../../../src/lib/storage/cookie-storage.ts","../../../src/lib/storage/local-storage.ts","../../../src/lib/url_helpers.ts","../../../src/lock/locks.ts","../../../src/lock/Lock.ts","../../../src/FaableAuthClient.ts","../../../src/utils.ts","../../../src/lib/with_timeout.ts","../../../src/createClient.ts","../../../src/lib/types.ts"],"sourcesContent":["/******************************************************************************\r\nCopyright (c) Microsoft Corporation.\r\n\r\nPermission to use, copy, modify, and/or distribute this software for any\r\npurpose with or without fee is hereby granted.\r\n\r\nTHE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH\r\nREGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY\r\nAND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,\r\nINDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM\r\nLOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR\r\nOTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR\r\nPERFORMANCE OF THIS SOFTWARE.\r\n***************************************************************************** */\r\n/* global Reflect, Promise, SuppressedError, Symbol, Iterator */\r\n\r\nvar extendStatics = function(d, b) {\r\n extendStatics = Object.setPrototypeOf ||\r\n ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||\r\n function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };\r\n return extendStatics(d, b);\r\n};\r\n\r\nexport function __extends(d, b) {\r\n if (typeof b !== \"function\" && b !== null)\r\n throw new TypeError(\"Class extends value \" + String(b) + \" is not a constructor or null\");\r\n extendStatics(d, b);\r\n function __() { this.constructor = d; }\r\n d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());\r\n}\r\n\r\nexport var __assign = function() {\r\n __assign = Object.assign || function __assign(t) {\r\n for (var s, i = 1, n = arguments.length; i < n; i++) {\r\n s = arguments[i];\r\n for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p];\r\n }\r\n return t;\r\n }\r\n return __assign.apply(this, arguments);\r\n}\r\n\r\nexport function __rest(s, e) {\r\n var t = {};\r\n for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)\r\n t[p] = s[p];\r\n if (s != null && typeof Object.getOwnPropertySymbols === \"function\")\r\n for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {\r\n if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))\r\n t[p[i]] = s[p[i]];\r\n }\r\n return t;\r\n}\r\n\r\nexport function __decorate(decorators, target, key, desc) {\r\n var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;\r\n if (typeof Reflect === \"object\" && typeof Reflect.decorate === \"function\") r = Reflect.decorate(decorators, target, key, desc);\r\n else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;\r\n return c > 3 && r && Object.defineProperty(target, key, r), r;\r\n}\r\n\r\nexport function __param(paramIndex, decorator) {\r\n return function (target, key) { decorator(target, key, paramIndex); }\r\n}\r\n\r\nexport function __esDecorate(ctor, descriptorIn, decorators, contextIn, initializers, extraInitializers) {\r\n function accept(f) { if (f !== void 0 && typeof f !== \"function\") throw new TypeError(\"Function expected\"); return f; }\r\n var kind = contextIn.kind, key = kind === \"getter\" ? \"get\" : kind === \"setter\" ? \"set\" : \"value\";\r\n var target = !descriptorIn && ctor ? contextIn[\"static\"] ? ctor : ctor.prototype : null;\r\n var descriptor = descriptorIn || (target ? Object.getOwnPropertyDescriptor(target, contextIn.name) : {});\r\n var _, done = false;\r\n for (var i = decorators.length - 1; i >= 0; i--) {\r\n var context = {};\r\n for (var p in contextIn) context[p] = p === \"access\" ? {} : contextIn[p];\r\n for (var p in contextIn.access) context.access[p] = contextIn.access[p];\r\n context.addInitializer = function (f) { if (done) throw new TypeError(\"Cannot add initializers after decoration has completed\"); extraInitializers.push(accept(f || null)); };\r\n var result = (0, decorators[i])(kind === \"accessor\" ? { get: descriptor.get, set: descriptor.set } : descriptor[key], context);\r\n if (kind === \"accessor\") {\r\n if (result === void 0) continue;\r\n if (result === null || typeof result !== \"object\") throw new TypeError(\"Object expected\");\r\n if (_ = accept(result.get)) descriptor.get = _;\r\n if (_ = accept(result.set)) descriptor.set = _;\r\n if (_ = accept(result.init)) initializers.unshift(_);\r\n }\r\n else if (_ = accept(result)) {\r\n if (kind === \"field\") initializers.unshift(_);\r\n else descriptor[key] = _;\r\n }\r\n }\r\n if (target) Object.defineProperty(target, contextIn.name, descriptor);\r\n done = true;\r\n};\r\n\r\nexport function __runInitializers(thisArg, initializers, value) {\r\n var useValue = arguments.length > 2;\r\n for (var i = 0; i < initializers.length; i++) {\r\n value = useValue ? initializers[i].call(thisArg, value) : initializers[i].call(thisArg);\r\n }\r\n return useValue ? value : void 0;\r\n};\r\n\r\nexport function __propKey(x) {\r\n return typeof x === \"symbol\" ? x : \"\".concat(x);\r\n};\r\n\r\nexport function __setFunctionName(f, name, prefix) {\r\n if (typeof name === \"symbol\") name = name.description ? \"[\".concat(name.description, \"]\") : \"\";\r\n return Object.defineProperty(f, \"name\", { configurable: true, value: prefix ? \"\".concat(prefix, \" \", name) : name });\r\n};\r\n\r\nexport function __metadata(metadataKey, metadataValue) {\r\n if (typeof Reflect === \"object\" && typeof Reflect.metadata === \"function\") return Reflect.metadata(metadataKey, metadataValue);\r\n}\r\n\r\nexport function __awaiter(thisArg, _arguments, P, generator) {\r\n function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }\r\n return new (P || (P = Promise))(function (resolve, reject) {\r\n function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }\r\n function rejected(value) { try { step(generator[\"throw\"](value)); } catch (e) { reject(e); } }\r\n function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }\r\n step((generator = generator.apply(thisArg, _arguments || [])).next());\r\n });\r\n}\r\n\r\nexport function __generator(thisArg, body) {\r\n var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === \"function\" ? Iterator : Object).prototype);\r\n return g.next = verb(0), g[\"throw\"] = verb(1), g[\"return\"] = verb(2), typeof Symbol === \"function\" && (g[Symbol.iterator] = function() { return this; }), g;\r\n function verb(n) { return function (v) { return step([n, v]); }; }\r\n function step(op) {\r\n if (f) throw new TypeError(\"Generator is already executing.\");\r\n while (g && (g = 0, op[0] && (_ = 0)), _) try {\r\n if (f = 1, y && (t = op[0] & 2 ? y[\"return\"] : op[0] ? y[\"throw\"] || ((t = y[\"return\"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;\r\n if (y = 0, t) op = [op[0] & 2, t.value];\r\n switch (op[0]) {\r\n case 0: case 1: t = op; break;\r\n case 4: _.label++; return { value: op[1], done: false };\r\n case 5: _.label++; y = op[1]; op = [0]; continue;\r\n case 7: op = _.ops.pop(); _.trys.pop(); continue;\r\n default:\r\n if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }\r\n if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }\r\n if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }\r\n if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }\r\n if (t[2]) _.ops.pop();\r\n _.trys.pop(); continue;\r\n }\r\n op = body.call(thisArg, _);\r\n } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }\r\n if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };\r\n }\r\n}\r\n\r\nexport var __createBinding = Object.create ? (function(o, m, k, k2) {\r\n if (k2 === undefined) k2 = k;\r\n var desc = Object.getOwnPropertyDescriptor(m, k);\r\n if (!desc || (\"get\" in desc ? !m.__esModule : desc.writable || desc.configurable)) {\r\n desc = { enumerable: true, get: function() { return m[k]; } };\r\n }\r\n Object.defineProperty(o, k2, desc);\r\n}) : (function(o, m, k, k2) {\r\n if (k2 === undefined) k2 = k;\r\n o[k2] = m[k];\r\n});\r\n\r\nexport function __exportStar(m, o) {\r\n for (var p in m) if (p !== \"default\" && !Object.prototype.hasOwnProperty.call(o, p)) __createBinding(o, m, p);\r\n}\r\n\r\nexport function __values(o) {\r\n var s = typeof Symbol === \"function\" && Symbol.iterator, m = s && o[s], i = 0;\r\n if (m) return m.call(o);\r\n if (o && typeof o.length === \"number\") return {\r\n next: function () {\r\n if (o && i >= o.length) o = void 0;\r\n return { value: o && o[i++], done: !o };\r\n }\r\n };\r\n throw new TypeError(s ? \"Object is not iterable.\" : \"Symbol.iterator is not defined.\");\r\n}\r\n\r\nexport function __read(o, n) {\r\n var m = typeof Symbol === \"function\" && o[Symbol.iterator];\r\n if (!m) return o;\r\n var i = m.call(o), r, ar = [], e;\r\n try {\r\n while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);\r\n }\r\n catch (error) { e = { error: error }; }\r\n finally {\r\n try {\r\n if (r && !r.done && (m = i[\"return\"])) m.call(i);\r\n }\r\n finally { if (e) throw e.error; }\r\n }\r\n return ar;\r\n}\r\n\r\n/** @deprecated */\r\nexport function __spread() {\r\n for (var ar = [], i = 0; i < arguments.length; i++)\r\n ar = ar.concat(__read(arguments[i]));\r\n return ar;\r\n}\r\n\r\n/** @deprecated */\r\nexport function __spreadArrays() {\r\n for (var s = 0, i = 0, il = arguments.length; i < il; i++) s += arguments[i].length;\r\n for (var r = Array(s), k = 0, i = 0; i < il; i++)\r\n for (var a = arguments[i], j = 0, jl = a.length; j < jl; j++, k++)\r\n r[k] = a[j];\r\n return r;\r\n}\r\n\r\nexport function __spreadArray(to, from, pack) {\r\n if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {\r\n if (ar || !(i in from)) {\r\n if (!ar) ar = Array.prototype.slice.call(from, 0, i);\r\n ar[i] = from[i];\r\n }\r\n }\r\n return to.concat(ar || Array.prototype.slice.call(from));\r\n}\r\n\r\nexport function __await(v) {\r\n return this instanceof __await ? (this.v = v, this) : new __await(v);\r\n}\r\n\r\nexport function __asyncGenerator(thisArg, _arguments, generator) {\r\n if (!Symbol.asyncIterator) throw new TypeError(\"Symbol.asyncIterator is not defined.\");\r\n var g = generator.apply(thisArg, _arguments || []), i, q = [];\r\n return i = Object.create((typeof AsyncIterator === \"function\" ? AsyncIterator : Object).prototype), verb(\"next\"), verb(\"throw\"), verb(\"return\", awaitReturn), i[Symbol.asyncIterator] = function () { return this; }, i;\r\n function awaitReturn(f) { return function (v) { return Promise.resolve(v).then(f, reject); }; }\r\n function verb(n, f) { if (g[n]) { i[n] = function (v) { return new Promise(function (a, b) { q.push([n, v, a, b]) > 1 || resume(n, v); }); }; if (f) i[n] = f(i[n]); } }\r\n function resume(n, v) { try { step(g[n](v)); } catch (e) { settle(q[0][3], e); } }\r\n function step(r) { r.value instanceof __await ? Promise.resolve(r.value.v).then(fulfill, reject) : settle(q[0][2], r); }\r\n function fulfill(value) { resume(\"next\", value); }\r\n function reject(value) { resume(\"throw\", value); }\r\n function settle(f, v) { if (f(v), q.shift(), q.length) resume(q[0][0], q[0][1]); }\r\n}\r\n\r\nexport function __asyncDelegator(o) {\r\n var i, p;\r\n return i = {}, verb(\"next\"), verb(\"throw\", function (e) { throw e; }), verb(\"return\"), i[Symbol.iterator] = function () { return this; }, i;\r\n function verb(n, f) { i[n] = o[n] ? function (v) { return (p = !p) ? { value: __await(o[n](v)), done: false } : f ? f(v) : v; } : f; }\r\n}\r\n\r\nexport function __asyncValues(o) {\r\n if (!Symbol.asyncIterator) throw new TypeError(\"Symbol.asyncIterator is not defined.\");\r\n var m = o[Symbol.asyncIterator], i;\r\n return m ? m.call(o) : (o = typeof __values === \"function\" ? __values(o) : o[Symbol.iterator](), i = {}, verb(\"next\"), verb(\"throw\"), verb(\"return\"), i[Symbol.asyncIterator] = function () { return this; }, i);\r\n function verb(n) { i[n] = o[n] && function (v) { return new Promise(function (resolve, reject) { v = o[n](v), settle(resolve, reject, v.done, v.value); }); }; }\r\n function settle(resolve, reject, d, v) { Promise.resolve(v).then(function(v) { resolve({ value: v, done: d }); }, reject); }\r\n}\r\n\r\nexport function __makeTemplateObject(cooked, raw) {\r\n if (Object.defineProperty) { Object.defineProperty(cooked, \"raw\", { value: raw }); } else { cooked.raw = raw; }\r\n return cooked;\r\n};\r\n\r\nvar __setModuleDefault = Object.create ? (function(o, v) {\r\n Object.defineProperty(o, \"default\", { enumerable: true, value: v });\r\n}) : function(o, v) {\r\n o[\"default\"] = v;\r\n};\r\n\r\nvar ownKeys = function(o) {\r\n ownKeys = Object.getOwnPropertyNames || function (o) {\r\n var ar = [];\r\n for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;\r\n return ar;\r\n };\r\n return ownKeys(o);\r\n};\r\n\r\nexport function __importStar(mod) {\r\n if (mod && mod.__esModule) return mod;\r\n var result = {};\r\n if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== \"default\") __createBinding(result, mod, k[i]);\r\n __setModuleDefault(result, mod);\r\n return result;\r\n}\r\n\r\nexport function __importDefault(mod) {\r\n return (mod && mod.__esModule) ? mod : { default: mod };\r\n}\r\n\r\nexport function __classPrivateFieldGet(receiver, state, kind, f) {\r\n if (kind === \"a\" && !f) throw new TypeError(\"Private accessor was defined without a getter\");\r\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError(\"Cannot read private member from an object whose class did not declare it\");\r\n return kind === \"m\" ? f : kind === \"a\" ? f.call(receiver) : f ? f.value : state.get(receiver);\r\n}\r\n\r\nexport function __classPrivateFieldSet(receiver, state, value, kind, f) {\r\n if (kind === \"m\") throw new TypeError(\"Private method is not writable\");\r\n if (kind === \"a\" && !f) throw new TypeError(\"Private accessor was defined without a setter\");\r\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError(\"Cannot write private member to an object whose class did not declare it\");\r\n return (kind === \"a\" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;\r\n}\r\n\r\nexport function __classPrivateFieldIn(state, receiver) {\r\n if (receiver === null || (typeof receiver !== \"object\" && typeof receiver !== \"function\")) throw new TypeError(\"Cannot use 'in' operator on non-object\");\r\n return typeof state === \"function\" ? receiver === state : state.has(receiver);\r\n}\r\n\r\nexport function __addDisposableResource(env, value, async) {\r\n if (value !== null && value !== void 0) {\r\n if (typeof value !== \"object\" && typeof value !== \"function\") throw new TypeError(\"Object expected.\");\r\n var dispose, inner;\r\n if (async) {\r\n if (!Symbol.asyncDispose) throw new TypeError(\"Symbol.asyncDispose is not defined.\");\r\n dispose = value[Symbol.asyncDispose];\r\n }\r\n if (dispose === void 0) {\r\n if (!Symbol.dispose) throw new TypeError(\"Symbol.dispose is not defined.\");\r\n dispose = value[Symbol.dispose];\r\n if (async) inner = dispose;\r\n }\r\n if (typeof dispose !== \"function\") throw new TypeError(\"Object not disposable.\");\r\n if (inner) dispose = function() { try { inner.call(this); } catch (e) { return Promise.reject(e); } };\r\n env.stack.push({ value: value, dispose: dispose, async: async });\r\n }\r\n else if (async) {\r\n env.stack.push({ async: true });\r\n }\r\n return value;\r\n\r\n}\r\n\r\nvar _SuppressedError = typeof SuppressedError === \"function\" ? SuppressedError : function (error, suppressed, message) {\r\n var e = new Error(message);\r\n return e.name = \"SuppressedError\", e.error = error, e.suppressed = suppressed, e;\r\n};\r\n\r\nexport function __disposeResources(env) {\r\n function fail(e) {\r\n env.error = env.hasError ? new _SuppressedError(e, env.error, \"An error was suppressed during disposal.\") : e;\r\n env.hasError = true;\r\n }\r\n var r, s = 0;\r\n function next() {\r\n while (r = env.stack.pop()) {\r\n try {\r\n if (!r.async && s === 1) return s = 0, env.stack.push(r), Promise.resolve().then(next);\r\n if (r.dispose) {\r\n var result = r.dispose.call(r.value);\r\n if (r.async) return s |= 2, Promise.resolve(result).then(next, function(e) { fail(e); return next(); });\r\n }\r\n else s |= 1;\r\n }\r\n catch (e) {\r\n fail(e);\r\n }\r\n }\r\n if (s === 1) return env.hasError ? Promise.reject(env.error) : Promise.resolve();\r\n if (env.hasError) throw env.error;\r\n }\r\n return next();\r\n}\r\n\r\nexport function __rewriteRelativeImportExtension(path, preserveJsx) {\r\n if (typeof path === \"string\" && /^\\.\\.?\\//.test(path)) {\r\n return path.replace(/\\.(tsx)$|((?:\\.d)?)((?:\\.[^./]+?)?)\\.([cm]?)ts$/i, function (m, tsx, d, ext, cm) {\r\n return tsx ? preserveJsx ? \".jsx\" : \".js\" : d && (!ext || !cm) ? m : (d + ext + \".\" + cm.toLowerCase() + \"js\");\r\n });\r\n }\r\n return path;\r\n}\r\n\r\nexport default {\r\n __extends: __extends,\r\n __assign: __assign,\r\n __rest: __rest,\r\n __decorate: __decorate,\r\n __param: __param,\r\n __esDecorate: __esDecorate,\r\n __runInitializers: __runInitializers,\r\n __propKey: __propKey,\r\n __setFunctionName: __setFunctionName,\r\n __metadata: __metadata,\r\n __awaiter: __awaiter,\r\n __generator: __generator,\r\n __createBinding: __createBinding,\r\n __exportStar: __exportStar,\r\n __values: __values,\r\n __read: __read,\r\n __spread: __spread,\r\n __spreadArrays: __spreadArrays,\r\n __spreadArray: __spreadArray,\r\n __await: __await,\r\n __asyncGenerator: __asyncGenerator,\r\n __asyncDelegator: __asyncDelegator,\r\n __asyncValues: __asyncValues,\r\n __makeTemplateObject: __makeTemplateObject,\r\n __importStar: __importStar,\r\n __importDefault: __importDefault,\r\n __classPrivateFieldGet: __classPrivateFieldGet,\r\n __classPrivateFieldSet: __classPrivateFieldSet,\r\n __classPrivateFieldIn: __classPrivateFieldIn,\r\n __addDisposableResource: __addDisposableResource,\r\n __disposeResources: __disposeResources,\r\n __rewriteRelativeImportExtension: __rewriteRelativeImportExtension,\r\n};\r\n","// Will be overwriten by .github/workflows/release.yml\nexport const version = '0.0.0'\n","import { version } from './lib/version'\n\nexport type BaseLogOptions = {\n debug?: boolean | ((message: string, ...args: any[]) => void)\n}\n\nexport abstract class BaseLog {\n protected logDebugMessages: boolean\n protected logger: (message: string, ...args: any[]) => void = console.log\n\n constructor(config: BaseLogOptions = {}) {\n this.logDebugMessages = !!config.debug\n if (typeof config.debug === 'function') {\n this.logger = config.debug\n }\n }\n\n protected extraPrint?(): string\n\n protected _debug(...args: any[]) {\n if (this.logDebugMessages) {\n const extra = this.extraPrint ? this.extraPrint() : ''\n this.logger(\n `FaableAuth@${extra} (${version}) ${new Date().toISOString()}`,\n ...args\n )\n }\n\n return this\n }\n}\n","import { BaseLog, BaseLogOptions } from './BaseLog'\n\nexport abstract class Base extends BaseLog {\n private static nextInstanceID = 0\n private instanceID: number\n\n constructor(config: BaseLogOptions = {}) {\n super(config)\n this.instanceID = Base.nextInstanceID\n Base.nextInstanceID += 1\n }\n\n /** @hidden */\n extraPrint() {\n return this.instanceID.toString()\n }\n}\n","const win: (Window & typeof globalThis) | undefined =\n typeof window !== 'undefined' ? window : undefined\n\nconst global: typeof globalThis | undefined =\n typeof globalThis !== 'undefined' ? globalThis : win\nexport const document = global?.document as Document\n\nexport { win as window }\n\nexport const fetch = (global as any).fetch as typeof globalThis.fetch\n","import { fetch } from './globals'\nimport { version } from './version'\n\nexport type JsonResponse<T = any> = {\n data: T | null\n error?: any\n}\n\ntype RequestInitWithToken = RequestInit & {\n token: string\n raw: boolean\n}\n\nconst headers = (init: Partial<RequestInitWithToken> = {}) => {\n // Identify ourselves as a first-party client so the auth server can tell\n // auth-js (browser OAuth SDK) traffic apart from the dashboard, the\n // management SDK, or third-party integrations. Format: `<name>/<version>`\n // (version injected at release time).\n let headers: Record<string, string> = {\n 'x-faable-client': `auth-js/${version}`\n }\n if (init?.token) {\n headers = { ...headers, Authorization: `Bearer ${init?.token}` }\n }\n return {\n ...init?.headers,\n ...headers\n }\n}\n\nconst _handleRes = async (\n res: Response,\n options: Partial<RequestInitWithToken> = {}\n) => {\n const body = options.raw ? await res.text() : await res.json()\n if (res.status >= 300) {\n return {\n data: body,\n error: options.raw ? JSON.parse(body)?.message : body?.message\n }\n }\n return { data: body, error: null }\n}\n\nexport const _post = async <T>(\n url: string,\n data: object,\n options: Partial<RequestInitWithToken> = {}\n): Promise<JsonResponse<T>> => {\n try {\n const res = await fetch(url, {\n method: 'POST',\n body: JSON.stringify(data),\n headers: { ...headers(options), 'Content-Type': 'application/json' }\n })\n\n return await _handleRes(res, options)\n } catch (e) {\n return { data: null, error: e }\n }\n}\n\nexport const _get = async <T>(\n url: string,\n options: Partial<RequestInitWithToken> = {}\n): Promise<JsonResponse<T>> => {\n try {\n const res = await fetch(url, {\n ...options,\n method: 'GET',\n headers: headers(options)\n })\n\n return await _handleRes(res, options)\n } catch (e) {\n return { data: null, error: e }\n }\n}\n","import { BaseLog, BaseLogOptions } from './BaseLog'\nimport { AuthError } from './lib/errors'\nimport { _get } from './lib/fetch'\n\nexport default class FaableAuthApi extends BaseLog {\n constructor(\n public base_url: string,\n config: BaseLogOptions\n ) {\n super(config)\n }\n protected extraPrint(): string {\n return 'api'\n }\n\n async signOut(params: {\n client_id: string\n returnTo?: string\n }): Promise<{ data: null; error: AuthError | null }> {\n const url = `${this.base_url}/logout?${new URLSearchParams(params)}`\n this._debug(`requesting ${url}`)\n const res = await _get(url)\n this._debug(res)\n if (res.error) {\n return { error: res.error, data: null }\n } else {\n return { error: null, data: null }\n }\n }\n}\n","/**\n * Picks the OAuth `response_type` for an authorize request.\n *\n * Browsers default to the authorization code flow (PKCE); non-browser\n * environments default to the implicit token flow. A caller-provided\n * value always wins.\n */\nexport const resolveResponseType = (\n options: { response_type?: string },\n isBrowserEnv: boolean\n): string => options.response_type || (isBrowserEnv ? 'code' : 'token')\n\n/**\n * Renders an HTML form returned by the authorization server and submits it,\n * triggering the browser navigation that completes the username/password\n * login flow.\n */\nexport const buildAndSubmitForm = (formHtml: string, doc: Document): void => {\n const div = doc.createElement('div')\n div.innerHTML = formHtml\n const form = doc.body.appendChild(div).children[0] as\n | HTMLFormElement\n | undefined\n if (!form) {\n throw new Error('Auth response did not contain a submittable form')\n }\n form.submit()\n}\n","import { SupportedStorage } from './types'\n\n// Storage helpers\nexport const setItemAsync = async (\n storage: SupportedStorage,\n key: string,\n data: any\n): Promise<void> => {\n await storage.setItem(key, JSON.stringify(data))\n}\n\nexport const getItemAsync = async (\n storage: SupportedStorage,\n key: string\n): Promise<unknown> => {\n const value = await storage.getItem(key)\n\n if (!value) {\n return null\n }\n\n try {\n return JSON.parse(value)\n } catch {\n return value\n }\n}\n","import { getItemAsync, setItemAsync } from './storage_helpers'\nimport type { SupportedStorage } from './types'\n\nexport const CODE_VERIFIER_TTL_MS = 10 * 60 * 1000\n\ntype StoredCodeVerifier = {\n verifier: string\n createdAt: number\n redirectType?: string\n returnTo?: string\n}\n\ntype LoadedCodeVerifier = {\n verifier: string\n redirectType?: string\n returnTo?: string\n}\n\nconst isStoredCodeVerifier = (value: unknown): value is StoredCodeVerifier =>\n typeof value === 'object' &&\n value !== null &&\n typeof (value as StoredCodeVerifier).verifier === 'string' &&\n typeof (value as StoredCodeVerifier).createdAt === 'number'\n\nexport const saveCodeVerifier = async (\n storage: SupportedStorage,\n key: string,\n {\n verifier,\n redirectType,\n returnTo,\n now = Date.now()\n }: {\n verifier: string\n redirectType?: string\n returnTo?: string\n now?: number\n }\n): Promise<void> => {\n const payload: StoredCodeVerifier = { verifier, createdAt: now }\n if (redirectType) {\n payload.redirectType = redirectType\n }\n if (returnTo) {\n payload.returnTo = returnTo\n }\n await setItemAsync(storage, key, payload)\n}\n\nexport const loadCodeVerifier = async (\n storage: SupportedStorage,\n key: string,\n { now = Date.now() }: { now?: number } = {}\n): Promise<LoadedCodeVerifier | null> => {\n const raw = await getItemAsync(storage, key)\n if (!isStoredCodeVerifier(raw)) {\n return null\n }\n\n if (now - raw.createdAt > CODE_VERIFIER_TTL_MS) {\n await storage.removeItem(key)\n return null\n }\n\n const loaded: LoadedCodeVerifier = { verifier: raw.verifier }\n if (raw.redirectType) {\n loaded.redirectType = raw.redirectType\n }\n if (raw.returnTo) {\n loaded.returnTo = raw.returnTo\n }\n return loaded\n}\n","import { JsonResponse } from './fetch'\nimport { saveCodeVerifier } from './pkce_storage'\nimport { AuthResponse, SupportedStorage, User } from './types'\n\nfunction dec2hex(dec: number) {\n return ('0' + dec.toString(16)).substr(-2)\n}\n\nexport function decodeBase64URL(value: string): string {\n const key =\n 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/='\n let base64 = ''\n let chr1, chr2, chr3\n let enc1, enc2, enc3, enc4\n let i = 0\n value = value.replace('-', '+').replace('_', '/')\n\n while (i < value.length) {\n enc1 = key.indexOf(value.charAt(i++))\n enc2 = key.indexOf(value.charAt(i++))\n enc3 = key.indexOf(value.charAt(i++))\n enc4 = key.indexOf(value.charAt(i++))\n chr1 = (enc1 << 2) | (enc2 >> 4)\n chr2 = ((enc2 & 15) << 4) | (enc3 >> 2)\n chr3 = ((enc3 & 3) << 6) | enc4\n base64 = base64 + String.fromCharCode(chr1)\n\n if (enc3 != 64 && chr2 != 0) {\n base64 = base64 + String.fromCharCode(chr2)\n }\n if (enc4 != 64 && chr3 != 0) {\n base64 = base64 + String.fromCharCode(chr3)\n }\n }\n return base64\n}\n\nexport function generatePKCEVerifier() {\n if (\n typeof crypto === 'undefined' ||\n typeof crypto.getRandomValues !== 'function'\n ) {\n throw new Error(\n 'Web Crypto API is required to generate a PKCE code verifier'\n )\n }\n const verifierLength = 56\n const array = new Uint32Array(verifierLength)\n crypto.getRandomValues(array)\n return Array.from(array, dec2hex).join('')\n}\n\nasync function sha256(randomString: string) {\n const encoder = new TextEncoder()\n const encodedData = encoder.encode(randomString)\n const hash = await crypto.subtle.digest('SHA-256', encodedData)\n const bytes = new Uint8Array(hash)\n\n return Array.from(bytes)\n .map(c => String.fromCharCode(c))\n .join('')\n}\n\nfunction base64urlencode(str: string) {\n return btoa(str).replace(/\\+/g, '-').replace(/\\//g, '_').replace(/=+$/, '')\n}\n\nexport async function generatePKCEChallenge(verifier: string) {\n const hasCryptoSupport =\n typeof crypto !== 'undefined' &&\n typeof crypto.subtle !== 'undefined' &&\n typeof TextEncoder !== 'undefined'\n\n if (!hasCryptoSupport) {\n console.warn(\n 'WebCrypto API is not supported. Code challenge method will default to use plain instead of sha256.'\n )\n return verifier\n }\n const hashed = await sha256(verifier)\n return base64urlencode(hashed)\n}\n\nexport async function getCodeChallengeAndMethod(\n storage: SupportedStorage,\n storageKey: string,\n isPasswordRecovery = false,\n returnTo?: string\n) {\n const codeVerifier = generatePKCEVerifier()\n await saveCodeVerifier(storage, `${storageKey}-code-verifier`, {\n verifier: codeVerifier,\n redirectType: isPasswordRecovery ? 'PASSWORD_RECOVERY' : undefined,\n returnTo\n })\n const codeChallenge = await generatePKCEChallenge(codeVerifier)\n const codeChallengeMethod = codeVerifier === codeChallenge ? 'plain' : 'S256'\n return [codeChallenge, codeChallengeMethod]\n}\n\nexport const isBrowser = () => typeof document !== 'undefined'\n\nconst localStorageWriteTests = {\n tested: false,\n writable: false\n}\n\n/**\n * Checks whether localStorage is supported on this browser.\n */\nexport const supportsLocalStorage = () => {\n if (!isBrowser()) {\n return false\n }\n\n try {\n if (typeof globalThis.localStorage !== 'object') {\n return false\n }\n } catch (_e) {\n // DOM exception when accessing `localStorage`\n return false\n }\n\n if (localStorageWriteTests.tested) {\n return localStorageWriteTests.writable\n }\n\n const randomKey = `lswt-${Math.random()}${Math.random()}`\n\n try {\n globalThis.localStorage.setItem(randomKey, randomKey)\n globalThis.localStorage.removeItem(randomKey)\n\n localStorageWriteTests.tested = true\n localStorageWriteTests.writable = true\n } catch (_e) {\n // localStorage can't be written to\n // https://www.chromium.org/for-testers/bug-reporting-guidelines/uncaught-securityerror-failed-to-read-the-localstorage-property-from-window-access-is-denied-for-this-document\n\n localStorageWriteTests.tested = true\n localStorageWriteTests.writable = false\n }\n\n return localStorageWriteTests.writable\n}\n\nexport function uuid() {\n return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {\n const r = (Math.random() * 16) | 0,\n v = c == 'x' ? r : (r & 0x3) | 0x8\n return v.toString(16)\n })\n}\n\nexport type RawAuthResponse = {\n expires_at: number\n expires_in: number\n user: User\n access_token: string\n refresh_token: string\n token_type: string\n}\n/**\n * hasSession checks if the response object contains a valid session\n * @param data A response object\n * @returns true if a session is in the response\n */\nfunction hasSession(data: Partial<RawAuthResponse>): data is RawAuthResponse {\n return !!data.access_token && !!data.refresh_token && !!data.expires_in\n}\n\nexport function expiresAt(expiresIn: number) {\n const timeNow = Math.round(Date.now() / 1000)\n return timeNow + expiresIn\n}\n\nexport function _sessionResponse({\n data\n}: JsonResponse<Partial<RawAuthResponse>>): AuthResponse {\n let session = null\n if (!data) throw new Error('Bad session response')\n if (hasSession(data)) {\n session = { ...data }\n if (!data.expires_at && data.expires_in) {\n session.expires_at = expiresAt(data.expires_in)\n }\n }\n\n const user: User = data.user ?? (data as User)\n return { data: { session, user }, error: null }\n}\n\n/**\n * A deferred represents some asynchronous work that is not yet finished, which\n * may or may not culminate in a value.\n * Taken from: https://github.com/mike-north/types/blob/master/src/async.ts\n */\nexport class Deferred<T = any> {\n public static promiseConstructor: PromiseConstructor = Promise\n\n public readonly promise!: PromiseLike<T>\n\n public readonly resolve!: (value?: T | PromiseLike<T>) => void\n\n public readonly reject!: (reason?: any) => any\n\n public constructor() {\n ;(this as any).promise = new Deferred.promiseConstructor((res, rej) => {\n ;(this as any).resolve = res\n ;(this as any).reject = rej\n })\n }\n}\n\n/**\n * Converts the provided async function into a retryable function. Each result\n * or thrown error is sent to the isRetryable function which should return true\n * if the function should run again.\n */\nexport function retryable<T>(\n fn: (attempt: number) => Promise<T>,\n isRetryable: (attempt: number, error: any | null, result?: T) => boolean\n): Promise<T> {\n const promise = new Promise<T>((accept, reject) => {\n ;(async () => {\n for (let attempt = 0; attempt < Infinity; attempt++) {\n try {\n const result = await fn(attempt)\n\n if (!isRetryable(attempt, null, result)) {\n accept(result)\n return\n }\n } catch (e: any) {\n if (!isRetryable(attempt, e)) {\n reject(e)\n return\n }\n }\n }\n })()\n })\n\n return promise\n}\n\n/**\n * Creates a promise that resolves to null after some time.\n */\nexport async function sleep(time: number): Promise<null> {\n return new Promise(accept => {\n setTimeout(() => accept(null), time)\n })\n}\n\nexport const checkExpiresInTime = ({\n expires_in,\n expires_at,\n refreshTick\n}: {\n expires_in: string\n expires_at?: string\n refreshTick: number\n}) => {\n const timeNow = Math.round(Date.now() / 1000)\n const expiresIn = parseInt(expires_in)\n let expiresAt = timeNow + expiresIn\n\n if (expires_at) {\n expiresAt = parseInt(expires_at)\n }\n\n const actuallyExpiresIn = expiresAt - timeNow\n if (actuallyExpiresIn * 1000 <= refreshTick) {\n console.warn(\n `@faable/auth-js: Session as retrieved from URL expires in ${actuallyExpiresIn}s, should have been closer to ${expiresIn}s`\n )\n }\n\n const issuedAt = expiresAt - expiresIn\n if (timeNow - issuedAt >= 120) {\n console.warn(\n '@faable/auth-js: Session as retrieved from URL was issued over 120s ago, URL could be stale',\n issuedAt,\n expiresAt,\n timeNow\n )\n } else if (timeNow - issuedAt < 0) {\n console.warn(\n '@faable/auth-js: Session as retrieved from URL was issued in the future? Check the device clok for skew',\n issuedAt,\n expiresAt,\n timeNow\n )\n }\n\n return { expiresIn, expiresAt }\n}\n","import { uuid } from './helpers'\nimport type { AuthChangeEvent, Session, Subscription } from './types'\n\ntype Listener = (\n event: AuthChangeEvent,\n session: Session | null\n) => void | Promise<void>\n\ntype DebugFn = (message: string, ...args: unknown[]) => void\n\nconst hasBroadcastChannel = (): boolean =>\n typeof globalThis !== 'undefined' &&\n typeof (globalThis as { BroadcastChannel?: unknown }).BroadcastChannel ===\n 'function'\n\n/**\n * Wraps a BroadcastChannel plus an in-process subscriber registry so the\n * auth client can fan out state changes to local subscribers and other tabs\n * in one call. Cross-tab messages are delivered to local subscribers but\n * NOT re-broadcast, to avoid echo loops.\n */\nexport class BroadcastSync {\n private channel: BroadcastChannel | null = null\n private subscribers = new Map<string, Subscription>()\n\n constructor(\n channelName: string,\n private debug: DebugFn\n ) {\n if (!hasBroadcastChannel() || !channelName) return\n try {\n this.channel = new globalThis.BroadcastChannel(channelName)\n this.channel.addEventListener('message', async event => {\n this.debug(\n 'broadcast_sync: received notification from another tab',\n event\n )\n await this.dispatch(event.data.event, event.data.session, false)\n })\n } catch (err) {\n console.error(\n 'Failed to create BroadcastChannel; cross-tab sync disabled',\n err\n )\n }\n }\n\n subscribe(callback: Listener): { subscription: Subscription } {\n const id = uuid()\n const subscription: Subscription = {\n id,\n callback,\n unsubscribe: () => {\n this.subscribers.delete(id)\n }\n }\n this.subscribers.set(id, subscription)\n return { subscription }\n }\n\n async notify(\n event: AuthChangeEvent,\n session: Session | null,\n broadcast = true\n ): Promise<void> {\n if (broadcast && this.channel) {\n this.channel.postMessage({ event, session })\n }\n await this.dispatch(event, session, broadcast)\n }\n\n private async dispatch(\n event: AuthChangeEvent,\n session: Session | null,\n _broadcast: boolean\n ): Promise<void> {\n const errors: unknown[] = []\n const tasks = Array.from(this.subscribers.values()).map(async sub => {\n try {\n await sub.callback(event, session)\n } catch (err) {\n errors.push(err)\n }\n })\n await Promise.all(tasks)\n if (errors.length > 0) {\n for (let i = 0; i < errors.length; i += 1) {\n console.error(errors[i])\n }\n throw errors[0]\n }\n }\n\n close(): void {\n this.subscribers.clear()\n try {\n this.channel?.close()\n } catch {\n // ignore — channel may already be closed\n }\n this.channel = null\n }\n}\n","export const STORAGE_KEY = 'faableauth'\nexport const EXPIRY_MARGIN = 10 // in seconds\n\nexport const API_VERSION_HEADER_NAME = 'X-Faableauth-Api-Version'\nexport const API_VERSIONS = {\n '2024-01-01': {\n timestamp: Date.parse('2024-01-01T00:00:00.0Z'),\n name: '2024-01-01'\n }\n}\n","/**\n * Known error codes. Note that the server may also return other error codes\n * not included in this list (if the client library is older than the version\n * on the server).\n */\nexport type ErrorCode =\n | 'unexpected_failure'\n | 'validation_failed'\n | 'bad_json'\n | 'email_exists'\n | 'phone_exists'\n | 'bad_jwt'\n | 'not_admin'\n | 'no_authorization'\n | 'user_not_found'\n | 'session_not_found'\n | 'flow_state_not_found'\n | 'flow_state_expired'\n | 'signup_disabled'\n | 'user_banned'\n | 'provider_email_needs_verification'\n | 'invite_not_found'\n | 'bad_oauth_state'\n | 'bad_oauth_callback'\n | 'oauth_provider_not_supported'\n | 'unexpected_audience'\n | 'single_identity_not_deletable'\n | 'email_conflict_identity_not_deletable'\n | 'identity_already_exists'\n | 'email_provider_disabled'\n | 'phone_provider_disabled'\n | 'too_many_enrolled_mfa_factors'\n | 'mfa_factor_name_conflict'\n | 'mfa_factor_not_found'\n | 'mfa_ip_address_mismatch'\n | 'mfa_challenge_expired'\n | 'mfa_verification_failed'\n | 'mfa_verification_rejected'\n | 'insufficient_aal'\n | 'captcha_failed'\n | 'saml_provider_disabled'\n | 'manual_linking_disabled'\n | 'sms_send_failed'\n | 'email_not_confirmed'\n | 'phone_not_confirmed'\n | 'reauth_nonce_missing'\n | 'saml_relay_state_not_found'\n | 'saml_relay_state_expired'\n | 'saml_idp_not_found'\n | 'saml_assertion_no_user_id'\n | 'saml_assertion_no_email'\n | 'user_already_exists'\n | 'sso_provider_not_found'\n | 'saml_metadata_fetch_failed'\n | 'saml_idp_already_exists'\n | 'sso_domain_already_exists'\n | 'saml_entity_id_mismatch'\n | 'conflict'\n | 'provider_disabled'\n | 'user_sso_managed'\n | 'reauthentication_needed'\n | 'same_password'\n | 'reauthentication_not_valid'\n | 'otp_expired'\n | 'otp_disabled'\n | 'identity_not_found'\n | 'weak_password'\n | 'over_request_rate_limit'\n | 'over_email_send_rate_limit'\n | 'over_sms_send_rate_limit'\n | 'bad_code_verifier'\n\nexport class AuthError extends Error {\n /**\n * Error code associated with the error. Most errors coming from\n * HTTP responses will have a code, though some errors that occur\n * before a response is received will not have one present. In that\n * case {@link AuthError.status} will also be undefined.\n */\n code: ErrorCode | string | undefined\n\n /** HTTP status code that caused the error. */\n status: number | undefined\n\n protected __isAuthError = true\n\n constructor(message: string, status?: number, code?: string) {\n super(message)\n this.name = 'AuthError'\n this.status = status\n this.code = code\n }\n}\n\nexport class CustomAuthError extends AuthError {\n name: string\n status: number\n\n constructor(\n message: string,\n name: string,\n status: number,\n code: string | undefined\n ) {\n super(message, status, code)\n this.name = name\n this.status = status\n }\n}\n\nexport class AuthSessionMissingError extends CustomAuthError {\n constructor() {\n super('Auth session missing!', 'AuthSessionMissingError', 400, undefined)\n }\n}\n\nexport function isAuthError(error: unknown): error is AuthError {\n return typeof error === 'object' && error !== null && '__isAuthError' in error\n}\n\nexport class AuthApiError extends AuthError {\n status: number\n\n constructor(message: string, status: number, code: string | undefined) {\n super(message, status, code)\n this.name = 'AuthApiError'\n this.status = status\n this.code = code\n }\n}\n\nexport function isAuthApiError(error: unknown): error is AuthApiError {\n return isAuthError(error) && error.name === 'AuthApiError'\n}\n\nexport class AuthImplicitGrantRedirectError extends CustomAuthError {\n details: { error: string; code: string } | null = null\n constructor(\n message: string,\n details: { error: string; code: string } | null = null\n ) {\n super(message, 'AuthImplicitGrantRedirectError', 500, undefined)\n this.details = details\n }\n\n toJSON() {\n return {\n name: this.name,\n message: this.message,\n status: this.status,\n details: this.details\n }\n }\n}\n\nexport class AuthPKCEGrantCodeExchangeError extends CustomAuthError {\n details: { error: string; code: string } | null = null\n\n constructor(\n message: string,\n details: { error: string; code: string } | null = null\n ) {\n super(message, 'AuthPKCEGrantCodeExchangeError', 500, undefined)\n this.details = details\n }\n\n toJSON() {\n return {\n name: this.name,\n message: this.message,\n status: this.status,\n details: this.details\n }\n }\n}\n\nexport class AuthUnknownError extends AuthError {\n originalError: unknown\n\n constructor(message: string, originalError: unknown) {\n super(message)\n this.name = 'AuthUnknownError'\n this.originalError = originalError\n }\n}\n\nexport class AuthInvalidTokenResponseError extends CustomAuthError {\n constructor() {\n super(\n 'Auth session or user missing',\n 'AuthInvalidTokenResponseError',\n 500,\n undefined\n )\n }\n}\n\nexport class AuthRetryableFetchError extends CustomAuthError {\n constructor(message: string, status: number) {\n super(message, 'AuthRetryableFetchError', status, undefined)\n }\n}\n\nexport function isAuthRetryableFetchError(\n error: unknown\n): error is AuthRetryableFetchError {\n return isAuthError(error) && error.name === 'AuthRetryableFetchError'\n}\n","import { window } from '../globals'\n\nfunction redirect(url: string) {\n getWindow().location = url as any\n}\n\nfunction getDocument() {\n return getWindow().document\n}\n\nfunction getWindow() {\n if (!window) throw new Error('No window in environment')\n return window\n}\n\nexport const windowHelpers = {\n redirect: redirect,\n getDocument: getDocument,\n getWindow: getWindow\n}\n","import { decodeBase64URL } from './helpers'\n\n/**\n * @ignore\n */\nexport interface JWTVerifyOptions {\n iss: string\n aud: string\n id_token: string\n nonce?: string\n leeway?: number\n max_age?: number\n organizationId?: string\n now?: number\n}\n\nexport interface IdToken {\n __raw: string\n name?: string\n given_name?: string\n family_name?: string\n middle_name?: string\n nickname?: string\n preferred_username?: string\n profile?: string\n picture?: string\n website?: string\n email?: string\n email_verified?: boolean\n gender?: string\n birthdate?: string\n zoneinfo?: string\n locale?: string\n phone_number?: string\n phone_number_verified?: boolean\n address?: string\n updated_at?: string\n iss?: string\n aud?: string\n exp?: number\n nbf?: number\n iat?: number\n jti?: string\n azp?: string\n nonce?: string\n auth_time?: string\n at_hash?: string\n c_hash?: string\n acr?: string\n amr?: string\n sub_jwk?: string\n cnf?: string\n sid?: string\n org_id?: string\n [key: string]: any\n}\n\nconst isNumber = (n: any) => typeof n === 'number'\n\nexport function decodeJWTPayload(token: string) {\n // Regex checks for base64url format\n const base64UrlRegex =\n /^([a-z0-9_-]{4})*($|[a-z0-9_-]{3}=?$|[a-z0-9_-]{2}(==)?$)$/i\n\n const parts = token.split('.')\n\n if (parts.length !== 3) {\n throw new Error('JWT is not valid: not a JWT structure')\n }\n\n if (!base64UrlRegex.test(parts[1])) {\n throw new Error('JWT is not valid: payload is not in base64url format')\n }\n\n const base64Url = parts[1]\n return JSON.parse(decodeBase64URL(base64Url))\n}\n\n/**\n * Derives a session's expiry from a redirect that may omit the OIDC envelope\n * (`expires_in` / `token_type`). Some flows hand the tokens back in the query\n * string with only the token pair; in that case we trust the access token's\n * own `exp` claim. An explicit `expires_at` (in seconds) wins when provided.\n *\n * @param accessToken The access token JWT to read `exp` from.\n * @param expiresAt Optional explicit absolute expiry (seconds since epoch).\n * @param now Current time in seconds (injectable for tests).\n * @returns Absolute `expiresAt` and relative `expiresIn`, both in seconds.\n */\nexport function expiryFromAccessToken(\n accessToken: string,\n expiresAt?: string | number,\n now: number = Date.now() / 1000\n): { expiresAt: number; expiresIn: number } {\n const payload = decodeJWTPayload(accessToken)\n const resolvedExpiresAt =\n expiresAt != null && expiresAt !== ''\n ? Number(expiresAt)\n : (payload.exp ?? now)\n return { expiresAt: resolvedExpiresAt, expiresIn: resolvedExpiresAt - now }\n}\n\nexport const verify = (options: JWTVerifyOptions) => {\n if (!options.id_token) {\n throw new Error('ID token is required but missing')\n }\n\n const decoded = decodeJWTPayload(options.id_token)\n\n if (!decoded.claims.iss) {\n throw new Error(\n 'Issuer (iss) claim must be a string present in the ID token'\n )\n }\n\n if (decoded.claims.iss !== options.iss) {\n throw new Error(\n `Issuer (iss) claim mismatch in the ID token; expected \"${options.iss}\", found \"${decoded.claims.iss}\"`\n )\n }\n\n if (!decoded.user.sub) {\n throw new Error(\n 'Subject (sub) claim must be a string present in the ID token'\n )\n }\n\n if (decoded.header.alg !== 'RS256') {\n throw new Error(\n `Signature algorithm of \"${decoded.header.alg}\" is not supported. Expected the ID token to be signed with \"RS256\".`\n )\n }\n\n if (\n !decoded.claims.aud ||\n !(\n typeof decoded.claims.aud === 'string' ||\n Array.isArray(decoded.claims.aud)\n )\n ) {\n throw new Error(\n 'Audience (aud) claim must be a string or array of strings present in the ID token'\n )\n }\n if (Array.isArray(decoded.claims.aud)) {\n if (!decoded.claims.aud.includes(options.aud)) {\n throw new Error(\n `Audience (aud) claim mismatch in the ID token; expected \"${\n options.aud\n }\" but was not one of \"${decoded.claims.aud.join(', ')}\"`\n )\n }\n if (decoded.claims.aud.length > 1) {\n if (!decoded.claims.azp) {\n throw new Error(\n 'Authorized Party (azp) claim must be a string present in the ID token when Audience (aud) claim has multiple values'\n )\n }\n if (decoded.claims.azp !== options.aud) {\n throw new Error(\n `Authorized Party (azp) claim mismatch in the ID token; expected \"${options.aud}\", found \"${decoded.claims.azp}\"`\n )\n }\n }\n } else if (decoded.claims.aud !== options.aud) {\n throw new Error(\n `Audience (aud) claim mismatch in the ID token; expected \"${options.aud}\" but found \"${decoded.claims.aud}\"`\n )\n }\n if (options.nonce) {\n if (!decoded.claims.nonce) {\n throw new Error(\n 'Nonce (nonce) claim must be a string present in the ID token'\n )\n }\n if (decoded.claims.nonce !== options.nonce) {\n throw new Error(\n `Nonce (nonce) claim mismatch in the ID token; expected \"${options.nonce}\", found \"${decoded.claims.nonce}\"`\n )\n }\n }\n\n if (options.max_age && !isNumber(decoded.claims.auth_time)) {\n throw new Error(\n 'Authentication Time (auth_time) claim must be a number present in the ID token when Max Age (max_age) is specified'\n )\n }\n\n /* c8 ignore next 5 */\n if (decoded.claims.exp == null || !isNumber(decoded.claims.exp)) {\n throw new Error(\n 'Expiration Time (exp) claim must be a number present in the ID token'\n )\n }\n if (!isNumber(decoded.claims.iat)) {\n throw new Error(\n 'Issued At (iat) claim must be a number present in the ID token'\n )\n }\n\n const leeway = options.leeway || 60\n const now = new Date(options.now || Date.now())\n const expDate = new Date(0)\n\n expDate.setUTCSeconds(decoded.claims.exp + leeway)\n\n if (now > expDate) {\n throw new Error(\n `Expiration Time (exp) claim error in the ID token; current time (${now}) is after expiration time (${expDate})`\n )\n }\n\n if (decoded.claims.nbf != null && isNumber(decoded.claims.nbf)) {\n const nbfDate = new Date(0)\n nbfDate.setUTCSeconds(decoded.claims.nbf - leeway)\n if (now < nbfDate) {\n throw new Error(\n `Not Before time (nbf) claim in the ID token indicates that this token can't be used just yet. Current time (${now}) is before ${nbfDate}`\n )\n }\n }\n\n if (decoded.claims.auth_time != null && isNumber(decoded.claims.auth_time)) {\n const authTimeDate = new Date(0)\n authTimeDate.setUTCSeconds(\n parseInt(decoded.claims.auth_time) + (options.max_age as number) + leeway\n )\n\n if (now > authTimeDate) {\n throw new Error(\n `Authentication Time (auth_time) claim in the ID token indicates that too much time has passed since the last end-user authentication. Current time (${now}) is after last auth at ${authTimeDate}`\n )\n }\n }\n\n if (options.organizationId) {\n if (!decoded.claims.org_id) {\n throw new Error(\n 'Organization ID (org_id) claim must be a string present in the ID token'\n )\n } else if (options.organizationId !== decoded.claims.org_id) {\n throw new Error(\n `Organization ID (org_id) claim mismatch in the ID token; expected \"${options.organizationId}\", found \"${decoded.claims.org_id}\"`\n )\n }\n }\n\n return decoded\n}\n","import { STORAGE_KEY } from './constants'\nimport { Session } from './types'\n\n/**\n * Reads the persisted session from cookies on the server.\n *\n * Pair this with the cookie storage adapter on the client: when the browser\n * stores its session under the cookie shared with the server, the same\n * `clientId` lets the server reconstruct it. Mirrors how the browser\n * adapter builds the storage key and reassembles chunked cookies, so no\n * extra wiring is required.\n *\n * @param cookiesStore Either the result of `cookies()` from `next/headers`,\n * or any plain `{ name: value }` map. Adapters with a `get(name)` method\n * are detected automatically.\n * @param options `{ clientId, storageKey? }`. `storageKey` defaults to the\n * library's built-in prefix — only set it when you customized\n * `storageKey` in `createClient`.\n * @returns The decoded {@link Session} or `null` when the cookie is absent\n * or malformed.\n * @example\n * ```ts\n * // app/page.tsx\n * import { cookies } from 'next/headers'\n * import { getSessionFromCookies } from '@faable/auth-js'\n *\n * export default async function Page() {\n * const session = getSessionFromCookies(cookies(), {\n * clientId: '<client_id>'\n * })\n * if (!session) return <SignIn />\n * return <Dashboard user={session.user} />\n * }\n * ```\n * @see {@link https://faable.com/docs/auth/quickstart/nextjs | Next.js Quickstart}\n */\nexport const getSessionFromCookies = (\n cookiesStore: any,\n options: { clientId: string; storageKey?: string }\n): Session | null => {\n const key = `${options.storageKey ?? STORAGE_KEY}-${options.clientId}`\n\n const cookieValue = readCookieValue(cookiesStore, key)\n if (!cookieValue) return null\n\n try {\n return JSON.parse(decodeURIComponent(cookieValue))\n } catch (e) {\n console.error('Failed to parse session from cookie', e)\n return null\n }\n}\n\n/**\n * Reads `key` (or its `<key>.0`, `<key>.1`, … chunks) out of either a Next.js\n * `cookies()` object or a plain `{ name: value }` map, mirroring how the\n * browser adapter writes them.\n */\nconst readCookieValue = (cookiesStore: any, key: string): string | null => {\n if (!cookiesStore) return null\n\n const readOne =\n typeof cookiesStore.get === 'function'\n ? (name: string) => cookiesStore.get(name)?.value\n : (name: string) => cookiesStore[name]\n\n const single = readOne(key)\n if (single) return single\n\n const chunks: string[] = []\n for (let i = 0; ; i++) {\n const value = readOne(`${key}.${i}`)\n if (!value) break\n chunks.push(value)\n }\n return chunks.length ? chunks.join('') : null\n}\n","import type { Session } from './types'\n\n/**\n * Type guard for a stored session blob — checks the presence of the fields\n * the client needs to consider the value usable. Does not validate the\n * cryptographic signature of the access/refresh tokens.\n */\nexport const isValidSession = (value: unknown): value is Session =>\n typeof value === 'object' &&\n value !== null &&\n 'access_token' in value &&\n 'refresh_token' in value &&\n 'expires_at' in value\n","export interface CookieAttributes {\n domain?: string\n path?: string\n sameSite?: 'Lax' | 'Strict' | 'None'\n secure?: boolean\n maxAge?: number\n}\n\n/**\n * Parses a raw cookie string (the shape of `document.cookie`) into a Map of\n * decoded name → value. Splitting happens BEFORE decoding so encoded `;` and\n * `=` characters inside a value don't break the parser.\n */\nexport const parseCookies = (cookieString: string): Map<string, string> => {\n const out = new Map<string, string>()\n if (!cookieString) return out\n\n for (const rawPair of cookieString.split(';')) {\n const pair = rawPair.trim()\n if (!pair) continue\n const eq = pair.indexOf('=')\n if (eq < 0) continue\n const name = decodeMaybe(pair.slice(0, eq).trim())\n const value = decodeMaybe(pair.slice(eq + 1).trim())\n if (name) out.set(name, value)\n }\n return out\n}\n\nconst decodeMaybe = (input: string): string => {\n try {\n return decodeURIComponent(input)\n } catch {\n return input\n }\n}\n\n/**\n * Builds a `name=value; Attr=...` string suitable for assignment to\n * `document.cookie`. Encodes name and value per RFC 6265 and forces `Secure`\n * when `SameSite=None` (browsers reject the cookie otherwise).\n */\nexport const serializeCookie = (\n name: string,\n value: string,\n attrs: CookieAttributes\n): string => {\n let out = `${encodeURIComponent(name)}=${encodeURIComponent(value)}`\n\n if (attrs.maxAge !== undefined) out += `; Max-Age=${attrs.maxAge}`\n if (attrs.domain) out += `; Domain=${attrs.domain}`\n if (attrs.path) out += `; Path=${attrs.path}`\n if (attrs.sameSite) out += `; SameSite=${attrs.sameSite}`\n\n // `SameSite=None` only works with Secure; emit Secure even if the caller\n // forgot it so the browser doesn't silently drop the cookie.\n const needsSecure = attrs.secure === true || attrs.sameSite === 'None'\n if (needsSecure) out += '; Secure'\n\n return out\n}\n\n/**\n * Builds the cookie string that clears `name`. Browsers will only remove a\n * cookie when the deletion attributes (Domain, Path, SameSite, Secure) match\n * those used at write time, so we mirror them here.\n */\nexport const serializeCookieRemoval = (\n name: string,\n attrs: CookieAttributes\n): string =>\n serializeCookie(name, '', {\n domain: attrs.domain,\n path: attrs.path,\n sameSite: attrs.sameSite,\n secure: attrs.secure,\n maxAge: 0\n })\n","import { isBrowser } from '../helpers'\nimport { SupportedStorage } from '../types'\nimport {\n CookieAttributes,\n parseCookies,\n serializeCookie,\n serializeCookieRemoval\n} from './cookie_helpers'\n\nexport type CookieOptions = CookieAttributes\n\n/**\n * Document-like surface the cookie adapter needs. Accepting a minimal shape\n * (instead of the full DOM `Document`) keeps the adapter testable without\n * jsdom and works in any environment that exposes a `cookie` property.\n */\nexport interface CookieJar {\n cookie: string\n}\n\n/** Default cookie lifetime when the caller doesn't override `maxAge`. */\nconst DEFAULT_COOKIE_MAX_AGE_SECONDS = 30 * 24 * 60 * 60\n\n/**\n * Maximum raw bytes we put in a single cookie value before splitting. Browsers\n * cap individual cookies at ~4096 bytes including name + attributes; after\n * URL-encoding (typical ratio ~1.1x for JSON sessions) and the attribute tail\n * (`Max-Age=…; Path=/; SameSite=Lax; …`) this leaves enough headroom even for\n * the longest realistic cookie names.\n */\nconst MAX_CHUNK_SIZE = 3200\n\nconst chunkKey = (key: string, idx: number): string => `${key}.${idx}`\n\n/**\n * Returns the chunk keys for `key` in numeric order. A \"chunk key\" is one\n * shaped like `<key>.<integer>`; foreign cookies that happen to share the\n * prefix (e.g. `key-suffix`) are ignored thanks to the dot + digits check.\n */\nconst collectChunkKeys = (\n parsed: Map<string, string>,\n key: string\n): string[] => {\n const prefix = `${key}.`\n const found: { name: string; idx: number }[] = []\n parsed.forEach((_value, name) => {\n if (!name.startsWith(prefix)) return\n const tail = name.slice(prefix.length)\n if (!/^\\d+$/.test(tail)) return\n found.push({ name, idx: Number(tail) })\n })\n found.sort((a, b) => a.idx - b.idx)\n return found.map(c => c.name)\n}\n\n/**\n * Reads `key` from the parsed cookie map. Prefers a single un-chunked cookie\n * (back-compat with sessions written by earlier SDK versions); falls back to\n * concatenating numbered chunks. Returns null when nothing is found.\n */\nexport const readChunkedCookieValue = (\n parsed: Map<string, string>,\n key: string\n): string | null => {\n const single = parsed.get(key)\n if (single !== undefined) return single\n const chunkNames = collectChunkKeys(parsed, key)\n if (chunkNames.length === 0) return null\n return chunkNames.map(name => parsed.get(name) as string).join('')\n}\n\n/**\n * Storage adapter that persists the session in `document.cookie`.\n *\n * Pick this adapter when you need SSR (server reads the cookie on every\n * request) or want to scope storage with `Secure`, `SameSite`, or `Domain`.\n * The simplest way to enable it is `createClient({ storage: 'cookie' })` or\n * by passing `cookieOptions` — the SDK calls this factory internally.\n *\n * Defaults applied to every cookie: `Path=/`, `SameSite=Lax`, `Secure` on\n * HTTPS, 30-day `Max-Age`. Override any of them through `options`. Values\n * larger than the per-cookie browser limit (~4 KB) are transparently split\n * across numbered chunks (`<key>.0`, `<key>.1`, …) and re-assembled on read.\n *\n * @param options Attribute overrides for every written cookie.\n * @param jar Document-like object whose `cookie` property is read/written.\n * Defaults to `document` in browsers and `null` (no-op) on the server —\n * only override for tests.\n * @returns A {@link SupportedStorage} ready to pass to {@link createClient}.\n * @example\n * ```ts\n * import { createClient } from '@faable/auth-js'\n *\n * export const auth = createClient({\n * domain: '<faableauth_domain>',\n * clientId: '<client_id>',\n * storage: 'cookie',\n * cookieOptions: { domain: '.example.com' }\n * })\n * ```\n * @see {@link https://faable.com/docs/auth/quickstart/nextjs | Next.js Quickstart}\n */\nexport const cookieStorageAdapter = (\n options: CookieOptions = {},\n jar: CookieJar | null = isBrowser() ? document : null\n): SupportedStorage => {\n const attrs: CookieAttributes = {\n path: '/',\n sameSite: 'Lax',\n secure: isBrowser() && window.location.protocol === 'https:',\n maxAge: DEFAULT_COOKIE_MAX_AGE_SECONDS,\n ...options\n }\n\n return {\n getItem: (key: string) => {\n if (!jar) return null\n const parsed = parseCookies(jar.cookie)\n return readChunkedCookieValue(parsed, key)\n },\n\n setItem: (key: string, value: string) => {\n if (!jar) return\n const parsed = parseCookies(jar.cookie)\n\n if (value.length <= MAX_CHUNK_SIZE) {\n // Single cookie path. Wipe any stale chunks left from a prior large\n // value so a subsequent `getItem` doesn't reassemble garbage.\n for (const name of collectChunkKeys(parsed, key)) {\n jar.cookie = serializeCookieRemoval(name, attrs)\n }\n jar.cookie = serializeCookie(key, value, attrs)\n return\n }\n\n // Chunked path. Drop a stale single (if any) and any chunks that fall\n // beyond the new count; the surviving chunk indices get overwritten by\n // the loop below.\n if (parsed.has(key)) {\n jar.cookie = serializeCookieRemoval(key, attrs)\n }\n const newCount = Math.ceil(value.length / MAX_CHUNK_SIZE)\n for (const name of collectChunkKeys(parsed, key)) {\n const idx = Number(name.slice(key.length + 1))\n if (idx >= newCount) {\n jar.cookie = serializeCookieRemoval(name, attrs)\n }\n }\n for (let pos = 0, i = 0; pos < value.length; pos += MAX_CHUNK_SIZE, i++) {\n const slice = value.slice(pos, pos + MAX_CHUNK_SIZE)\n jar.cookie = serializeCookie(chunkKey(key, i), slice, attrs)\n }\n },\n\n removeItem: (key: string) => {\n if (!jar) return\n // Always emit the single removal so the call mirrors a `Set-Cookie:\n // key=; Max-Age=0` (browsers no-op on absent cookies) and additionally\n // clear every chunk we can see.\n const parsed = parseCookies(jar.cookie)\n jar.cookie = serializeCookieRemoval(key, attrs)\n for (const name of collectChunkKeys(parsed, key)) {\n jar.cookie = serializeCookieRemoval(name, attrs)\n }\n }\n }\n}\n","import { supportsLocalStorage } from '../helpers'\nimport { SupportedStorage } from '../types'\n\n/**\n * Provides safe access to the globalThis.localStorage property.\n */\nexport const localStorageAdapter: SupportedStorage = {\n getItem: key => {\n if (!supportsLocalStorage()) {\n return null\n }\n\n return globalThis.localStorage.getItem(key)\n },\n setItem: (key, value) => {\n if (!supportsLocalStorage()) {\n return\n }\n\n globalThis.localStorage.setItem(key, value)\n },\n removeItem: key => {\n if (!supportsLocalStorage()) {\n return\n }\n\n globalThis.localStorage.removeItem(key)\n }\n}\n\n/**\n * Returns a localStorage-like object that stores the key-value pairs in\n * memory.\n */\nexport function memoryLocalStorageAdapter(\n store: { [key: string]: string } = {}\n): SupportedStorage {\n return {\n getItem: key => {\n return store[key] || null\n },\n\n setItem: (key, value) => {\n store[key] = value\n },\n\n removeItem: key => {\n delete store[key]\n }\n }\n}\n","/**\n * Extracts parameters encoded in the URL both in the query and fragment.\n */\nexport function parseParametersFromURL(href: string = '') {\n const result: { [parameter: string]: string } = {}\n\n const url = new URL(href)\n\n if (url.hash && url.hash[0] === '#') {\n try {\n const hashSearchParams = new URLSearchParams(url.hash.substring(1))\n hashSearchParams.forEach((value, key) => {\n result[key] = value\n })\n } catch (_e) {\n // hash is not a query string\n }\n }\n\n // search parameters take precedence over hash parameters\n url.searchParams.forEach((value, key) => {\n result[key] = value\n })\n\n return result\n}\n\nexport const clearURLParameters = (delete_params: string[] = []) => {\n const url = new URL(window.location.href)\n\n delete_params.forEach(param => {\n url.searchParams.delete(param)\n })\n\n url.hash = ''\n\n window.history.replaceState(window.history.state, '', url.toString())\n}\n","import { supportsLocalStorage } from '../lib/helpers'\n\n/**\n * Provide your own global lock implementation instead of the default\n * implementation. The function should acquire a lock for the duration of the\n * `fn` async function, such that no other client instances will be able to\n * hold it at the same time.\n *\n * @experimental\n *\n * @param name Name of the lock to be acquired.\n * @param acquireTimeout If negative, no timeout should occur. If positive it\n * should throw an Error with an `isAcquireTimeout`\n * property set to true if the operation fails to be\n * acquired after this much time (ms).\n * @param fn The operation to execute when the lock is acquired.\n */\nexport type LockFunc = <R>(\n name: string,\n acquireTimeout: number,\n fn: () => Promise<R>\n) => Promise<R>\n\n/**\n * @experimental\n */\nexport const internals = {\n /**\n * @experimental\n */\n debug: !!(\n globalThis &&\n supportsLocalStorage() &&\n globalThis.localStorage &&\n globalThis.localStorage.getItem('faable.auth.locks.debug') === 'true'\n )\n}\n\n/**\n * An error thrown when a lock cannot be acquired after some amount of time.\n *\n * Use the {@link #isAcquireTimeout} property instead of checking with `instanceof`.\n */\nexport abstract class LockAcquireTimeoutError extends Error {\n public readonly isAcquireTimeout = true\n\n constructor(message: string) {\n super(message)\n }\n}\n\nexport class NavigatorLockAcquireTimeoutError extends LockAcquireTimeoutError {}\n\n/**\n * Implements a global exclusive lock using the Navigator LockManager API. It\n * is available on all browsers released after 2022-03-15 with Safari being the\n * last one to release support. If the API is not available, this function will\n * throw. Make sure you check availability before passing this lock to the\n * client.\n *\n * You can turn on debugging by setting the `faable.auth.locks.debug`\n * local storage item to `true`.\n *\n * Internals:\n *\n * Since the LockManager API does not preserve stack traces for the async\n * function passed in the `request` method, a trick is used where acquiring the\n * lock releases a previously started promise to run the operation in the `fn`\n * function. The lock waits for that promise to finish (with or without error),\n * while the function will finally wait for the result anyway.\n *\n * @param name Name of the lock to be acquired.\n * @param acquireTimeout If negative, no timeout. If 0 an error is thrown if\n * the lock can't be acquired without waiting. If positive, the lock acquire\n * will time out after so many milliseconds. An error is\n * a timeout if it has `isAcquireTimeout` set to true.\n * @param fn The operation to run once the lock is acquired.\n */\nexport async function navigatorLock<R>(\n name: string,\n acquireTimeout: number,\n fn: () => Promise<R>\n): Promise<R> {\n if (internals.debug) {\n console.log(\n '@faable/auth-js: navigatorLock: acquire lock',\n name,\n acquireTimeout\n )\n }\n\n const abortController = new globalThis.AbortController()\n\n if (acquireTimeout > 0) {\n setTimeout(() => {\n abortController.abort()\n if (internals.debug) {\n console.log('@faable/auth-js: navigatorLock acquire timed out', name)\n }\n }, acquireTimeout)\n }\n\n // MDN article: https://developer.mozilla.org/en-US/docs/Web/API/LockManager/request\n\n return await globalThis.navigator.locks.request(\n name,\n acquireTimeout === 0\n ? {\n mode: 'exclusive',\n ifAvailable: true\n }\n : {\n mode: 'exclusive',\n signal: abortController.signal\n },\n async lock => {\n if (lock) {\n if (internals.debug) {\n console.log(\n '@faable/auth-js: navigatorLock: acquired',\n name,\n lock.name\n )\n }\n\n try {\n return await fn()\n } finally {\n if (internals.debug) {\n console.log(\n '@faable/auth-js: navigatorLock: released',\n name,\n lock.name\n )\n }\n }\n } else {\n if (acquireTimeout === 0) {\n if (internals.debug) {\n console.log(\n '@faable/auth-js: navigatorLock: not immediately available',\n name\n )\n }\n\n throw new NavigatorLockAcquireTimeoutError(\n `Acquiring an exclusive Navigator LockManager lock \"${name}\" immediately failed`\n )\n } else {\n if (internals.debug) {\n try {\n const result = await globalThis.navigator.locks.query()\n\n console.log(\n '@faable/auth-js: Navigator LockManager state',\n JSON.stringify(result, null, ' ')\n )\n } catch (e: any) {\n console.warn(\n '@faable/auth-js: Error when querying Navigator LockManager state',\n e\n )\n }\n }\n\n // Browser is not following the Navigator LockManager spec, it\n // returned a null lock when we didn't use ifAvailable. So we can\n // pretend the lock is acquired in the name of backward compatibility\n // and user experience and just run the function.\n console.warn(\n '@faable/auth-js: Navigator LockManager returned a null lock when using #request without ifAvailable set to true, it appears this browser is not following the LockManager spec https://developer.mozilla.org/en-US/docs/Web/API/LockManager/request'\n )\n\n return await fn()\n }\n }\n }\n )\n}\n\nexport async function lockNoOp<R>(\n name: string,\n acquireTimeout: number,\n fn: () => Promise<R>\n): Promise<R> {\n return await fn()\n}\n","import { Base } from '../Base'\nimport { BaseLogOptions } from '../BaseLog'\nimport { LockFunc, lockNoOp } from './locks'\n\ntype LockOptions = {\n storageKey: string\n lock?: LockFunc\n} & BaseLogOptions\n\nexport class Lock extends Base {\n protected lock: LockFunc\n lockAcquired = false\n protected pendingInLock: Promise<any>[] = []\n\n protected storageKey: string\n\n constructor(options: LockOptions) {\n super({ debug: options.debug })\n this.lock = options.lock || lockNoOp\n this.storageKey = options.storageKey\n }\n\n /**\n * Acquires a global lock based on the storage key.\n */\n async _acquireLock<R>(\n acquireTimeout: number,\n fn: () => Promise<R>\n ): Promise<R> {\n this._debug('#_acquireLock', 'begin', acquireTimeout)\n\n try {\n if (this.lockAcquired) {\n const last = this.pendingInLock.length\n ? this.pendingInLock[this.pendingInLock.length - 1]\n : Promise.resolve()\n\n const result = (async () => {\n await last\n return await fn()\n })()\n\n this.pendingInLock.push(\n (async () => {\n try {\n await result\n } catch (_e) {\n // we just care if it finished\n }\n })()\n )\n\n return result\n }\n\n return await this.lock(\n `lock:${this.storageKey}`,\n acquireTimeout,\n async () => {\n this._debug(\n '#_acquireLock',\n 'lock acquired for storage key',\n this.storageKey\n )\n\n try {\n this.lockAcquired = true\n\n const result = fn()\n\n this.pendingInLock.push(\n (async () => {\n try {\n await result\n } catch (_e) {\n // we just care if it finished\n }\n })()\n )\n\n await result\n\n // keep draining the queue until there's nothing to wait on\n while (this.pendingInLock.length) {\n const waitOn = [...this.pendingInLock]\n\n await Promise.all(waitOn)\n\n this.pendingInLock.splice(0, waitOn.length)\n }\n\n return await result\n } finally {\n this._debug(\n '#_acquireLock',\n 'lock released for storage key',\n this.storageKey\n )\n\n this.lockAcquired = false\n }\n }\n )\n } finally {\n this._debug('#_acquireLock', 'end')\n }\n }\n}\n","import { Base } from './Base'\nimport FaableAuthApi from './FaableAuthApi'\nimport { buildAndSubmitForm, resolveResponseType } from './lib/auth_helpers'\nimport { BroadcastSync } from './lib/broadcast_sync'\nimport { EXPIRY_MARGIN, STORAGE_KEY } from './lib/constants'\nimport {\n AuthApiError,\n AuthError,\n AuthImplicitGrantRedirectError,\n AuthInvalidTokenResponseError,\n AuthPKCEGrantCodeExchangeError,\n AuthSessionMissingError,\n AuthUnknownError,\n isAuthApiError,\n isAuthError,\n isAuthRetryableFetchError\n} from './lib/errors'\nimport { _get, _post } from './lib/fetch'\nimport { document, window } from './lib/globals'\nimport {\n Deferred,\n RawAuthResponse,\n _sessionResponse,\n checkExpiresInTime,\n getCodeChallengeAndMethod,\n isBrowser,\n retryable,\n sleep\n} from './lib/helpers'\nimport { windowHelpers } from './lib/helpers/window'\nimport { decodeJWTPayload, expiryFromAccessToken } from './lib/jwt'\nimport { getSessionFromCookies } from './lib/nextjs'\nimport { loadCodeVerifier } from './lib/pkce_storage'\nimport { isValidSession } from './lib/session_helpers'\nimport { cookieStorageAdapter } from './lib/storage/cookie-storage'\nimport { localStorageAdapter } from './lib/storage/local-storage'\nimport { getItemAsync, setItemAsync } from './lib/storage_helpers'\nimport {\n AuthFlowType,\n CallRefreshTokenResult,\n InitializeResult,\n OAuthResponse,\n SignInWithOAuthConnection,\n Subscription,\n SupportedStorage,\n User\n} from './lib/types'\nimport {\n AuthChangeEvent,\n AuthResponse,\n FaableAuthClientConfig\n} from './lib/types'\nimport { Session, SignOut } from './lib/types'\nimport { clearURLParameters, parseParametersFromURL } from './lib/url_helpers'\nimport { withTimeout } from './lib/with_timeout'\nimport { Lock } from './lock/Lock'\nimport { LockAcquireTimeoutError } from './lock/locks'\nimport { getDomain, getTokenIssuer } from './utils'\n\nexport { cookieStorageAdapter, getSessionFromCookies }\n\n/** Current session will be checked for refresh at this interval. */\nconst AUTO_REFRESH_TICK_DURATION = 30 * 1000\n\n/**\n * A token refresh will be attempted this many ticks before the current session expires. */\nconst AUTO_REFRESH_TICK_THRESHOLD = 3\n\n/** Hard upper bound for a single refresh-token call before it's aborted. */\nconst REFRESH_TIMEOUT_MS = 30 * 1000\n\nconst resolveStorage = (config: FaableAuthClientConfig): SupportedStorage => {\n const { storage, cookieOptions } = config\n if (storage === 'cookie' || cookieOptions) {\n return cookieStorageAdapter(cookieOptions)\n }\n if (storage === 'localStorage' || storage === undefined) {\n return localStorageAdapter\n }\n return storage\n}\n\n/**\n * The main entry point of the SDK: an isomorphic client bound to a Faable\n * Auth tenant that drives every authentication flow.\n *\n * Prefer creating it through the {@link createClient} factory in app code.\n * Once instantiated it begins loading its session in the background, so you\n * can subscribe to {@link FaableAuthClient.onAuthStateChange | auth-state\n * changes} and trigger sign-ins right away. The most common starting points\n * are the {@link FaableAuthClient.signInWithOauthConnection | sign-in}\n * methods and {@link FaableAuthClient.getSession | getSession}.\n *\n * @category Getting started\n * @see {@link https://faable.com/docs/auth/get-started | Get Started with Faable Auth}\n */\nexport class FaableAuthClient extends Base {\n domainUrl: string\n tokenIssuer: string\n redirectUri: string\n scope?: string\n audience?: string\n sessionCheckExpiryDays: number\n\n protected initializePromise: Promise<InitializeResult> | null = null\n protected _lastInitializeResult: InitializeResult | null = null\n protected detectSessionInUrl = true\n\n protected storageKey: string\n\n protected clientId: string\n protected storage: SupportedStorage\n protected api: FaableAuthApi\n\n protected autoRefreshToken: boolean\n protected autoRefreshTicker: ReturnType<typeof setInterval> | null = null\n protected visibilityChangedCallback: (() => Promise<any>) | null = null\n\n protected refreshingDeferred: Deferred<CallRefreshTokenResult> | null = null\n\n /**\n * Cross-tab broadcaster + local subscriber registry for state changes.\n */\n protected broadcastSync: BroadcastSync\n protected _session: Session | null = null\n\n /**\n * Initiation flow to use when redirecting to /authorize. Defaults to\n * PKCE in browsers (recommended for SPAs) and implicit otherwise.\n * Distinct from the callback-side flow which is detected from URL params.\n */\n protected flowType: AuthFlowType\n\n protected lock: Lock\n\n /**\n * Creates a new authentication client bound to a Faable Auth tenant.\n *\n * The constructor kicks off {@link FaableAuthClient.initialize} in the\n * background; you do not need to await anything before calling other methods.\n * Prefer the {@link createClient} factory in app code — it has the same\n * effect with less ceremony.\n *\n * @param config Tenant settings. `domain` and `clientId` are required and\n * throw synchronously when missing.\n * @example\n * ```ts\n * const auth = new FaableAuthClient({\n * domain: '<faableauth_domain>',\n * clientId: '<client_id>',\n * redirectUri: window.location.origin\n * })\n * ```\n * @see {@link https://faable.com/docs/auth/get-started | Get Started with Faable Auth}\n * @see {@link https://faable.com/docs/auth/clients | Clients}\n * @category Getting started\n */\n constructor(config: FaableAuthClientConfig) {\n const debug = config?.debug || false\n super({ debug })\n\n this.sessionCheckExpiryDays = 1\n this.redirectUri = config?.redirectUri || ''\n if (!config?.domain) {\n throw new Error('Missing domain')\n }\n this.domainUrl = getDomain(config.domain)\n\n this.tokenIssuer = getTokenIssuer('', this.domainUrl)\n if (!config.clientId) {\n throw new Error('Missing clientId')\n }\n this.clientId = config.clientId\n this.audience = config.audience\n\n this.api = new FaableAuthApi(this.domainUrl, { debug })\n\n // Storage key\n const key_prefix = config?.storageKey || STORAGE_KEY\n this.storageKey = `${key_prefix}-${this.clientId}`\n\n this.storage = resolveStorage(config)\n\n this.lock = new Lock({\n lock: config.lock,\n storageKey: this.storageKey,\n debug: config.debug\n })\n\n this.broadcastSync = new BroadcastSync(\n isBrowser() ? this.storageKey : '',\n (msg, ...args) => this._debug(msg, ...args)\n )\n\n this.flowType = config.flowType ?? (isBrowser() ? 'pkce' : 'implicit')\n\n this.autoRefreshToken = true\n\n this.initialize()\n }\n\n /**\n * Cached session value last persisted by the client.\n *\n * This is a synchronous accessor that returns whatever the client has\n * already loaded into memory. It can lag behind storage (for example,\n * across tabs before the broadcast event arrives) and never triggers a\n * refresh. Prefer {@link FaableAuthClient.getSession} when you need an\n * authoritative value, especially on the server.\n *\n * @returns The cached {@link Session} or `null` if no user is signed in.\n * @see {@link https://faable.com/docs/auth/oidc/userinfo | UserInfo}\n * @category Sessions\n */\n get session() {\n return this._session\n }\n\n /**\n * Initializes the client session either from the URL or from storage.\n *\n * Automatically called once from the constructor and idempotent — extra\n * calls return the same in-flight promise. Call it explicitly when you\n * need to await an OAuth, magic link, or password-recovery redirect to\n * finish processing so you can surface any returned error.\n *\n * @returns A promise that resolves to `{ error }` — non-null when the URL\n * carried a failure or storage was corrupt; never throws.\n * @example\n * ```ts\n * const { error } = await auth.initialize()\n * if (error) console.error('Auth redirect failed', error)\n * ```\n * @see {@link https://faable.com/docs/auth/oauth-flows/authorization-code | Authorization Code with PKCE}\n * @category Lifecycle\n */\n async initialize(): Promise<InitializeResult> {\n if (this.initializePromise) {\n return await this.initializePromise\n }\n\n this.initializePromise = (async () => {\n return await this.lock._acquireLock(-1, async () => {\n return await this._initialize()\n })\n })()\n\n const result = await this.initializePromise\n this._lastInitializeResult = result\n return result\n }\n\n /**\n * The result of the most recent {@link FaableAuthClient.initialize} run, or\n * `null` while the first one is still in flight.\n *\n * The constructor starts `initialize()` in the background and discards the\n * promise; this accessor lets code that cannot await it (for example a\n * React provider effect) read whether the last OAuth/redirect attempt\n * errored, instead of being stuck with a session that silently stays\n * `null`.\n *\n * @category Lifecycle\n */\n get lastInitializeResult(): InitializeResult | null {\n return this._lastInitializeResult\n }\n\n /**\n * Completes an OAuth / magic-link / password-recovery redirect on your\n * callback route and reports the outcome.\n *\n * The SDK already consumes the URL during the `initialize()` it kicks off\n * from the constructor; this is a thin, discoverable wrapper that awaits\n * that same in-flight run (idempotent) so you can:\n *\n * - redirect **only once** the token exchange has finished, and\n * - surface `error` instead of hanging on a \"Signing you in…\" screen when\n * the exchange fails (e.g. an expired PKCE verifier).\n *\n * It also returns `returnTo` — the app-side destination you optionally\n * passed to `signInWith*({ returnTo })` — so you don't need a side channel\n * (like `sessionStorage`) to remember where to send the user.\n *\n * @example\n * ```ts\n * // app/callback/page.tsx\n * const { error, returnTo } = await auth.handleRedirectCallback()\n * if (error) showError(error.message)\n * else router.replace(returnTo ?? '/')\n * ```\n * @see {@link FaableAuthClient.initialize}\n * @category Lifecycle\n */\n async handleRedirectCallback(): Promise<InitializeResult> {\n return await this.initialize()\n }\n\n /**\n * IMPORTANT:\n * 1. Never throw in this method, as it is called from the constructor\n * 2. Never return a session from this method as it would be cached over\n * the whole lifetime of the client\n */\n private async _initialize(): Promise<InitializeResult> {\n try {\n const flow = await this._detectFlowType()\n\n this._debug('#_initialize()', 'begin', 'flow_type', flow)\n\n // if exists any flow, process the session\n if (flow) {\n const { data, error } = await this._getSessionFromURL(flow)\n if (error) {\n this._debug(\n '#_initialize()',\n 'error detecting session from URL',\n error\n )\n\n // hacky workaround to keep the existing session if there's an error returned from identity linking\n // TODO: once error codes are ready, we should match against it instead of the message\n if (\n error?.message === 'Identity is already linked' ||\n error?.message === 'Identity is already linked to another user'\n ) {\n return { error }\n }\n\n // failed login attempt via url,\n // remove old session as in verifyOtp, signUp and signInWith*\n await this._removeSession()\n\n return { error }\n }\n\n const { session, redirectType, returnTo, is_new_user } = data\n\n this._debug(\n '#_initialize()',\n 'detected session in URL',\n session,\n 'redirect type',\n redirectType\n )\n\n await this._saveSession(session)\n\n setTimeout(async () => {\n if (redirectType === 'recovery') {\n await this._notifyAllSubscribers('PASSWORD_RECOVERY', session)\n } else {\n await this._notifyAllSubscribers('SIGNED_IN', session)\n }\n }, 0)\n\n return { error: null, redirectType, returnTo, is_new_user }\n }\n // no login attempt via callback url try to recover session from storage\n await this._recoverAndRefresh()\n return { error: null }\n } catch (error) {\n if (isAuthError(error)) {\n return { error }\n }\n\n return {\n error: new AuthUnknownError(\n 'Unexpected error during initialization',\n error\n )\n }\n } finally {\n await this._handleVisibilityChange()\n this._debug('#_initialize()', 'end')\n }\n }\n\n /**\n * Gets the session data from a URL string\n */\n private async _getSessionFromURL(flow: AuthFlowType): Promise<\n | {\n data: {\n session: Session\n redirectType: string | null\n returnTo: string | null\n is_new_user: boolean\n }\n error: null\n }\n | {\n data: {\n session: null\n redirectType: null\n returnTo: null\n is_new_user: false\n }\n error: AuthError\n }\n > {\n try {\n const params = parseParametersFromURL(window?.location.href)\n // The auth server appends `?signup=true` to the callback when the login\n // just created a new account (social/OAuth only). Surface it so the app\n // can branch into onboarding; strip it from the URL alongside the tokens.\n const is_new_user = params.signup === 'true'\n if (flow == 'pkce') {\n if (!params.code) {\n throw new AuthPKCEGrantCodeExchangeError('No code detected.')\n }\n\n const { data, error } = await this._exchangeCodeForSession(params.code)\n if (error) throw error\n\n // Remove code (and the signup marker) from URL\n clearURLParameters(['code', 'signup'])\n\n return {\n data: {\n session: data.session,\n redirectType: data.redirectType,\n returnTo: data.returnTo,\n is_new_user\n },\n error: null\n }\n }\n\n if (params.error || params.error_description || params.error_code) {\n throw new AuthImplicitGrantRedirectError(\n params.error_description ||\n 'Error in URL with unspecified error_description',\n {\n error: params.error || 'unspecified_error',\n code: params.error_code || 'unspecified_code'\n }\n )\n }\n\n const {\n provider_token,\n provider_refresh_token,\n access_token,\n refresh_token,\n expires_in,\n expires_at,\n token_type\n } = params\n\n // We only strictly need the token pair. Some flows hand the tokens back\n // in the query string without the full OIDC envelope (`expires_in` /\n // `token_type`); fall back to the access token's own `exp` claim and a\n // `bearer` default instead of rejecting an otherwise-valid callback.\n if (!access_token || !refresh_token) {\n throw new AuthImplicitGrantRedirectError('No session defined in URL')\n }\n\n let expiresAt: number\n let expiresIn: number\n if (expires_in) {\n // Check time is valid\n ;({ expiresAt, expiresIn } = checkExpiresInTime({\n expires_in,\n expires_at,\n refreshTick: AUTO_REFRESH_TICK_DURATION\n }))\n } else {\n ;({ expiresAt, expiresIn } = expiryFromAccessToken(\n access_token,\n expires_at\n ))\n }\n\n const { data: user, error } = await this._getUser(access_token)\n\n if (error || !user) throw error\n\n const session: Session = {\n provider_token,\n provider_refresh_token,\n access_token,\n expires_in: expiresIn,\n expires_at: expiresAt,\n refresh_token,\n token_type: token_type || 'bearer',\n user\n }\n\n // Remove tokens from URL\n clearURLParameters([\n 'access_token',\n 'expires_in',\n 'refresh_token',\n 'token_type',\n 'scope',\n 'signup'\n ])\n this._debug('#_getSessionFromURL()', 'clearing window.location.hash')\n\n return {\n data: {\n session,\n redirectType: params.type,\n returnTo: null,\n is_new_user\n },\n error: null\n }\n } catch (error) {\n this._debug(error)\n if (isAuthError(error)) {\n return {\n data: {\n session: null,\n redirectType: null,\n returnTo: null,\n is_new_user: false\n },\n error\n }\n }\n throw error\n }\n }\n\n private async _exchangeCodeForSession(authCode: string): Promise<\n | {\n data: {\n session: Session\n user: User\n redirectType: string | null\n returnTo: string | null\n }\n error: null\n }\n | {\n data: {\n session: null\n user: null\n redirectType: null\n returnTo: null\n }\n error: AuthError\n }\n > {\n const stored = await loadCodeVerifier(\n this.storage,\n `${this.storageKey}-code-verifier`\n )\n if (!stored) {\n return {\n data: { user: null, session: null, redirectType: null, returnTo: null },\n error: new AuthPKCEGrantCodeExchangeError(\n 'No active PKCE code verifier — the authorization flow has expired or was not started'\n )\n }\n }\n const {\n verifier: codeVerifier,\n redirectType = null,\n returnTo = null\n } = stored\n\n const rawResponse = await _post<Partial<RawAuthResponse>>(\n `${this.domainUrl}/oauth/token`,\n {\n client_id: this.clientId,\n grant_type: 'authorization_code',\n code: authCode,\n code_verifier: codeVerifier,\n ...(this.audience ? { audience: this.audience } : {})\n }\n )\n\n const { data, error } = _sessionResponse(rawResponse)\n\n if (!data) {\n throw new Error('Missing data')\n }\n\n await this.storage.removeItem(`${this.storageKey}-code-verifier`)\n\n if (error) {\n return {\n data: { user: null, session: null, redirectType: null, returnTo: null },\n error\n }\n } else if (!data || !data.session || !data.user) {\n return {\n data: { user: null, session: null, redirectType: null, returnTo: null },\n error: new AuthInvalidTokenResponseError()\n }\n }\n let session = data.session as Session\n if (session) {\n const { data: user, error } = await this._getUser(session.access_token)\n if (error || !user) {\n throw error\n }\n\n session = {\n ...session,\n user\n }\n data.session = session\n\n await this._saveSession(session)\n await this._notifyAllSubscribers('SIGNED_IN', session)\n }\n return {\n data: {\n ...data,\n redirectType: redirectType ?? null,\n returnTo: returnTo ?? null\n } as any,\n error\n }\n }\n\n /**\n * Registers callbacks on the browser / platform, which in-turn run\n * algorithms when the browser window/tab are in foreground. On non-browser\n * platforms it assumes always foreground.\n */\n private async _handleVisibilityChange() {\n this._debug('#_handleVisibilityChange()')\n\n if (!isBrowser() || !window?.addEventListener) {\n if (this.autoRefreshToken) {\n // in non-browser environments the refresh token ticker runs always\n this.startAutoRefresh()\n }\n\n return false\n }\n\n try {\n this.visibilityChangedCallback = async () =>\n await this._onVisibilityChanged(false)\n\n window?.addEventListener(\n 'visibilitychange',\n this.visibilityChangedCallback\n )\n\n // now immediately call the visbility changed callback to setup with the\n // current visbility state\n await this._onVisibilityChanged(true) // initial call\n } catch (error) {\n console.error('_handleVisibilityChange', error)\n }\n }\n\n /**\n * Callback registered with `window.addEventListener('visibilitychange')`.\n */\n private async _onVisibilityChanged(calledFromInitialize: boolean) {\n const methodName = `#_onVisibilityChanged(${calledFromInitialize})`\n this._debug(methodName, 'visibilityState', document.visibilityState)\n\n if (document.visibilityState === 'visible') {\n if (this.autoRefreshToken) {\n // in browser environments the refresh token ticker runs only on focused tabs\n // which prevents race conditions\n this._startAutoRefresh()\n }\n\n if (!calledFromInitialize) {\n // called when the visibility has changed, i.e. the browser\n // transitioned from hidden -> visible so we need to see if the session\n // should be recovered immediately... but to do that we need to acquire\n // the lock first asynchronously\n await this.initializePromise\n\n await this.lock._acquireLock(-1, async () => {\n if (document.visibilityState !== 'visible') {\n this._debug(\n methodName,\n 'acquired the lock to recover the session, but the browser visibilityState is no longer visible, aborting'\n )\n\n // visibility has changed while waiting for the lock, abort\n return\n }\n\n // recover the session\n await this._recoverAndRefresh()\n })\n }\n } else if (document.visibilityState === 'hidden') {\n if (this.autoRefreshToken) {\n this._stopAutoRefresh()\n }\n }\n }\n\n /**\n * Recovers the session from LocalStorage and refreshes\n * Note: this method is async to accommodate for AsyncStorage e.g. in React native.\n */\n private async _recoverAndRefresh() {\n const debugName = '#_recoverAndRefresh()'\n this._debug(debugName, 'begin')\n\n try {\n const currentSession = await getItemAsync(this.storage, this.storageKey)\n this._debug(debugName, 'session from storage', currentSession)\n\n if (!isValidSession(currentSession)) {\n this._debug(debugName, 'session is not valid')\n if (currentSession !== null) {\n await this._removeSession()\n }\n\n return\n }\n\n const timeNow = Math.round(Date.now() / 1000)\n const expiresWithMargin =\n (currentSession.expires_at ?? Infinity) < timeNow + EXPIRY_MARGIN\n\n this._debug(\n debugName,\n `session has${\n expiresWithMargin ? '' : ' not'\n } expired with margin of ${EXPIRY_MARGIN}s`\n )\n\n if (expiresWithMargin) {\n if (this.autoRefreshToken && currentSession.refresh_token) {\n const { error } = await this._callRefreshToken(\n currentSession.refresh_token\n )\n\n if (error) {\n console.error(error)\n\n if (!isAuthRetryableFetchError(error)) {\n this._debug(\n debugName,\n 'refresh failed with a non-retryable error, removing the session',\n error\n )\n await this._removeSession()\n }\n }\n }\n } else {\n // no need to persist currentSession again, as we just loaded it from\n // local storage; persisting it again may overwrite a value saved by\n // another client with access to the same local storage\n this._session = currentSession\n await this._notifyAllSubscribers('SIGNED_IN', currentSession)\n }\n } catch (err) {\n this._debug(debugName, 'error', err)\n\n console.error(err)\n return\n } finally {\n this._debug(debugName, 'end')\n }\n }\n\n /**\n * Removes any registered visibilitychange callback.\n *\n * @see startAutoRefresh\n * @see stopAutoRefresh\n */\n private _removeVisibilityChangedCallback() {\n this._debug('#_removeVisibilityChangedCallback()')\n\n const callback = this.visibilityChangedCallback\n this.visibilityChangedCallback = null\n\n try {\n if (callback && isBrowser() && window?.removeEventListener) {\n window.removeEventListener('visibilitychange', callback)\n }\n } catch (e) {\n console.error('removing visibilitychange callback failed', e)\n }\n }\n\n /**\n * Starts an auto-refresh process in the background. The session is checked\n * every few seconds. Close to the time of expiration a process is started to\n * refresh the session. If refreshing fails it will be retried for as long as\n * necessary.\n *\n * If `autoRefreshToken` is enabled in the client config you don't need to\n * call this function, it will be called for you.\n *\n * On browsers the refresh process works only when the tab/window is in the\n * foreground to conserve resources as well as prevent race conditions and\n * flooding auth with requests. If you call this method any managed\n * visibility change callback will be removed and you must manage visibility\n * changes on your own.\n *\n * On non-browser platforms the refresh process works *continuously* in the\n * background, which may not be desirable. You should hook into your\n * platform's foreground indication mechanism and call these methods\n * appropriately to conserve resources.\n *\n * @example\n * ```ts\n * // React Native / Node: drive the refresh loop on focus events yourself\n * appState.addEventListener('change', state => {\n * if (state === 'active') auth.startAutoRefresh()\n * })\n * ```\n * @see {@link https://faable.com/docs/auth/oauth-flows/refresh-token | Refresh Token}\n * @category Sessions\n */\n async startAutoRefresh() {\n this._removeVisibilityChangedCallback()\n await this._startAutoRefresh()\n }\n\n /**\n * This is the private implementation of {@link #startAutoRefresh}. Use this\n * within the library.\n */\n private async _startAutoRefresh() {\n await this._stopAutoRefresh()\n\n this._debug('#_startAutoRefresh()')\n\n const ticker = setInterval(\n () => this._autoRefreshTokenTick(),\n AUTO_REFRESH_TICK_DURATION\n )\n this.autoRefreshTicker = ticker\n\n if (\n ticker &&\n typeof ticker === 'object' &&\n typeof ticker.unref === 'function'\n ) {\n // ticker is a NodeJS Timeout object that has an `unref` method\n // https://nodejs.org/api/timers.html#timeoutunref\n // When auto refresh is used in NodeJS (like for testing) the\n // `setInterval` is preventing the process from being marked as\n // finished and tests run endlessly. This can be prevented by calling\n // `unref()` on the returned object.\n ticker.unref()\n } else if (\n typeof (globalThis as any).Deno !== 'undefined' &&\n typeof (globalThis as any).Deno.unrefTimer === 'function'\n ) {\n // Same intent as Node's unref(), via the Deno API.\n // https://deno.land/api@latest?unstable&s=Deno.unrefTimer\n ;(globalThis as any).Deno.unrefTimer(ticker)\n }\n\n // run the tick immediately, but in the next pass of the event loop so that\n // #_initialize can be allowed to complete without recursively waiting on\n // itself\n setTimeout(async () => {\n await this.initializePromise\n await this._autoRefreshTokenTick()\n }, 0)\n }\n\n /**\n * This is the private implementation of {@link #stopAutoRefresh}. Use this\n * within the library.\n */\n private async _stopAutoRefresh() {\n this._debug('#_stopAutoRefresh()')\n\n const ticker = this.autoRefreshTicker\n this.autoRefreshTicker = null\n\n if (ticker) {\n clearInterval(ticker)\n }\n }\n\n /**\n * Runs the auto refresh token tick.\n */\n private async _autoRefreshTokenTick() {\n this._debug('#_autoRefreshTokenTick()', 'begin')\n\n try {\n await this.lock._acquireLock(0, async () => {\n try {\n const now = Date.now()\n\n try {\n return await this._useSession(async result => {\n const {\n data: { session }\n } = result\n\n if (!session || !session.refresh_token || !session.expires_at) {\n this._debug('#_autoRefreshTokenTick()', 'no session')\n return\n }\n\n // session will expire in this many ticks (or has already expired if <= 0)\n const expiresInTicks = Math.floor(\n (session.expires_at * 1000 - now) / AUTO_REFRESH_TICK_DURATION\n )\n\n this._debug(\n '#_autoRefreshTokenTick()',\n `access token expires in ${expiresInTicks} ticks, a tick lasts ${AUTO_REFRESH_TICK_DURATION}ms, refresh threshold is ${AUTO_REFRESH_TICK_THRESHOLD} ticks`\n )\n\n if (expiresInTicks <= AUTO_REFRESH_TICK_THRESHOLD) {\n await this._callRefreshToken(session.refresh_token)\n }\n })\n } catch (e: any) {\n console.error(\n 'Auto refresh tick failed with error. This is likely a transient error.',\n e\n )\n }\n } finally {\n this._debug('#_autoRefreshTokenTick()', 'end')\n }\n })\n } catch (e: any) {\n if (e.isAcquireTimeout || e instanceof LockAcquireTimeoutError) {\n this._debug('auto refresh token tick lock not available')\n } else {\n throw e\n }\n }\n }\n\n private async _detectFlowType(): Promise<AuthFlowType | null> {\n const params = parseParametersFromURL(window?.location.href)\n\n const browser = isBrowser()\n\n // PKCE\n if (browser && params.code) {\n return 'pkce'\n }\n\n // Implicit\n if (browser && (params.access_token || params.error_description)) {\n return 'implicit'\n }\n return null\n }\n\n private _scope() {\n return this.scope || 'openid profile email'\n }\n\n private async _getUrlForConnection(\n url: string,\n params: {\n connection?: string\n connection_id?: string\n redirectTo?: string\n returnTo?: string\n scopes?: string\n response_type?: 'code' | 'token'\n queryParams?: { [key: string]: string }\n skipBrowserRedirect?: boolean\n audience?: string\n }\n ) {\n let urlParams: Record<string, any> = params.queryParams || {}\n\n const authorize_params: Record<string, any> = {\n client_id: this.clientId,\n response_type: params.response_type,\n redirect_uri:\n params.redirectTo || this.redirectUri || window?.location.origin,\n scope: params.scopes || this._scope()\n }\n\n if (this.flowType === 'pkce') {\n const [codeChallenge, codeChallengeMethod] =\n await getCodeChallengeAndMethod(\n this.storage,\n this.storageKey,\n false,\n params.returnTo\n )\n\n urlParams = {\n ...urlParams,\n code_challenge: codeChallenge,\n code_challenge_method: codeChallengeMethod\n }\n }\n\n if (params.connection_id) {\n authorize_params.connection_id = params.connection_id\n } else if (params.connection) {\n authorize_params.connection = params.connection\n }\n\n const audience = params.audience ?? this.audience\n if (audience) {\n authorize_params.audience = audience\n }\n\n return `${url}?${new URLSearchParams({\n ...urlParams,\n ...authorize_params\n })}`\n }\n\n /**\n * Starts an OAuth / social login by redirecting the browser to the tenant's\n * `/authorize` endpoint for the chosen connection.\n *\n * In browsers the SDK redirects the current window unless\n * `skipBrowserRedirect` is `true`; the call resolves to the authorization\n * URL so you can drive the navigation yourself. PKCE is used by default in\n * browsers, falling back to the implicit flow elsewhere. Prefer\n * `connection_id` when known — the backend resolves it without an extra\n * lookup; `connection` (by name) is kept for legacy tenants.\n *\n * @example\n * ```ts\n * await auth.signInWithOauthConnection({\n * connection: 'google',\n * redirectTo: 'https://app.example.com/callback'\n * })\n * ```\n * @see {@link https://faable.com/docs/auth/connections | Connections}\n * @see {@link https://faable.com/docs/auth/oauth-flows/authorization-code | Authorization Code with PKCE}\n * @category Sign in\n */\n async signInWithOauthConnection(\n credentials: SignInWithOAuthConnection\n ): Promise<OAuthResponse> {\n return await this._handleConnectionSignIn({\n connection: credentials.connection,\n connection_id: credentials.connection_id,\n redirectTo: credentials?.redirectTo,\n returnTo: credentials?.returnTo,\n scopes: credentials?.scopes,\n queryParams: credentials.queryParams,\n skipBrowserRedirect: credentials.skipBrowserRedirect,\n audience: credentials.audience\n })\n }\n\n /**\n * Signs the user in with a username + password against a database\n * connection on the tenant.\n *\n * The server responds with an HTML form that posts the user back to the\n * tenant's `/login/callback` to complete the OAuth flow; the SDK\n * auto-submits it from the current document. That is why the success path\n * resolves to `{ data: null, error: null }` — the actual session lands on\n * the redirect target, not on this return value. Subscribe with\n * {@link FaableAuthClient.onAuthStateChange} to observe the resulting\n * `SIGNED_IN` event.\n *\n * @example\n * ```ts\n * await auth.signInWithUsernamePassword({\n * username: 'user@example.com',\n * password: '••••••••',\n * redirectTo: 'https://app.example.com/callback'\n * })\n * ```\n * @see {@link https://faable.com/docs/auth/connections | Connections}\n * @category Sign in\n */\n async signInWithUsernamePassword(data: {\n username: string\n password: string\n redirectTo?: string\n state?: string\n audience?: string\n }): Promise<{ data: null; error: AuthError | null }> {\n const audience = data.audience ?? this.audience\n const rawAuthResponse = await _post<string>(\n `${this.domainUrl}/usernamepassword/login`,\n {\n username: data.username,\n password: data.password,\n redirect_uri:\n data.redirectTo || this.redirectUri || window?.location.origin,\n client_id: this.clientId,\n state: data.state,\n ...(audience ? { audience } : {})\n },\n { raw: true }\n )\n\n if (!rawAuthResponse.data || rawAuthResponse.error) {\n return {\n data: null,\n error: new AuthUnknownError(\n rawAuthResponse.error || 'Error in username password login',\n rawAuthResponse.error\n )\n }\n }\n buildAndSubmitForm(rawAuthResponse.data, document)\n return { data: null, error: null }\n }\n\n /**\n * Registers a new user against the tenant's database connection with an\n * email + password, then signs them in — so an email/password signup form\n * can live entirely in the browser with no backend of your own.\n *\n * This calls the public `POST /dbconnections/signup` endpoint (the Faable\n * analogue of Auth0's `/dbconnections/signup`) which creates the user and\n * its credential in one step, then chains\n * {@link FaableAuthClient.signInWithUsernamePassword} to establish the\n * session.\n *\n * **Auto-login navigates the browser.** Like every interactive\n * username/password login in this SDK, the sign-in step submits a form that\n * round-trips through the auth server, so on success the page redirects to\n * your `redirectTo` and the live session is delivered there by\n * {@link FaableAuthClient.initialize} (and a `SIGNED_IN` event). This method\n * only returns synchronously when signup itself fails, or in non-navigating\n * runtimes (e.g. tests).\n *\n * The user is created with `email_verified: false`; any verification /\n * welcome email is driven by the tenant's account settings.\n *\n * @param data The new user's email, password and optional profile fields.\n * @example\n * ```ts\n * const { error } = await auth.signUp({\n * email: 'user@example.com',\n * password: '••••••••',\n * name: 'Ada Lovelace',\n * redirectTo: 'https://app.example.com/callback'\n * })\n * if (error) showError(error.message) // e.g. 'email_taken', 'signup_disabled'\n * // otherwise the browser is already navigating to complete the login\n * ```\n * @see {@link https://faable.com/docs/auth/connections | Connections}\n * @category Sign in\n */\n async signUp(data: {\n email: string\n password: string\n name?: string\n given_name?: string\n family_name?: string\n user_metadata?: Record<string, unknown>\n connection?: string\n redirectTo?: string\n state?: string\n audience?: string\n }): Promise<{ data: null; error: AuthError | null }> {\n if (!data?.email || !data?.password) {\n return {\n data: null,\n error: new AuthUnknownError('email and password are required', null)\n }\n }\n\n const { data: body, error } = await _post(\n `${this.domainUrl}/dbconnections/signup`,\n {\n client_id: this.clientId,\n email: data.email,\n password: data.password,\n ...(data.name ? { name: data.name } : {}),\n ...(data.given_name ? { given_name: data.given_name } : {}),\n ...(data.family_name ? { family_name: data.family_name } : {}),\n ...(data.user_metadata ? { user_metadata: data.user_metadata } : {}),\n ...(data.connection ? { connection: data.connection } : {})\n }\n )\n\n if (error) {\n // `_post` hands back the server's `{ status, message }` body as `data`\n // and its `message` as `error`. Map the HTTP status to a stable\n // ErrorCode so callers can branch without string-matching the message.\n const status = (body as any)?.status as number | undefined\n const code =\n status === 403\n ? 'signup_disabled'\n : status === 409\n ? 'email_exists'\n : undefined\n return {\n data: null,\n error: new AuthApiError(String(error), status ?? 500, code)\n }\n }\n\n // Auto-login through the standard redirect flow (no ROPC grant exists for\n // database connections, so this is the same path a manual login takes).\n return this.signInWithUsernamePassword({\n username: data.email,\n password: data.password,\n redirectTo: data.redirectTo,\n state: data.state,\n audience: data.audience\n })\n }\n\n /**\n * Completes a passwordless login by exchanging an OTP code for a session.\n *\n * Pair this with {@link FaableAuthClient.signInWithPasswordless} called\n * with `type: 'code'`. On success the new session is persisted to storage\n * and a `SIGNED_IN` event is broadcast.\n *\n * @param data The user identifier and the OTP code they received.\n * @example\n * ```ts\n * const { data, error } = await auth.signInWithOtp({\n * username: 'user@example.com',\n * otp: '123456'\n * })\n * ```\n * @see {@link https://faable.com/docs/auth/passwordless | Passwordless Authentication}\n * @category Sign in\n */\n async signInWithOtp(data: {\n username: string\n otp: string\n audience?: string\n }): Promise<AuthResponse> {\n const audience = data.audience ?? this.audience\n const rawResponse = await _post<Partial<RawAuthResponse>>(\n `${this.domainUrl}/oauth/token`,\n {\n client_id: this.clientId,\n grant_type: 'http://auth0.com/oauth/grant-type/passwordless/otp',\n username: data.username,\n otp: data.otp,\n ...(audience ? { audience } : {})\n }\n )\n\n const { data: sessionData, error } = _sessionResponse(rawResponse)\n\n if (error) {\n return { data: { user: null, session: null }, error }\n }\n\n if (!sessionData || !sessionData.session) {\n return {\n data: { user: null, session: null },\n error: new AuthInvalidTokenResponseError()\n }\n }\n\n const session = sessionData.session as Session\n const { data: user, error: userError } = await this._getUser(\n session.access_token\n )\n\n if (userError || !user) {\n return {\n data: { user: null, session: null },\n error:\n userError || new AuthUnknownError('Could not fetch user info', null)\n }\n }\n\n session.user = user\n await this._saveSession(session)\n await this._notifyAllSubscribers('SIGNED_IN', session)\n\n return {\n data: { user: session.user, session },\n error: null\n }\n }\n\n /**\n * Starts a passwordless login flow by emailing the user either an OTP code\n * or a magic link.\n *\n * - `type: 'code'` sends a short code the user pastes into your UI; finish\n * the flow with {@link FaableAuthClient.signInWithOtp}.\n * - `type: 'link'` sends a clickable link that lands on your `redirectUri`\n * with the tokens already attached, processed by\n * {@link FaableAuthClient.initialize} on page load.\n *\n * @param data The user's email and the delivery mechanism.\n * @example\n * ```ts\n * await auth.signInWithPasswordless({\n * email: 'user@example.com',\n * type: 'code'\n * })\n * ```\n * @see {@link https://faable.com/docs/auth/passwordless | Passwordless Authentication}\n * @category Sign in\n */\n async signInWithPasswordless(data: {\n email: string\n type: 'code' | 'link'\n audience?: string\n }): Promise<{ data: any; error: AuthError | null }> {\n const audience = data.audience ?? this.audience\n const response = await _post(`${this.domainUrl}/passwordless/start`, {\n client_id: this.clientId,\n email: data.email,\n send: data.type,\n ...(audience ? { audience } : {})\n })\n\n return { data: response.data, error: response.error }\n }\n\n /**\n * Triggers a \"change your password\" email for a database-connection user.\n *\n * The current session is unaffected — the user clicks the link in the\n * email and completes the reset on the tenant's hosted pages. The promise\n * resolves once the email has been queued.\n *\n * @param params The user's email address.\n * @example\n * ```ts\n * await auth.changePassword({ email: 'user@example.com' })\n * ```\n * @see {@link https://faable.com/docs/auth/connections | Connections}\n * @category Account\n */\n async changePassword(params: {\n email: string\n }): Promise<{ data: unknown; error: AuthError | null }> {\n if (!params?.email) {\n return {\n data: null,\n error: new AuthUnknownError('email is required', null)\n }\n }\n\n const { data, error } = await _post(\n `${this.domainUrl}/dbconnections/change_password`,\n { email: params.email }\n )\n return {\n data: data ?? null,\n error: error ? new AuthUnknownError(String(error), error) : null\n }\n }\n\n /**\n * Resolves the signed-in user's id from a session. Prefers the userinfo\n * shape (`user.id`) returned by `/me`, falls back to a `sub` claim on the\n * user object, and finally decodes the access token's `sub` — the id is\n * always present there, so this never reports a live session as missing.\n */\n private _resolveUserId(session: Session): string | undefined {\n const fromUser = (session.user as any)?.id ?? session.user?.sub\n if (fromUser) return fromUser\n try {\n const payload = decodeJWTPayload(session.access_token)\n return payload?.sub\n } catch {\n return undefined\n }\n }\n\n /**\n * Starts a verified email change for the currently signed-in user.\n *\n * The user must be authenticated — the call is made with the session's\n * access token, and the auth server only lets a user change their own\n * email. It creates a verification ticket and emails the user; the change\n * is applied only after they click the link, which the server handles and\n * then redirects to `redirect_uri`. The current session is unaffected until\n * then.\n *\n * @param params The new email plus optional verification policy.\n * - `verification_mode`: `'new_only'` verifies just the new address;\n * `'old_and_new'` also requires confirming from the old one. When\n * omitted the account's default policy applies.\n * - `redirect_uri`: where the server sends the user after they verify.\n * @example\n * ```ts\n * const { data, error } = await auth.changeEmail({\n * new_email: 'new@example.com',\n * redirect_uri: 'https://app.example.com/account'\n * })\n * // data: { status: 'verification_sent', ticket_id, verification_mode }\n * ```\n * @see {@link https://faable.com/docs/auth/change-email | Change Email}\n * @category Account\n */\n async changeEmail(params: {\n new_email: string\n verification_mode?: 'new_only' | 'old_and_new'\n redirect_uri?: string\n }): Promise<{ data: unknown; error: AuthError | null }> {\n if (!params?.new_email) {\n return {\n data: null,\n error: new AuthUnknownError('new_email is required', null)\n }\n }\n\n const { data: sessionData, error: sessionError } = await this.getSession()\n const session = sessionData?.session\n if (sessionError || !session) {\n return {\n data: null,\n error: sessionError || new AuthSessionMissingError()\n }\n }\n\n // Resolve the user id defensively. `/me` (userinfo) exposes it as\n // `user.id`, but older/other shapes use the `sub` claim; fall back to the\n // access token's own `sub` so we never mistake a present session for a\n // missing one (that regression shipped `changeEmail` reading only `.sub`).\n const user_id = this._resolveUserId(session)\n if (!user_id) {\n return { data: null, error: new AuthSessionMissingError() }\n }\n\n const { data, error } = await _post(\n `${this.domainUrl}/user/${user_id}/change-email`,\n {\n new_email: params.new_email,\n ...(params.verification_mode\n ? { verification_mode: params.verification_mode }\n : {}),\n ...(params.redirect_uri ? { redirect_uri: params.redirect_uri } : {})\n },\n { token: session.access_token }\n )\n return {\n data: data ?? null,\n error: error ? new AuthUnknownError(String(error), error) : null\n }\n }\n\n /**\n * Builds the tenant's `/authorize` URL without redirecting the browser.\n *\n * Useful when you need to render a login link, open the page in a popup,\n * or hand the URL to a different runtime (e.g. a webview). For the\n * everyday \"click → redirect\" flow use {@link FaableAuthClient.authorize}\n * or {@link FaableAuthClient.signInWithOauthConnection}.\n *\n * The redirect target is resolved with this precedence:\n * `options.redirectTo` → `config.redirectUri` → `window.location.origin`.\n *\n * @returns The fully-qualified authorize URL.\n * @example\n * ```ts\n * const url = auth.buildAuthorizeUrl({\n * connection: 'google',\n * redirectTo: 'https://app.example.com/callback'\n * })\n * window.open(url, 'login', 'popup')\n * ```\n * @see {@link https://faable.com/docs/auth/oauth-flows/authorization-code | Authorization Code with PKCE}\n * @category Authorize URLs\n */\n buildAuthorizeUrl(\n options: {\n connection?: string\n redirectTo?: string\n scope?: string\n response_type?: string\n audience?: string\n } = {}\n ): string {\n const params: Record<string, string | undefined> = {\n client_id: this.clientId,\n redirect_uri:\n options.redirectTo || this.redirectUri || window?.location.origin,\n response_type: resolveResponseType(options, isBrowser()),\n audience: options.audience ?? this.audience,\n scope: options.scope,\n connection: options.connection\n }\n\n const definedParams = Object.fromEntries(\n Object.entries(params).filter(([, value]) => !!value)\n ) as Record<string, string>\n\n return `${this.domainUrl}/authorize?${new URLSearchParams(definedParams).toString()}`\n }\n\n /**\n * Redirects the current window to the tenant's `/authorize` endpoint.\n *\n * Fire-and-forget: there is no return value because the browser navigates\n * away. The session lands back on your `redirectUri`, where\n * {@link FaableAuthClient.initialize} consumes it on the next page load.\n *\n * @example\n * ```ts\n * auth.authorize({\n * response_type: 'code',\n * redirectTo: 'https://app.example.com/callback'\n * })\n * ```\n * @see {@link https://faable.com/docs/auth/oauth-flows/authorization-code | Authorization Code with PKCE}\n * @category Authorize URLs\n */\n authorize(options: {\n redirectTo?: string\n scope?: string\n response_type: string\n audience?: string\n }) {\n const url = this.buildAuthorizeUrl(options)\n windowHelpers.redirect(url)\n }\n\n private async _handleConnectionSignIn(options: {\n connection?: string\n connection_id?: string\n redirectTo?: string\n returnTo?: string\n scopes?: string\n queryParams?: { [key: string]: string }\n skipBrowserRedirect?: boolean\n audience?: string\n }) {\n const url: string = await this._getUrlForConnection(\n `${this.domainUrl}/authorize`,\n {\n response_type: isBrowser() ? 'code' : 'token',\n connection: options.connection,\n connection_id: options.connection_id,\n redirectTo: options.redirectTo,\n returnTo: options.returnTo,\n scopes: options.scopes,\n queryParams: options.queryParams,\n audience: options.audience\n }\n )\n\n this._debug('#_handleConnectionSignIn()', 'options', options, 'url', url)\n\n // try to open on the browser\n if (isBrowser() && !options.skipBrowserRedirect) {\n window?.location.assign(url)\n }\n\n return { data: { url }, error: null }\n }\n\n /**\n * Adopts an externally-provided session into the client.\n *\n * Decodes the access token to find its expiry; refreshes immediately when\n * already expired, otherwise fetches the user info to round-trip the\n * session. Persists the result and broadcasts `SIGNED_IN`. An invalid\n * refresh or access token surfaces as `error` on the returned object.\n *\n * @param currentSession Minimal session shape — an access token and a\n * refresh token. Other fields are recomputed.\n * @example\n * ```ts\n * // After receiving tokens from a custom server-side handoff\n * await auth.setSession({ access_token, refresh_token })\n * ```\n * @see {@link https://faable.com/docs/auth/oidc/userinfo | UserInfo}\n * @category Sessions\n */\n async setSession(currentSession: {\n access_token: string\n refresh_token: string\n }): Promise<AuthResponse> {\n await this.initializePromise\n\n return await this.lock._acquireLock(-1, async () => {\n return await this._setSession(currentSession)\n })\n }\n\n /**\n * Returns the session, refreshing it if necessary.\n *\n * The session returned can be `null` if no user is signed in or the last\n * one has logged out.\n *\n * **IMPORTANT:** This method loads values directly from the storage\n * attached to the client. If that storage is based on request cookies (for\n * example, on the server) the values in it may not be authentic and\n * therefore it's strongly advised against using this method and its\n * results in such circumstances — a warning will be emitted when the\n * storage exposes `isServer: true`. Re-fetch the user with a verified\n * call (or verify the access token yourself) before trusting it.\n *\n * @example\n * ```ts\n * const { data, error } = await auth.getSession()\n * if (data.session) console.log(data.session.user)\n * ```\n * @see {@link https://faable.com/docs/auth/oidc/userinfo | UserInfo}\n * @category Sessions\n */\n async getSession() {\n await this.initializePromise\n\n const result = await this.lock._acquireLock(-1, async () => {\n return this._useSession(async result => {\n return result\n })\n })\n\n return result\n }\n\n /**\n * Use instead of {@link #getSession} inside the library. It is\n * semantically usually what you want, as getting a session involves some\n * processing afterwards that requires only one client operating on the\n * session at once across multiple tabs or processes.\n */\n private async _useSession<R>(\n fn: (\n result:\n | {\n data: {\n session: Session\n }\n error: null\n }\n | {\n data: {\n session: null\n }\n error: AuthError\n }\n | {\n data: {\n session: null\n }\n error: null\n }\n ) => Promise<R>\n ): Promise<R> {\n this._debug('#_useSession', 'begin')\n\n try {\n // the use of __loadSession here is the only correct use of the function!\n const result = await this.__loadSession()\n\n return await fn(result)\n } finally {\n this._debug('#_useSession', 'end')\n }\n }\n\n /**\n * NEVER USE DIRECTLY!\n *\n * Always use {@link #_useSession}.\n */\n private async __loadSession(): Promise<\n | {\n data: {\n session: Session\n }\n error: null\n }\n | {\n data: {\n session: null\n }\n error: AuthError\n }\n | {\n data: {\n session: null\n }\n error: null\n }\n > {\n this._debug('#__loadSession()', 'begin')\n\n if (!this.lock.lockAcquired) {\n this._debug(\n '#__loadSession()',\n 'used outside of an acquired lock!',\n new Error().stack\n )\n }\n\n try {\n let currentSession: Session | null = null\n\n const maybeSession = await getItemAsync(this.storage, this.storageKey)\n\n this._debug('#getSession()', 'session from storage', maybeSession)\n\n if (maybeSession !== null) {\n if (isValidSession(maybeSession)) {\n currentSession = maybeSession\n } else {\n this._debug('#getSession()', 'session from storage is not valid')\n await this._removeSession()\n }\n }\n\n if (!currentSession) {\n return { data: { session: null }, error: null }\n }\n\n const hasExpired = currentSession.expires_at\n ? currentSession.expires_at <= Date.now() / 1000\n : false\n\n this._debug(\n '#__loadSession()',\n `session has${hasExpired ? '' : ' not'} expired`,\n 'expires_at',\n currentSession.expires_at\n )\n\n if (!hasExpired) {\n if (this.storage.isServer) {\n const proxySession: Session = new Proxy(currentSession, {\n get(target: any, prop: string, receiver: any) {\n if (prop === 'user') {\n // only show warning when the user object is being accessed from the server\n console.warn(\n 'Reading `session.user` from a server-side cookie store can be insecure: the value is whatever the cookie contains and has not been verified against Faable Auth. Re-fetch the user with `auth.getUser()` (or verify the access token yourself) before trusting it on the server.'\n )\n }\n return Reflect.get(target, prop, receiver)\n }\n })\n currentSession = proxySession\n }\n\n return { data: { session: currentSession }, error: null }\n }\n\n const { session, error } = await this._callRefreshToken(\n currentSession.refresh_token\n )\n if (error) {\n return { data: { session: null }, error }\n }\n\n return { data: { session }, error: null }\n } finally {\n this._debug('#__loadSession()', 'end')\n }\n }\n\n private async _removeSession() {\n this._debug('#_removeSession()')\n this._session = null\n await this.storage.removeItem(this.storageKey)\n }\n\n protected async _setSession(currentSession: {\n access_token: string\n refresh_token: string\n }): Promise<AuthResponse> {\n try {\n if (!currentSession.access_token || !currentSession.refresh_token) {\n throw new AuthSessionMissingError()\n }\n\n const timeNow = Date.now() / 1000\n let expiresAt = timeNow\n let hasExpired = true\n let session: Session | null = null\n const payload = decodeJWTPayload(currentSession.access_token)\n if (payload.exp) {\n expiresAt = payload.exp\n hasExpired = expiresAt <= timeNow\n }\n\n if (hasExpired) {\n const { session: refreshedSession, error } =\n await this._callRefreshToken(currentSession.refresh_token)\n if (error) {\n return { data: { user: null, session: null }, error: error }\n }\n\n if (!refreshedSession) {\n return { data: { user: null, session: null }, error: null }\n }\n session = refreshedSession\n } else {\n const { data: user, error } = await this._getUser(\n currentSession.access_token\n )\n if (error || !user) {\n throw error\n }\n session = {\n access_token: currentSession.access_token,\n refresh_token: currentSession.refresh_token,\n user,\n token_type: 'bearer',\n expires_in: expiresAt - timeNow,\n expires_at: expiresAt\n }\n await this._saveSession(session)\n await this._notifyAllSubscribers('SIGNED_IN', session)\n }\n\n return { data: { user: session.user, session }, error: null }\n } catch (error) {\n if (isAuthError(error)) {\n return { data: { session: null, user: null }, error }\n }\n\n throw error\n }\n }\n\n /**\n * set currentSession and currentUser\n * process to _startAutoRefreshToken if possible\n */\n private async _saveSession(session: Session) {\n this._debug('#_saveSession()', session)\n this._session = session\n\n await setItemAsync(this.storage, this.storageKey, session)\n }\n\n private async _getUser(access_token: string) {\n if (!access_token) throw new Error('Cannot fetch user without token')\n this._debug('#_getUser() begin')\n const res = await _get<User>(`${this.domainUrl}/me`, {\n token: access_token\n })\n this._debug('#_getUser() end')\n return { data: res.data, error: res.error }\n }\n\n private async _callRefreshToken(refreshToken: string) {\n if (!refreshToken) {\n throw new AuthSessionMissingError()\n }\n\n // refreshing is already in progress\n if (this.refreshingDeferred) {\n return this.refreshingDeferred.promise\n }\n\n const debugName = `#_callRefreshToken(${refreshToken.substring(0, 5)}...)`\n\n this._debug(debugName, 'begin')\n\n try {\n this.refreshingDeferred = new Deferred<CallRefreshTokenResult>()\n\n const { data, error } = await withTimeout(\n this._refreshAccessToken(refreshToken),\n REFRESH_TIMEOUT_MS,\n 'Token refresh timed out'\n )\n if (error) throw error\n if (!data.session) throw new AuthSessionMissingError()\n\n await this._saveSession(data.session)\n await this._notifyAllSubscribers('TOKEN_REFRESHED', data.session)\n\n const result = { session: data.session, error: null }\n\n this.refreshingDeferred.resolve(result)\n\n return result\n } catch (error) {\n this._debug(debugName, 'error', error)\n\n if (isAuthError(error)) {\n const result = { session: null, error }\n\n if (!isAuthRetryableFetchError(error)) {\n await this._removeSession()\n await this._notifyAllSubscribers('SIGNED_OUT', null)\n }\n\n this.refreshingDeferred?.resolve(result)\n\n return result\n }\n\n this.refreshingDeferred?.reject(error)\n throw error\n } finally {\n this.refreshingDeferred = null\n this._debug(debugName, 'end')\n }\n }\n\n /**\n * Generates a new JWT.\n * @param refreshToken A valid refresh token that was returned on login.\n */\n private async _refreshAccessToken(\n refreshToken: string\n ): Promise<AuthResponse> {\n const debugName = `#_refreshAccessToken(${refreshToken.substring(0, 5)}...)`\n this._debug(debugName, 'begin')\n\n try {\n const startedAt = Date.now()\n\n // will attempt to refresh the token with exponential backoff\n\n return await retryable(\n async attempt => {\n if (attempt > 0) {\n await sleep(200 * Math.pow(2, attempt - 1)) // 200, 400, 800, ...\n }\n\n this._debug(debugName, 'refreshing attempt', attempt)\n\n // return await _post(`${this.url}/token?grant_type=refresh_token`, {\n // body: { refresh_token: refreshToken },\n // headers: this.headers,\n // xform: _sessionResponse,\n // });\n const rawResponse = await _post<Partial<RawAuthResponse>>(\n `${this.domainUrl}/oauth/token`,\n {\n client_id: this.clientId,\n grant_type: 'refresh_token',\n refresh_token: refreshToken,\n ...(this.audience ? { audience: this.audience } : {})\n }\n )\n if (rawResponse.error) {\n throw new AuthUnknownError(\n `Refresh token request failed: ${rawResponse.error}`,\n rawResponse.error\n )\n }\n const session_res = _sessionResponse(rawResponse)\n\n if (!session_res.data.session?.access_token) {\n throw new AuthInvalidTokenResponseError()\n }\n const { data: user, error } = await this._getUser(\n session_res.data.session?.access_token\n )\n\n if (error) {\n throw new AuthUnknownError('Could not fetch user info', error)\n }\n if (!user) {\n throw new AuthUnknownError('Refresh response missing user', null)\n }\n\n const x = {\n data: {\n session: {\n ...session_res.data.session,\n user\n },\n user\n },\n error: null\n }\n // this._debug(x);\n return x\n },\n (attempt, error) => {\n const nextBackOffInterval = 200 * Math.pow(2, attempt)\n return (\n error &&\n isAuthRetryableFetchError(error) &&\n // retryable only if the request can be sent before the backoff overflows the tick duration\n Date.now() + nextBackOffInterval - startedAt <\n AUTO_REFRESH_TICK_DURATION\n )\n }\n )\n } catch (error) {\n this._debug(debugName, 'error', error)\n\n if (isAuthError(error)) {\n return { data: { session: null, user: null }, error }\n }\n throw error\n } finally {\n this._debug(debugName, 'end')\n }\n }\n\n private async _notifyAllSubscribers(\n event: AuthChangeEvent,\n session: Session | null,\n broadcast = true\n ) {\n const debugName = `#_notifyAllSubscribers(${event})`\n this._debug(debugName, 'begin', session, `broadcast = ${broadcast}`)\n try {\n await this.broadcastSync.notify(event, session, broadcast)\n } finally {\n this._debug(debugName, 'end')\n }\n }\n\n /**\n * Signs the user out and clears the session from storage.\n *\n * In a browser context this removes the persisted session and broadcasts a\n * `SIGNED_OUT` event to every tab listening on the same `storageKey`. The\n * access token JWT itself remains valid until its `exp` — keep that\n * expiry short.\n *\n * Scopes:\n * - `'global'` (default) — invalidate all refresh tokens for the user\n * - `'local'` — only clear this client's storage\n * - `'others'` — invalidate every refresh token except this device's; no\n * `SIGNED_OUT` event is fired locally\n *\n * @example\n * ```ts\n * await auth.signOut() // global — all sessions for this user\n * await auth.signOut({ scope: 'local' }) // only this device\n * ```\n * @see {@link https://faable.com/docs/auth/oidc/logout | Logout}\n * @category Sign out\n */\n async signOut(\n options: SignOut = { scope: 'global' }\n ): Promise<{ error: AuthError | null }> {\n await this.initializePromise\n\n return await this.lock._acquireLock(-1, async () => {\n return await this._signOut(options)\n })\n }\n\n protected async _signOut(\n { scope }: SignOut = { scope: 'global' }\n ): Promise<{ error: AuthError | null }> {\n return await this._useSession(async result => {\n const { data, error: sessionError } = result\n if (sessionError) {\n return { error: sessionError }\n }\n const accessToken = data.session?.access_token\n if (accessToken) {\n const { error } = await this.api.signOut({\n client_id: this.clientId\n })\n if (error) {\n // ignore 404s since user might not exist anymore\n // ignore 401s since an invalid or expired JWT should sign out the current session\n if (\n !(\n isAuthApiError(error) &&\n (error.status === 404 || error.status === 401)\n )\n ) {\n return { error }\n }\n }\n }\n if (scope !== 'others') {\n await this._removeSession()\n await this.storage.removeItem(`${this.storageKey}-code-verifier`)\n await this._notifyAllSubscribers('SIGNED_OUT', null)\n }\n return { error: null }\n })\n }\n\n /**\n * Subscribes to auth-state changes for this client.\n *\n * The callback fires for `INITIAL_SESSION` once shortly after subscribing\n * (so consumers don't have to special-case \"no event yet\"), and then for\n * every `SIGNED_IN`, `SIGNED_OUT`, `TOKEN_REFRESHED`, `PASSWORD_RECOVERY`,\n * and `USER_UPDATED` event. Events are broadcast across tabs through\n * `BroadcastChannel`, so a sign-in or sign-out in one tab reaches every\n * other tab using the same `storageKey`.\n *\n * @param callback Invoked with the event name and the new session (or\n * `null` on `SIGNED_OUT`). Can return a promise — the SDK awaits it.\n * @returns `{ data: { subscription } }` — call `subscription.unsubscribe()`\n * to stop listening.\n * @example\n * ```ts\n * const { data: { subscription } } = auth.onAuthStateChange((event, session) => {\n * if (event === 'SIGNED_IN') console.log('Welcome', session?.user.email)\n * })\n * // later\n * subscription.unsubscribe()\n * ```\n * @see {@link https://faable.com/docs/auth/get-started | Get Started with Faable Auth}\n * @category Sessions\n */\n onAuthStateChange(\n callback: (\n event: AuthChangeEvent,\n session: Session | null\n ) => void | Promise<void>\n ): {\n data: { subscription: Subscription }\n } {\n const { subscription } = this.broadcastSync.subscribe(callback)\n this._debug(\n '#onAuthStateChange()',\n 'registered callback with id',\n subscription.id\n )\n ;(async () => {\n await this.initializePromise\n await this.lock._acquireLock(-1, async () => {\n this._emitInitialSession(subscription)\n })\n })()\n\n return { data: { subscription } }\n }\n\n private async _emitInitialSession(subscription: Subscription): Promise<void> {\n return await this._useSession(async result => {\n try {\n const {\n data: { session },\n error\n } = result\n if (error) throw error\n\n await subscription.callback('INITIAL_SESSION', session)\n this._debug(\n 'INITIAL_SESSION',\n 'callback id',\n subscription.id,\n 'session',\n session\n )\n } catch (err) {\n await subscription.callback('INITIAL_SESSION', null)\n this._debug(\n 'INITIAL_SESSION',\n 'callback id',\n subscription.id,\n 'error',\n err\n )\n console.error(err)\n }\n })\n }\n\n /**\n * Forces a new session by exchanging a refresh token regardless of expiry.\n *\n * Normally the SDK handles refresh transparently via the auto-refresh\n * ticker; call this only when you need to force an immediate refresh —\n * e.g. right after a server-side action that changed the user's claims.\n * Omit `currentSession` to reuse whatever {@link FaableAuthClient.getSession}\n * returns.\n *\n * @param currentSession Optional session shape carrying the refresh token\n * to exchange. When passed it must include `refresh_token`.\n * @example\n * ```ts\n * const { data, error } = await auth.refreshSession()\n * ```\n * @see {@link https://faable.com/docs/auth/oauth-flows/refresh-token | Refresh Token}\n * @category Sessions\n */\n async refreshSession(currentSession?: {\n refresh_token: string\n }): Promise<AuthResponse> {\n await this.initializePromise\n\n return await this.lock._acquireLock(-1, async () => {\n return await this._refreshSession(currentSession)\n })\n }\n\n protected async _refreshSession(currentSession?: {\n refresh_token: string\n }): Promise<AuthResponse> {\n try {\n return await this._useSession(async result => {\n if (!currentSession) {\n const { data, error } = result\n if (error) {\n throw error\n }\n\n currentSession = data.session ?? undefined\n }\n\n if (!currentSession?.refresh_token) {\n throw new AuthSessionMissingError()\n }\n\n const { session, error } = await this._callRefreshToken(\n currentSession.refresh_token\n )\n if (error) {\n return { data: { user: null, session: null }, error: error }\n }\n\n if (!session) {\n return { data: { user: null, session: null }, error: null }\n }\n\n return { data: { user: (session as any).user, session }, error: null }\n })\n } catch (error) {\n if (isAuthError(error)) {\n return { data: { user: null, session: null }, error }\n }\n\n throw error\n }\n }\n}\n","import { AuthenticationResult } from './lib/types'\n\nexport const parseAuthenticationResult = (\n queryString: string\n): AuthenticationResult => {\n if (queryString.indexOf('#') > -1) {\n queryString = queryString.substring(0, queryString.indexOf('#'))\n }\n\n const searchParams = new URLSearchParams(queryString)\n\n return {\n state: searchParams.get('state')!,\n code: searchParams.get('code') || undefined,\n error: searchParams.get('error') || undefined,\n error_description: searchParams.get('error_description') || undefined\n }\n}\n\nconst stripUndefined = (params: any) => {\n return Object.keys(params)\n .filter(k => typeof params[k] !== 'undefined')\n .reduce((acc, key) => ({ ...acc, [key]: params[key] }), {})\n}\n\nexport const createQueryParams = ({ clientId: client_id, ...params }: any) => {\n return new URLSearchParams(\n stripUndefined({ client_id, ...params })\n ).toString()\n}\n\n/**\n * @ignore\n */\nexport const getTokenIssuer = (\n issuer: string | undefined,\n domainUrl: string\n) => {\n if (issuer) {\n return issuer.startsWith('https://') ? issuer : `https://${issuer}`\n }\n\n return `${domainUrl}`\n}\n\n// Normaliza el `domain` para que dé igual cómo lo pase el usuario: con o sin\n// protocolo, con trailing slash, o incluso con protocolo duplicado (el valor\n// que el dashboard copia ya trae `https://`). Siempre devuelve\n// `<protocol>://<host>` sin barra final.\nexport const getDomain = (domainUrl: string) => {\n const raw = (domainUrl ?? '').trim().replace(/\\/+$/, '')\n // Usuario pasó protocolo (uno o varios, p.ej. \"https://https://x\"):\n // preservar http/https intencionado y descartar duplicados.\n const match = raw.match(/^(https?):\\/\\/(.*)$/i)\n if (match) {\n const host = match[2].replace(/^(https?:\\/\\/)+/i, '')\n return `${match[1].toLowerCase()}://${host}`\n }\n // Sin protocolo: heredar el del documento actual en browser, https fuera de él.\n const protocol =\n typeof location !== 'undefined' && location?.protocol\n ? location.protocol.replace(/:$/, '')\n : 'https'\n return `${protocol}://${raw}`\n}\n\nexport const encode = (value: string) => btoa(value)\nexport const decode = (value: string) => atob(value)\n\n// https://stackoverflow.com/questions/30106476/\nconst decodeB64 = (input: string) =>\n decodeURIComponent(\n atob(input)\n .split('')\n .map(c => {\n return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2)\n })\n .join('')\n )\n\nconst urlEncodeB64 = (input: string) => {\n const b64Chars: { [index: string]: string } = { '+': '-', '/': '_', '=': '' }\n return input.replace(/[+/=]/g, (m: string) => b64Chars[m])\n}\n\nexport const urlDecodeB64 = (input: string) =>\n decodeB64(input.replace(/_/g, '/').replace(/-/g, '+'))\n\nexport const bufferToBase64UrlEncoded = (input: number[] | Uint8Array) => {\n const ie11SafeInput = new Uint8Array(input)\n return urlEncodeB64(\n window.btoa(String.fromCharCode(...Array.from(ie11SafeInput)))\n )\n}\n\nexport const parseNumber = (value: any): number | undefined => {\n if (typeof value !== 'string') {\n return value\n }\n return parseInt(value, 10) || undefined\n}\n\n/**\n * @ignore\n */\nexport const buildIsAuthenticatedCookieName = (clientId: string) =>\n `auth0.${clientId}.is.authenticated`\n","/**\n * Races a promise against a deadline. If `promise` settles first the result\n * passes through; if the deadline elapses first the returned promise rejects\n * with an Error whose message is `timeoutMessage`. The internal timer is\n * cleared once `promise` settles, regardless of outcome.\n */\nexport const withTimeout = <T>(\n promise: Promise<T>,\n timeoutMs: number,\n timeoutMessage: string\n): Promise<T> => {\n let timer: ReturnType<typeof setTimeout> | undefined\n const timeoutPromise = new Promise<T>((_, reject) => {\n timer = setTimeout(() => reject(new Error(timeoutMessage)), timeoutMs)\n })\n return Promise.race([\n promise.finally(() => {\n if (timer !== undefined) clearTimeout(timer)\n }),\n timeoutPromise\n ])\n}\n","import { FaableAuthClient } from './FaableAuthClient'\nimport { FaableAuthClientConfig } from './lib/types'\n\n/**\n * Creates a {@link FaableAuthClient} bound to a Faable Auth tenant.\n *\n * This is the recommended entry point for app code. The returned client\n * begins initializing its session in the background as soon as it's created,\n * so you can start subscribing to events or triggering sign-ins right away.\n *\n * @param config Tenant settings. `domain` and `clientId` are required.\n * @example\n * ```ts\n * import { createClient } from '@faable/auth-js'\n *\n * export const auth = createClient({\n * domain: '<faableauth_domain>',\n * clientId: '<client_id>',\n * redirectUri: window.location.origin\n * })\n * ```\n * @see {@link https://faable.com/docs/auth/get-started | Get Started with Faable Auth}\n * @see {@link https://faable.com/docs/auth/clients | Clients}\n * @category Getting started\n */\nexport const createClient = (config: FaableAuthClientConfig) => {\n return new FaableAuthClient(config)\n}\n","import { BaseLogOptions } from '../BaseLog'\nimport { LockFunc } from '../lock/locks'\nimport { AuthError } from './errors'\n\n/**\n * @ignore\n */\nexport interface AuthenticationResult {\n state: string\n code?: string\n error?: string\n error_description?: string\n}\n\n/**\n * OpenID Connect–style user profile returned by the tenant's userinfo\n * endpoint.\n *\n * Standard OIDC claims are typed explicitly; provider-specific or custom\n * claims (e.g. `org_id`, `roles`) surface through the index signature.\n *\n * @see {@link https://faable.com/docs/auth/oidc/userinfo | UserInfo}\n */\nexport class User {\n name?: string\n profile?: string\n picture?: string\n email?: string\n website?: string\n birthdate?: string\n locale?: string\n sub?: string;\n [key: string]: any\n}\n\n/**\n * The state of the application before the user was redirected to the login page.\n */\nexport type AppState = {\n returnTo?: string\n [key: string]: any\n}\n\nexport interface AuthorizationParams {\n /**\n * - `'page'`: displays the UI with a full page view\n * - `'popup'`: displays the UI with a popup window\n * - `'touch'`: displays the UI in a way that leverages a touch interface\n * - `'wap'`: displays the UI with a \"feature phone\" type interface\n */\n display?: 'page' | 'popup' | 'touch' | 'wap'\n\n /**\n * - `'none'`: do not prompt user for login or consent on reauthentication\n * - `'login'`: prompt user for reauthentication\n * - `'consent'`: prompt user for consent before processing request\n * - `'select_account'`: prompt user to select an account\n */\n prompt?: 'none' | 'login' | 'consent' | 'select_account'\n\n /**\n * Maximum allowable elapsed time (in seconds) since authentication.\n * If the last time the user authenticated is greater than this value,\n * the user must be reauthenticated.\n */\n max_age?: string | number\n\n /**\n * The space-separated list of language tags, ordered by preference.\n * For example: `'fr-CA fr en'`.\n */\n ui_locales?: string\n\n /**\n * Previously issued ID Token.\n */\n id_token_hint?: string\n\n /**\n * Provides a hint to Auth0 as to what flow should be displayed.\n * The default behavior is to show a login page but you can override\n * this by passing 'signup' to show the signup page instead.\n *\n * This only affects the New Universal Login Experience.\n */\n screen_hint?: 'signup' | 'login' | string\n\n /**\n * The user's email address or other identifier. When your app knows\n * which user is trying to authenticate, you can provide this parameter\n * to pre-fill the email box or select the right session for sign-in.\n *\n * This currently only affects the classic Lock experience.\n */\n login_hint?: string\n\n acr_values?: string\n\n /**\n * The default scope to be used on authentication requests.\n *\n * This defaults to `profile email` if not set. If you are setting extra scopes and require\n * `profile` and `email` to be included then you must include them in the provided scope.\n *\n * Note: The `openid` scope is **always applied** regardless of this setting.\n */\n scope?: string\n\n /**\n * The default audience to be used for requesting API access.\n */\n audience?: string\n\n /**\n * The name of the connection configured for your application.\n * If null, it will redirect to the Auth0 Login Page and show\n * the Login Widget.\n */\n connection?: string\n\n /**\n * The Id of an organization to log in to.\n *\n * This will specify an `organization` parameter in your user's login request and will add a step to validate\n * the `org_id` claim in your user's ID Token.\n */\n organization?: string\n\n /**\n * The Id of an invitation to accept. This is available from the user invitation URL that is given when participating in a user invitation flow.\n */\n invitation?: string\n\n /**\n * The default URL where Auth0 will redirect your browser to with\n * the authentication result. It must be whitelisted in\n * the \"Allowed Callback URLs\" field in your Auth0 Application's\n * settings. If not provided here, it should be provided in the other\n * methods that provide authentication.\n */\n redirect_uri?: string\n\n /**\n * If you need to send custom parameters to the Authorization Server,\n * make sure to use the original parameter name.\n */\n [key: string]: any\n}\n\ninterface BaseLoginOptions {\n /**\n * URL parameters that will be sent back to the Authorization Server. This can be known parameters\n * defined by Auth0 or custom parameters that you define.\n */\n authorizationParams?: AuthorizationParams\n}\n\nexport interface RedirectLoginOptions<\n TAppState = any\n> extends BaseLoginOptions {\n /**\n * Used to store state before doing the redirect\n */\n appState?: TAppState\n}\n\nexport interface IdToken {\n __raw: string\n name?: string\n given_name?: string\n family_name?: string\n middle_name?: string\n nickname?: string\n preferred_username?: string\n profile?: string\n picture?: string\n website?: string\n email?: string\n email_verified?: boolean\n gender?: string\n birthdate?: string\n zoneinfo?: string\n locale?: string\n phone_number?: string\n phone_number_verified?: boolean\n address?: string\n updated_at?: string\n iss?: string\n aud?: string\n exp?: number\n nbf?: number\n iat?: number\n jti?: string\n azp?: string\n nonce?: string\n auth_time?: string\n at_hash?: string\n c_hash?: string\n acr?: string\n amr?: string\n sub_jwk?: string\n cnf?: string\n sid?: string\n org_id?: string\n [key: string]: any\n}\n\nexport interface GetTokenSilentlyOptions {\n /**\n * When `off`, ignores the cache and always sends a\n * request to Auth0.\n * When `cache-only`, only reads from the cache and never sends a request to Auth0.\n * Defaults to `on`, where it both reads from the cache and sends a request to Auth0 as needed.\n */\n cacheMode?: 'on' | 'off' | 'cache-only'\n\n /**\n * Parameters that will be sent back to Auth0 as part of a request.\n */\n authorizationParams?: {\n /**\n * There's no actual redirect when getting a token silently,\n * but, according to the spec, a `redirect_uri` param is required.\n * Auth0 uses this parameter to validate that the current `origin`\n * matches the `redirect_uri` `origin` when sending the response.\n * It must be whitelisted in the \"Allowed Web Origins\" in your\n * Auth0 Application's settings.\n */\n redirect_uri?: string\n\n /**\n * The scope that was used in the authentication request\n */\n scope?: string\n\n /**\n * The audience that was used in the authentication request\n */\n audience?: string\n\n /**\n * If you need to send custom parameters to the Authorization Server,\n * make sure to use the original parameter name.\n */\n [key: string]: any\n }\n\n /** A maximum number of seconds to wait before declaring the background /authorize call as failed for timeout\n * Defaults to 60s.\n */\n timeoutInSeconds?: number\n\n /**\n * If true, the full response from the /oauth/token endpoint (or the cache, if the cache was used) is returned\n * (minus `refresh_token` if one was issued). Otherwise, just the access token is returned.\n *\n * The default is `false`.\n */\n detailedResponse?: boolean\n}\n\nexport type GetTokenSilentlyVerboseResponse = Omit<\n TokenEndpointResponse,\n 'refresh_token'\n>\n\nexport type TokenEndpointResponse = {\n id_token: string\n access_token: string\n refresh_token?: string\n expires_in: number\n scope?: string\n}\n\n/**\n * Attribute overrides for the bundled cookie storage adapter.\n *\n * Defaults: `Path=/`, `SameSite=Lax`, `Secure` on HTTPS, `Max-Age` 30 days.\n * Use this to share the session across subdomains or tighten `SameSite`.\n *\n * @see {@link https://faable.com/docs/auth/quickstart/nextjs | Next.js Quickstart}\n */\nexport interface CookieOptions {\n /** (Optional) The domain of the cookie. Use a leading dot to share across subdomains, e.g. `.example.com`. */\n domain?: string\n /** (Optional) The path of the cookie. Defaults to `/`. */\n path?: string\n /** (Optional) The same-site attribute of the cookie. Defaults to `'Lax'`. */\n sameSite?: 'Lax' | 'Strict' | 'None'\n /** (Optional) Whether the cookie should only be sent over HTTPS. Defaults to `true` when the current page is HTTPS. */\n secure?: boolean\n /** (Optional) The maximum age of the cookie in seconds. Defaults to 30 days. */\n maxAge?: number\n}\n\n/**\n * Configuration accepted by {@link createClient} and the\n * `FaableAuthClient` constructor.\n *\n * `domain` and `clientId` are the only required fields. Everything else has\n * sensible defaults — see the individual properties for the specifics.\n *\n * @see {@link https://faable.com/docs/auth/get-started | Get Started with Faable Auth}\n * @see {@link https://faable.com/docs/auth/clients | Clients}\n */\nexport type FaableAuthClientConfig = {\n /** **Required.** Your Faable Auth tenant domain. */\n domain: string\n /** **Required.** Application client ID from the dashboard. */\n clientId: string\n\n // Optional\n /** Space-separated scopes. Defaults to `openid profile email`. */\n scope?: string\n /**\n * Default API audience the access tokens issued for this client should be\n * bound to. Forwarded to `/authorize` and to the `/oauth/token` POST bodies\n * (code exchange, refresh, OTP). `signInWith*` methods accept an `audience`\n * argument to override it per call.\n */\n audience?: string\n /** Default callback URL. Falls back to `window.location.origin`. */\n redirectUri?: string\n authorizationParams?: AuthorizationParams\n cookieDomain?: string\n useRefreshTokens?: boolean\n /** OAuth flow used when initiating sign-in. Defaults to `'pkce'` in browsers and `'implicit'` elsewhere. */\n flowType?: AuthFlowType\n /**\n * Where to keep the session. Pass `'localStorage'` (default) or `'cookie'`\n * for the bundled adapters, or any custom `SupportedStorage` implementation.\n * The cookie adapter ships with sane defaults (`Path=/`, `SameSite=Lax`,\n * auto `Secure` on HTTPS, 30-day `Max-Age`); use `cookieOptions` to override.\n */\n storage?: SupportedStorage | 'cookie' | 'localStorage'\n /** Optional prefix for the storage key. Final key is `${storageKey}-${clientId}`. */\n storageKey?: string\n\n /**\n * (Optional) Overrides for the cookie storage attributes. Setting this also\n * implicitly switches to the cookie adapter, so passing `storage: 'cookie'`\n * is not required when you only want to tweak attributes.\n */\n cookieOptions?: CookieOptions\n\n /**\n * Provide your own locking mechanism based on the environment. By default no locking is done at this time.\n *\n * @experimental\n */\n lock?: LockFunc\n} & BaseLogOptions\n\ntype AnyFunction = (...args: any[]) => any\ntype MaybePromisify<T> = T | Promise<T>\ntype PromisifyMethods<T> = {\n [K in keyof T]: T[K] extends AnyFunction\n ? (...args: Parameters<T[K]>) => MaybePromisify<ReturnType<T[K]>>\n : T[K]\n}\n\n/**\n * Minimal storage contract the SDK relies on. Compatible with `localStorage`,\n * `sessionStorage`, the bundled cookie adapter, and any custom adapter you\n * provide. Methods may return synchronously or asynchronously.\n *\n * @example\n * ```ts\n * const memoryStorage: SupportedStorage = {\n * store: new Map<string, string>(),\n * getItem: k => memoryStorage.store.get(k) ?? null,\n * setItem: (k, v) => void memoryStorage.store.set(k, v),\n * removeItem: k => void memoryStorage.store.delete(k)\n * }\n * ```\n */\nexport type SupportedStorage = PromisifyMethods<\n Pick<Storage, 'getItem' | 'setItem' | 'removeItem'>\n> & {\n /**\n * Set to `true` when the storage medium reads from an untrusted source\n * (e.g. request cookies on the server). Triggers a warning when consumers\n * access `session.user` so they refresh against a verified source instead.\n */\n isServer?: boolean\n}\n\n/**\n * Built-in social OAuth providers. Custom enterprise / SAML / OIDC\n * connections are addressed by their `connection` name or `connection_id`.\n *\n * @see {@link https://faable.com/docs/auth/connections | Connections}\n */\nexport type Provider = 'google' | 'github'\n\n/**\n * OAuth initiation flow.\n *\n * - `'pkce'` — recommended for SPAs / public clients; the SDK stores a code\n * verifier and exchanges the auth code for a session on the callback.\n * - `'implicit'` — tokens are returned directly in the URL fragment.\n *\n * @see {@link https://faable.com/docs/auth/oauth-flows/authorization-code | Authorization Code with PKCE}\n */\nexport type AuthFlowType = 'implicit' | 'pkce'\n\n/**\n * Options accepted by {@link FaableAuthClient.signInWithOauthConnection}.\n *\n * @see {@link https://faable.com/docs/auth/connections | Connections}\n */\nexport type SignInWithOAuthConnection = {\n /**\n * Identifier of the connection to use. Preferred over `connection` when\n * known, as the backend resolves it without additional lookups. If both\n * are provided, `connection_id` wins.\n */\n connection_id?: string\n /** Default connection is used if not setted. Kept for compatibility with tenants using connection names. */\n connection?: string\n /** A URL to send the user to after they are confirmed. */\n redirectTo?: string\n /**\n * App-side destination to return the user to once the callback has been\n * processed. It is stored locally alongside the PKCE verifier (never sent\n * to the server) and surfaced back as `returnTo` on the result of\n * {@link FaableAuthClient.handleRedirectCallback} / {@link FaableAuthClient.initialize}.\n */\n returnTo?: string\n /** A space-separated list of scopes granted to the OAuth application. */\n scopes?: string\n /** An object of query params */\n queryParams?: { [key: string]: string }\n /** If set to true does not immediately redirect the current browser context to visit the OAuth authorization page for the provider. */\n skipBrowserRedirect?: boolean\n /**\n * Override the API audience the issued access token should be bound to.\n * Falls back to `FaableAuthClientConfig.audience` when omitted.\n */\n audience?: string\n}\n\n/**\n * Result of {@link FaableAuthClient.signInWithOauthConnection}. Carries the\n * authorize URL on success (useful when `skipBrowserRedirect: true` so you\n * can drive the navigation yourself) or an {@link AuthError} on failure.\n */\nexport type OAuthResponse =\n | {\n data: {\n url: string\n }\n error: null\n }\n | {\n data: {\n url: null\n }\n error: AuthError\n }\n\n/**\n * A signed-in session as persisted by the client.\n *\n * Use {@link FaableAuthClient.getSession} to obtain the current value; the\n * SDK refreshes it automatically before `expires_at`.\n *\n * @see {@link https://faable.com/docs/auth/oidc/userinfo | UserInfo}\n */\nexport interface Session {\n /**\n * The oauth provider token. If present, this can be used to make external API requests to the oauth provider used.\n */\n provider_token?: string | null\n /**\n * The oauth provider refresh token. If present, this can be used to refresh the provider_token via the oauth provider's API.\n * Not all oauth providers return a provider refresh token. If the provider_refresh_token is missing, please refer to the oauth provider's documentation for information on how to obtain the provider refresh token.\n */\n provider_refresh_token?: string | null\n /**\n * The access token jwt. It is recommended to set the JWT_EXPIRY to a shorter expiry value.\n */\n access_token: string\n /**\n * A one-time used refresh token that never expires.\n */\n refresh_token: string\n /**\n * The number of seconds until the token expires (since it was issued). Returned when a login is confirmed.\n */\n expires_in: number\n /**\n * A timestamp of when the token will expire. Returned when a login is confirmed.\n */\n expires_at?: number\n token_type: string\n user: User\n}\n\n/**\n * Discriminated union returned by every sign-in / set-session / refresh\n * method. Always check `error` first — `data` fields are `null` on failure.\n */\nexport type AuthResponse =\n | {\n data: {\n user: User | null\n session: Session | null\n }\n error: null\n }\n | {\n data: {\n user: null\n session: null\n }\n error: AuthError\n }\n\nexport type AuthChangeEventMFA = 'MFA_CHALLENGE_VERIFIED'\n\n/**\n * Event names delivered to {@link FaableAuthClient.onAuthStateChange}\n * callbacks.\n *\n * - `INITIAL_SESSION` — fired once on subscribe with the currently-loaded session\n * - `SIGNED_IN` — a session was newly stored or adopted\n * - `SIGNED_OUT` — the session was cleared (locally or via global sign-out)\n * - `TOKEN_REFRESHED` — the SDK refreshed the access token in the background\n * - `PASSWORD_RECOVERY` — the user landed back from a password-reset link\n * - `USER_UPDATED` — the user object was reloaded from `/me`\n *\n * @see {@link https://faable.com/docs/auth/get-started | Get Started with Faable Auth}\n */\nexport type AuthChangeEvent =\n | 'INITIAL_SESSION'\n | 'PASSWORD_RECOVERY'\n | 'SIGNED_IN'\n | 'SIGNED_OUT'\n | 'TOKEN_REFRESHED'\n | 'USER_UPDATED'\n | AuthChangeEventMFA\n\n/**\n * Handle returned by {@link FaableAuthClient.onAuthStateChange}.\n *\n * Call `unsubscribe()` to stop receiving events — for example, in a React\n * `useEffect` cleanup.\n */\nexport interface Subscription {\n /** Subscriber UUID assigned by the client. */\n id: string\n /** Invoked every time an auth event happens. */\n callback: (event: AuthChangeEvent, session: Session | null) => void\n /** Call to remove the listener. */\n unsubscribe: () => void\n}\n\n/**\n * Options accepted by {@link FaableAuthClient.signOut}.\n *\n * @see {@link https://faable.com/docs/auth/oidc/logout | Logout}\n */\nexport type SignOut = {\n /**\n * Which sessions to log out.\n *\n * - `'global'` — every refresh token for the user (default)\n * - `'local'` — only this client's storage\n * - `'others'` — every other session except this device's; no\n * `SIGNED_OUT` event is fired locally\n */\n scope?: 'global' | 'local' | 'others'\n}\n\nexport type InitializeResult = {\n error: AuthError | null\n /**\n * Set when a sign-in redirect was consumed from the URL (e.g.\n * `'PASSWORD_RECOVERY'`). Absent when the session was recovered from\n * storage or there was nothing to process.\n */\n redirectType?: string | null\n /**\n * The app-side destination passed as `returnTo` when starting the sign-in,\n * round-tripped through the flow so the callback page can navigate there.\n */\n returnTo?: string | null\n /**\n * `true` when the callback that was just consumed created a brand-new\n * account (the auth server appended `?signup=true` to the redirect). Use it\n * to branch into onboarding / welcome UX or fire a signup analytics event.\n *\n * Only social / OAuth logins signal this today — passwordless and\n * username/password callbacks always report `false`. Absent when no sign-in\n * redirect was consumed (session recovered from storage).\n */\n is_new_user?: boolean\n}\n\nexport type UserResponse =\n | {\n data: {\n user: User\n }\n error: null\n }\n | {\n data: {\n user: null\n }\n error: AuthError\n }\n\nexport type CallRefreshTokenResult =\n | {\n session: Session\n error: null\n }\n | {\n session: null\n error: AuthError\n }\n"],"names":["extendStatics","d","b","Object","setPrototypeOf","__proto__","Array","p","prototype","hasOwnProperty","call","__extends","TypeError","String","__","this","constructor","create","__assign","assign","t","s","i","n","arguments","length","apply","__awaiter","thisArg","_arguments","P","generator","Promise","resolve","reject","fulfilled","value","step","next","e","rejected","result","done","then","__generator","body","f","y","_","label","sent","trys","ops","g","Iterator","verb","Symbol","iterator","v","op","pop","push","__spreadArray","to","from","pack","ar","l","slice","concat","SuppressedError","version","BaseLog","config","logger","console","log","logDebugMessages","debug","_debug","args","_i","extra","extraPrint","Date","toISOString","Base","_super","_this","instanceID","nextInstanceID","toString","win","window","undefined","global","globalThis","document","fetch","headers","init","token","Authorization","_handleRes","res_1","args_1","res","options","raw","text","_a","_c","json","status","data","error","_b","JSON","parse","message","_post","url_1","data_1","url","method","stringify","_get","FaableAuthApi","base_url","signOut","params","URLSearchParams","resolveResponseType","isBrowserEnv","response_type","setItemAsync","storage","key","setItem","getItemAsync","getItem","saveCodeVerifier","verifier","redirectType","returnTo","now","payload","createdAt","_d","loadCodeVerifier","storage_1","key_1","removeItem","loaded","dec2hex","dec","substr","sha256","randomString","encoder","TextEncoder","encodedData","encode","crypto","subtle","digest","hash","bytes","Uint8Array","map","c","fromCharCode","join","generatePKCEChallenge","warn","hashed","str","btoa","replace","getCodeChallengeAndMethod","storageKey_1","storageKey","isPasswordRecovery","codeVerifier","getRandomValues","Error","array","Uint32Array","generatePKCEVerifier","codeChallenge","isBrowser","localStorageWriteTests","tested","writable","supportsLocalStorage","localStorage","_e","randomKey","Math","random","_sessionResponse","expiresIn","session","access_token","refresh_token","expires_in","hasSession","expires_at","round","user","Deferred","promise","promiseConstructor","rej","retryable","fn","isRetryable","accept","attempt","Infinity","e_1","sleep","time","setTimeout","BroadcastSync","channelName","channel","subscribers","Map","BroadcastChannel","addEventListener","event","dispatch","err","subscribe","callback","id","r","subscription","unsubscribe","delete","set","notify","event_1","session_1","broadcast","postMessage","_broadcast","errors","tasks","values","sub","err_1","all","close","clear","STORAGE_KEY","AuthError","code","__isAuthError","name","CustomAuthError","AuthSessionMissingError","isAuthError","AuthApiError","AuthImplicitGrantRedirectError","details","toJSON","AuthPKCEGrantCodeExchangeError","AuthUnknownError","originalError","AuthInvalidTokenResponseError","isAuthRetryableFetchError","getWindow","AuthRetryableFetchError","windowHelpers","redirect","location","getDocument","decodeJWTPayload","parts","split","test","base64Url","chr1","chr2","chr3","enc2","enc3","enc4","base64","indexOf","charAt","decodeBase64URL","getSessionFromCookies","cookiesStore","clientId","cookieValue","readCookieValue","decodeURIComponent","readOne","get","single","chunks","isValidSession","parseCookies","cookieString","out","pair","trim","eq","name_1","decodeMaybe","input","serializeCookie","attrs","encodeURIComponent","maxAge","domain","path","sameSite","secure","serializeCookieRemoval","MAX_CHUNK_SIZE","chunkKey","idx","collectChunkKeys","parsed","prefix","found","forEach","_value","startsWith","tail","Number","sort","a","cookieStorageAdapter","jar","protocol","chunkNames","readChunkedCookieValue","cookie","has","newCount","ceil","name_2","pos","name_3","localStorageAdapter","parseParametersFromURL","href","URL","substring","searchParams","clearURLParameters","delete_params","param","history","replaceState","state","LockAcquireTimeoutError","isAcquireTimeout","lockNoOp","acquireTimeout","NavigatorLockAcquireTimeoutError","Lock","lockAcquired","pendingInLock","lock","_acquireLock","last_1","result_1","result_2","waitOn","splice","AUTO_REFRESH_TICK_DURATION","FaableAuthClient","domainUrl","initializePromise","_lastInitializeResult","detectSessionInUrl","autoRefreshTicker","visibilityChangedCallback","refreshingDeferred","_session","sessionCheckExpiryDays","redirectUri","match","host","toLowerCase","getDomain","tokenIssuer","audience","api","key_prefix","cookieOptions","resolveStorage","broadcastSync","msg","flowType","autoRefreshToken","initialize","defineProperty","_initialize","handleRedirectCallback","_detectFlowType","flow","_getSessionFromURL","_removeSession","redirectType_1","is_new_user","_saveSession","_notifyAllSubscribers","_recoverAndRefresh","error_1","_handleVisibilityChange","signup","_exchangeCodeForSession","error_3","error_description","error_code","provider_token","provider_refresh_token","token_type","expiresAt","refreshTick","timeNow","parseInt","actuallyExpiresIn","issuedAt","checkExpiresInTime","accessToken","resolvedExpiresAt","exp","expiryFromAccessToken","_getUser","type","error_2","authCode","stored","client_id","grant_type","code_verifier","rawResponse","error_4","startAutoRefresh","_onVisibilityChanged","error_5","calledFromInitialize","methodName","visibilityState","_startAutoRefresh","_stopAutoRefresh","debugName","currentSession","expiresWithMargin","_callRefreshToken","_removeVisibilityChangedCallback","removeEventListener","ticker","setInterval","_autoRefreshTokenTick","unref","Deno","unrefTimer","clearInterval","now_1","_useSession","expiresInTicks","floor","e_2","browser","_scope","scope","_getUrlForConnection","urlParams","queryParams","authorize_params","redirect_uri","redirectTo","origin","scopes","codeChallengeMethod","code_challenge","code_challenge_method","connection_id","connection","signInWithOauthConnection","credentials","_handleConnectionSignIn","skipBrowserRedirect","signInWithUsernamePassword","username","password","rawAuthResponse","formHtml","doc","div","createElement","innerHTML","form","appendChild","children","submit","buildAndSubmitForm","signUp","email","given_name","family_name","user_metadata","status_1","signInWithOtp","otp","sessionData","userError","signInWithPasswordless","send","response","changePassword","_resolveUserId","fromUser","changeEmail","new_email","getSession","sessionError","user_id","verification_mode","buildAuthorizeUrl","definedParams","fromEntries","entries","filter","authorize","setSession","_setSession","__loadSession","stack","maybeSession","hasExpired","isServer","proxySession","Proxy","target","prop","receiver","Reflect","refreshedSession","error_6","refreshToken","_refreshAccessToken","timeoutMs","timeoutMessage","timeoutPromise","timer","race","finally","clearTimeout","error_7","startedAt_1","pow","session_res","nextBackOffInterval","error_8","session_2","_signOut","isAuthApiError","onAuthStateChange","_emitInitialSession","err_2","refreshSession","_refreshSession","error_10","error_9","createClient","User"],"mappings":"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","x_google_ignoreList":[0]}