limen-auth 0.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +72 -0
- package/dist/bearer-Cqmrmjjf.mjs +84 -0
- package/dist/bearer-Cqmrmjjf.mjs.map +1 -0
- package/dist/client-Er91De-z.mjs +705 -0
- package/dist/client-Er91De-z.mjs.map +1 -0
- package/dist/constants-CsR2pQ_9.mjs +15 -0
- package/dist/constants-CsR2pQ_9.mjs.map +1 -0
- package/dist/define-plugin-C7WOGU4b.mjs +24 -0
- package/dist/define-plugin-C7WOGU4b.mjs.map +1 -0
- package/dist/define-plugin-Dv0xXIaH.d.mts +450 -0
- package/dist/define-plugin-Dv0xXIaH.d.mts.map +1 -0
- package/dist/errors-4YJYt6f0.mjs +37 -0
- package/dist/errors-4YJYt6f0.mjs.map +1 -0
- package/dist/helpers-Cs3VtXdv.mjs +54 -0
- package/dist/helpers-Cs3VtXdv.mjs.map +1 -0
- package/dist/helpers-CvmKjWi2.d.mts +10 -0
- package/dist/helpers-CvmKjWi2.d.mts.map +1 -0
- package/dist/index-B8SpHkSd.d.mts +48 -0
- package/dist/index-B8SpHkSd.d.mts.map +1 -0
- package/dist/index-C6atwjEq.d.mts +65 -0
- package/dist/index-C6atwjEq.d.mts.map +1 -0
- package/dist/index-C9EuA9UZ.d.mts +32 -0
- package/dist/index-C9EuA9UZ.d.mts.map +1 -0
- package/dist/index-Cgr2wHmM.d.mts +87 -0
- package/dist/index-Cgr2wHmM.d.mts.map +1 -0
- package/dist/index-DV6YcNSu.d.mts +81 -0
- package/dist/index-DV6YcNSu.d.mts.map +1 -0
- package/dist/index-dEksIImj.d.mts +28 -0
- package/dist/index-dEksIImj.d.mts.map +1 -0
- package/dist/index.d.mts +30 -0
- package/dist/index.d.mts.map +1 -0
- package/dist/index.mjs +12 -0
- package/dist/index.mjs.map +1 -0
- package/dist/plugins/bearer/index.d.mts +2 -0
- package/dist/plugins/bearer/index.mjs +2 -0
- package/dist/plugins/credential/index.d.mts +2 -0
- package/dist/plugins/credential/index.mjs +50 -0
- package/dist/plugins/credential/index.mjs.map +1 -0
- package/dist/plugins/index.d.mts +7 -0
- package/dist/plugins/index.mjs +7 -0
- package/dist/plugins/magic-link/index.d.mts +2 -0
- package/dist/plugins/magic-link/index.mjs +21 -0
- package/dist/plugins/magic-link/index.mjs.map +1 -0
- package/dist/plugins/oauth/index.d.mts +2 -0
- package/dist/plugins/oauth/index.mjs +56 -0
- package/dist/plugins/oauth/index.mjs.map +1 -0
- package/dist/plugins/session-jwt/index.d.mts +2 -0
- package/dist/plugins/session-jwt/index.mjs +2 -0
- package/dist/plugins/two-factor/index.d.mts +2 -0
- package/dist/plugins/two-factor/index.mjs +52 -0
- package/dist/plugins/two-factor/index.mjs.map +1 -0
- package/dist/react/index.d.mts +24 -0
- package/dist/react/index.d.mts.map +1 -0
- package/dist/react/index.mjs +31 -0
- package/dist/react/index.mjs.map +1 -0
- package/dist/route-DGxvFqWl.mjs +19 -0
- package/dist/route-DGxvFqWl.mjs.map +1 -0
- package/dist/session-jwt-DgLdMQxP.mjs +129 -0
- package/dist/session-jwt-DgLdMQxP.mjs.map +1 -0
- package/dist/solid/index.d.mts +25 -0
- package/dist/solid/index.d.mts.map +1 -0
- package/dist/solid/index.mjs +28 -0
- package/dist/solid/index.mjs.map +1 -0
- package/dist/svelte/index.d.mts +25 -0
- package/dist/svelte/index.d.mts.map +1 -0
- package/dist/svelte/index.mjs +18 -0
- package/dist/svelte/index.mjs.map +1 -0
- package/dist/vue/index.d.mts +36 -0
- package/dist/vue/index.d.mts.map +1 -0
- package/dist/vue/index.mjs +36 -0
- package/dist/vue/index.mjs.map +1 -0
- package/package.json +123 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client-Er91De-z.mjs","names":[],"sources":["../src/path.ts","../src/serialize.ts","../src/pipeline.ts","../src/build-tree.ts","../src/envelope.ts","../src/fetcher.ts","../src/hooks.ts","../src/normalize.ts","../src/routes.ts","../src/broadcast-channel.ts","../src/json-deep-equal.ts","../src/session-sync.ts","../src/session-store.ts","../src/client.ts"],"sourcesContent":["import { kebabToCamel } from \"./helpers\";\n\n/**\n * Derive the public client chain from a route path. Mirrors the type-level\n * `PathSegments` in `infer.ts` exactly, so runtime materialization and compile\n * time inference can never drift.\n *\n * \"/otp/send\" -> [\"otp\", \"send\"]\n * \"/revoke-sessions\" -> [\"revokeSessions\"]\n * \"/:provider/authorize\" -> [\"authorize\"] (param segments are dropped)\n */\nexport function pathToChain(path: string): string[] {\n return path\n .split(\"/\")\n .filter((seg) => seg.length > 0 && !seg.startsWith(\":\"))\n .map(kebabToCamel);\n}\n\nexport function chainFromDotted(chain: string): string[] {\n return chain.split(\".\").filter((seg) => seg.length > 0);\n}\n\ntype ResolvedPath = {\n /** Path with `:param` segments substituted. */\n path: string;\n /** Input with declared param keys removed. */\n rest: unknown;\n};\n\n/**\n * Substitute declared path params from `input` into `path` and strip them from\n * the payload.\n */\nexport function resolvePath(path: string, params: readonly string[] | undefined, input: unknown): ResolvedPath {\n if (!params || params.length === 0) {\n return { path, rest: input };\n }\n const source = (input ?? {}) as Record<string, unknown>;\n const rest: Record<string, unknown> = { ...source };\n let resolved = path;\n for (const param of params) {\n const value = rest[param];\n if (value === undefined) {\n throw new Error(`Missing required path param \"${param}\" for route \"${path}\"`);\n }\n resolved = resolved.replace(`:${param}`, encodeURIComponent(value as string));\n delete rest[param];\n }\n return { path: resolved, rest };\n}\n","import { camelToSnake } from \"./helpers\";\n\n/**\n * Default request serializer: shallow camelCase → snake_case, drops `undefined`,\n * leaves non-objects unchanged.\n *\n * `additionalFields` entries are merged into the top-level body verbatim.\n * Known route fields win on key collisions.\n */\nexport function defaultSerialize(input: unknown): unknown {\n if (input === null || input === undefined) {\n return input;\n }\n if (typeof input !== \"object\" || Array.isArray(input)) {\n return input;\n }\n const { additionalFields, ...rest } = input as Record<string, unknown>;\n const out: Record<string, unknown> = {};\n\n if (additionalFields && typeof additionalFields === \"object\" && !Array.isArray(additionalFields)) {\n Object.assign(out, additionalFields);\n }\n\n for (const [key, value] of Object.entries(rest)) {\n if (value === undefined) {\n continue;\n }\n out[camelToSnake(key)] = value;\n }\n return out;\n}\n","import type { AnyRouteContext } from \"./context\";\nimport type { LimenError } from \"./errors\";\nimport { camelizeEach } from \"./helpers\";\nimport { resolvePath } from \"./path\";\nimport type { FetchInit } from \"./plugin\";\nimport type { AnyRoute, HttpRunner, RouteCallOptions } from \"./route\";\nimport { defaultSerialize } from \"./serialize\";\nimport type { Session } from \"./types\";\n\n/**\n * Run the default HTTP steps for a route — merge defaults, resolve path params,\n * serialize, dispatch, parse — without applying session effects.\n */\nasync function runHttp(ctx: AnyRouteContext, def: AnyRoute, input: unknown): Promise<unknown> {\n let merged = input;\n if (def.defaults !== undefined) {\n merged = { ...(def.defaults as Record<string, unknown>), ...((input ?? {}) as Record<string, unknown>) };\n }\n\n const { path, rest } = resolvePath(def.path, def.params, merged);\n const payload = def.serialize !== undefined ? def.serialize(rest) : defaultSerialize(rest);\n\n const init: FetchInit = { method: def.method, absolute: def.absolute ?? false };\n if (def.method === \"GET\" && payload !== undefined) {\n init.query = payload as Record<string, string>;\n } else {\n init.body = payload;\n }\n\n const raw = await ctx.fetch<unknown>(path, init);\n\n if (def.parseSession === true) {\n return ctx.parseSession(raw);\n }\n\n if (def.parse !== undefined) {\n return def.parse(raw);\n }\n return Array.isArray(raw) ? camelizeEach(raw) : raw;\n}\n\nasync function applyEffects(ctx: AnyRouteContext, def: AnyRoute, result: unknown): Promise<void> {\n if (def.clearSession === true) {\n ctx.store.setData(null);\n }\n\n if (def.parseSession === true && def.skipStore !== true) {\n if (result !== null && typeof result === \"object\" && \"user\" in result) {\n ctx.store.setData(result as Session<unknown>);\n }\n }\n\n if (def.refetchSession === true) {\n await ctx.store.refetch();\n }\n}\n\nfunction makeHttpRunner(ctx: AnyRouteContext, def: AnyRoute, boundInput: unknown): HttpRunner<unknown> {\n const run = (override?: unknown): Promise<unknown> =>\n runHttp(ctx, def, override === undefined ? boundInput : override);\n return run as HttpRunner<unknown>;\n}\n\n/**\n * Execute a route's behaviour: delegate to its `handler` when present (handler\n * owns all behaviour, including any effects), otherwise run the default\n * pipeline and apply declarative effects once at the top level.\n */\nasync function dispatchRoute(ctx: AnyRouteContext, def: AnyRoute, input: unknown): Promise<unknown> {\n if (def.handler !== undefined) {\n return def.handler(ctx, input, makeHttpRunner(ctx, def, input));\n }\n const result = await runHttp(ctx, def, input);\n await applyEffects(ctx, def, result);\n return result;\n}\n\n/**\n * Run a route as a public client call, firing the per-call `onSuccess` /\n * `onError` hooks around the resolved value or thrown error.\n */\nexport async function runRoute(\n ctx: AnyRouteContext,\n def: AnyRoute,\n input: unknown,\n opts?: RouteCallOptions,\n): Promise<unknown> {\n try {\n const result = await dispatchRoute(ctx, def, input);\n opts?.onSuccess?.(result);\n return result;\n } catch (error) {\n opts?.onError?.(error as LimenError);\n throw error;\n }\n}\n","import type { AnyRouteContext, RouteContext } from \"./context\";\nimport type { AnyClientPlugin, RunRoute } from \"./define-plugin\";\nimport type { Fetcher } from \"./fetcher\";\nimport { ensureLeadingSlash, kebabToCamel, normalizeBasePath } from \"./helpers\";\nimport { chainFromDotted, pathToChain } from \"./path\";\nimport { runRoute } from \"./pipeline\";\nimport type { FetchInit } from \"./plugin\";\nimport type { AnyRoute, AnyRouteDescriptor, RouteCallOptions } from \"./route\";\n\nexport type ClientOverrides = Record<string, { basePath?: string } | undefined> | undefined;\n\n/** Scope a context's `fetch` to one plugin's base path (after client `overrides`). */\nfunction scopeContext(\n ctx: AnyRouteContext,\n fetcher: Fetcher,\n plugin: AnyClientPlugin,\n overrides: ClientOverrides,\n): RouteContext {\n const defaultBase = normalizeBasePath(plugin.basePath ?? \"\");\n const overrideBase = overrides?.[kebabToCamel(plugin.id)]?.basePath;\n const resolvedBase = normalizeBasePath(overrideBase ?? plugin.basePath ?? \"\");\n return {\n ...ctx,\n fetch: <T>(path: string, init?: FetchInit) => {\n const absolute = init?.absolute === true;\n const requestPath = (absolute ? \"\" : resolvedBase) + ensureLeadingSlash(path);\n const routePath = (absolute ? \"\" : defaultBase) + ensureLeadingSlash(path);\n return fetcher.fetch<T>(requestPath, init, routePath);\n },\n };\n}\n\nfunction chainFor(plugin: AnyClientPlugin, def: AnyRoute): string[] {\n if (typeof def.as === \"string\") {\n return chainFromDotted(def.as);\n }\n return [...pathToChain(plugin.basePath ?? \"\"), ...pathToChain(def.path)];\n}\n\nfunction mountAtChain(target: Record<string, unknown>, pathSegments: string[], callable: unknown): void {\n let current = target;\n for (let i = 0; i < pathSegments.length - 1; i += 1) {\n const segment = pathSegments[i] as string;\n const child = current[segment];\n if (child === undefined) {\n const namespace: Record<string, unknown> = {};\n current[segment] = namespace;\n current = namespace;\n } else {\n current = child as Record<string, unknown>;\n }\n }\n const finalSegment = pathSegments[pathSegments.length - 1] as string;\n current[finalSegment] = callable;\n}\n\nfunction isNamespace(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value) && typeof value !== \"function\";\n}\n\nfunction mergeInto(target: Record<string, unknown>, source: Record<string, unknown>): void {\n for (const [key, value] of Object.entries(source)) {\n const existing = target[key];\n if (isNamespace(existing) && isNamespace(value)) {\n mergeInto(existing, value);\n continue;\n }\n target[key] = value;\n }\n}\n\ntype BuildClientTreeArgs = {\n plugins: readonly AnyClientPlugin[];\n ctx: AnyRouteContext;\n fetcher: Fetcher;\n overrides: ClientOverrides;\n};\n\n/**\n * Build the public API object from plugin routes and actions.\n */\nexport function buildClientTree({ plugins, ctx, fetcher, overrides }: BuildClientTreeArgs): Record<string, unknown> {\n const api: Record<string, unknown> = {};\n\n for (const plugin of plugins) {\n const scopedCtx = scopeContext(ctx, fetcher, plugin, overrides);\n const contribution: Record<string, unknown> = {};\n\n for (const def of plugin.routes as readonly AnyRoute[]) {\n if (def.expose === false) {\n continue;\n }\n const call = (input?: unknown, opts?: RouteCallOptions) => runRoute(scopedCtx, def, input, opts);\n mountAtChain(contribution, chainFor(plugin, def), call);\n }\n\n if (plugin.actions !== undefined) {\n const run: RunRoute = (route, input) => runRoute(scopedCtx, route as AnyRouteDescriptor, input) as Promise<never>;\n mergeInto(contribution, plugin.actions(scopedCtx, run) as Record<string, unknown>);\n }\n\n mergeInto(api, contribution);\n }\n\n return api;\n}\n","import { DEFAULT_ENVELOPE_FIELDS } from \"./constants\";\nimport { type EnvelopeConfig } from \"./types\";\n\n/**\n * Unwrap a parsed JSON success body according to envelope config.\n *\n * - `mode: \"off\"`: return as-is.\n * - `mode: \"wrap-success\" | \"always\"`: extract `body[fields.data]` if present;\n * if the key is missing (server didn't wrap this particular response), fall\n * back to the raw body so we don't lose data.\n *\n * Returning `unknown` is intentional: the caller knows the expected shape and\n * narrows / validates it. Trying to be clever here would invite false typing.\n */\nexport function unwrapPayload(body: unknown, envelope: EnvelopeConfig): unknown {\n if (envelope.mode === \"off\") {\n return body;\n }\n if (body === null || typeof body !== \"object\") {\n return body;\n }\n const fields = envelope.fields ?? DEFAULT_ENVELOPE_FIELDS;\n const record = body as Record<string, unknown>;\n if (fields.data in record) {\n return record[fields.data];\n }\n return body;\n}\n\n/**\n * Pull the human-readable error message out of a non-2xx body.\n *\n * - `mode: \"off\" | \"wrap-success\"`: error bodies look like `{ message }`\n * - `mode: \"always\"`: error bodies use the configured `fields.message` key.\n *\n * Returns `undefined` when no message can be located; the caller substitutes\n * a status-based fallback (e.g. HTTP status text).\n */\nexport function unwrapErrorMessage(body: unknown, envelope: EnvelopeConfig): string | undefined {\n if (body === null || typeof body !== \"object\") {\n return undefined;\n }\n const record = body as Record<string, unknown>;\n const fields = envelope.fields ?? DEFAULT_ENVELOPE_FIELDS;\n const key = envelope.mode === \"always\" ? fields.message : \"message\";\n const value = record[key];\n return typeof value === \"string\" ? value : undefined;\n}\n","import { unwrapErrorMessage, unwrapPayload } from \"./envelope\";\nimport { LimenError, deriveErrorCode } from \"./errors\";\nimport { ensureLeadingSlash, joinURL, stripTrailingSlash } from \"./helpers\";\nimport type { HookRunner } from \"./hooks\";\nimport type { FetchInit, RequestContext, ResponseContext } from \"./plugin\";\nimport type { EnvelopeConfig, HTTPMethod } from \"./types\";\n\ntype ClientFetchCallbackContext = ResponseContext & {};\n\nexport type FetcherFetchOptions = {\n /** Whether to send credentials (cookies). Defaults to `\"include\"`. */\n credentials?: RequestCredentials;\n /** Custom fetch impl. Defaults to `globalThis.fetch`. */\n impl?: typeof fetch;\n /** Default headers merged into every request. Per-request headers override these. */\n headers?: HeadersInit;\n /** Callback function to be called when the request is successful. */\n onSuccess?: (context: ClientFetchCallbackContext & { response: Response }) => void;\n /** Callback function to be called when the request fails. */\n onError?: (context: ClientFetchCallbackContext & { error: Error }) => void;\n};\n\ntype FetcherOptions = {\n baseURL: string;\n basePath: string;\n fetchOptions: FetcherFetchOptions;\n hooks: HookRunner;\n envelope: EnvelopeConfig;\n};\n\nexport class Fetcher {\n private readonly fetchImpl: typeof fetch;\n private readonly credentials: RequestCredentials;\n\n constructor(private readonly opts: FetcherOptions) {\n this.fetchImpl = opts.fetchOptions.impl ?? globalThis.fetch.bind(globalThis);\n this.credentials = opts.fetchOptions.credentials ?? \"include\";\n }\n\n async fetch<T>(path: string, init?: FetchInit, routePath: string = path): Promise<T> {\n const method: HTTPMethod = init?.method ?? (init?.body !== undefined ? \"POST\" : \"GET\");\n return this.run<T>({\n method,\n path,\n routePath,\n body: init?.body,\n headers: init?.headers,\n query: init?.query,\n });\n }\n\n /**\n * Builds the request context, runs hooks, does\n * the fetch, parses the response, runs hooks again, throws on non-2xx.\n */\n private async run<T>(args: {\n method: HTTPMethod;\n path: string;\n routePath: string;\n body: unknown;\n headers: HeadersInit | undefined;\n query: Record<string, string> | undefined;\n }): Promise<T> {\n const fullPath = this.normalizeRelativePath(this.opts.basePath, args.path, args.query);\n const url = joinURL(this.opts.baseURL, fullPath);\n\n const headers = new Headers({ ...args.headers, ...(this.opts.fetchOptions.headers ?? {}) });\n if (!headers.has(\"Content-Type\")) {\n headers.set(\"Content-Type\", \"application/json\");\n }\n if (!headers.has(\"Accept\")) {\n headers.set(\"Accept\", \"application/json\");\n }\n\n let reqCtx: RequestContext = {\n method: args.method,\n fullPath: fullPath,\n path: args.path,\n routePath: args.routePath,\n url,\n headers,\n body: args.body,\n };\n\n reqCtx = await this.opts.hooks.runBeforeRequest(reqCtx);\n\n const payload = reqCtx.body !== undefined && reqCtx.body !== null ? JSON.stringify(reqCtx.body) : undefined;\n\n const requestInit: RequestInit = {\n method: reqCtx.method,\n headers: reqCtx.headers,\n credentials: this.credentials,\n };\n\n if (payload !== undefined) {\n requestInit.body = payload;\n }\n\n let response: Response;\n try {\n response = await this.fetchImpl(reqCtx.url, requestInit);\n } catch (err) {\n this.opts.fetchOptions.onError?.({\n ...reqCtx,\n status: 0,\n ok: false,\n error: err as Error,\n });\n throw new LimenError(err instanceof Error ? err.message : \"Network request failed\", 0, \"unknown\");\n }\n\n const parsedBody = await this.parseResponseBody(response);\n const unwrapped =\n response.ok && parsedBody !== undefined ? unwrapPayload(parsedBody, this.opts.envelope) : parsedBody;\n\n let resCtx: ResponseContext = {\n method: args.method,\n fullPath: fullPath,\n path: args.path,\n routePath: args.routePath,\n status: response.status,\n ok: response.ok,\n headers: response.headers,\n body: unwrapped,\n };\n\n resCtx = await this.opts.hooks.runAfterResponse(resCtx);\n\n if (resCtx.ok) {\n this.opts.fetchOptions.onSuccess?.({\n ...resCtx,\n response,\n });\n return resCtx.body as T;\n }\n\n const message =\n unwrapErrorMessage(resCtx.body, this.opts.envelope) ??\n response.statusText ??\n `Request failed with status ${response.status}`;\n\n const error = new LimenError(message, response.status, deriveErrorCode(response.status));\n this.opts.fetchOptions.onError?.({\n ...reqCtx,\n status: response.status,\n ok: false,\n error,\n });\n throw error;\n }\n\n private async parseResponseBody(response: Response): Promise<unknown> {\n if (response.status === 204) {\n return undefined;\n }\n const text = await response.text();\n if (text.length === 0) {\n return undefined;\n }\n return JSON.parse(text) as unknown;\n }\n\n private normalizeRelativePath(\n basePath: string,\n relativePath: string,\n query: Record<string, string> | undefined,\n ): string {\n const base = basePath === \"\" || basePath === \"/\" ? \"\" : ensureLeadingSlash(stripTrailingSlash(basePath));\n let path = base + ensureLeadingSlash(relativePath);\n if (query !== undefined) {\n const params = new URLSearchParams(query);\n const qs = params.toString();\n if (qs.length > 0) {\n path = `${path}?${qs}`;\n }\n }\n return path;\n }\n}\n","import type {\n AfterResponseHook,\n BeforeRequestHook,\n PluginHooks,\n RequestContext,\n ResponseContext,\n RouteMatcher,\n} from \"./plugin\";\n\ntype HookProvider = {\n hooks?: PluginHooks;\n};\n\nfunction matchesRoute(matcher: RouteMatcher | undefined, routePath: string): boolean {\n if (matcher === undefined) {\n return true;\n }\n if (typeof matcher === \"string\") {\n return routePath === matcher;\n }\n if (typeof matcher === \"function\") {\n return matcher({ path: routePath });\n }\n return routePath !== undefined && matcher.includes(routePath);\n}\n\nexport class HookRunner {\n private readonly before: BeforeRequestHook[];\n private readonly after: AfterResponseHook[];\n\n constructor(plugins: readonly HookProvider[]) {\n this.before = plugins.flatMap((p) => p.hooks?.beforeRequest ?? []);\n this.after = plugins.flatMap((p) => p.hooks?.afterResponse ?? []);\n }\n\n async runBeforeRequest(initial: RequestContext): Promise<RequestContext> {\n let ctx = initial;\n for (const hook of this.before) {\n if (!matchesRoute(hook.match, ctx.routePath)) {\n continue;\n }\n ctx = await hook.run(ctx);\n }\n return ctx;\n }\n\n async runAfterResponse(initial: ResponseContext): Promise<ResponseContext> {\n let ctx = initial;\n for (const hook of this.after) {\n if (!matchesRoute(hook.match, ctx.routePath)) {\n continue;\n }\n if (!hook.allowOnFailure && ctx.status >= 400) {\n continue;\n }\n ctx = await hook.run(ctx);\n }\n return ctx;\n }\n}\n","import { toCamelCaseKey } from \"./helpers\";\nimport type { Session, User } from \"./types\";\n\n/**\n * Convert snake_case User keys from server payloads to camelCase. Unknown\n * extension fields are converted with the same rule so consumers consistently\n * read camelCase in SDK responses.\n */\nexport function normalizeUser<F = unknown>(raw: Record<string, unknown>): User<F> {\n const out: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(raw)) {\n out[toCamelCaseKey(key)] = value;\n }\n return out as User<F>;\n}\n\nexport function defaultSessionParse<F = unknown>(raw: unknown): Session<F> {\n if (!raw || typeof raw !== \"object\") {\n throw new TypeError(`Expected session response to be an object, got ${raw === null ? \"null\" : typeof raw}`);\n }\n const obj = raw as Record<string, unknown>;\n const userRaw = (obj[\"user\"] ?? obj) as Record<string, unknown>;\n return { user: normalizeUser<F>(userRaw) };\n}\n","import type { RouteContext } from \"./context\";\nimport type { InferPluginContribution } from \"./define-plugin\";\nimport { defineClientPlugin, defineRoutes } from \"./define-plugin\";\nimport { route } from \"./route\";\nimport type { Session } from \"./types\";\n\nexport type VerifyEmailInput = {\n token: string;\n};\n\nexport type ActiveSession = {\n id: string | number;\n token: string;\n userId: unknown;\n createdAt: string;\n expiresAt: string;\n lastAccess: string;\n metadata?: Record<string, unknown>;\n};\n\n/**\n * Core routes available on every client.\n */\nexport function coreClientPlugin<TFields = unknown>() {\n const routes = defineRoutes(\n route<void, ActiveSession[]>()({\n method: \"GET\",\n path: \"/sessions\",\n }),\n route<void, void>()({\n method: \"POST\",\n path: \"/signout\",\n clearSession: true,\n }),\n route<void, void>()({\n method: \"POST\",\n path: \"/revoke-sessions\",\n clearSession: true,\n }),\n route<VerifyEmailInput, string>()({\n method: \"POST\",\n path: \"/verify-email\",\n refetchSession: true,\n }),\n route<void, string>()({\n method: \"POST\",\n path: \"/email-verifications\",\n as: \"requestEmailVerification\",\n }),\n );\n\n return defineClientPlugin({\n id: \"core\",\n basePath: \"/\",\n routes,\n actions: (ctx) => ({\n /**\n * Revalidate session state with `GET /me`, update `$session`, and return the\n * resolved value (`null` when signed out).\n *\n * Prefer subscribing to `$session` for reactive UI state (`data`, `isPending`,\n * `error`). Use `getSession()` when you need an awaited server re-check, such\n * as route guards or SSR revalidation after `initialSession`.\n */\n getSession: async (): Promise<Session<TFields> | null> => {\n await ctx.refetchSession();\n const state = ctx.store.$session.get();\n if (state.error) {\n throw state.error;\n }\n return state.data as Session<TFields> | null;\n },\n }),\n });\n}\n\nexport type CoreContribution<TFields = unknown> = InferPluginContribution<ReturnType<typeof coreClientPlugin<TFields>>>;\n\n/**\n * Fetch and parse the current session for the reactive store.\n */\nexport function createSessionHydrator<TFields>(\n ctx: Pick<RouteContext<TFields>, \"fetch\" | \"parseSession\">,\n): () => Promise<Session<TFields>> {\n return async () => {\n const raw = await ctx.fetch<unknown>(\"/me\", { method: \"GET\" });\n return ctx.parseSession(raw);\n };\n}\n","/**\n * Cross-tab message transport: callers post and\n * subscribe to typed messages. Uses `BroadcastChannel` where available, falling\n * back to `localStorage` `storage` events. A no-op in non-browser environments.\n */\ntype BroadcastPort<T> = {\n post(message: T): void;\n subscribe(listener: (message: T) => void): () => void;\n close(): void;\n};\n\nconst NOOP_PORT: BroadcastPort<unknown> = {\n post() {},\n subscribe: () => () => {},\n close() {},\n};\n\nexport function createBroadcastChannel<T>(name: string): BroadcastPort<T> {\n if (typeof window === \"undefined\") {\n return NOOP_PORT as BroadcastPort<T>;\n }\n\n const storageKey = `${name}-sync`;\n const listeners = new Set<(message: T) => void>();\n const emit = (message: T): void => {\n for (const listener of listeners) {\n listener(message);\n }\n };\n\n const channel = typeof BroadcastChannel !== \"undefined\" ? new BroadcastChannel(name) : null;\n if (channel) {\n channel.onmessage = (event: MessageEvent<T>) => {\n if (event.data != null) {\n emit(event.data);\n }\n };\n }\n\n const onStorage = (event: StorageEvent): void => {\n if (event.key !== storageKey || !event.newValue) {\n return;\n }\n\n emit(JSON.parse(event.newValue) as T);\n };\n\n if (!channel) {\n window.addEventListener(\"storage\", onStorage);\n }\n\n return {\n post(message) {\n if (channel) {\n channel.postMessage(message);\n return;\n }\n\n if (typeof globalThis.localStorage !== \"undefined\") {\n globalThis.localStorage.setItem(storageKey, JSON.stringify(message));\n globalThis.localStorage.removeItem(storageKey);\n }\n },\n subscribe(listener) {\n listeners.add(listener);\n return () => {\n listeners.delete(listener);\n };\n },\n close() {\n listeners.clear();\n if (channel) {\n channel.close();\n return;\n }\n window.removeEventListener(\"storage\", onStorage);\n },\n };\n}\n","function isPlainObject(value: unknown): value is Record<string, unknown> {\n if (typeof value !== \"object\" || value === null) {\n return false;\n }\n const proto = Object.getPrototypeOf(value);\n return proto === Object.prototype || proto === null;\n}\n\nfunction equalArrays(a: unknown[], b: unknown[]): boolean {\n if (a.length !== b.length) {\n return false;\n }\n\n for (let i = 0; i < a.length; i += 1) {\n if (!deepJsonEqual(a[i], b[i])) {\n return false;\n }\n }\n return true;\n}\n\nfunction equalObjects(a: Record<string, unknown>, b: Record<string, unknown>): boolean {\n const aKeys = Object.keys(a);\n const bKeys = Object.keys(b);\n if (aKeys.length !== bKeys.length) {\n return false;\n }\n\n for (const key of aKeys) {\n if (!Object.hasOwn(b, key) || !deepJsonEqual(a[key], b[key])) {\n return false;\n }\n }\n return true;\n}\n\n/** Structural equality for JSON-shaped values. */\nexport function deepJsonEqual(a: unknown, b: unknown): boolean {\n if (Object.is(a, b)) {\n return true;\n }\n\n const aIsArray = Array.isArray(a);\n const bIsArray = Array.isArray(b);\n if (aIsArray && bIsArray) {\n return equalArrays(a, b);\n }\n\n if (!isPlainObject(a) || !isPlainObject(b)) {\n return false;\n }\n return equalObjects(a, b);\n}\n","import { onNotify } from \"nanostores\";\nimport { createBroadcastChannel } from \"./broadcast-channel\";\nimport { deepJsonEqual } from \"./json-deep-equal\";\nimport type { SessionStore } from \"./session-store\";\nimport type { Session } from \"./types\";\n\nconst CHANNEL_NAME = \"limen.session\";\nconst FOCUS_REFETCH_THROTTLE_MS = 5_000;\n\ntype SyncMessage<TFields> = { data: Session<TFields> | null };\n\ntype SessionSyncOptions = {\n /** Fetch the session on mount. */\n fetchOnMount: boolean;\n /** Mirror session changes to other same-origin tabs. */\n crossTabSync: boolean;\n /** Re-validate against `/me` when the tab returns to the foreground. */\n refetchOnWindowFocus: boolean;\n};\n\nexport function createSessionSync<TFields = unknown>(\n store: SessionStore<TFields>,\n options: SessionSyncOptions,\n): () => void {\n if (options.fetchOnMount) {\n void store.refetch();\n }\n\n const teardowns: Array<() => void> = [];\n if (options.crossTabSync) {\n teardowns.push(syncAcrossTabs(store));\n }\n\n if (options.refetchOnWindowFocus) {\n teardowns.push(refetchOnFocus(store));\n }\n\n return () => {\n for (const teardown of teardowns) {\n teardown();\n }\n };\n}\n\nfunction syncAcrossTabs<TFields>(store: SessionStore<TFields>): () => void {\n const port = createBroadcastChannel<SyncMessage<TFields>>(CHANNEL_NAME);\n let lastData = store.$session.get().data;\n\n const unsubscribe = port.subscribe((message) => {\n // Mark remote updates as seen before applying them to avoid echoing them.\n lastData = message.data;\n store.setData(message.data);\n });\n\n const unbindNotify = onNotify(store.$session, () => {\n const data = store.$session.get().data;\n if (deepJsonEqual(data, lastData)) {\n return;\n }\n lastData = data;\n port.post({ data: data });\n });\n\n return () => {\n unbindNotify();\n unsubscribe();\n port.close();\n };\n}\n\nfunction refetchOnFocus<TFields>(store: SessionStore<TFields>): () => void {\n if (typeof document === \"undefined\") {\n return () => {};\n }\n const onVisibilityChange = (): void => {\n if (document.visibilityState === \"visible\") {\n void store.refetch({ maxAgeMs: FOCUS_REFETCH_THROTTLE_MS, skipSignedOut: true });\n }\n };\n document.addEventListener(\"visibilitychange\", onVisibilityChange);\n return () => document.removeEventListener(\"visibilitychange\", onVisibilityChange);\n}\n","import { atom, onMount, type ReadableAtom } from \"nanostores\";\nimport { LimenError } from \"./errors\";\nimport { createSessionSync } from \"./session-sync\";\nimport type { Session } from \"./types\";\n\nexport type SessionState<TFields = unknown> = {\n /** The current session, or `null` when signed out. */\n data: Session<TFields> | null;\n /** True while a `/me` fetch is in flight. */\n isPending: boolean;\n /**\n * The last non-401 failure (network error, 5xx, etc.). A 401 is not an error\n * — it resolves to `data: null`. `error` is cleared on the next successful or\n * 401 outcome.\n */\n error: LimenError | null;\n};\n\ntype RefetchOptions = {\n /** Skip the fetch when the last hydration ran within this many milliseconds. */\n maxAgeMs?: number;\n /** Skip the fetch when the session is signed out. */\n skipSignedOut?: boolean;\n};\n\nexport type SessionStore<TFields = unknown> = {\n readonly $session: ReadableAtom<SessionState<TFields>>;\n setData(session: Session<TFields> | null): void;\n /**\n * Re-validate the session from the server.\n */\n refetch(options?: RefetchOptions): Promise<void>;\n};\n\ntype CreateSessionStoreArgs<TFields = unknown> = {\n hydrator: () => Promise<Session<TFields>>;\n initialSession?: Session<TFields> | null;\n /** Mirror session changes to other same-origin tabs. */\n crossTabSync?: boolean;\n /** Re-validate against `/me` when the tab returns to the foreground. */\n refetchOnWindowFocus?: boolean;\n};\n\nexport function createSessionStore<TFields = unknown>(options: CreateSessionStoreArgs<TFields>): SessionStore<TFields> {\n const $session = atom<SessionState<TFields>>({\n data: options.initialSession ?? null,\n isPending: false,\n error: null,\n });\n\n let inFlightHydration: Promise<void> | null = null;\n // Bumped on every write so older async refresh results cannot overwrite newer state.\n let writeVersion = 0;\n // Timestamp the most recent session refetched.\n let lastRefreshedAt = 0;\n const isStale = (requestVersion: number): boolean => requestVersion !== writeVersion;\n\n const fetchSessionFromServer = async (): Promise<void> => {\n const requestVersion = ++writeVersion;\n $session.set({ data: $session.get().data, isPending: true, error: null });\n try {\n const session = await options.hydrator();\n\n if (isStale(requestVersion)) {\n return;\n }\n\n $session.set({ data: session, isPending: false, error: null });\n } catch (err) {\n if (isStale(requestVersion)) {\n return;\n }\n\n if (err instanceof LimenError && err.isUnauthorized) {\n // Not an error — the user is simply signed out.\n $session.set({ data: null, isPending: false, error: null });\n return;\n }\n\n const error =\n err instanceof LimenError\n ? err\n : new LimenError(err instanceof Error ? err.message : \"Failed to load session\", 0, \"unknown\");\n // Preserve the last known session; surface the failure via `error`.\n $session.set({ data: $session.get().data, isPending: false, error });\n }\n };\n\n const refetch = (options?: RefetchOptions): Promise<void> => {\n const { skipSignedOut, maxAgeMs } = options ?? {};\n if (skipSignedOut && $session.get().data === null) {\n return Promise.resolve();\n }\n\n if (maxAgeMs !== undefined && Date.now() - lastRefreshedAt < maxAgeMs) {\n return Promise.resolve();\n }\n\n if (!inFlightHydration) {\n inFlightHydration = fetchSessionFromServer().finally(() => {\n inFlightHydration = null;\n lastRefreshedAt = Date.now();\n });\n }\n return inFlightHydration;\n };\n\n const setData = (session: Session<TFields> | null): void => {\n writeVersion++; // supersede any in-flight hydrate so it can't overwrite this\n $session.set({ data: session, isPending: false, error: null });\n };\n\n const store: SessionStore<TFields> = { $session, setData, refetch };\n\n onMount($session, () =>\n createSessionSync(store, {\n fetchOnMount: options.initialSession === undefined,\n crossTabSync: options.crossTabSync ?? false,\n refetchOnWindowFocus: options.refetchOnWindowFocus ?? false,\n }),\n );\n\n return store;\n}\n","import type { ClientOverrides } from \"./build-tree\";\nimport { buildClientTree } from \"./build-tree\";\nimport { DEFAULT_ENVELOPE_CONFIG } from \"./constants\";\nimport type { RouteContext } from \"./context\";\nimport type { AnyClientPlugin } from \"./define-plugin\";\nimport { Fetcher } from \"./fetcher\";\nimport { normalizeBasePath, stripTrailingSlash } from \"./helpers\";\nimport { HookRunner } from \"./hooks\";\nimport { defaultSessionParse } from \"./normalize\";\nimport type { FetchInit } from \"./plugin\";\nimport { coreClientPlugin, createSessionHydrator } from \"./routes\";\nimport { createSessionStore } from \"./session-store\";\nimport type { AuthClient, ClientFetchOptions, CreateAuthClientOptions, EnvelopeConfig, RedirectFn } from \"./types\";\n\nexport function createAuthClient<const Plugins extends readonly AnyClientPlugin[] = readonly [], TFields = unknown>(\n opts: CreateAuthClientOptions<Plugins, TFields>,\n): AuthClient<Plugins, TFields> {\n const baseURL = stripTrailingSlash(opts.baseURL);\n const basePath = normalizeBasePath(opts.basePath ?? \"/auth\");\n\n const userPlugins = (opts.plugins ?? []) as readonly AnyClientPlugin[];\n const plugins: readonly AnyClientPlugin[] = [coreClientPlugin<TFields>(), ...userPlugins];\n\n const hooks = new HookRunner(plugins);\n const envelope = { ...DEFAULT_ENVELOPE_CONFIG, ...opts.envelope } satisfies EnvelopeConfig;\n const fetcher = buildFetcher(baseURL, basePath, envelope, hooks, opts.fetchOptions ?? {});\n\n const parseSession = opts.parseSession ?? defaultSessionParse;\n const redirect = resolveRedirect(opts.redirectFn);\n const baseFetch = <T>(path: string, init?: FetchInit) => fetcher.fetch<T>(path, init);\n\n const store = createSessionStore<TFields>({\n hydrator: createSessionHydrator<TFields>({ fetch: baseFetch, parseSession }),\n crossTabSync: opts.crossTabSync !== false,\n refetchOnWindowFocus: opts.refetchOnWindowFocus !== false,\n ...(opts.initialSession !== undefined ? { initialSession: opts.initialSession } : {}),\n });\n\n const ctx: RouteContext<TFields> = {\n fetch: baseFetch,\n redirect,\n parseSession,\n setSession: (session) => store.setData(session),\n refetchSession: () => store.refetch(),\n store,\n };\n\n const api = buildClientTree({\n plugins,\n ctx,\n fetcher,\n overrides: opts.overrides as ClientOverrides,\n });\n\n const client: Record<string, unknown> = {\n baseURL,\n basePath,\n ...api,\n $session: store.$session,\n };\n\n return client as AuthClient<Plugins, TFields>;\n}\n\nfunction buildFetcher(\n baseURL: string,\n basePath: string,\n envelope: EnvelopeConfig,\n hooks: HookRunner,\n fetchOptions: ClientFetchOptions,\n): Fetcher {\n return new Fetcher({\n baseURL,\n basePath,\n envelope,\n hooks,\n fetchOptions,\n });\n}\n\nfunction resolveRedirect(redirect: RedirectFn | undefined): RedirectFn {\n return (url: string) => {\n if (redirect !== undefined) {\n return redirect(url);\n }\n if (typeof window !== \"undefined\" && typeof window.location !== \"undefined\") {\n window.location.href = url;\n return true;\n }\n return false;\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;;AAWA,SAAgB,YAAY,MAAwB;CAClD,OAAO,KACJ,MAAM,GAAG,CAAC,CACV,QAAQ,QAAQ,IAAI,SAAS,KAAK,CAAC,IAAI,WAAW,GAAG,CAAC,CAAC,CACvD,IAAI,YAAY;AACrB;AAEA,SAAgB,gBAAgB,OAAyB;CACvD,OAAO,MAAM,MAAM,GAAG,CAAC,CAAC,QAAQ,QAAQ,IAAI,SAAS,CAAC;AACxD;;;;;AAaA,SAAgB,YAAY,MAAc,QAAuC,OAA8B;CAC7G,IAAI,CAAC,UAAU,OAAO,WAAW,GAC/B,OAAO;EAAE;EAAM,MAAM;CAAM;CAG7B,MAAM,OAAgC,EAAE,GADxB,SAAS,CAAC,EACwB;CAClD,IAAI,WAAW;CACf,KAAK,MAAM,SAAS,QAAQ;EAC1B,MAAM,QAAQ,KAAK;EACnB,IAAI,UAAU,KAAA,GACZ,MAAM,IAAI,MAAM,gCAAgC,MAAM,eAAe,KAAK,EAAE;EAE9E,WAAW,SAAS,QAAQ,IAAI,SAAS,mBAAmB,KAAe,CAAC;EAC5E,OAAO,KAAK;CACd;CACA,OAAO;EAAE,MAAM;EAAU;CAAK;AAChC;;;;;;;;;;ACxCA,SAAgB,iBAAiB,OAAyB;CACxD,IAAI,UAAU,QAAQ,UAAU,KAAA,GAC9B,OAAO;CAET,IAAI,OAAO,UAAU,YAAY,MAAM,QAAQ,KAAK,GAClD,OAAO;CAET,MAAM,EAAE,kBAAkB,GAAG,SAAS;CACtC,MAAM,MAA+B,CAAC;CAEtC,IAAI,oBAAoB,OAAO,qBAAqB,YAAY,CAAC,MAAM,QAAQ,gBAAgB,GAC7F,OAAO,OAAO,KAAK,gBAAgB;CAGrC,KAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,IAAI,GAAG;EAC/C,IAAI,UAAU,KAAA,GACZ;EAEF,IAAI,aAAa,GAAG,KAAK;CAC3B;CACA,OAAO;AACT;;;;;;;ACjBA,eAAe,QAAQ,KAAsB,KAAe,OAAkC;CAC5F,IAAI,SAAS;CACb,IAAI,IAAI,aAAa,KAAA,GACnB,SAAS;EAAE,GAAI,IAAI;EAAsC,GAAK,SAAS,CAAC;CAA+B;CAGzG,MAAM,EAAE,MAAM,SAAS,YAAY,IAAI,MAAM,IAAI,QAAQ,MAAM;CAC/D,MAAM,UAAU,IAAI,cAAc,KAAA,IAAY,IAAI,UAAU,IAAI,IAAI,iBAAiB,IAAI;CAEzF,MAAM,OAAkB;EAAE,QAAQ,IAAI;EAAQ,UAAU,IAAI,YAAY;CAAM;CAC9E,IAAI,IAAI,WAAW,SAAS,YAAY,KAAA,GACtC,KAAK,QAAQ;MAEb,KAAK,OAAO;CAGd,MAAM,MAAM,MAAM,IAAI,MAAe,MAAM,IAAI;CAE/C,IAAI,IAAI,iBAAiB,MACvB,OAAO,IAAI,aAAa,GAAG;CAG7B,IAAI,IAAI,UAAU,KAAA,GAChB,OAAO,IAAI,MAAM,GAAG;CAEtB,OAAO,MAAM,QAAQ,GAAG,IAAI,aAAa,GAAG,IAAI;AAClD;AAEA,eAAe,aAAa,KAAsB,KAAe,QAAgC;CAC/F,IAAI,IAAI,iBAAiB,MACvB,IAAI,MAAM,QAAQ,IAAI;CAGxB,IAAI,IAAI,iBAAiB,QAAQ,IAAI,cAAc;MAC7C,WAAW,QAAQ,OAAO,WAAW,YAAY,UAAU,QAC7D,IAAI,MAAM,QAAQ,MAA0B;CAAA;CAIhD,IAAI,IAAI,mBAAmB,MACzB,MAAM,IAAI,MAAM,QAAQ;AAE5B;AAEA,SAAS,eAAe,KAAsB,KAAe,YAA0C;CACrG,MAAM,OAAO,aACX,QAAQ,KAAK,KAAK,aAAa,KAAA,IAAY,aAAa,QAAQ;CAClE,OAAO;AACT;;;;;;AAOA,eAAe,cAAc,KAAsB,KAAe,OAAkC;CAClG,IAAI,IAAI,YAAY,KAAA,GAClB,OAAO,IAAI,QAAQ,KAAK,OAAO,eAAe,KAAK,KAAK,KAAK,CAAC;CAEhE,MAAM,SAAS,MAAM,QAAQ,KAAK,KAAK,KAAK;CAC5C,MAAM,aAAa,KAAK,KAAK,MAAM;CACnC,OAAO;AACT;;;;;AAMA,eAAsB,SACpB,KACA,KACA,OACA,MACkB;CAClB,IAAI;EACF,MAAM,SAAS,MAAM,cAAc,KAAK,KAAK,KAAK;EAClD,MAAM,YAAY,MAAM;EACxB,OAAO;CACT,SAAS,OAAO;EACd,MAAM,UAAU,KAAmB;EACnC,MAAM;CACR;AACF;;;;ACnFA,SAAS,aACP,KACA,SACA,QACA,WACc;CACd,MAAM,cAAc,kBAAkB,OAAO,YAAY,EAAE;CAC3D,MAAM,eAAe,YAAY,aAAa,OAAO,EAAE,EAAE,EAAE;CAC3D,MAAM,eAAe,kBAAkB,gBAAgB,OAAO,YAAY,EAAE;CAC5E,OAAO;EACL,GAAG;EACH,QAAW,MAAc,SAAqB;GAC5C,MAAM,WAAW,MAAM,aAAa;GACpC,MAAM,eAAe,WAAW,KAAK,gBAAgB,mBAAmB,IAAI;GAC5E,MAAM,aAAa,WAAW,KAAK,eAAe,mBAAmB,IAAI;GACzE,OAAO,QAAQ,MAAS,aAAa,MAAM,SAAS;EACtD;CACF;AACF;AAEA,SAAS,SAAS,QAAyB,KAAyB;CAClE,IAAI,OAAO,IAAI,OAAO,UACpB,OAAO,gBAAgB,IAAI,EAAE;CAE/B,OAAO,CAAC,GAAG,YAAY,OAAO,YAAY,EAAE,GAAG,GAAG,YAAY,IAAI,IAAI,CAAC;AACzE;AAEA,SAAS,aAAa,QAAiC,cAAwB,UAAyB;CACtG,IAAI,UAAU;CACd,KAAK,IAAI,IAAI,GAAG,IAAI,aAAa,SAAS,GAAG,KAAK,GAAG;EACnD,MAAM,UAAU,aAAa;EAC7B,MAAM,QAAQ,QAAQ;EACtB,IAAI,UAAU,KAAA,GAAW;GACvB,MAAM,YAAqC,CAAC;GAC5C,QAAQ,WAAW;GACnB,UAAU;EACZ,OACE,UAAU;CAEd;CACA,MAAM,eAAe,aAAa,aAAa,SAAS;CACxD,QAAQ,gBAAgB;AAC1B;AAEA,SAAS,YAAY,OAAkD;CACrE,OAAO,OAAO,UAAU,YAAY,UAAU,QAAQ,CAAC,MAAM,QAAQ,KAAK,KAAK,OAAO,UAAU;AAClG;AAEA,SAAS,UAAU,QAAiC,QAAuC;CACzF,KAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,MAAM,GAAG;EACjD,MAAM,WAAW,OAAO;EACxB,IAAI,YAAY,QAAQ,KAAK,YAAY,KAAK,GAAG;GAC/C,UAAU,UAAU,KAAK;GACzB;EACF;EACA,OAAO,OAAO;CAChB;AACF;;;;AAYA,SAAgB,gBAAgB,EAAE,SAAS,KAAK,SAAS,aAA2D;CAClH,MAAM,MAA+B,CAAC;CAEtC,KAAK,MAAM,UAAU,SAAS;EAC5B,MAAM,YAAY,aAAa,KAAK,SAAS,QAAQ,SAAS;EAC9D,MAAM,eAAwC,CAAC;EAE/C,KAAK,MAAM,OAAO,OAAO,QAA+B;GACtD,IAAI,IAAI,WAAW,OACjB;GAEF,MAAM,QAAQ,OAAiB,SAA4B,SAAS,WAAW,KAAK,OAAO,IAAI;GAC/F,aAAa,cAAc,SAAS,QAAQ,GAAG,GAAG,IAAI;EACxD;EAEA,IAAI,OAAO,YAAY,KAAA,GAAW;GAChC,MAAM,OAAiB,OAAO,UAAU,SAAS,WAAW,OAA6B,KAAK;GAC9F,UAAU,cAAc,OAAO,QAAQ,WAAW,GAAG,CAA4B;EACnF;EAEA,UAAU,KAAK,YAAY;CAC7B;CAEA,OAAO;AACT;;;;;;;;;;;;;;AC3FA,SAAgB,cAAc,MAAe,UAAmC;CAC9E,IAAI,SAAS,SAAS,OACpB,OAAO;CAET,IAAI,SAAS,QAAQ,OAAO,SAAS,UACnC,OAAO;CAET,MAAM,SAAS,SAAS,UAAU;CAClC,MAAM,SAAS;CACf,IAAI,OAAO,QAAQ,QACjB,OAAO,OAAO,OAAO;CAEvB,OAAO;AACT;;;;;;;;;;AAWA,SAAgB,mBAAmB,MAAe,UAA8C;CAC9F,IAAI,SAAS,QAAQ,OAAO,SAAS,UACnC;CAEF,MAAM,SAAS;CACf,MAAM,SAAS,SAAS,UAAU;CAElC,MAAM,QAAQ,OADF,SAAS,SAAS,WAAW,OAAO,UAAU;CAE1D,OAAO,OAAO,UAAU,WAAW,QAAQ,KAAA;AAC7C;;;ACjBA,IAAa,UAAb,MAAqB;CAIU;CAH7B;CACA;CAEA,YAAY,MAAuC;EAAtB,KAAA,OAAA;EAC3B,KAAK,YAAY,KAAK,aAAa,QAAQ,WAAW,MAAM,KAAK,UAAU;EAC3E,KAAK,cAAc,KAAK,aAAa,eAAe;CACtD;CAEA,MAAM,MAAS,MAAc,MAAkB,YAAoB,MAAkB;EACnF,MAAM,SAAqB,MAAM,WAAW,MAAM,SAAS,KAAA,IAAY,SAAS;EAChF,OAAO,KAAK,IAAO;GACjB;GACA;GACA;GACA,MAAM,MAAM;GACZ,SAAS,MAAM;GACf,OAAO,MAAM;EACf,CAAC;CACH;;;;;CAMA,MAAc,IAAO,MAON;EACb,MAAM,WAAW,KAAK,sBAAsB,KAAK,KAAK,UAAU,KAAK,MAAM,KAAK,KAAK;EACrF,MAAM,MAAM,QAAQ,KAAK,KAAK,SAAS,QAAQ;EAE/C,MAAM,UAAU,IAAI,QAAQ;GAAE,GAAG,KAAK;GAAS,GAAI,KAAK,KAAK,aAAa,WAAW,CAAC;EAAG,CAAC;EAC1F,IAAI,CAAC,QAAQ,IAAI,cAAc,GAC7B,QAAQ,IAAI,gBAAgB,kBAAkB;EAEhD,IAAI,CAAC,QAAQ,IAAI,QAAQ,GACvB,QAAQ,IAAI,UAAU,kBAAkB;EAG1C,IAAI,SAAyB;GAC3B,QAAQ,KAAK;GACH;GACV,MAAM,KAAK;GACX,WAAW,KAAK;GAChB;GACA;GACA,MAAM,KAAK;EACb;EAEA,SAAS,MAAM,KAAK,KAAK,MAAM,iBAAiB,MAAM;EAEtD,MAAM,UAAU,OAAO,SAAS,KAAA,KAAa,OAAO,SAAS,OAAO,KAAK,UAAU,OAAO,IAAI,IAAI,KAAA;EAElG,MAAM,cAA2B;GAC/B,QAAQ,OAAO;GACf,SAAS,OAAO;GAChB,aAAa,KAAK;EACpB;EAEA,IAAI,YAAY,KAAA,GACd,YAAY,OAAO;EAGrB,IAAI;EACJ,IAAI;GACF,WAAW,MAAM,KAAK,UAAU,OAAO,KAAK,WAAW;EACzD,SAAS,KAAK;GACZ,KAAK,KAAK,aAAa,UAAU;IAC/B,GAAG;IACH,QAAQ;IACR,IAAI;IACJ,OAAO;GACT,CAAC;GACD,MAAM,IAAI,WAAW,eAAe,QAAQ,IAAI,UAAU,0BAA0B,GAAG,SAAS;EAClG;EAEA,MAAM,aAAa,MAAM,KAAK,kBAAkB,QAAQ;EACxD,MAAM,YACJ,SAAS,MAAM,eAAe,KAAA,IAAY,cAAc,YAAY,KAAK,KAAK,QAAQ,IAAI;EAE5F,IAAI,SAA0B;GAC5B,QAAQ,KAAK;GACH;GACV,MAAM,KAAK;GACX,WAAW,KAAK;GAChB,QAAQ,SAAS;GACjB,IAAI,SAAS;GACb,SAAS,SAAS;GAClB,MAAM;EACR;EAEA,SAAS,MAAM,KAAK,KAAK,MAAM,iBAAiB,MAAM;EAEtD,IAAI,OAAO,IAAI;GACb,KAAK,KAAK,aAAa,YAAY;IACjC,GAAG;IACH;GACF,CAAC;GACD,OAAO,OAAO;EAChB;EAOA,MAAM,QAAQ,IAAI,WAJhB,mBAAmB,OAAO,MAAM,KAAK,KAAK,QAAQ,KAClD,SAAS,cACT,8BAA8B,SAAS,UAEH,SAAS,QAAQ,gBAAgB,SAAS,MAAM,CAAC;EACvF,KAAK,KAAK,aAAa,UAAU;GAC/B,GAAG;GACH,QAAQ,SAAS;GACjB,IAAI;GACJ;EACF,CAAC;EACD,MAAM;CACR;CAEA,MAAc,kBAAkB,UAAsC;EACpE,IAAI,SAAS,WAAW,KACtB;EAEF,MAAM,OAAO,MAAM,SAAS,KAAK;EACjC,IAAI,KAAK,WAAW,GAClB;EAEF,OAAO,KAAK,MAAM,IAAI;CACxB;CAEA,sBACE,UACA,cACA,OACQ;EAER,IAAI,QADS,aAAa,MAAM,aAAa,MAAM,KAAK,mBAAmB,mBAAmB,QAAQ,CAAC,KACrF,mBAAmB,YAAY;EACjD,IAAI,UAAU,KAAA,GAAW;GAEvB,MAAM,KAAK,IADQ,gBAAgB,KACnB,CAAC,CAAC,SAAS;GAC3B,IAAI,GAAG,SAAS,GACd,OAAO,GAAG,KAAK,GAAG;EAEtB;EACA,OAAO;CACT;AACF;;;ACrKA,SAAS,aAAa,SAAmC,WAA4B;CACnF,IAAI,YAAY,KAAA,GACd,OAAO;CAET,IAAI,OAAO,YAAY,UACrB,OAAO,cAAc;CAEvB,IAAI,OAAO,YAAY,YACrB,OAAO,QAAQ,EAAE,MAAM,UAAU,CAAC;CAEpC,OAAO,cAAc,KAAA,KAAa,QAAQ,SAAS,SAAS;AAC9D;AAEA,IAAa,aAAb,MAAwB;CACtB;CACA;CAEA,YAAY,SAAkC;EAC5C,KAAK,SAAS,QAAQ,SAAS,MAAM,EAAE,OAAO,iBAAiB,CAAC,CAAC;EACjE,KAAK,QAAQ,QAAQ,SAAS,MAAM,EAAE,OAAO,iBAAiB,CAAC,CAAC;CAClE;CAEA,MAAM,iBAAiB,SAAkD;EACvE,IAAI,MAAM;EACV,KAAK,MAAM,QAAQ,KAAK,QAAQ;GAC9B,IAAI,CAAC,aAAa,KAAK,OAAO,IAAI,SAAS,GACzC;GAEF,MAAM,MAAM,KAAK,IAAI,GAAG;EAC1B;EACA,OAAO;CACT;CAEA,MAAM,iBAAiB,SAAoD;EACzE,IAAI,MAAM;EACV,KAAK,MAAM,QAAQ,KAAK,OAAO;GAC7B,IAAI,CAAC,aAAa,KAAK,OAAO,IAAI,SAAS,GACzC;GAEF,IAAI,CAAC,KAAK,kBAAkB,IAAI,UAAU,KACxC;GAEF,MAAM,MAAM,KAAK,IAAI,GAAG;EAC1B;EACA,OAAO;CACT;AACF;;;;;;;;ACnDA,SAAgB,cAA2B,KAAuC;CAChF,MAAM,MAA+B,CAAC;CACtC,KAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,GAAG,GAC3C,IAAI,eAAe,GAAG,KAAK;CAE7B,OAAO;AACT;AAEA,SAAgB,oBAAiC,KAA0B;CACzE,IAAI,CAAC,OAAO,OAAO,QAAQ,UACzB,MAAM,IAAI,UAAU,kDAAkD,QAAQ,OAAO,SAAS,OAAO,KAAK;CAE5G,MAAM,MAAM;CAEZ,OAAO,EAAE,MAAM,cADE,IAAI,WAAW,GACO,EAAE;AAC3C;;;;;;ACAA,SAAgB,mBAAsC;CA4BpD,OAAO,mBAAmB;EACxB,IAAI;EACJ,UAAU;EACV,QA9Ba,aACb,MAA6B,CAAC,CAAC;GAC7B,QAAQ;GACR,MAAM;EACR,CAAC,GACD,MAAkB,CAAC,CAAC;GAClB,QAAQ;GACR,MAAM;GACN,cAAc;EAChB,CAAC,GACD,MAAkB,CAAC,CAAC;GAClB,QAAQ;GACR,MAAM;GACN,cAAc;EAChB,CAAC,GACD,MAAgC,CAAC,CAAC;GAChC,QAAQ;GACR,MAAM;GACN,gBAAgB;EAClB,CAAC,GACD,MAAoB,CAAC,CAAC;GACpB,QAAQ;GACR,MAAM;GACN,IAAI;EACN,CAAC,CAMI;EACL,UAAU,SAAS;;;;;;;;;AASjB,YAAY,YAA8C;GACxD,MAAM,IAAI,eAAe;GACzB,MAAM,QAAQ,IAAI,MAAM,SAAS,IAAI;GACrC,IAAI,MAAM,OACR,MAAM,MAAM;GAEd,OAAO,MAAM;EACf,EACF;CACF,CAAC;AACH;;;;AAOA,SAAgB,sBACd,KACiC;CACjC,OAAO,YAAY;EACjB,MAAM,MAAM,MAAM,IAAI,MAAe,OAAO,EAAE,QAAQ,MAAM,CAAC;EAC7D,OAAO,IAAI,aAAa,GAAG;CAC7B;AACF;;;AC7EA,MAAM,YAAoC;CACxC,OAAO,CAAC;CACR,uBAAuB,CAAC;CACxB,QAAQ,CAAC;AACX;AAEA,SAAgB,uBAA0B,MAAgC;CACxE,IAAI,OAAO,WAAW,aACpB,OAAO;CAGT,MAAM,aAAa,GAAG,KAAK;CAC3B,MAAM,4BAAY,IAAI,IAA0B;CAChD,MAAM,QAAQ,YAAqB;EACjC,KAAK,MAAM,YAAY,WACrB,SAAS,OAAO;CAEpB;CAEA,MAAM,UAAU,OAAO,qBAAqB,cAAc,IAAI,iBAAiB,IAAI,IAAI;CACvF,IAAI,SACF,QAAQ,aAAa,UAA2B;EAC9C,IAAI,MAAM,QAAQ,MAChB,KAAK,MAAM,IAAI;CAEnB;CAGF,MAAM,aAAa,UAA8B;EAC/C,IAAI,MAAM,QAAQ,cAAc,CAAC,MAAM,UACrC;EAGF,KAAK,KAAK,MAAM,MAAM,QAAQ,CAAM;CACtC;CAEA,IAAI,CAAC,SACH,OAAO,iBAAiB,WAAW,SAAS;CAG9C,OAAO;EACL,KAAK,SAAS;GACZ,IAAI,SAAS;IACX,QAAQ,YAAY,OAAO;IAC3B;GACF;GAEA,IAAI,OAAO,WAAW,iBAAiB,aAAa;IAClD,WAAW,aAAa,QAAQ,YAAY,KAAK,UAAU,OAAO,CAAC;IACnE,WAAW,aAAa,WAAW,UAAU;GAC/C;EACF;EACA,UAAU,UAAU;GAClB,UAAU,IAAI,QAAQ;GACtB,aAAa;IACX,UAAU,OAAO,QAAQ;GAC3B;EACF;EACA,QAAQ;GACN,UAAU,MAAM;GAChB,IAAI,SAAS;IACX,QAAQ,MAAM;IACd;GACF;GACA,OAAO,oBAAoB,WAAW,SAAS;EACjD;CACF;AACF;;;AC9EA,SAAS,cAAc,OAAkD;CACvE,IAAI,OAAO,UAAU,YAAY,UAAU,MACzC,OAAO;CAET,MAAM,QAAQ,OAAO,eAAe,KAAK;CACzC,OAAO,UAAU,OAAO,aAAa,UAAU;AACjD;AAEA,SAAS,YAAY,GAAc,GAAuB;CACxD,IAAI,EAAE,WAAW,EAAE,QACjB,OAAO;CAGT,KAAK,IAAI,IAAI,GAAG,IAAI,EAAE,QAAQ,KAAK,GACjC,IAAI,CAAC,cAAc,EAAE,IAAI,EAAE,EAAE,GAC3B,OAAO;CAGX,OAAO;AACT;AAEA,SAAS,aAAa,GAA4B,GAAqC;CACrF,MAAM,QAAQ,OAAO,KAAK,CAAC;CAC3B,MAAM,QAAQ,OAAO,KAAK,CAAC;CAC3B,IAAI,MAAM,WAAW,MAAM,QACzB,OAAO;CAGT,KAAK,MAAM,OAAO,OAChB,IAAI,CAAC,OAAO,OAAO,GAAG,GAAG,KAAK,CAAC,cAAc,EAAE,MAAM,EAAE,IAAI,GACzD,OAAO;CAGX,OAAO;AACT;;AAGA,SAAgB,cAAc,GAAY,GAAqB;CAC7D,IAAI,OAAO,GAAG,GAAG,CAAC,GAChB,OAAO;CAKT,IAFiB,MAAM,QAAQ,CAEpB,KADM,MAAM,QAAQ,CACR,GACrB,OAAO,YAAY,GAAG,CAAC;CAGzB,IAAI,CAAC,cAAc,CAAC,KAAK,CAAC,cAAc,CAAC,GACvC,OAAO;CAET,OAAO,aAAa,GAAG,CAAC;AAC1B;;;AC9CA,MAAM,eAAe;AACrB,MAAM,4BAA4B;AAalC,SAAgB,kBACd,OACA,SACY;CACZ,IAAI,QAAQ,cACV,MAAW,QAAQ;CAGrB,MAAM,YAA+B,CAAC;CACtC,IAAI,QAAQ,cACV,UAAU,KAAK,eAAe,KAAK,CAAC;CAGtC,IAAI,QAAQ,sBACV,UAAU,KAAK,eAAe,KAAK,CAAC;CAGtC,aAAa;EACX,KAAK,MAAM,YAAY,WACrB,SAAS;CAEb;AACF;AAEA,SAAS,eAAwB,OAA0C;CACzE,MAAM,OAAO,uBAA6C,YAAY;CACtE,IAAI,WAAW,MAAM,SAAS,IAAI,CAAC,CAAC;CAEpC,MAAM,cAAc,KAAK,WAAW,YAAY;EAE9C,WAAW,QAAQ;EACnB,MAAM,QAAQ,QAAQ,IAAI;CAC5B,CAAC;CAED,MAAM,eAAe,SAAS,MAAM,gBAAgB;EAClD,MAAM,OAAO,MAAM,SAAS,IAAI,CAAC,CAAC;EAClC,IAAI,cAAc,MAAM,QAAQ,GAC9B;EAEF,WAAW;EACX,KAAK,KAAK,EAAQ,KAAK,CAAC;CAC1B,CAAC;CAED,aAAa;EACX,aAAa;EACb,YAAY;EACZ,KAAK,MAAM;CACb;AACF;AAEA,SAAS,eAAwB,OAA0C;CACzE,IAAI,OAAO,aAAa,aACtB,aAAa,CAAC;CAEhB,MAAM,2BAAiC;EACrC,IAAI,SAAS,oBAAoB,WAC/B,MAAW,QAAQ;GAAE,UAAU;GAA2B,eAAe;EAAK,CAAC;CAEnF;CACA,SAAS,iBAAiB,oBAAoB,kBAAkB;CAChE,aAAa,SAAS,oBAAoB,oBAAoB,kBAAkB;AAClF;;;ACtCA,SAAgB,mBAAsC,SAAiE;CACrH,MAAM,WAAW,KAA4B;EAC3C,MAAM,QAAQ,kBAAkB;EAChC,WAAW;EACX,OAAO;CACT,CAAC;CAED,IAAI,oBAA0C;CAE9C,IAAI,eAAe;CAEnB,IAAI,kBAAkB;CACtB,MAAM,WAAW,mBAAoC,mBAAmB;CAExE,MAAM,yBAAyB,YAA2B;EACxD,MAAM,iBAAiB,EAAE;EACzB,SAAS,IAAI;GAAE,MAAM,SAAS,IAAI,CAAC,CAAC;GAAM,WAAW;GAAM,OAAO;EAAK,CAAC;EACxE,IAAI;GACF,MAAM,UAAU,MAAM,QAAQ,SAAS;GAEvC,IAAI,QAAQ,cAAc,GACxB;GAGF,SAAS,IAAI;IAAE,MAAM;IAAS,WAAW;IAAO,OAAO;GAAK,CAAC;EAC/D,SAAS,KAAK;GACZ,IAAI,QAAQ,cAAc,GACxB;GAGF,IAAI,eAAe,cAAc,IAAI,gBAAgB;IAEnD,SAAS,IAAI;KAAE,MAAM;KAAM,WAAW;KAAO,OAAO;IAAK,CAAC;IAC1D;GACF;GAEA,MAAM,QACJ,eAAe,aACX,MACA,IAAI,WAAW,eAAe,QAAQ,IAAI,UAAU,0BAA0B,GAAG,SAAS;GAEhG,SAAS,IAAI;IAAE,MAAM,SAAS,IAAI,CAAC,CAAC;IAAM,WAAW;IAAO;GAAM,CAAC;EACrE;CACF;CAEA,MAAM,WAAW,YAA4C;EAC3D,MAAM,EAAE,eAAe,aAAa,WAAW,CAAC;EAChD,IAAI,iBAAiB,SAAS,IAAI,CAAC,CAAC,SAAS,MAC3C,OAAO,QAAQ,QAAQ;EAGzB,IAAI,aAAa,KAAA,KAAa,KAAK,IAAI,IAAI,kBAAkB,UAC3D,OAAO,QAAQ,QAAQ;EAGzB,IAAI,CAAC,mBACH,oBAAoB,uBAAuB,CAAC,CAAC,cAAc;GACzD,oBAAoB;GACpB,kBAAkB,KAAK,IAAI;EAC7B,CAAC;EAEH,OAAO;CACT;CAEA,MAAM,WAAW,YAA2C;EAC1D;EACA,SAAS,IAAI;GAAE,MAAM;GAAS,WAAW;GAAO,OAAO;EAAK,CAAC;CAC/D;CAEA,MAAM,QAA+B;EAAE;EAAU;EAAS;CAAQ;CAElE,QAAQ,gBACN,kBAAkB,OAAO;EACvB,cAAc,QAAQ,mBAAmB,KAAA;EACzC,cAAc,QAAQ,gBAAgB;EACtC,sBAAsB,QAAQ,wBAAwB;CACxD,CAAC,CACH;CAEA,OAAO;AACT;;;AC7GA,SAAgB,iBACd,MAC8B;CAC9B,MAAM,UAAU,mBAAmB,KAAK,OAAO;CAC/C,MAAM,WAAW,kBAAkB,KAAK,YAAY,OAAO;CAE3D,MAAM,cAAe,KAAK,WAAW,CAAC;CACtC,MAAM,UAAsC,CAAC,iBAA0B,GAAG,GAAG,WAAW;CAExF,MAAM,QAAQ,IAAI,WAAW,OAAO;CAEpC,MAAM,UAAU,aAAa,SAAS,UAAU;EAD7B,GAAG;EAAyB,GAAG,KAAK;CACA,GAAG,OAAO,KAAK,gBAAgB,CAAC,CAAC;CAExF,MAAM,eAAe,KAAK,gBAAgB;CAC1C,MAAM,WAAW,gBAAgB,KAAK,UAAU;CAChD,MAAM,aAAgB,MAAc,SAAqB,QAAQ,MAAS,MAAM,IAAI;CAEpF,MAAM,QAAQ,mBAA4B;EACxC,UAAU,sBAA+B;GAAE,OAAO;GAAW;EAAa,CAAC;EAC3E,cAAc,KAAK,iBAAiB;EACpC,sBAAsB,KAAK,yBAAyB;EACpD,GAAI,KAAK,mBAAmB,KAAA,IAAY,EAAE,gBAAgB,KAAK,eAAe,IAAI,CAAC;CACrF,CAAC;CAyBD,OAAO;EANL;EACA;EACA,GAVU,gBAAgB;GAC1B;GACA,KAAA;IAVA,OAAO;IACP;IACA;IACA,aAAa,YAAY,MAAM,QAAQ,OAAO;IAC9C,sBAAsB,MAAM,QAAQ;IACpC;GAKE;GACF;GACA,WAAW,KAAK;EAClB,CAKO;EACL,UAAU,MAAM;CAGN;AACd;AAEA,SAAS,aACP,SACA,UACA,UACA,OACA,cACS;CACT,OAAO,IAAI,QAAQ;EACjB;EACA;EACA;EACA;EACA;CACF,CAAC;AACH;AAEA,SAAS,gBAAgB,UAA8C;CACrE,QAAQ,QAAgB;EACtB,IAAI,aAAa,KAAA,GACf,OAAO,SAAS,GAAG;EAErB,IAAI,OAAO,WAAW,eAAe,OAAO,OAAO,aAAa,aAAa;GAC3E,OAAO,SAAS,OAAO;GACvB,OAAO;EACT;EACA,OAAO;CACT;AACF"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
//#region src/constants.ts
|
|
2
|
+
const DEFAULT_ENVELOPE_CONFIG = { mode: "off" };
|
|
3
|
+
const DEFAULT_ENVELOPE_FIELDS = {
|
|
4
|
+
data: "data",
|
|
5
|
+
message: "message"
|
|
6
|
+
};
|
|
7
|
+
/** Response headers the server emits for the JWT and rotated refresh token. */
|
|
8
|
+
const SET_AUTH_TOKEN_HEADER = "Set-Auth-Token";
|
|
9
|
+
const SET_REFRESH_TOKEN_HEADER = "Set-Refresh-Token";
|
|
10
|
+
/** Default `localStorage` key for the persisted tokens. */
|
|
11
|
+
const DEFAULT_TOKEN_STORAGE_KEY = "limen.tokens";
|
|
12
|
+
//#endregion
|
|
13
|
+
export { SET_REFRESH_TOKEN_HEADER as a, SET_AUTH_TOKEN_HEADER as i, DEFAULT_ENVELOPE_FIELDS as n, DEFAULT_TOKEN_STORAGE_KEY as r, DEFAULT_ENVELOPE_CONFIG as t };
|
|
14
|
+
|
|
15
|
+
//# sourceMappingURL=constants-CsR2pQ_9.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"constants-CsR2pQ_9.mjs","names":[],"sources":["../src/constants.ts"],"sourcesContent":["import type { EnvelopeConfig, EnvelopeFields } from \"./types\";\n\nexport const DEFAULT_ENVELOPE_CONFIG: EnvelopeConfig = {\n mode: \"off\",\n};\n\nexport const DEFAULT_ENVELOPE_FIELDS: EnvelopeFields = {\n data: \"data\",\n message: \"message\",\n};\n\n/** Response headers the server emits for the JWT and rotated refresh token. */\nexport const SET_AUTH_TOKEN_HEADER = \"Set-Auth-Token\";\nexport const SET_REFRESH_TOKEN_HEADER = \"Set-Refresh-Token\";\n\n/** Default `localStorage` key for the persisted tokens. */\nexport const DEFAULT_TOKEN_STORAGE_KEY = \"limen.tokens\";\n"],"mappings":";AAEA,MAAa,0BAA0C,EACrD,MAAM,MACR;AAEA,MAAa,0BAA0C;CACrD,MAAM;CACN,SAAS;AACX;;AAGA,MAAa,wBAAwB;AACrC,MAAa,2BAA2B;;AAGxC,MAAa,4BAA4B"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
//#region src/define-plugin.ts
|
|
2
|
+
/**
|
|
3
|
+
* Register a plugin's routes while preserving each route's input/output types
|
|
4
|
+
* for the generated client API.
|
|
5
|
+
*/
|
|
6
|
+
function defineRoutes(...routes) {
|
|
7
|
+
return routes;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Define a client plugin for `createAuthClient`.
|
|
11
|
+
*/
|
|
12
|
+
function defineClientPlugin(def) {
|
|
13
|
+
return {
|
|
14
|
+
id: def.id,
|
|
15
|
+
basePath: def.basePath ?? "",
|
|
16
|
+
routes: def.routes,
|
|
17
|
+
...def.hooks !== void 0 ? { hooks: def.hooks } : {},
|
|
18
|
+
...def.actions !== void 0 ? { actions: def.actions } : {}
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
//#endregion
|
|
22
|
+
export { defineRoutes as n, defineClientPlugin as t };
|
|
23
|
+
|
|
24
|
+
//# sourceMappingURL=define-plugin-C7WOGU4b.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"define-plugin-C7WOGU4b.mjs","names":[],"sources":["../src/define-plugin.ts"],"sourcesContent":["import type { RouteContext } from \"./context\";\nimport type { InferRoutes, PathSegments } from \"./infer\";\nimport type { PluginHooks } from \"./plugin\";\nimport type { AnyRouteDescriptor, RouteDescriptor } from \"./route\";\nimport type { IsAny, UnionToIntersection } from \"./type-utils\";\n\n/** Invoke one of the plugin's routes from `actions`. */\nexport type RunRoute = <I, O>(route: RouteDescriptor<I, O>, input: I) => Promise<O>;\n\n/**\n * Client plugin contract\n */\nexport type ClientPlugin<\n Id extends string,\n BasePath extends string,\n Routes extends readonly AnyRouteDescriptor[],\n Actions,\n> = {\n readonly id: Id;\n /** Default mount path relative to the client `basePath`, e.g. `\"/magic-link\"`; omit for the root (`\"\"`). */\n readonly basePath?: BasePath;\n readonly routes: Routes;\n readonly hooks?: PluginHooks;\n readonly actions?: (ctx: RouteContext, run: RunRoute) => Actions;\n};\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any -- match any plugin shape\nexport type AnyClientPlugin = ClientPlugin<string, string, readonly AnyRouteDescriptor[], any>;\n\n/**\n * Register a plugin's routes while preserving each route's input/output types\n * for the generated client API.\n */\nexport function defineRoutes<Routes extends readonly AnyRouteDescriptor[]>(...routes: Routes): Routes {\n return routes;\n}\n\n/**\n * Define a client plugin for `createAuthClient`.\n */\nexport function defineClientPlugin<\n const Id extends string,\n const Routes extends readonly AnyRouteDescriptor[],\n Actions = Record<never, never>,\n const BasePath extends string = \"\",\n>(def: ClientPlugin<Id, BasePath, Routes, Actions>): ClientPlugin<Id, BasePath, Routes, Actions> {\n return {\n id: def.id,\n basePath: (def.basePath ?? \"\") as BasePath,\n routes: def.routes,\n ...(def.hooks !== undefined ? { hooks: def.hooks } : {}),\n ...(def.actions !== undefined ? { actions: def.actions } : {}),\n };\n}\n\n/**\n * The client-only methods a plugin contributes. Widened `any` contributes\n * nothing so the client does not become permissive.\n */\ntype ActionsOf<P> = P extends { actions?: (ctx: never, run: never) => infer A }\n ? IsAny<A> extends true\n ? unknown\n : A extends object\n ? A\n : unknown\n : unknown;\n\nexport type InferPluginContribution<P> =\n P extends ClientPlugin<infer _Id, infer BasePath, infer Routes, infer _Actions>\n ? InferRoutes<Routes, PathSegments<BasePath>> & ActionsOf<P>\n : unknown;\n\nexport type CombinedClientContributions<Plugins extends readonly unknown[]> = UnionToIntersection<\n { [K in keyof Plugins]: InferPluginContribution<Plugins[K]> }[number]\n>;\n"],"mappings":";;;;;AAiCA,SAAgB,aAA2D,GAAG,QAAwB;CACpG,OAAO;AACT;;;;AAKA,SAAgB,mBAKd,KAA+F;CAC/F,OAAO;EACL,IAAI,IAAI;EACR,UAAW,IAAI,YAAY;EAC3B,QAAQ,IAAI;EACZ,GAAI,IAAI,UAAU,KAAA,IAAY,EAAE,OAAO,IAAI,MAAM,IAAI,CAAC;EACtD,GAAI,IAAI,YAAY,KAAA,IAAY,EAAE,SAAS,IAAI,QAAQ,IAAI,CAAC;CAC9D;AACF"}
|
|
@@ -0,0 +1,450 @@
|
|
|
1
|
+
import { ReadableAtom } from "nanostores";
|
|
2
|
+
|
|
3
|
+
//#region src/type-utils.d.ts
|
|
4
|
+
/** Collapse an intersection into a single readable object type on hover. */
|
|
5
|
+
type Prettify<T> = { [K in keyof T]: T[K] } & {};
|
|
6
|
+
/** Turn a union `A | B | C` into the intersection `A & B & C`. */
|
|
7
|
+
type UnionToIntersection<U> = (U extends unknown ? (x: U) => void : never) extends ((x: infer I) => void) ? I : never;
|
|
8
|
+
/**
|
|
9
|
+
* Convert a kebab-case literal to camelCase: `"magic-link"` -> `"magicLink"`.
|
|
10
|
+
*/
|
|
11
|
+
type KebabToCamel<S extends string> = S extends `${infer Head}-${infer Tail}` ? `${Head}${Capitalize<KebabToCamel<Tail>>}` : S;
|
|
12
|
+
/** Split a string literal into a tuple on a delimiter, dropping empty segments. */
|
|
13
|
+
type Split<S extends string, D extends string> = S extends `${infer Head}${D}${infer Tail}` ? Head extends "" ? Split<Tail, D> : [Head, ...Split<Tail, D>] : S extends "" ? [] : [S];
|
|
14
|
+
/** Check if a type is `any`. */
|
|
15
|
+
type IsAny<T> = 0 extends 1 & T ? true : false;
|
|
16
|
+
//#endregion
|
|
17
|
+
//#region src/fetcher.d.ts
|
|
18
|
+
type ClientFetchCallbackContext = ResponseContext & {};
|
|
19
|
+
type FetcherFetchOptions = {
|
|
20
|
+
/** Whether to send credentials (cookies). Defaults to `"include"`. */credentials?: RequestCredentials; /** Custom fetch impl. Defaults to `globalThis.fetch`. */
|
|
21
|
+
impl?: typeof fetch; /** Default headers merged into every request. Per-request headers override these. */
|
|
22
|
+
headers?: HeadersInit; /** Callback function to be called when the request is successful. */
|
|
23
|
+
onSuccess?: (context: ClientFetchCallbackContext & {
|
|
24
|
+
response: Response;
|
|
25
|
+
}) => void; /** Callback function to be called when the request fails. */
|
|
26
|
+
onError?: (context: ClientFetchCallbackContext & {
|
|
27
|
+
error: Error;
|
|
28
|
+
}) => void;
|
|
29
|
+
};
|
|
30
|
+
//#endregion
|
|
31
|
+
//#region src/errors.d.ts
|
|
32
|
+
type LimenErrorCode = "unauthorized" | "forbidden" | "not_found" | "rate_limited" | "validation_error" | "conflict" | "server_error" | "unknown";
|
|
33
|
+
/** Map HTTP status → typed code. Anything unmapped becomes `"unknown"`. */
|
|
34
|
+
declare function deriveErrorCode(status: number): LimenErrorCode;
|
|
35
|
+
/**
|
|
36
|
+
* The single error type every SDK call throws on non-2xx. Carries the raw
|
|
37
|
+
* server message, the HTTP status, and a derived typed code. Subclass-free so
|
|
38
|
+
* `instanceof LimenError` is the only check consumers need.
|
|
39
|
+
*/
|
|
40
|
+
declare class LimenError extends Error {
|
|
41
|
+
readonly name = "LimenError";
|
|
42
|
+
readonly status: number;
|
|
43
|
+
readonly code: LimenErrorCode;
|
|
44
|
+
constructor(message: string, status: number, code?: LimenErrorCode);
|
|
45
|
+
get isUnauthorized(): boolean;
|
|
46
|
+
get isRateLimited(): boolean;
|
|
47
|
+
}
|
|
48
|
+
//#endregion
|
|
49
|
+
//#region src/route.d.ts
|
|
50
|
+
declare const INPUT: unique symbol;
|
|
51
|
+
declare const OUTPUT: unique symbol;
|
|
52
|
+
/**
|
|
53
|
+
* Runs the route's default HTTP request and parser without session effects.
|
|
54
|
+
* Pass an input override when a handler needs to omit client-only fields.
|
|
55
|
+
*/
|
|
56
|
+
type HttpRunner<I> = <R = unknown>(input?: I) => Promise<R>;
|
|
57
|
+
/**
|
|
58
|
+
* Custom route behavior for flows that need more than the default request
|
|
59
|
+
* pipeline.
|
|
60
|
+
*/
|
|
61
|
+
type RouteHandler<I, O, TFields = unknown> = (ctx: RouteContext<TFields>, input: I, http: HttpRunner<I>) => Promise<O>;
|
|
62
|
+
/**
|
|
63
|
+
* Per-call options accepted as the final argument of every generated route
|
|
64
|
+
* method.
|
|
65
|
+
*/
|
|
66
|
+
type RouteCallOptions<O = unknown> = {
|
|
67
|
+
/** Invoked with the resolved value after the call succeeds. */onSuccess?: (data: O) => void; /** Invoked with the error just before it is re-thrown. */
|
|
68
|
+
onError?: (error: LimenError) => void;
|
|
69
|
+
};
|
|
70
|
+
/**
|
|
71
|
+
* Declarative client route definition. The public client chain is derived from
|
|
72
|
+
* `path` unless `as` is provided.
|
|
73
|
+
*/
|
|
74
|
+
type RouteDef<I, O> = {
|
|
75
|
+
method: HTTPMethod;
|
|
76
|
+
path: `/${string}`; /** Dotted client chain override, e.g. `"twoFactor.getTotpUri"`. */
|
|
77
|
+
as?: string; /** Merged under the caller's input before serialization. */
|
|
78
|
+
defaults?: Partial<I>; /** SDK input → wire body/query. Defaults to shallow camelCase → snake_case. */
|
|
79
|
+
serialize?: (input: I) => unknown; /** Raw response → typed output. Ignored when `parseSession` is set. */
|
|
80
|
+
parse?: (raw: unknown) => O;
|
|
81
|
+
/**
|
|
82
|
+
* Parse the response as a session and store it when it contains a `user`.
|
|
83
|
+
* Set `skipStore` to return the parsed session without writing it.
|
|
84
|
+
*/
|
|
85
|
+
parseSession?: boolean; /** Resolve `path` from the client base path instead of the plugin base path. */
|
|
86
|
+
absolute?: boolean; /** Input keys used as `:param` path values. */
|
|
87
|
+
params?: readonly (keyof I & string)[]; /** For `parseSession` routes, skip the session-store write. */
|
|
88
|
+
skipStore?: boolean; /** Clear the session store on success. */
|
|
89
|
+
clearSession?: boolean; /** Revalidate the session after success. */
|
|
90
|
+
refetchSession?: boolean; /** Set `false` to keep the route out of the public client API. */
|
|
91
|
+
expose?: boolean; /** Override the default route call behavior. */
|
|
92
|
+
handler?: RouteHandler<I, O>;
|
|
93
|
+
};
|
|
94
|
+
/**
|
|
95
|
+
* A route definition carrying its input and output types for inference.
|
|
96
|
+
*/
|
|
97
|
+
type RouteDescriptor<I, O, D extends RouteDef<I, O> = RouteDef<I, O>> = D & {
|
|
98
|
+
readonly [INPUT]: I;
|
|
99
|
+
readonly [OUTPUT]: O;
|
|
100
|
+
};
|
|
101
|
+
/**
|
|
102
|
+
* Loose route-descriptor constraint for route tuples and plugin definitions.
|
|
103
|
+
*/
|
|
104
|
+
type AnyRouteDescriptor = RouteDescriptor<any, any, any>;
|
|
105
|
+
type InputOf<R> = R extends {
|
|
106
|
+
readonly [INPUT]: infer I;
|
|
107
|
+
} ? I : never;
|
|
108
|
+
type OutputOf<R> = R extends {
|
|
109
|
+
readonly [OUTPUT]: infer O;
|
|
110
|
+
} ? O : never;
|
|
111
|
+
/**
|
|
112
|
+
* Define an HTTP-backed client method for a plugin. The input/output types
|
|
113
|
+
* become the generated method's argument and resolved value.
|
|
114
|
+
*
|
|
115
|
+
* @example
|
|
116
|
+
* route<VerifyInput, Session<TFields>>()({
|
|
117
|
+
* method: "POST",
|
|
118
|
+
* path: "/verify",
|
|
119
|
+
* parseSession: true,
|
|
120
|
+
* })
|
|
121
|
+
*/
|
|
122
|
+
declare function route<I = void, O = unknown>(): <const D extends RouteDef<I, O>>(def: D) => RouteDescriptor<I, O, D>;
|
|
123
|
+
//#endregion
|
|
124
|
+
//#region src/routes.d.ts
|
|
125
|
+
type VerifyEmailInput = {
|
|
126
|
+
token: string;
|
|
127
|
+
};
|
|
128
|
+
type ActiveSession = {
|
|
129
|
+
id: string | number;
|
|
130
|
+
token: string;
|
|
131
|
+
userId: unknown;
|
|
132
|
+
createdAt: string;
|
|
133
|
+
expiresAt: string;
|
|
134
|
+
lastAccess: string;
|
|
135
|
+
metadata?: Record<string, unknown>;
|
|
136
|
+
};
|
|
137
|
+
/**
|
|
138
|
+
* Core routes available on every client.
|
|
139
|
+
*/
|
|
140
|
+
declare function coreClientPlugin<TFields = unknown>(): ClientPlugin<"core", "/", [RouteDescriptor<void, ActiveSession[], {
|
|
141
|
+
readonly method: "GET";
|
|
142
|
+
readonly path: "/sessions";
|
|
143
|
+
}>, RouteDescriptor<void, void, {
|
|
144
|
+
readonly method: "POST";
|
|
145
|
+
readonly path: "/signout";
|
|
146
|
+
readonly clearSession: true;
|
|
147
|
+
}>, RouteDescriptor<void, void, {
|
|
148
|
+
readonly method: "POST";
|
|
149
|
+
readonly path: "/revoke-sessions";
|
|
150
|
+
readonly clearSession: true;
|
|
151
|
+
}>, RouteDescriptor<VerifyEmailInput, string, {
|
|
152
|
+
readonly method: "POST";
|
|
153
|
+
readonly path: "/verify-email";
|
|
154
|
+
readonly refetchSession: true;
|
|
155
|
+
}>, RouteDescriptor<void, string, {
|
|
156
|
+
readonly method: "POST";
|
|
157
|
+
readonly path: "/email-verifications";
|
|
158
|
+
readonly as: "requestEmailVerification";
|
|
159
|
+
}>], {
|
|
160
|
+
/**
|
|
161
|
+
* Revalidate session state with `GET /me`, update `$session`, and return the
|
|
162
|
+
* resolved value (`null` when signed out).
|
|
163
|
+
*
|
|
164
|
+
* Prefer subscribing to `$session` for reactive UI state (`data`, `isPending`,
|
|
165
|
+
* `error`). Use `getSession()` when you need an awaited server re-check, such
|
|
166
|
+
* as route guards or SSR revalidation after `initialSession`.
|
|
167
|
+
*/
|
|
168
|
+
getSession: () => Promise<Session<TFields> | null>;
|
|
169
|
+
}>;
|
|
170
|
+
type CoreContribution<TFields = unknown> = InferPluginContribution<ReturnType<typeof coreClientPlugin<TFields>>>;
|
|
171
|
+
//#endregion
|
|
172
|
+
//#region src/session-store.d.ts
|
|
173
|
+
type SessionState<TFields = unknown> = {
|
|
174
|
+
/** The current session, or `null` when signed out. */data: Session<TFields> | null; /** True while a `/me` fetch is in flight. */
|
|
175
|
+
isPending: boolean;
|
|
176
|
+
/**
|
|
177
|
+
* The last non-401 failure (network error, 5xx, etc.). A 401 is not an error
|
|
178
|
+
* — it resolves to `data: null`. `error` is cleared on the next successful or
|
|
179
|
+
* 401 outcome.
|
|
180
|
+
*/
|
|
181
|
+
error: LimenError | null;
|
|
182
|
+
};
|
|
183
|
+
type RefetchOptions = {
|
|
184
|
+
/** Skip the fetch when the last hydration ran within this many milliseconds. */maxAgeMs?: number; /** Skip the fetch when the session is signed out. */
|
|
185
|
+
skipSignedOut?: boolean;
|
|
186
|
+
};
|
|
187
|
+
type SessionStore<TFields = unknown> = {
|
|
188
|
+
readonly $session: ReadableAtom<SessionState<TFields>>;
|
|
189
|
+
setData(session: Session<TFields> | null): void;
|
|
190
|
+
/**
|
|
191
|
+
* Re-validate the session from the server.
|
|
192
|
+
*/
|
|
193
|
+
refetch(options?: RefetchOptions): Promise<void>;
|
|
194
|
+
};
|
|
195
|
+
//#endregion
|
|
196
|
+
//#region src/types.d.ts
|
|
197
|
+
type ClientFetchOptions = Partial<FetcherFetchOptions>;
|
|
198
|
+
type CreateAuthClientOptions<Plugins extends readonly AnyClientPlugin[], TFields = unknown> = {
|
|
199
|
+
/** Server origin, e.g. `"http://localhost:8080"`. Trailing slash is stripped. */baseURL: string; /** Path where the Limen handler is mounted. Defaults to `"/auth"`. */
|
|
200
|
+
basePath?: string; /** Options that modify how the SDK performs HTTP requests. */
|
|
201
|
+
fetchOptions?: ClientFetchOptions;
|
|
202
|
+
/**
|
|
203
|
+
* Optional transformer for non-default session payloads.
|
|
204
|
+
*
|
|
205
|
+
* Provide this when your server returns custom user/session fields. It must
|
|
206
|
+
* map the raw response into `Session<TFields>`.
|
|
207
|
+
*/
|
|
208
|
+
parseSession?: ParseSession<TFields>;
|
|
209
|
+
/**
|
|
210
|
+
* How the SDK navigates the browser when a flow hands control to an external
|
|
211
|
+
* page (e.g. an OAuth provider's authorization URL). Defaults to
|
|
212
|
+
* `window.location.href = url` when a `window` is available; a no-op in
|
|
213
|
+
* non-browser environments. Provide a custom function to integrate with a
|
|
214
|
+
* client-side router.
|
|
215
|
+
*/
|
|
216
|
+
redirectFn?: RedirectFn; /** Plugins to register. */
|
|
217
|
+
plugins?: Plugins;
|
|
218
|
+
/**
|
|
219
|
+
* Response-envelope config. Set this when the server wraps successful or all
|
|
220
|
+
* responses.
|
|
221
|
+
*/
|
|
222
|
+
envelope?: EnvelopeConfig;
|
|
223
|
+
/**
|
|
224
|
+
* Per-plugin route overrides. Keys are camelCased plugin ids, e.g.
|
|
225
|
+
* `{ magicLink: { basePath: "/passwordless" } }`.
|
|
226
|
+
*/
|
|
227
|
+
overrides?: PluginOverrides<Plugins>;
|
|
228
|
+
/**
|
|
229
|
+
* SSR seed for the session store. Provide the session resolved server-side to
|
|
230
|
+
* avoid a hydration flash. When provided, lazy hydration is skipped until you
|
|
231
|
+
* call `getSession()` or the store revalidates.
|
|
232
|
+
*/
|
|
233
|
+
initialSession?: Session<TFields> | null;
|
|
234
|
+
/**
|
|
235
|
+
* Keep session state in sync across browser tabs.
|
|
236
|
+
* Enabled by default in browsers. Set `false` to disable.
|
|
237
|
+
*/
|
|
238
|
+
crossTabSync?: boolean;
|
|
239
|
+
/**
|
|
240
|
+
* Refresh session state when the tab becomes active again.
|
|
241
|
+
* Enabled by default in browsers. Set `false` to disable.
|
|
242
|
+
*/
|
|
243
|
+
refetchOnWindowFocus?: boolean;
|
|
244
|
+
};
|
|
245
|
+
type AuthClient<Plugins extends readonly AnyClientPlugin[], TFields = unknown> = Prettify<{
|
|
246
|
+
readonly baseURL: string;
|
|
247
|
+
readonly basePath: string;
|
|
248
|
+
/**
|
|
249
|
+
* Reactive session store holding `{ data, isPending, error }`. Read it with
|
|
250
|
+
* `.get()` / `.listen()` or a framework `useStore`.
|
|
251
|
+
*/
|
|
252
|
+
readonly $session: ReadableAtom<SessionState<TFields>>;
|
|
253
|
+
} & CoreContribution<TFields> & CombinedClientContributions<Plugins>>;
|
|
254
|
+
/**
|
|
255
|
+
* The user object returned from `/me` and any session-bearing response.
|
|
256
|
+
*
|
|
257
|
+
* `TFields` lets consumers extend the shape with custom user fields. The
|
|
258
|
+
* fields listed here are always present.
|
|
259
|
+
*
|
|
260
|
+
* @example
|
|
261
|
+
* type AppUser = User<{ firstName: string; orgId: string }>;
|
|
262
|
+
*/
|
|
263
|
+
type User<TFields = unknown> = {
|
|
264
|
+
id: string;
|
|
265
|
+
email: string;
|
|
266
|
+
emailVerifiedAt: string | null;
|
|
267
|
+
} & TFields;
|
|
268
|
+
type Session<TFields = unknown> = {
|
|
269
|
+
user: User<TFields>;
|
|
270
|
+
};
|
|
271
|
+
type EnvelopeMode = "off" | "wrap-success" | "always";
|
|
272
|
+
type EnvelopeFields = {
|
|
273
|
+
data: string;
|
|
274
|
+
message: string;
|
|
275
|
+
};
|
|
276
|
+
type EnvelopeConfig = {
|
|
277
|
+
mode: EnvelopeMode;
|
|
278
|
+
fields?: EnvelopeFields;
|
|
279
|
+
};
|
|
280
|
+
type ParseSession<TFields = unknown> = (raw: unknown) => Session<TFields>;
|
|
281
|
+
type HTTPMethod = "GET" | "POST" | "PUT" | "DELETE" | "PATCH" | "HEAD" | "OPTIONS";
|
|
282
|
+
type RedirectFn = (url: string) => boolean;
|
|
283
|
+
//#endregion
|
|
284
|
+
//#region src/plugin.d.ts
|
|
285
|
+
/**
|
|
286
|
+
* Route filter for hooks. Matches the stable route path, so client overrides do
|
|
287
|
+
* not change which hooks run.
|
|
288
|
+
*/
|
|
289
|
+
type RouteMatcher = string | readonly string[] | ((ctx: {
|
|
290
|
+
path: string;
|
|
291
|
+
}) => boolean);
|
|
292
|
+
/**
|
|
293
|
+
* Mutable request context passed to `beforeRequest` hooks. Return the updated
|
|
294
|
+
* context, or throw to abort the request.
|
|
295
|
+
*/
|
|
296
|
+
type RequestContext = {
|
|
297
|
+
method: HTTPMethod; /** Path relative to `baseURL` (already includes the configured `basePath`). */
|
|
298
|
+
fullPath: string; /** Path relative to the client `basePath`. */
|
|
299
|
+
path: string; /** Stable route identifier, unaffected by client overrides. */
|
|
300
|
+
routePath: string; /** Full request URL. */
|
|
301
|
+
url: string;
|
|
302
|
+
headers: Headers;
|
|
303
|
+
body: unknown;
|
|
304
|
+
};
|
|
305
|
+
/**
|
|
306
|
+
* Mutable response context passed to `afterResponse` hooks. The body has
|
|
307
|
+
* already been envelope-unwrapped.
|
|
308
|
+
*/
|
|
309
|
+
type ResponseContext = Omit<RequestContext, "url"> & {
|
|
310
|
+
/** Status code. */status: number; /** Whether the response is successful. */
|
|
311
|
+
ok: boolean;
|
|
312
|
+
};
|
|
313
|
+
type BeforeRequestHook = {
|
|
314
|
+
/** Optional route filter. Omit to run for every request. */match?: RouteMatcher;
|
|
315
|
+
run: (req: RequestContext) => RequestContext | Promise<RequestContext>;
|
|
316
|
+
};
|
|
317
|
+
type AfterResponseHook = {
|
|
318
|
+
match?: RouteMatcher; /** Run even for failed responses. */
|
|
319
|
+
allowOnFailure?: boolean;
|
|
320
|
+
run: (res: ResponseContext) => ResponseContext | Promise<ResponseContext>;
|
|
321
|
+
};
|
|
322
|
+
/**
|
|
323
|
+
* Request and response hooks contributed by a plugin.
|
|
324
|
+
*/
|
|
325
|
+
type PluginHooks = {
|
|
326
|
+
beforeRequest?: BeforeRequestHook[];
|
|
327
|
+
afterResponse?: AfterResponseHook[];
|
|
328
|
+
};
|
|
329
|
+
/** Options accepted by `ctx.fetch(path, init)`. */
|
|
330
|
+
type FetchInit = {
|
|
331
|
+
method?: HTTPMethod; /** JSON body. The fetcher stringifies. */
|
|
332
|
+
body?: unknown; /** Appended as `?k=v` query string. */
|
|
333
|
+
query?: Record<string, string>; /** Extra headers to merge with the defaults (`Content-Type`, `Accept`). */
|
|
334
|
+
headers?: HeadersInit;
|
|
335
|
+
/**
|
|
336
|
+
* Resolve `path` from the client base path instead of the plugin base path.
|
|
337
|
+
*/
|
|
338
|
+
absolute?: boolean;
|
|
339
|
+
};
|
|
340
|
+
type PluginIdOf<P> = P extends {
|
|
341
|
+
readonly id: infer Id extends string;
|
|
342
|
+
} ? Id : never;
|
|
343
|
+
type PluginClientOverride = {
|
|
344
|
+
/** Replace the plugin's default base path (relative to the client `basePath`). */basePath?: string;
|
|
345
|
+
};
|
|
346
|
+
/**
|
|
347
|
+
* Per-plugin client overrides, keyed by camelCased plugin id.
|
|
348
|
+
*/
|
|
349
|
+
type PluginOverrides<Plugins extends readonly unknown[]> = Partial<Record<KebabToCamel<PluginIdOf<Plugins[number]>>, PluginClientOverride>>;
|
|
350
|
+
//#endregion
|
|
351
|
+
//#region src/context.d.ts
|
|
352
|
+
/**
|
|
353
|
+
* Context passed to route handlers and plugin actions.
|
|
354
|
+
*/
|
|
355
|
+
type RouteContext<TFields = unknown> = {
|
|
356
|
+
/**
|
|
357
|
+
* Fetch a path relative to the plugin base path. Pass
|
|
358
|
+
* `init.absolute = true` to resolve from the client base path instead.
|
|
359
|
+
*/
|
|
360
|
+
fetch: <T>(path: string, init?: FetchInit) => Promise<T>;
|
|
361
|
+
/**
|
|
362
|
+
* Navigate to an absolute URL. Returns whether navigation happened.
|
|
363
|
+
*/
|
|
364
|
+
readonly redirect: RedirectFn;
|
|
365
|
+
/**
|
|
366
|
+
* Parse a session-bearing response.
|
|
367
|
+
*/
|
|
368
|
+
readonly parseSession: ParseSession<TFields>;
|
|
369
|
+
/**
|
|
370
|
+
* Write a session into the reactive store, or `null` to clear it.
|
|
371
|
+
*/
|
|
372
|
+
setSession: (session: Session<TFields> | null) => void; /** Revalidate the current session. */
|
|
373
|
+
refetchSession: () => Promise<void>; /** Reactive session store. */
|
|
374
|
+
readonly store: SessionStore<TFields>;
|
|
375
|
+
};
|
|
376
|
+
type AnyRouteContext = RouteContext<any>;
|
|
377
|
+
//#endregion
|
|
378
|
+
//#region src/infer.d.ts
|
|
379
|
+
type IsParam<S extends string> = S extends `:${string}` ? true : false;
|
|
380
|
+
/**
|
|
381
|
+
* Turn a route path literal into its camelCased client-chain segments, dropping
|
|
382
|
+
* leading slashes and `:param` segments. `"/otp/send"` -> `["otp", "send"]`.
|
|
383
|
+
*/
|
|
384
|
+
type PathSegments<P extends string> = P extends `/${infer Rest}` ? PathSegments<Rest> : P extends `${infer Head}/${infer Tail}` ? Head extends "" ? PathSegments<Tail> : IsParam<Head> extends true ? PathSegments<Tail> : [KebabToCamel<Head>, ...PathSegments<Tail>] : P extends "" ? [] : IsParam<P> extends true ? [] : [KebabToCamel<P>];
|
|
385
|
+
type PathOf<R> = R extends {
|
|
386
|
+
path: infer P extends string;
|
|
387
|
+
} ? P : never;
|
|
388
|
+
/**
|
|
389
|
+
* The resolved chain for one route: an absolute `as` wins, otherwise it is the
|
|
390
|
+
* plugin's base-path segments followed by the route-path segments.
|
|
391
|
+
*/
|
|
392
|
+
type ChainSegments<R, BasePrefix extends readonly string[]> = R extends {
|
|
393
|
+
as: infer A extends string;
|
|
394
|
+
} ? Split<A, "."> : [...BasePrefix, ...PathSegments<PathOf<R>>];
|
|
395
|
+
type Nest<Segs extends readonly string[], Fn> = Segs extends readonly [infer Head extends string, ...infer Rest extends readonly string[]] ? string extends Head ? unknown : { [K in Head]: Nest<Rest, Fn> } : Fn;
|
|
396
|
+
/**
|
|
397
|
+
* A no-input route (`I` is `void`) takes no input — only the optional, trailing
|
|
398
|
+
* call options; everything else takes `input` followed by the call options.
|
|
399
|
+
* Options are always the trailing argument so the runtime can place them
|
|
400
|
+
* unambiguously (a lone argument is always the route input).
|
|
401
|
+
*/
|
|
402
|
+
type InferRouteFn<I, O> = [I] extends [void] ? (input?: void, opts?: RouteCallOptions<O>) => Promise<O> : (input: I, opts?: RouteCallOptions<O>) => Promise<O>;
|
|
403
|
+
type IsExposed<R> = R extends {
|
|
404
|
+
expose: false;
|
|
405
|
+
} ? false : true;
|
|
406
|
+
type RouteFn<R> = InferRouteFn<InputOf<R>, OutputOf<R>>;
|
|
407
|
+
type InferOneRoute<R, BasePrefix extends readonly string[]> = IsExposed<R> extends false ? unknown : Nest<ChainSegments<R, BasePrefix>, RouteFn<R>>;
|
|
408
|
+
/**
|
|
409
|
+
* Infer the public API tree for a list of route descriptors, given the owning
|
|
410
|
+
* plugin's base-path segments. Each route mounts a callable at its resolved
|
|
411
|
+
* chain; sibling keys merge via intersection, so `signin.credential` and
|
|
412
|
+
* `signup.credential` coexist and both autocomplete.
|
|
413
|
+
*/
|
|
414
|
+
type InferRoutes<Routes extends readonly unknown[], BasePrefix extends readonly string[]> = UnionToIntersection<{ [K in keyof Routes]: InferOneRoute<Routes[K], BasePrefix> }[number]>;
|
|
415
|
+
//#endregion
|
|
416
|
+
//#region src/define-plugin.d.ts
|
|
417
|
+
/** Invoke one of the plugin's routes from `actions`. */
|
|
418
|
+
type RunRoute = <I, O>(route: RouteDescriptor<I, O>, input: I) => Promise<O>;
|
|
419
|
+
/**
|
|
420
|
+
* Client plugin contract
|
|
421
|
+
*/
|
|
422
|
+
type ClientPlugin<Id extends string, BasePath extends string, Routes extends readonly AnyRouteDescriptor[], Actions> = {
|
|
423
|
+
readonly id: Id; /** Default mount path relative to the client `basePath`, e.g. `"/magic-link"`; omit for the root (`""`). */
|
|
424
|
+
readonly basePath?: BasePath;
|
|
425
|
+
readonly routes: Routes;
|
|
426
|
+
readonly hooks?: PluginHooks;
|
|
427
|
+
readonly actions?: (ctx: RouteContext, run: RunRoute) => Actions;
|
|
428
|
+
};
|
|
429
|
+
type AnyClientPlugin = ClientPlugin<string, string, readonly AnyRouteDescriptor[], any>;
|
|
430
|
+
/**
|
|
431
|
+
* Register a plugin's routes while preserving each route's input/output types
|
|
432
|
+
* for the generated client API.
|
|
433
|
+
*/
|
|
434
|
+
declare function defineRoutes<Routes extends readonly AnyRouteDescriptor[]>(...routes: Routes): Routes;
|
|
435
|
+
/**
|
|
436
|
+
* Define a client plugin for `createAuthClient`.
|
|
437
|
+
*/
|
|
438
|
+
declare function defineClientPlugin<const Id extends string, const Routes extends readonly AnyRouteDescriptor[], Actions = Record<never, never>, const BasePath extends string = "">(def: ClientPlugin<Id, BasePath, Routes, Actions>): ClientPlugin<Id, BasePath, Routes, Actions>;
|
|
439
|
+
/**
|
|
440
|
+
* The client-only methods a plugin contributes. Widened `any` contributes
|
|
441
|
+
* nothing so the client does not become permissive.
|
|
442
|
+
*/
|
|
443
|
+
type ActionsOf<P> = P extends {
|
|
444
|
+
actions?: (ctx: never, run: never) => infer A;
|
|
445
|
+
} ? IsAny<A> extends true ? unknown : A extends object ? A : unknown : unknown;
|
|
446
|
+
type InferPluginContribution<P> = P extends ClientPlugin<infer _Id, infer BasePath, infer Routes, infer _Actions> ? InferRoutes<Routes, PathSegments<BasePath>> & ActionsOf<P> : unknown;
|
|
447
|
+
type CombinedClientContributions<Plugins extends readonly unknown[]> = UnionToIntersection<{ [K in keyof Plugins]: InferPluginContribution<Plugins[K]> }[number]>;
|
|
448
|
+
//#endregion
|
|
449
|
+
export { ActiveSession as A, deriveErrorCode as B, HTTPMethod as C, User as D, Session as E, RouteDescriptor as F, RouteHandler as I, route as L, VerifyEmailInput as M, coreClientPlugin as N, SessionState as O, RouteCallOptions as P, LimenError as R, EnvelopeMode as S, RedirectFn as T, Prettify as V, AuthClient as _, defineRoutes as a, EnvelopeConfig as b, AfterResponseHook as c, PluginClientOverride as d, PluginIdOf as f, RouteMatcher as g, ResponseContext as h, defineClientPlugin as i, CoreContribution as j, SessionStore as k, BeforeRequestHook as l, RequestContext as m, ClientPlugin as n, AnyRouteContext as o, PluginOverrides as p, RunRoute as r, RouteContext as s, AnyClientPlugin as t, FetchInit as u, ClientFetchOptions as v, ParseSession as w, EnvelopeFields as x, CreateAuthClientOptions as y, LimenErrorCode as z };
|
|
450
|
+
//# sourceMappingURL=define-plugin-Dv0xXIaH.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"define-plugin-Dv0xXIaH.d.mts","names":[],"sources":["../src/type-utils.ts","../src/fetcher.ts","../src/errors.ts","../src/route.ts","../src/routes.ts","../src/session-store.ts","../src/types.ts","../src/plugin.ts","../src/context.ts","../src/infer.ts","../src/define-plugin.ts"],"mappings":";;;;KACY,QAAA,oBAA4B,CAAA,GAAI,CAAA,CAAE,CAAA;;KAGlC,mBAAA,OAA0B,CAAA,oBAAqB,CAAA,EAAG,CAAC,6BAA4B,CAAA,sBACvF,CAAA;;;;KAMQ,YAAA,qBAAiC,CAAA,4CACtC,IAAA,GAAO,UAAA,CAAW,YAAA,CAAa,IAAA,OAClC,CAAA;;KAGQ,KAAA,uCAA4C,CAAA,yBAA0B,CAAA,kBAC9E,IAAA,cACE,KAAA,CAAM,IAAA,EAAM,CAAA,KACX,IAAA,KAAS,KAAA,CAAM,IAAA,EAAM,CAAA,KACxB,CAAA,oBAEG,CAAA;;KAGK,KAAA,oBAAyB,CAAC;;;KClBjC,0BAAA,GAA6B,eAAe;AAAA,KAErC,mBAAA;EDRQ,sECUlB,WAAA,GAAc,kBAAA,EDV4B;ECY1C,IAAA,UAAc,KAAA,EDZ+B;ECc7C,OAAA,GAAU,WAAA,EDdS;ECgBnB,SAAA,IAAa,OAAA,EAAS,0BAAA;IAA+B,QAAA,EAAU,QAAA;EAAA,YDhBnB;ECkB5C,OAAA,IAAW,OAAA,EAAS,0BAAA;IAA+B,KAAA,EAAO,KAAA;EAAA;AAAA;;;KCnBhD,cAAA;;iBAYI,eAAA,CAAgB,MAAA,WAAiB,cAAc;AFX/D;;;;;AAAA,cE2Ba,UAAA,SAAmB,KAAA;EAAA,SACZ,IAAA;EAAA,SACT,MAAA;EAAA,SACA,IAAA,EAAM,cAAA;cAEH,OAAA,UAAiB,MAAA,UAAgB,IAAA,GAAO,cAAA;EAAA,IAMhD,cAAA;EAAA,IAIA,aAAA;AAAA;;;cCvCQ,KAAA;AAAA,cACA,MAAA;;;;;KAMF,UAAA,oBAA8B,KAAA,GAAQ,CAAA,KAAM,OAAA,CAAQ,CAAA;;;;;KAMpD,YAAA,6BACV,GAAA,EAAK,YAAA,CAAa,OAAA,GAClB,KAAA,EAAO,CAAA,EACP,IAAA,EAAM,UAAA,CAAW,CAAA,MACd,OAAA,CAAQ,CAAA;;;AHpBkC;AAG/C;KGuBY,gBAAA;EHvBmB,+DGyB7B,SAAA,IAAa,IAAA,EAAM,CAAA,WHzBW;EG2B9B,OAAA,IAAW,KAAA,EAAO,UAAU;AAAA;;;;;KAOlB,QAAA;EACV,MAAA,EAAQ,UAAA;EACR,IAAA,gBH7BsB;EGgCtB,EAAA,WHhC2C;EGmC3C,QAAA,GAAW,OAAA,CAAQ,CAAA,GHlCiB;EGoCpC,SAAA,IAAa,KAAA,EAAO,CAAA,cHpCR;EGsCZ,KAAA,IAAS,GAAA,cAAiB,CAAA;EHrCvB;;;;EG0CH,YAAA,YH5C4E;EG8C5E,QAAA,YH7CY;EGgDZ,MAAA,mBAAyB,CAAA,cHhDW;EGmDpC,SAAA,YHlDG;EGoDH,YAAA,YHjDU;EGmDV,cAAA,YHnDe;EGsDf,MAAA,YHtDgF;EGyDhF,OAAA,GAAU,YAAA,CAAa,CAAA,EAAG,CAAA;AAAA;;;;KAMhB,eAAA,iBAAgC,QAAA,CAAS,CAAA,EAAG,CAAA,IAAK,QAAA,CAAS,CAAA,EAAG,CAAA,KAAM,CAAA;EAAA,UACnE,KAAA,GAAQ,CAAA;EAAA,UACR,MAAA,GAAS,CAAA;AAAA;;;;KAOT,kBAAA,GAAqB,eAAe;AAAA,KAQpC,OAAA,MAAa,CAAA;EAAA,UAAsB,KAAK;AAAA,IAAe,CAAA;AAAA,KACvD,QAAA,MAAc,CAAA;EAAA,UAAsB,MAAM;AAAA,IAAe,CAAA;;;;;;AH3E7D;AAGR;;;;AAAsC;iBGqFtB,KAAA,4CACU,QAAA,CAAS,CAAA,EAAG,CAAA,GAAI,GAAA,EAAK,CAAA,KAAI,eAAA,CAAgB,CAAA,EAAG,CAAA,EAAG,CAAA;;;KCzG7D,gBAAA;EACV,KAAK;AAAA;AAAA,KAGK,aAAA;EACV,EAAA;EACA,KAAA;EACA,MAAA;EACA,SAAA;EACA,SAAA;EACA,UAAA;EACA,QAAA,GAAW,MAAM;AAAA;;;AJhB4B;iBIsB/B,gBAAA,uBAyCmB,YAAA,eAzCe,eAAA,OAAA,aAAA;EAAA;;IAAA,eAAA;EAAA;;;;;;;;;;;;;;;;EJXpC;;;;;;;;oBIoDc,OAAA,CAAQ,OAAA,CAAQ,OAAA;AAAA;AAAA,KAYhC,gBAAA,sBAAsC,uBAAA,CAAwB,UAAA,QAAkB,gBAAA,CAAiB,OAAA;;;KCvEjG,YAAA;ELJQ,sDKMlB,IAAA,EAAM,OAAA,CAAQ,OAAA,ULNwB;EKQtC,SAAA;ELR4C;;;;;EKc5C,KAAA,EAAO,UAAA;AAAA;AAAA,KAGJ,cAAA;ELjB0C,gFKmB7C,QAAA,WLhBU;EKkBV,aAAa;AAAA;AAAA,KAGH,YAAA;EAAA,SACD,QAAA,EAAU,YAAA,CAAa,YAAA,CAAa,OAAA;EAC7C,OAAA,CAAQ,OAAA,EAAS,OAAA,CAAQ,OAAA;ELvBmC;;;EK2B5D,OAAA,CAAQ,OAAA,GAAU,cAAA,GAAiB,OAAA;AAAA;;;KCvBzB,kBAAA,GAAqB,OAAO,CAAC,mBAAA;AAAA,KAE7B,uBAAA,0BAAiD,eAAA;ENTd,iFMW7C,OAAA,UNXmB;EManB,QAAA,WNbsC;EMetC,YAAA,GAAe,kBAAA;ENf6B;;AAAC;AAG/C;;;EMmBE,YAAA,GAAe,YAAA,CAAa,OAAA;ENnBE;;;;;;;EM2B9B,UAAA,GAAa,UAAA,EN1BV;EM4BH,OAAA,GAAU,OAAA;ENtBY;;;;EM2BtB,QAAA,GAAW,cAAA;EN1BY;;;;EM+BvB,SAAA,GAAY,eAAA,CAAgB,OAAA;ENhCL;;;;;EMsCvB,cAAA,GAAiB,OAAA,CAAQ,OAAA;ENrCF;;;;EM0CvB,YAAA;ENtCU;;;;EM2CV,oBAAA;AAAA;AAAA,KAGU,UAAA,0BAAoC,eAAA,yBAAwC,QAAA;EAAA,SAE3E,OAAA;EAAA,SACA,QAAA;EN9CS;;;;EAAA,SMmDT,QAAA,EAAU,YAAA,CAAa,YAAA,CAAa,OAAA;AAAA,IAC3C,gBAAA,CAAiB,OAAA,IACnB,2BAAA,CAA4B,OAAA;;;;;;;;;;KAYpB,IAAA;EACV,EAAA;EACA,KAAA;EACA,eAAA;AAAA,IACE,OAAO;AAAA,KAEC,OAAA;EACV,IAAA,EAAM,IAAI,CAAC,OAAA;AAAA;AAAA,KAGD,YAAA;AAAA,KAEA,cAAA;EACV,IAAA;EACA,OAAO;AAAA;AAAA,KAGG,cAAA;EACV,IAAA,EAAM,YAAA;EACN,MAAA,GAAS,cAAc;AAAA;AAAA,KAGb,YAAA,uBAAmC,GAAA,cAAiB,OAAO,CAAC,OAAA;AAAA,KAE5D,UAAA;AAAA,KAEA,UAAA,IAAc,GAAW;;;;AN7GrC;;;KOMY,YAAA,kCAA8C,GAAqB;EAAd,IAAA;AAAA;;;;;KAMrD,cAAA;EACV,MAAA,EAAQ,UAAA,EPboC;EOe5C,QAAA,UPf6C;EOiB7C,IAAA,UPd6B;EOgB7B,SAAA,UPhB6D;EOkB7D,GAAA;EACA,OAAA,EAAS,OAAO;EAChB,IAAA;AAAA;;;;;KAOU,eAAA,GAAkB,IAAI,CAAC,cAAA;EPpBvB,mBOsBV,MAAA,UPtBsB;EOwBtB,EAAA;AAAA;AAAA,KAGU,iBAAA;EP1Ba,4DO4BvB,KAAA,GAAQ,YAAA;EACR,GAAA,GAAM,GAAA,EAAK,cAAA,KAAmB,cAAA,GAAiB,OAAA,CAAQ,cAAA;AAAA;AAAA,KAG7C,iBAAA;EACV,KAAA,GAAQ,YAAA,EPlCmC;EOoC3C,cAAA;EACA,GAAA,GAAM,GAAA,EAAK,eAAA,KAAoB,eAAA,GAAkB,OAAA,CAAQ,eAAA;AAAA;;;;KAM/C,WAAA;EACV,aAAA,GAAgB,iBAAA;EAChB,aAAA,GAAgB,iBAAiB;AAAA;;KAIvB,SAAA;EACV,MAAA,GAAS,UAAA,EP7CuE;EO+ChF,IAAA,YP7CgB;EO+ChB,KAAA,GAAQ,MAAA,kBP9CH;EOgDL,OAAA,GAAU,WAAA;EPhDgB;;;EOoD1B,QAAA;AAAA;AAAA,KAGU,UAAA,MAAgB,CAAC;EAAA,SAAoB,EAAA;AAAA,IAAgC,EAAA;AAAA,KAErE,oBAAA;EP5D+D,kFO8DzE,QAAQ;AAAA;;;;KAME,eAAA,uCAAsD,OAAA,CAChE,MAAA,CAAO,YAAA,CAAa,UAAA,CAAW,OAAA,YAAmB,oBAAA;;;APpFpD;;;AAAA,KQMY,YAAA;ERNgC;;;;EQW1C,KAAA,MAAW,IAAA,UAAc,IAAA,GAAO,SAAA,KAAc,OAAA,CAAQ,CAAA;ERX3B;;;EAAA,SQelB,QAAA,EAAU,UAAA;ERf0B;AAAA;AAG/C;EAH+C,SQmBpC,YAAA,EAAc,YAAA,CAAa,OAAA;ERhBP;;;EQoB7B,UAAA,GAAa,OAAA,EAAS,OAAA,CAAQ,OAAA,mBRpB8B;EQsB5D,cAAA,QAAsB,OAAA,QRtB4E;EAAA,SQwBzF,KAAA,EAAO,YAAA,CAAa,OAAA;AAAA;AAAA,KAInB,eAAA,GAAkB,YAAY;;;KC7BrC,OAAA,qBAA4B,CAAC;ATFlC;;;;AAAA,KSQY,YAAA,qBAAiC,CAAA,4BACzC,YAAA,CAAa,IAAA,IACb,CAAA,yCACE,IAAA,cACE,YAAA,CAAa,IAAA,IACb,OAAA,CAAQ,IAAA,iBACN,YAAA,CAAa,IAAA,KACZ,YAAA,CAAa,IAAA,MAAU,YAAA,CAAa,IAAA,KACzC,CAAA,mBAEE,OAAA,CAAQ,CAAA,uBAEL,YAAA,CAAa,CAAA;AAAA,KAEnB,MAAA,MAAY,CAAC;EAAW,IAAA;AAAA,IAAiC,CAAA;;;;;KAMzD,aAAA,4CAAyD,CAAA;EAAY,EAAA;AAAA,IACtE,KAAA,CAAM,CAAA,aACF,UAAA,KAAe,YAAA,CAAa,MAAA,CAAO,CAAA;AAAA,KAEtC,IAAA,uCAA2C,IAAA,wGAK7B,IAAA,qBAEL,IAAA,GAAO,IAAA,CAAK,IAAA,EAAM,EAAA,MAC5B,EAAA;;;;;;;KAQC,YAAA,UAAsB,CAAA,oBACtB,KAAA,SAAc,IAAA,GAAO,gBAAA,CAAiB,CAAA,MAAO,OAAA,CAAQ,CAAA,KACrD,KAAA,EAAO,CAAA,EAAG,IAAA,GAAO,gBAAA,CAAiB,CAAA,MAAO,OAAA,CAAQ,CAAA;AAAA,KAEjD,SAAA,MAAe,CAAC;EAAW,MAAA;AAAA;AAAA,KAE3B,OAAA,MAAa,YAAA,CAAa,OAAA,CAAQ,CAAA,GAAI,QAAA,CAAS,CAAA;AAAA,KAE/C,aAAA,4CACH,SAAA,CAAU,CAAA,4BAA6B,IAAA,CAAK,aAAA,CAAc,CAAA,EAAG,UAAA,GAAa,OAAA,CAAQ,CAAA;;;;;;;KAQxE,WAAA,4EAAuF,mBAAA,eACnF,MAAA,GAAS,aAAA,CAAc,MAAA,CAAO,CAAA,GAAI,UAAA;;;;KC5DtC,QAAA,UAAkB,KAAA,EAAO,eAAA,CAAgB,CAAA,EAAG,CAAA,GAAI,KAAA,EAAO,CAAA,KAAM,OAAA,CAAQ,CAAA;;;;KAKrE,YAAA,qEAGc,kBAAA;EAAA,SAGf,EAAA,EAAI,EAAA,EVjBc;EAAA,SUmBlB,QAAA,GAAW,QAAA;EAAA,SACX,MAAA,EAAQ,MAAA;EAAA,SACR,KAAA,GAAQ,WAAA;EAAA,SACR,OAAA,IAAW,GAAA,EAAK,YAAA,EAAc,GAAA,EAAK,QAAA,KAAa,OAAA;AAAA;AAAA,KAI/C,eAAA,GAAkB,YAAY,0BAA0B,kBAAA;;;;;iBAMpD,YAAA,yBAAqC,kBAAA,OAAyB,MAAA,EAAQ,MAAA,GAAS,MAAA;;;;iBAO/E,kBAAA,wDAEgB,kBAAA,cACpB,MAAA,oDAEV,GAAA,EAAK,YAAA,CAAa,EAAA,EAAI,QAAA,EAAU,MAAA,EAAQ,OAAA,IAAW,YAAA,CAAa,EAAA,EAAI,QAAA,EAAU,MAAA,EAAQ,OAAA;;;AVxCnF;AAML;KUgDK,SAAA,MAAe,CAAA;EAAY,OAAA,IAAW,GAAA,SAAY,GAAA;AAAA,IACnD,KAAA,CAAM,CAAA,2BAEJ,CAAA,kBACE,CAAA;AAAA,KAII,uBAAA,MACV,CAAA,SAAU,YAAA,4DACN,WAAA,CAAY,MAAA,EAAQ,YAAA,CAAa,QAAA,KAAa,SAAA,CAAU,CAAA;AAAA,KAGlD,2BAAA,uCAAkE,mBAAA,eAC9D,OAAA,GAAU,uBAAA,CAAwB,OAAA,CAAQ,CAAA"}
|