@robelest/convex-auth 0.0.4-preview.13 → 0.0.4-preview.16
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +140 -9
- package/dist/bin.cjs +5957 -5478
- package/dist/client/index.d.ts +3 -7
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/index.js +27 -26
- package/dist/client/index.js.map +1 -1
- package/dist/component/_generated/api.d.ts +14 -0
- package/dist/component/_generated/api.d.ts.map +1 -1
- package/dist/component/_generated/api.js.map +1 -1
- package/dist/component/_generated/component.d.ts +1672 -24
- package/dist/component/_generated/component.d.ts.map +1 -1
- package/dist/component/convex.config.d.ts +2 -2
- package/dist/component/convex.config.d.ts.map +1 -1
- package/dist/component/index.d.ts +1 -1
- package/dist/component/index.js +2 -2
- package/dist/component/model.d.ts +153 -0
- package/dist/component/model.d.ts.map +1 -0
- package/dist/component/model.js +343 -0
- package/dist/component/model.js.map +1 -0
- package/dist/component/providers/sso.d.ts +1 -1
- package/dist/component/public/enterprise.d.ts +54 -0
- package/dist/component/public/enterprise.d.ts.map +1 -0
- package/dist/component/public/enterprise.js +515 -0
- package/dist/component/public/enterprise.js.map +1 -0
- package/dist/component/public/factors.d.ts +52 -0
- package/dist/component/public/factors.d.ts.map +1 -0
- package/dist/component/public/factors.js +285 -0
- package/dist/component/public/factors.js.map +1 -0
- package/dist/component/public/groups.d.ts +116 -0
- package/dist/component/public/groups.d.ts.map +1 -0
- package/dist/component/public/groups.js +596 -0
- package/dist/component/public/groups.js.map +1 -0
- package/dist/component/public/identity.d.ts +93 -0
- package/dist/component/public/identity.d.ts.map +1 -0
- package/dist/component/public/identity.js +426 -0
- package/dist/component/public/identity.js.map +1 -0
- package/dist/component/public/keys.d.ts +41 -0
- package/dist/component/public/keys.d.ts.map +1 -0
- package/dist/component/public/keys.js +157 -0
- package/dist/component/public/keys.js.map +1 -0
- package/dist/component/public/shared.d.ts +26 -0
- package/dist/component/public/shared.d.ts.map +1 -0
- package/dist/component/public/shared.js +32 -0
- package/dist/component/public/shared.js.map +1 -0
- package/dist/component/public.d.ts +9 -321
- package/dist/component/public.d.ts.map +1 -1
- package/dist/component/public.js +6 -2145
- package/dist/component/schema.d.ts +406 -260
- package/dist/component/schema.js +37 -32
- package/dist/component/schema.js.map +1 -1
- package/dist/component/server/auth.d.ts +161 -15
- package/dist/component/server/auth.d.ts.map +1 -1
- package/dist/component/server/auth.js +100 -7
- package/dist/component/server/auth.js.map +1 -1
- package/dist/component/server/cookies.js +3 -0
- package/dist/component/server/cookies.js.map +1 -1
- package/dist/component/server/db.js +1 -0
- package/dist/component/server/db.js.map +1 -1
- package/dist/component/server/device.js +3 -1
- package/dist/component/server/device.js.map +1 -1
- package/dist/component/server/domains/core.js +629 -0
- package/dist/component/server/domains/core.js.map +1 -0
- package/dist/component/server/domains/sso.js +884 -0
- package/dist/component/server/domains/sso.js.map +1 -0
- package/dist/component/server/factory.d.ts +136 -0
- package/dist/component/server/factory.d.ts.map +1 -0
- package/dist/component/server/factory.js +1134 -0
- package/dist/component/server/factory.js.map +1 -0
- package/dist/component/server/fx.js +2 -1
- package/dist/component/server/fx.js.map +1 -1
- package/dist/component/server/http.js +287 -0
- package/dist/component/server/http.js.map +1 -0
- package/dist/component/server/identity.js +13 -0
- package/dist/component/server/identity.js.map +1 -0
- package/dist/component/server/keys.js +4 -0
- package/dist/component/server/keys.js.map +1 -1
- package/dist/component/server/mutations/account.js +1 -1
- package/dist/component/server/mutations/index.js +2 -2
- package/dist/component/server/mutations/index.js.map +1 -1
- package/dist/component/server/mutations/invalidate.js +1 -1
- package/dist/component/server/mutations/oauth.js +10 -7
- package/dist/component/server/mutations/oauth.js.map +1 -1
- package/dist/component/server/mutations/refresh.js +1 -1
- package/dist/component/server/mutations/register.js +1 -1
- package/dist/component/server/mutations/retrieve.js +1 -1
- package/dist/component/server/mutations/signature.js +1 -1
- package/dist/component/server/mutations/store.js +6 -3
- package/dist/component/server/mutations/store.js.map +1 -1
- package/dist/component/server/mutations/verify.js +1 -1
- package/dist/component/server/oauth.js +3 -0
- package/dist/component/server/oauth.js.map +1 -1
- package/dist/component/server/passkey.js +3 -2
- package/dist/component/server/passkey.js.map +1 -1
- package/dist/component/server/provider.js +2 -0
- package/dist/component/server/provider.js.map +1 -1
- package/dist/component/server/providers.js +10 -0
- package/dist/component/server/providers.js.map +1 -1
- package/dist/component/server/ratelimit.js +3 -0
- package/dist/component/server/ratelimit.js.map +1 -1
- package/dist/component/server/redirects.js +2 -0
- package/dist/component/server/redirects.js.map +1 -1
- package/dist/component/server/refresh.js +5 -0
- package/dist/component/server/refresh.js.map +1 -1
- package/dist/component/server/sessions.js +5 -0
- package/dist/component/server/sessions.js.map +1 -1
- package/dist/component/server/signin.js +2 -1
- package/dist/component/server/signin.js.map +1 -1
- package/dist/component/server/sso.js +166 -19
- package/dist/component/server/sso.js.map +1 -1
- package/dist/component/server/tokens.js +1 -0
- package/dist/component/server/tokens.js.map +1 -1
- package/dist/component/server/totp.js +4 -2
- package/dist/component/server/totp.js.map +1 -1
- package/dist/component/server/types.d.ts +106 -38
- package/dist/component/server/types.d.ts.map +1 -1
- package/dist/component/server/types.js.map +1 -1
- package/dist/component/server/users.js +1 -0
- package/dist/component/server/users.js.map +1 -1
- package/dist/component/server/utils.js +44 -2
- package/dist/component/server/utils.js.map +1 -1
- package/dist/providers/anonymous.d.ts +1 -1
- package/dist/providers/credentials.d.ts +1 -1
- package/dist/providers/password.d.ts +1 -1
- package/dist/providers/sso.d.ts +1 -1
- package/dist/providers/sso.js.map +1 -1
- package/dist/server/auth.d.ts +163 -17
- package/dist/server/auth.d.ts.map +1 -1
- package/dist/server/auth.js +100 -7
- package/dist/server/auth.js.map +1 -1
- package/dist/server/cookies.d.ts +1 -38
- package/dist/server/cookies.js +3 -0
- package/dist/server/cookies.js.map +1 -1
- package/dist/server/db.d.ts +1 -125
- package/dist/server/db.js +1 -0
- package/dist/server/db.js.map +1 -1
- package/dist/server/device.d.ts +1 -24
- package/dist/server/device.js +3 -1
- package/dist/server/device.js.map +1 -1
- package/dist/server/domains/core.d.ts +434 -0
- package/dist/server/domains/core.d.ts.map +1 -0
- package/dist/server/domains/core.js +629 -0
- package/dist/server/domains/core.js.map +1 -0
- package/dist/server/domains/sso.d.ts +409 -0
- package/dist/server/domains/sso.d.ts.map +1 -0
- package/dist/server/domains/sso.js +884 -0
- package/dist/server/domains/sso.js.map +1 -0
- package/dist/server/enterpriseValidators.d.ts +1 -0
- package/dist/server/enterpriseValidators.js +60 -0
- package/dist/server/enterpriseValidators.js.map +1 -0
- package/dist/server/factory.d.ts +136 -0
- package/dist/server/factory.d.ts.map +1 -0
- package/dist/server/factory.js +1134 -0
- package/dist/server/factory.js.map +1 -0
- package/dist/server/fx.d.ts +1 -16
- package/dist/server/fx.d.ts.map +1 -1
- package/dist/server/fx.js +1 -0
- package/dist/server/fx.js.map +1 -1
- package/dist/server/http.d.ts +59 -0
- package/dist/server/http.d.ts.map +1 -0
- package/dist/server/http.js +287 -0
- package/dist/server/http.js.map +1 -0
- package/dist/server/identity.d.ts +1 -0
- package/dist/server/identity.js +13 -0
- package/dist/server/identity.js.map +1 -0
- package/dist/server/index.d.ts +468 -1
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +530 -36
- package/dist/server/index.js.map +1 -1
- package/dist/server/keys.d.ts +1 -57
- package/dist/server/keys.js +4 -0
- package/dist/server/keys.js.map +1 -1
- package/dist/server/mutations/account.d.ts +7 -7
- package/dist/server/mutations/account.d.ts.map +1 -1
- package/dist/server/mutations/code.d.ts +13 -13
- package/dist/server/mutations/code.d.ts.map +1 -1
- package/dist/server/mutations/index.d.ts +107 -107
- package/dist/server/mutations/index.d.ts.map +1 -1
- package/dist/server/mutations/index.js +1 -1
- package/dist/server/mutations/index.js.map +1 -1
- package/dist/server/mutations/invalidate.d.ts +5 -5
- package/dist/server/mutations/invalidate.d.ts.map +1 -1
- package/dist/server/mutations/oauth.d.ts +10 -10
- package/dist/server/mutations/oauth.d.ts.map +1 -1
- package/dist/server/mutations/oauth.js +9 -6
- package/dist/server/mutations/oauth.js.map +1 -1
- package/dist/server/mutations/refresh.d.ts +4 -4
- package/dist/server/mutations/register.d.ts +12 -12
- package/dist/server/mutations/register.d.ts.map +1 -1
- package/dist/server/mutations/retrieve.d.ts +7 -7
- package/dist/server/mutations/signature.d.ts +5 -5
- package/dist/server/mutations/signin.d.ts +6 -6
- package/dist/server/mutations/signin.d.ts.map +1 -1
- package/dist/server/mutations/signout.d.ts +1 -1
- package/dist/server/mutations/store.d.ts +3 -2
- package/dist/server/mutations/store.d.ts.map +1 -1
- package/dist/server/mutations/store.js +6 -3
- package/dist/server/mutations/store.js.map +1 -1
- package/dist/server/mutations/verifier.d.ts +1 -1
- package/dist/server/mutations/verify.d.ts +11 -11
- package/dist/server/mutations/verify.d.ts.map +1 -1
- package/dist/server/oauth.d.ts +1 -59
- package/dist/server/oauth.js +3 -0
- package/dist/server/oauth.js.map +1 -1
- package/dist/server/passkey.d.ts.map +1 -1
- package/dist/server/passkey.js +3 -2
- package/dist/server/passkey.js.map +1 -1
- package/dist/server/provider.d.ts +1 -14
- package/dist/server/provider.d.ts.map +1 -1
- package/dist/server/provider.js +2 -0
- package/dist/server/provider.js.map +1 -1
- package/dist/server/providers.js +10 -0
- package/dist/server/providers.js.map +1 -1
- package/dist/server/ratelimit.d.ts +1 -22
- package/dist/server/ratelimit.js +3 -0
- package/dist/server/ratelimit.js.map +1 -1
- package/dist/server/redirects.d.ts +1 -10
- package/dist/server/redirects.js +2 -0
- package/dist/server/redirects.js.map +1 -1
- package/dist/server/refresh.d.ts +1 -37
- package/dist/server/refresh.js +5 -0
- package/dist/server/refresh.js.map +1 -1
- package/dist/server/sessions.d.ts +1 -28
- package/dist/server/sessions.js +5 -0
- package/dist/server/sessions.js.map +1 -1
- package/dist/server/signin.d.ts +1 -55
- package/dist/server/signin.js +2 -1
- package/dist/server/signin.js.map +1 -1
- package/dist/server/sso.d.ts +1 -348
- package/dist/server/sso.js +165 -18
- package/dist/server/sso.js.map +1 -1
- package/dist/server/templates.d.ts +1 -21
- package/dist/server/templates.js +1 -0
- package/dist/server/templates.js.map +1 -1
- package/dist/server/tokens.d.ts +1 -11
- package/dist/server/tokens.js +1 -0
- package/dist/server/tokens.js.map +1 -1
- package/dist/server/totp.d.ts +1 -23
- package/dist/server/totp.js +4 -2
- package/dist/server/totp.js.map +1 -1
- package/dist/server/types.d.ts +114 -77
- package/dist/server/types.d.ts.map +1 -1
- package/dist/server/types.js.map +1 -1
- package/dist/server/users.d.ts +1 -31
- package/dist/server/users.js +1 -0
- package/dist/server/users.js.map +1 -1
- package/dist/server/utils.d.ts +1 -27
- package/dist/server/utils.js +44 -2
- package/dist/server/utils.js.map +1 -1
- package/dist/server/version.d.ts +1 -1
- package/dist/server/version.js +1 -1
- package/dist/server/version.js.map +1 -1
- package/package.json +4 -5
- package/src/cli/bin.ts +5 -0
- package/src/cli/index.ts +22 -9
- package/src/cli/keys.ts +3 -0
- package/src/client/index.ts +36 -37
- package/src/component/_generated/api.ts +14 -0
- package/src/component/_generated/component.ts +2106 -9
- package/src/component/index.ts +3 -1
- package/src/component/model.ts +441 -0
- package/src/component/public/enterprise.ts +753 -0
- package/src/component/public/factors.ts +332 -0
- package/src/component/public/groups.ts +932 -0
- package/src/component/public/identity.ts +566 -0
- package/src/component/public/keys.ts +209 -0
- package/src/component/public/shared.ts +119 -0
- package/src/component/public.ts +5 -2965
- package/src/component/schema.ts +68 -63
- package/src/providers/sso.ts +1 -1
- package/src/server/auth.ts +413 -18
- package/src/server/cookies.ts +3 -0
- package/src/server/db.ts +3 -0
- package/src/server/device.ts +3 -1
- package/src/server/domains/core.ts +1071 -0
- package/src/server/domains/sso.ts +1749 -0
- package/src/server/enterpriseValidators.ts +93 -0
- package/src/server/factory.ts +2181 -0
- package/src/server/fx.ts +1 -0
- package/src/server/http.ts +529 -0
- package/src/server/identity.ts +18 -0
- package/src/server/index.ts +806 -40
- package/src/server/keys.ts +4 -0
- package/src/server/mutations/index.ts +1 -1
- package/src/server/mutations/oauth.ts +36 -8
- package/src/server/mutations/store.ts +6 -3
- package/src/server/oauth.ts +6 -0
- package/src/server/passkey.ts +3 -2
- package/src/server/provider.ts +2 -0
- package/src/server/providers.ts +20 -0
- package/src/server/ratelimit.ts +3 -0
- package/src/server/redirects.ts +2 -0
- package/src/server/refresh.ts +5 -0
- package/src/server/sessions.ts +5 -0
- package/src/server/signin.ts +1 -0
- package/src/server/sso.ts +259 -17
- package/src/server/templates.ts +1 -0
- package/src/server/tokens.ts +1 -0
- package/src/server/totp.ts +4 -2
- package/src/server/types.ts +178 -83
- package/src/server/users.ts +1 -0
- package/src/server/utils.ts +71 -1
- package/src/server/version.ts +1 -1
- package/dist/component/public.js.map +0 -1
- package/dist/component/server/implementation.d.ts +0 -1264
- package/dist/component/server/implementation.d.ts.map +0 -1
- package/dist/component/server/implementation.js +0 -2365
- package/dist/component/server/implementation.js.map +0 -1
- package/dist/server/cookies.d.ts.map +0 -1
- package/dist/server/db.d.ts.map +0 -1
- package/dist/server/device.d.ts.map +0 -1
- package/dist/server/implementation.d.ts +0 -1264
- package/dist/server/implementation.d.ts.map +0 -1
- package/dist/server/implementation.js +0 -2365
- package/dist/server/implementation.js.map +0 -1
- package/dist/server/keys.d.ts.map +0 -1
- package/dist/server/oauth.d.ts.map +0 -1
- package/dist/server/ratelimit.d.ts.map +0 -1
- package/dist/server/redirects.d.ts.map +0 -1
- package/dist/server/refresh.d.ts.map +0 -1
- package/dist/server/sessions.d.ts.map +0 -1
- package/dist/server/signin.d.ts.map +0 -1
- package/dist/server/sso.d.ts.map +0 -1
- package/dist/server/templates.d.ts.map +0 -1
- package/dist/server/tokens.d.ts.map +0 -1
- package/dist/server/totp.d.ts.map +0 -1
- package/dist/server/users.d.ts.map +0 -1
- package/dist/server/utils.d.ts.map +0 -1
- package/src/server/implementation.ts +0 -5336
package/dist/client/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":["url","key","options","result"],"sources":["../../src/client/index.ts"],"sourcesContent":["import { Fx } from \"@robelest/fx\";\nimport { ConvexHttpClient } from \"convex/browser\";\nimport type { FunctionReference } from \"convex/server\";\nimport { ConvexError, Value } from \"convex/values\";\n\nimport { AUTH_ERRORS } from \"../server/errors\";\n\n// Re-export error utilities so consumers can import from `@robelest/convex-auth/client`.\nexport {\n isAuthError,\n parseAuthError,\n AUTH_ERRORS,\n type AuthErrorCode,\n} from \"../server/errors\";\n\n/**\n * Structural interface for any Convex client.\n * Satisfied by `ConvexClient` (`convex/browser`),\n * `ConvexReactClient` (`convex/react`), and similar transports.\n *\n * `clearAuth` is present on `ConvexReactClient` and `BaseConvexClient`\n * but not on the simplified `ConvexClient`. When available we call it\n * during sign-out for a clean deauthentication.\n */\ninterface ConvexTransport {\n action(action: any, args: any): Promise<any>;\n setAuth(\n fetchToken: (args: {\n forceRefreshToken: boolean;\n }) => Promise<string | null | undefined>,\n onChange?: (isAuthenticated: boolean) => void,\n ): void;\n clearAuth?(): void;\n}\n\n/** Pluggable key-value storage (defaults to `localStorage`). */\nexport interface Storage {\n getItem(\n key: string,\n ): string | null | undefined | Promise<string | null | undefined>;\n setItem(key: string, value: string): void | Promise<void>;\n removeItem(key: string): void | Promise<void>;\n}\n\ntype AuthSession = {\n token: string;\n refreshToken: string;\n};\n\ntype SignInActionResult =\n | { kind: \"signedIn\"; tokens: AuthSession | null }\n | { kind: \"redirect\"; redirect: string; verifier: string }\n | { kind: \"started\" }\n | { kind: \"passkeyOptions\"; options: Record<string, any>; verifier: string }\n | { kind: \"totpRequired\"; verifier: string }\n | {\n kind: \"totpSetup\";\n totpSetup: { uri: string; secret: string; totpId: string };\n verifier: string;\n }\n | {\n kind: \"deviceCode\";\n deviceCode: {\n deviceCode: string;\n userCode: string;\n verificationUri: string;\n verificationUriComplete: string;\n expiresIn: number;\n interval: number;\n };\n };\n\n/**\n * Device code response returned when signing in with the `\"device\"` provider.\n *\n * The device displays the `userCode` (or `verification_uri_complete`) and\n * polls via `auth.device.poll()` until the user authorizes.\n */\nexport type DeviceCodeResult = {\n /** High-entropy device code used for polling (keep secret). */\n deviceCode: string;\n /** Short human-readable code the user enters (e.g. \"WDJB-MJHT\"). */\n userCode: string;\n /** Base verification URL (e.g. \"https://myapp.com/device\"). */\n verification_uri: string;\n /** Verification URL with user code pre-filled as `?code=XXXX-XXXX`. */\n verification_uri_complete: string;\n /** Lifetime of the codes in seconds. */\n expiresIn: number;\n /** Minimum polling interval in seconds. */\n interval: number;\n};\n\n/**\n * Result of a `signIn` call.\n *\n * - `kind: \"signedIn\"` — credentials were accepted and the user is authenticated.\n * - `kind: \"redirect\"` — OAuth flow initiated; redirect the user to `redirect.toString()`.\n * - `kind: \"totpRequired\"` — credentials valid but 2FA is needed; call `auth.totp.verify()`.\n * - `kind: \"deviceCode\"` — device flow initiated; display the code and poll via `auth.device.poll()`.\n * - `kind: \"started\"` — a non-immediate flow started (for example email/phone verification).\n */\nexport type SignInResult =\n | { kind: \"signedIn\" }\n | { kind: \"redirect\"; redirect: URL; verifier: string }\n | { kind: \"totpRequired\"; verifier: string }\n | { kind: \"deviceCode\"; deviceCode: DeviceCodeResult }\n | { kind: \"started\" };\n\n/** Reactive auth state snapshot returned by `auth.state` and `auth.onChange`. */\nexport type AuthState = {\n /** High-level auth phase for deterministic UI state handling. */\n phase: \"loading\" | \"handshake\" | \"authenticated\" | \"unauthenticated\";\n /** `true` during initial hydration before the first token is resolved. */\n isLoading: boolean;\n /** `true` only after Convex confirms authentication with the backend. */\n isAuthenticated: boolean;\n /** The raw JWT string, or `null` when not authenticated. */\n token: string | null;\n};\n\n/**\n * Typed Convex API references for the auth functions.\n * Pass these from your generated `api` object.\n */\nexport type AuthApiRefs<\n HasPasskey extends boolean = boolean,\n HasTotp extends boolean = boolean,\n HasDevice extends boolean = boolean,\n> = {\n session: {\n start: FunctionReference<\"action\", \"public\", any, any>;\n stop: FunctionReference<\"action\", \"public\", any, any>;\n };\n store: {\n run: FunctionReference<\"mutation\", \"public\", any, any>;\n };\n /** @internal Set automatically by `createAuth` — do not set manually. */\n _capabilities?: {\n passkey: HasPasskey;\n totp: HasTotp;\n device: HasDevice;\n };\n};\n\n/** Passkey (WebAuthn) client-side helpers. */\nexport interface PasskeyClient {\n isSupported(): boolean;\n isAutofillSupported(): Promise<boolean>;\n register(opts?: Record<string, any>): Promise<SignInResult>;\n authenticate(opts?: Record<string, any>): Promise<SignInResult>;\n}\n\n/** TOTP two-factor authentication client-side helpers. */\nexport interface TotpClient {\n setup(opts?: Record<string, any>): Promise<Record<string, any>>;\n confirm(opts: Record<string, any>): Promise<void>;\n verify(opts: Record<string, any>): Promise<void>;\n}\n\n/** Device authorization (RFC 8628) client-side helpers. */\nexport interface DeviceClient {\n poll(code: any): Promise<void>;\n verify(userCode: string): Promise<void>;\n}\n\n/** Extract capability flags from an AuthApiRefs type. */\ntype InferCaps<Api extends AuthApiRefs<boolean, boolean, boolean>> =\n Api extends AuthApiRefs<infer P, infer T, infer D>\n ? { passkey: P; totp: T; device: D }\n : { passkey: boolean; totp: boolean; device: boolean };\n\n/** Base auth client — always present. */\nexport interface AuthClientBase {\n readonly state: AuthState;\n signIn: (\n provider: string,\n params?: Record<string, any>,\n ) => Promise<SignInResult>;\n signOut: () => Promise<void>;\n onChange: (callback: () => void) => () => void;\n destroy: () => void;\n}\n\n/**\n * Auth client return type — conditionally includes `passkey`, `totp`, and\n * `device` helpers based on the capabilities in the `AuthApiRefs` type.\n */\nexport type AuthClient<\n Api extends AuthApiRefs<boolean, boolean, boolean> = AuthApiRefs,\n> = AuthClientBase &\n (InferCaps<Api>[\"passkey\"] extends true ? { passkey: PasskeyClient } : {}) &\n (InferCaps<Api>[\"totp\"] extends true ? { totp: TotpClient } : {}) &\n (InferCaps<Api>[\"device\"] extends true ? { device: DeviceClient } : {});\n\n/** Options for {@link client}. */\nexport type ClientOptions = {\n /** Any Convex client (`ConvexClient` or `ConvexReactClient`). */\n convex: ConvexTransport;\n /**\n * Typed Convex API references for the auth functions.\n * Required in SPA mode. Optional when `proxyPath` is set (proxy mode\n * routes through the SSR proxy instead of calling Convex directly).\n *\n * ```ts\n * import { api } from \"../convex/_generated/api\";\n * client({\n * convex,\n * api: { session: api.auth.session, store: api.auth.store },\n * });\n * ```\n */\n api?: AuthApiRefs<boolean, boolean, boolean>;\n /**\n * Convex deployment URL. Derived automatically from the client internals\n * when omitted — pass explicitly only if auto-detection fails.\n */\n url?: string;\n /**\n * Key-value storage for persisting tokens.\n *\n * - Defaults to `localStorage` in SPA mode.\n * - Defaults to `null` (in-memory only) when `proxyPath` is set,\n * since httpOnly cookies handle persistence.\n */\n storage?: Storage | null;\n /** Override how the URL bar is updated after OAuth code exchange. */\n replaceUrl?: (relativeUrl: string) => void | Promise<void>;\n /**\n * SSR proxy endpoint (e.g. `\"/api/auth\"`).\n *\n * When set, `signIn`/`signOut`/token refresh POST to this URL\n * (with `credentials: \"include\"`) instead of calling Convex directly.\n * The server handles httpOnly cookies for token persistence.\n *\n * Pair with {@link ClientOptions.tokenSeed} for flash-free SSR hydration.\n */\n proxyPath?: string;\n /**\n * JWT from server-side hydration.\n *\n * In proxy mode the server reads the JWT from an httpOnly cookie\n * and passes it to the client during SSR. This avoids a loading\n * flash on first render — the client is immediately authenticated.\n */\n tokenSeed?: string | null;\n};\n\nconst VERIFIER_STORAGE_KEY = \"__convexAuthOAuthVerifier\";\nconst JWT_STORAGE_KEY = \"__convexAuthJWT\";\nconst REFRESH_TOKEN_STORAGE_KEY = \"__convexAuthRefreshToken\";\n\nconst RETRY_BASE_MS = 500;\nconst RETRY_MAX_RETRIES = 2;\nconst AUTH_HANDSHAKE_TIMEOUT_MS = 5000;\nconst NETWORK_ERROR_PATTERN = /(network|fetch|load failed|failed to fetch)/i;\n\ntype AuthHandshakeErrorCode =\n | \"AUTH_HANDSHAKE_TIMEOUT\"\n | \"AUTH_HANDSHAKE_REJECTED\";\n\ntype AuthFlowContext = {\n provider?: string;\n flow: string;\n};\n\ntype HandshakeWaiter = {\n epoch: number;\n context: AuthFlowContext;\n resolve: () => void;\n reject: (error: ConvexError<Value>) => void;\n timeoutId: ReturnType<typeof setTimeout>;\n};\n\n/**\n * Resolve the Convex deployment URL from the client.\n *\n * `ConvexReactClient` exposes `.url` directly.\n * `ConvexClient` exposes `.client.url` via `BaseConvexClient`.\n */\nfunction resolveUrl(convex: ConvexTransport, explicit?: string): string {\n if (explicit) return explicit;\n const c = convex as any;\n const url: unknown = c.url ?? c.client?.url;\n if (typeof url === \"string\") return url;\n throw new Error(\n \"Could not determine Convex deployment URL. Pass `url` explicitly.\",\n );\n}\n\nfunction isTransientNetworkError(error: unknown): boolean {\n return (\n error instanceof TypeError ||\n (error instanceof Error && NETWORK_ERROR_PATTERN.test(error.message || \"\"))\n );\n}\n\nfunction isRetriableProxyRefreshError(error: unknown): boolean {\n if (isTransientNetworkError(error)) {\n return true;\n }\n if (!(error instanceof Error)) {\n return false;\n }\n const statusMatch = error.message.match(/Proxy request failed:\\s*(\\d{3})/);\n if (statusMatch === null) {\n return false;\n }\n const statusCode = Number(statusMatch[1]);\n return statusCode >= 500 && statusCode < 600;\n}\n\n/**\n * Create a framework-agnostic auth client.\n *\n * Returns an object with `signIn`, `signOut`, `onChange`, `state`,\n * `passkey`, and `totp` — everything needed for client-side auth.\n *\n * ### SPA mode (default)\n *\n * ```ts\n * import { ConvexClient } from 'convex/browser';\n * import { client } from '@robelest/convex-auth/client';\n *\n * const convex = new ConvexClient(CONVEX_URL);\n * const auth = client({ convex });\n * ```\n *\n * ### SSR / proxy mode\n *\n * ```ts\n * const auth = client({\n * convex,\n * proxyPath: '/api/auth',\n * tokenSeed: tokenFromServer, // JWT read from httpOnly cookie during SSR\n * });\n * ```\n *\n * In proxy mode all auth operations go through the proxy URL.\n * Tokens are stored in httpOnly cookies server-side — the client\n * holds the JWT in memory only.\n *\n * @param options - Client configuration. See {@link ClientOptions}.\n * @returns Auth client with conditional `passkey`, `totp`, and `device` helpers.\n */\nexport function client<\n Api extends AuthApiRefs<boolean, boolean, boolean> = AuthApiRefs,\n>(options: ClientOptions): AuthClient<Api> {\n const { convex, proxyPath, api: apiRefs } = options;\n const proxy = proxyPath;\n\n function requireApiRefs() {\n if (!apiRefs) {\n throw new Error(\n \"The `api` option is required when `proxyPath` is not set. \" +\n \"Pass { api: { session: api.auth.session, store: api.auth.store } }.\",\n );\n }\n return apiRefs;\n }\n\n // In proxy mode, default storage to null (cookies handle persistence).\n const storage =\n options.storage !== undefined\n ? options.storage\n : proxy\n ? null\n : typeof window === \"undefined\"\n ? null\n : window.localStorage;\n\n const replaceUrl =\n options.replaceUrl ??\n ((url: string) => {\n if (typeof window !== \"undefined\") {\n window.history.replaceState({}, \"\", url);\n }\n });\n\n const url = proxy ? undefined : resolveUrl(convex, options.url);\n const escapedNamespace = proxy\n ? proxy.replace(/[^a-zA-Z0-9]/g, \"\")\n : url!.replace(/[^a-zA-Z0-9]/g, \"\");\n const key = (name: string) => `${name}_${escapedNamespace}`;\n const subscribers = new Set<() => void>();\n let disposeStorageListener: (() => void) | null = null;\n\n // Unauthenticated HTTP client for code verification & OAuth exchange.\n // Only needed in SPA mode — proxy mode routes everything through the proxy.\n const httpClient = proxy ? null : new ConvexHttpClient(url!);\n\n // ---------------------------------------------------------------------------\n // State\n // ---------------------------------------------------------------------------\n\n // If a server-provided token was supplied (SSR hydration), treat it as\n // immediately authenticated to avoid a handshake-only loading screen.\n const serverToken =\n typeof options.tokenSeed === \"string\" && options.tokenSeed.trim().length > 0\n ? options.tokenSeed\n : null;\n const hasServerToken = serverToken !== null;\n\n let token: string | null = serverToken;\n let isLoading = !hasServerToken;\n let authConfirmed = hasServerToken;\n let handshakePending = false;\n let authEpoch = 0;\n let destroyed = false;\n const handshakeWaiters = new Set<HandshakeWaiter>();\n let snapshot: AuthState = {\n phase: hasServerToken\n ? \"authenticated\"\n : isLoading\n ? \"loading\"\n : \"unauthenticated\",\n isLoading,\n isAuthenticated: hasServerToken,\n token,\n };\n let handlingCodeFlow = false;\n\n const createHandshakeError = (\n code: AuthHandshakeErrorCode,\n context: Record<string, unknown>,\n ) => {\n return new ConvexError({\n code,\n message: AUTH_ERRORS[code],\n ...context,\n } as Value);\n };\n\n const settleHandshakeWaiters = (\n epoch: number,\n outcome:\n | { type: \"resolve\" }\n | { type: \"reject\"; error: ConvexError<Value> },\n ) => {\n for (const waiter of Array.from(handshakeWaiters)) {\n if (waiter.epoch !== epoch) {\n continue;\n }\n clearTimeout(waiter.timeoutId);\n handshakeWaiters.delete(waiter);\n if (outcome.type === \"resolve\") {\n waiter.resolve();\n } else {\n waiter.reject(outcome.error);\n }\n }\n };\n\n const rejectObsoleteHandshakeWaiters = (activeEpoch: number) => {\n for (const waiter of Array.from(handshakeWaiters)) {\n if (waiter.epoch >= activeEpoch) {\n continue;\n }\n clearTimeout(waiter.timeoutId);\n handshakeWaiters.delete(waiter);\n waiter.reject(\n createHandshakeError(\"AUTH_HANDSHAKE_REJECTED\", {\n ...waiter.context,\n reason: \"token_changed\",\n }),\n );\n }\n };\n\n const waitForAuthHandshake = async (context: AuthFlowContext) => {\n if (token === null) {\n return;\n }\n if (authConfirmed && !handshakePending) {\n return;\n }\n if (!handshakePending) {\n throw createHandshakeError(\"AUTH_HANDSHAKE_REJECTED\", {\n ...context,\n reason: \"auth_rejected\",\n });\n }\n\n const epoch = authEpoch;\n await new Promise<void>((resolve, reject) => {\n const waiterRef: { current: HandshakeWaiter | null } = { current: null };\n const timeoutId = setTimeout(() => {\n if (waiterRef.current !== null) {\n handshakeWaiters.delete(waiterRef.current);\n }\n reject(\n createHandshakeError(\"AUTH_HANDSHAKE_TIMEOUT\", {\n ...context,\n timeoutMs: AUTH_HANDSHAKE_TIMEOUT_MS,\n }),\n );\n }, AUTH_HANDSHAKE_TIMEOUT_MS);\n\n const waiter: HandshakeWaiter = {\n epoch,\n context,\n resolve,\n reject,\n timeoutId,\n };\n waiterRef.current = waiter;\n handshakeWaiters.add(waiter);\n });\n };\n\n const handleConvexAuthChange = (isAuthenticated: boolean) => {\n if (destroyed) {\n return;\n }\n\n if (isAuthenticated) {\n authConfirmed = true;\n handshakePending = false;\n settleHandshakeWaiters(authEpoch, { type: \"resolve\" });\n } else {\n authConfirmed = false;\n // Do not reject immediately while a handshake is pending.\n // Convex can transiently emit `false` while reauth is still in flight,\n // and a subsequent `true` confirms the same session.\n }\n\n if (updateSnapshot()) {\n notify();\n }\n };\n\n const notify = () => {\n for (const cb of subscribers) cb();\n };\n\n const updateSnapshot = () => {\n const phaseDispatch = {\n tag:\n token !== null && handshakePending\n ? \"handshake\"\n : isLoading\n ? \"loading\"\n : token !== null && authConfirmed\n ? \"authenticated\"\n : \"unauthenticated\",\n } as const;\n\n const phase = {\n handshake: \"handshake\",\n loading: \"loading\",\n authenticated: \"authenticated\",\n unauthenticated: \"unauthenticated\",\n }[phaseDispatch.tag] as AuthState[\"phase\"];\n\n const next: AuthState = {\n phase,\n isLoading: phase === \"loading\" || phase === \"handshake\",\n isAuthenticated: phase === \"authenticated\",\n token,\n };\n if (\n snapshot.phase === next.phase &&\n snapshot.isLoading === next.isLoading &&\n snapshot.isAuthenticated === next.isAuthenticated &&\n snapshot.token === next.token\n ) {\n return false;\n }\n snapshot = next;\n return true;\n };\n\n const finalizeLoadingState = () => {\n if (!isLoading) {\n return;\n }\n isLoading = false;\n if (updateSnapshot()) {\n notify();\n }\n };\n\n // ---------------------------------------------------------------------------\n // Storage helpers (SPA mode only)\n // ---------------------------------------------------------------------------\n\n const storageGet = async (name: string): Promise<string | null> => {\n if (!storage) {\n return null;\n }\n return Fx.run(\n Fx.from({\n ok: async () => (await storage.getItem(key(name))) ?? null,\n err: (e) => e,\n }).pipe(\n Fx.inspect((error) =>\n Fx.sync(() =>\n console.error(\n `[convex-auth] Failed to read ${name} from storage:`,\n error,\n ),\n ),\n ),\n Fx.recover(() => Fx.succeed(null)),\n ),\n );\n };\n\n const storageSet = async (name: string, value: string): Promise<void> => {\n if (!storage) {\n return;\n }\n await Fx.run(\n Fx.from({\n ok: () => storage.setItem(key(name), value),\n err: (e) => e,\n }).pipe(\n Fx.inspect((error) =>\n Fx.sync(() =>\n console.error(\n `[convex-auth] Failed to write ${name} to storage:`,\n error,\n ),\n ),\n ),\n Fx.recover(() => Fx.succeed(undefined)),\n ),\n );\n };\n\n const storageRemove = async (name: string): Promise<void> => {\n if (!storage) {\n return;\n }\n await Fx.run(\n Fx.from({\n ok: () => storage.removeItem(key(name)),\n err: (e) => e,\n }).pipe(\n Fx.inspect((error) =>\n Fx.sync(() =>\n console.error(\n `[convex-auth] Failed to remove ${name} from storage:`,\n error,\n ),\n ),\n ),\n Fx.recover(() => Fx.succeed(undefined)),\n ),\n );\n };\n\n // ---------------------------------------------------------------------------\n // Token management\n // ---------------------------------------------------------------------------\n\n const bindConvexAuth = () => {\n convex.setAuth(fetchAccessToken, handleConvexAuthChange);\n };\n\n const setToken = async (\n args:\n | {\n shouldStore: true;\n tokens: AuthSession | null;\n requireHandshake?: boolean;\n resyncConvexAuth?: boolean;\n }\n | {\n shouldStore: false;\n tokens: { token: string } | null;\n requireHandshake?: boolean;\n resyncConvexAuth?: boolean;\n },\n ) => {\n const previousToken = token;\n\n if (args.tokens === null) {\n token = null;\n if (args.shouldStore) {\n await storageRemove(JWT_STORAGE_KEY);\n await storageRemove(REFRESH_TOKEN_STORAGE_KEY);\n }\n } else {\n token = args.tokens.token;\n if (args.shouldStore && \"refreshToken\" in args.tokens) {\n await storageSet(JWT_STORAGE_KEY, args.tokens.token);\n await storageSet(REFRESH_TOKEN_STORAGE_KEY, args.tokens.refreshToken);\n }\n }\n\n if (token !== previousToken) {\n authEpoch += 1;\n rejectObsoleteHandshakeWaiters(authEpoch);\n }\n\n if (token === null) {\n authConfirmed = false;\n handshakePending = false;\n settleHandshakeWaiters(authEpoch, {\n type: \"reject\",\n error: createHandshakeError(\"AUTH_HANDSHAKE_REJECTED\", {\n reason: \"token_cleared\",\n }),\n });\n } else {\n const shouldEnterHandshake =\n args.requireHandshake === true || !authConfirmed;\n if (shouldEnterHandshake) {\n authConfirmed = false;\n handshakePending = true;\n } else {\n handshakePending = false;\n }\n }\n\n const hadPendingLoad = isLoading;\n isLoading = false;\n const changed = updateSnapshot();\n if (args.resyncConvexAuth !== false) {\n bindConvexAuth();\n }\n if (hadPendingLoad || changed) {\n notify();\n }\n };\n\n const setTokenAndMaybeWait = async (\n args:\n | {\n shouldStore: true;\n tokens: AuthSession | null;\n waitForHandshake: boolean;\n context: AuthFlowContext;\n }\n | {\n shouldStore: false;\n tokens: { token: string } | null;\n waitForHandshake: boolean;\n context: AuthFlowContext;\n },\n ): Promise<boolean> => {\n const { waitForHandshake, context, ...tokenArgs } = args;\n await setToken({\n ...(tokenArgs as\n | { shouldStore: true; tokens: AuthSession | null }\n | { shouldStore: false; tokens: { token: string } | null }),\n requireHandshake: waitForHandshake,\n });\n if (tokenArgs.tokens === null) {\n return false;\n }\n if (waitForHandshake) {\n await waitForAuthHandshake(context);\n }\n return true;\n };\n\n // ---------------------------------------------------------------------------\n // Proxy fetch helper\n // ---------------------------------------------------------------------------\n\n const resolveProxyUrl = () => {\n const origin =\n typeof window !== \"undefined\" &&\n typeof window.location?.origin === \"string\"\n ? window.location.origin\n : typeof location !== \"undefined\" && typeof location.origin === \"string\"\n ? location.origin\n : null;\n if (origin !== null) {\n return new URL(proxy!, origin).toString();\n }\n return Fx.run(\n Fx.from({\n ok: () => new URL(proxy!).toString(),\n err: () => proxy! as string,\n }).pipe(Fx.recover((fallback) => Fx.succeed(fallback))),\n );\n };\n\n const isAbsoluteUrl = (value: string) => {\n return Fx.run(\n Fx.from({\n ok: () => {\n new URL(value);\n return true;\n },\n err: () => false as const,\n }).pipe(Fx.recover((v) => Fx.succeed(v))),\n );\n };\n\n const proxyFetch = async (body: Record<string, unknown>) => {\n const proxyUrl = await resolveProxyUrl();\n if (typeof window === \"undefined\" && !(await isAbsoluteUrl(proxyUrl))) {\n throw new Error(\n `Cannot call relative proxy URL \\`${proxy!}\\` without a browser origin. ` +\n \"Pass an absolute proxy URL for server runtimes.\",\n );\n }\n\n const response = await fetch(proxyUrl, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n credentials: \"include\",\n body: JSON.stringify(body),\n });\n if (!response.ok) {\n const errorBody = await Fx.run(\n Fx.from({\n ok: () => response.json() as Promise<Record<string, unknown>>,\n err: () => ({}) as Record<string, unknown>,\n }).pipe(Fx.recover((fallback) => Fx.succeed(fallback))),\n );\n // Reconstruct ConvexError when the proxy forwards structured auth error data.\n if (\n typeof errorBody === \"object\" &&\n errorBody !== null &&\n \"authError\" in errorBody &&\n typeof (errorBody as Record<string, unknown>).authError === \"object\"\n ) {\n throw new ConvexError(\n (errorBody as Record<string, unknown>).authError as Value,\n );\n }\n throw new Error(\n ((errorBody as Record<string, unknown>).error as string) ??\n `Proxy request failed: ${response.status}`,\n );\n }\n return Fx.run(\n Fx.from({\n ok: () => response.json(),\n err: () => new Error(\"Proxy response was not valid JSON\"),\n }).pipe(Fx.recover((e) => Fx.fatal(e))),\n );\n };\n\n // ---------------------------------------------------------------------------\n // Code verification with retries (SPA mode only)\n // ---------------------------------------------------------------------------\n\n const verifyCode = async (\n args: { code: string; verifier?: string } | { refreshToken: string },\n ) => {\n const verifyCodeRetryPolicy = Fx.retry.while(\n Fx.retry.compose(\n Fx.retry.jittered(Fx.retry.exponential(RETRY_BASE_MS)),\n Fx.retry.recurs(RETRY_MAX_RETRIES),\n ),\n (meta) => isTransientNetworkError(meta.input),\n );\n\n return Fx.run(\n Fx.from({\n ok: () =>\n httpClient!.action(\n requireApiRefs().session.start,\n \"code\" in args\n ? { params: { code: args.code }, verifier: args.verifier }\n : args,\n ),\n err: (e) => e,\n }).pipe(\n Fx.retry(verifyCodeRetryPolicy),\n Fx.recover((e) => Fx.fatal(e)),\n ),\n );\n };\n\n const verifyCodeAndSetToken = async (\n args: { code: string; verifier?: string } | { refreshToken: string },\n opts?: { resyncConvexAuth?: boolean },\n ) => {\n const { tokens } = await verifyCode(args);\n await setToken({\n shouldStore: true,\n tokens: (tokens as AuthSession | null) ?? null,\n resyncConvexAuth: opts?.resyncConvexAuth,\n });\n return tokens !== null;\n };\n\n const normalizeDeviceCodeResult = (device_code: any): DeviceCodeResult => {\n return {\n deviceCode: device_code.deviceCode,\n userCode: device_code.userCode,\n verification_uri:\n device_code.verification_uri ?? device_code.verificationUri,\n verification_uri_complete:\n device_code.verification_uri_complete ??\n device_code.verificationUriComplete,\n expiresIn: device_code.expiresIn,\n interval: device_code.interval,\n };\n };\n\n // ---------------------------------------------------------------------------\n // signIn\n // ---------------------------------------------------------------------------\n\n /**\n * Sign in with a provider.\n *\n * @param provider - Provider ID (e.g. `\"email\"`, `\"password\"`, `\"google\"`).\n * Omit when exchanging an OAuth code (the code carries the provider info).\n * @param args - Provider-specific arguments. Pass a `Record<string, Value>`\n * or `FormData`. Common fields: `email`, `password`, `code`, `redirectTo`.\n * @returns A {@link SignInResult} indicating the outcome.\n *\n * @example Email magic link\n * ```ts\n * await auth.signIn('email', { email: 'user@example.com' });\n * ```\n *\n * @example Password\n * ```ts\n * const result = await auth.signIn('password', { email, password, flow: 'signIn' });\n * if (result.kind === 'totpRequired') {\n * await auth.totp.verify({ code: totpCode, verifier: result.verifier });\n * }\n * ```\n *\n * @example OAuth (triggers redirect)\n * ```ts\n * await auth.signIn('google'); // redirects to Google\n * ```\n */\n const signIn = async (\n provider?: string,\n args?: FormData | Record<string, Value>,\n ): Promise<SignInResult> => {\n const params =\n args instanceof FormData\n ? (() => {\n const formParams: Record<string, Value> = {};\n args.forEach((value, key) => {\n formParams[key] = typeof value === \"string\" ? value : value.name;\n });\n return formParams;\n })()\n : (args ?? {});\n const flow =\n typeof params.flow === \"string\" && params.flow.length > 0\n ? params.flow\n : \"signIn\";\n\n const handleSignInActionResult = async (\n result: SignInActionResult,\n options: { shouldStore: boolean; persistVerifier: boolean },\n ): Promise<SignInResult> =>\n Fx.run(\n Fx.match(result, result.kind, {\n redirect: (redirectResult) =>\n Fx.from({\n ok: async () => {\n const redirectUrl = new URL(redirectResult.redirect);\n if (options.persistVerifier) {\n await storageSet(\n VERIFIER_STORAGE_KEY,\n redirectResult.verifier,\n );\n }\n if (typeof window !== \"undefined\") {\n window.location.href = redirectUrl.toString();\n }\n return {\n kind: \"redirect\" as const,\n redirect: redirectUrl,\n verifier: redirectResult.verifier,\n };\n },\n err: (e) => e as never,\n }),\n totpRequired: (totpRequiredResult) =>\n Fx.succeed({\n kind: \"totpRequired\" as const,\n verifier: totpRequiredResult.verifier,\n }),\n deviceCode: (deviceCodeResult) =>\n Fx.succeed({\n kind: \"deviceCode\" as const,\n deviceCode: normalizeDeviceCodeResult(\n deviceCodeResult.deviceCode,\n ),\n }),\n signedIn: (signedInResult) =>\n Fx.from({\n ok: async () => {\n const signingIn = await setTokenAndMaybeWait(\n options.shouldStore\n ? {\n shouldStore: true as const,\n tokens: signedInResult.tokens,\n waitForHandshake: true,\n context: { provider, flow },\n }\n : {\n shouldStore: false as const,\n tokens:\n signedInResult.tokens === null\n ? null\n : { token: signedInResult.tokens.token },\n waitForHandshake: true,\n context: { provider, flow },\n },\n );\n return signingIn\n ? ({ kind: \"signedIn\" as const } as SignInResult)\n : ({ kind: \"started\" as const } as SignInResult);\n },\n err: (e) => e as never,\n }),\n started: (_startedResult) => Fx.succeed({ kind: \"started\" as const }),\n passkeyOptions: (_passkeyOptionsResult) =>\n Fx.succeed({ kind: \"started\" as const }),\n totpSetup: (_totpSetupResult) =>\n Fx.succeed({ kind: \"started\" as const }),\n }),\n );\n\n if (proxy) {\n const result = (await proxyFetch({\n action: \"auth/session:start\",\n args: { provider, params },\n })) as SignInActionResult;\n return handleSignInActionResult(result, {\n shouldStore: false,\n persistVerifier: false,\n });\n }\n\n // SPA mode: call Convex directly.\n const verifier = (await storageGet(VERIFIER_STORAGE_KEY)) ?? undefined;\n await storageRemove(VERIFIER_STORAGE_KEY);\n const result = (await convex.action(requireApiRefs().session.start, {\n provider,\n params,\n verifier,\n })) as SignInActionResult;\n return handleSignInActionResult(result, {\n shouldStore: true,\n persistVerifier: true,\n });\n };\n\n // ---------------------------------------------------------------------------\n // signOut\n // ---------------------------------------------------------------------------\n\n /**\n * Sign out the current user.\n *\n * Invalidates the server session and clears local token state.\n * Errors are silently caught — calling `signOut` on an already\n * signed-out user is a no-op.\n */\n const signOut = async () => {\n if (proxy) {\n await Fx.run(\n Fx.from({\n ok: () => proxyFetch({ action: \"auth/session:stop\", args: {} }),\n err: () => undefined,\n }).pipe(Fx.recover(() => Fx.succeed(undefined))),\n );\n await setToken({ shouldStore: false, tokens: null });\n if (convex.clearAuth) convex.clearAuth();\n return;\n }\n\n // SPA mode.\n await Fx.run(\n Fx.from({\n ok: () => convex.action(requireApiRefs().session.stop, {}),\n err: () => undefined,\n }).pipe(Fx.recover(() => Fx.succeed(undefined))),\n );\n await setToken({ shouldStore: true, tokens: null });\n if (convex.clearAuth) convex.clearAuth();\n };\n\n // ---------------------------------------------------------------------------\n // fetchAccessToken — called by convex.setAuth()\n // ---------------------------------------------------------------------------\n\n const fetchAccessToken = async ({\n forceRefreshToken,\n }: {\n forceRefreshToken: boolean;\n }): Promise<string | null> => {\n if (!forceRefreshToken) return token;\n\n if (proxy) {\n // Proxy mode: POST to the proxy to refresh.\n // The proxy reads the real refresh token from the httpOnly cookie.\n const resolvedProxyUrl = await resolveProxyUrl();\n if (\n typeof window === \"undefined\" &&\n !(await isAbsoluteUrl(resolvedProxyUrl))\n ) {\n finalizeLoadingState();\n return token;\n }\n\n const tokenBeforeRefresh = token;\n return await browserMutex(\"__convexAuthProxyRefresh\", async () => {\n // Another tab/call may have already refreshed.\n if (token !== tokenBeforeRefresh) return token;\n\n const proxyRefreshRetryPolicy = Fx.retry.while(\n Fx.retry.compose(\n Fx.retry.jittered(Fx.retry.exponential(RETRY_BASE_MS)),\n Fx.retry.recurs(RETRY_MAX_RETRIES),\n ),\n (meta) => isRetriableProxyRefreshError(meta.input),\n );\n\n await Fx.run(\n Fx.from({\n ok: () =>\n proxyFetch({\n action: \"auth/session:start\",\n args: { refreshToken: true },\n }),\n err: (e) => e,\n }).pipe(\n Fx.retry(proxyRefreshRetryPolicy),\n Fx.chain((result: any) =>\n Fx.from({\n ok: async () => {\n if (result.tokens) {\n await setToken({\n shouldStore: false,\n tokens: { token: result.tokens.token },\n resyncConvexAuth: false,\n });\n } else {\n await setToken({\n shouldStore: false,\n tokens: null,\n resyncConvexAuth: false,\n });\n }\n },\n err: (e) => e,\n }),\n ),\n Fx.inspect((error) =>\n Fx.sync(() =>\n console.error(\"[convex-auth] Proxy refresh failed:\", error),\n ),\n ),\n Fx.recover(() => {\n if (token === null) {\n finalizeLoadingState();\n }\n return Fx.succeed(undefined);\n }),\n ),\n );\n return token;\n });\n }\n\n // SPA mode: refresh via localStorage + httpClient.\n const tokenBeforeLockAcquisition = token;\n return await browserMutex(REFRESH_TOKEN_STORAGE_KEY, async () => {\n const tokenAfterLockAcquisition = token;\n if (tokenAfterLockAcquisition !== tokenBeforeLockAcquisition) {\n return tokenAfterLockAcquisition;\n }\n const refreshToken =\n (await storageGet(REFRESH_TOKEN_STORAGE_KEY)) ?? null;\n if (!refreshToken) {\n finalizeLoadingState();\n return null;\n }\n await verifyCodeAndSetToken(\n { refreshToken },\n { resyncConvexAuth: false },\n );\n return token;\n });\n };\n\n // ---------------------------------------------------------------------------\n // OAuth code flow (SPA mode only — server handles this in proxy mode)\n // ---------------------------------------------------------------------------\n\n const handleCodeFlow = async () => {\n if (typeof window === \"undefined\") return;\n if (handlingCodeFlow) return;\n const code = new URLSearchParams(window.location.search).get(\"code\");\n if (!code) return;\n handlingCodeFlow = true;\n await Fx.run(\n Fx.from({\n ok: async () => {\n await signIn(undefined, { code });\n const codeUrl = new URL(window.location.href);\n codeUrl.searchParams.delete(\"code\");\n await replaceUrl(codeUrl.pathname + codeUrl.search + codeUrl.hash);\n },\n err: (e) => e,\n }).pipe(\n Fx.recover(() => Fx.succeed(undefined)),\n Fx.tap(() =>\n Fx.sync(() => {\n handlingCodeFlow = false;\n }),\n ),\n Fx.inspect(() =>\n Fx.sync(() => {\n handlingCodeFlow = false;\n }),\n ),\n ),\n );\n // The flag is always reset — Fx.recover above ensures success path,\n // but reset defensively here too.\n handlingCodeFlow = false;\n };\n\n // ---------------------------------------------------------------------------\n // Hydrate from storage (SPA mode only)\n // ---------------------------------------------------------------------------\n\n const hydrateFromStorage = async () => {\n const storedToken = (await storageGet(JWT_STORAGE_KEY)) ?? null;\n await setToken({\n shouldStore: false,\n tokens: storedToken === null ? null : { token: storedToken },\n });\n };\n\n // ---------------------------------------------------------------------------\n // Subscribe\n // ---------------------------------------------------------------------------\n\n /**\n * Subscribe to auth state changes. Invokes the callback immediately\n * with the current state, then again on every state transition.\n *\n * ```ts\n * const unsub = auth.onChange(setState);\n * ```\n *\n * @param cb - Callback receiving the latest {@link AuthState}.\n * @returns An unsubscribe function.\n */\n const onChange = (cb: (state: AuthState) => void): (() => void) => {\n cb(snapshot);\n const wrapped = () => cb(snapshot);\n subscribers.add(wrapped);\n return () => {\n subscribers.delete(wrapped);\n };\n };\n\n // ---------------------------------------------------------------------------\n // Initialization\n // ---------------------------------------------------------------------------\n\n // Cross-tab sync via storage events (SPA mode only).\n if (!proxy && typeof window !== \"undefined\") {\n const registryKey = key(JWT_STORAGE_KEY);\n const registry = getStorageListenerRegistry();\n const existingListener = registry[registryKey];\n if (existingListener !== undefined) {\n window.removeEventListener(\"storage\", existingListener);\n }\n\n const onStorage = (event: StorageEvent) => {\n Fx.detach(async () => {\n if (event.key !== key(JWT_STORAGE_KEY)) return;\n await setToken({\n shouldStore: false,\n tokens: event.newValue === null ? null : { token: event.newValue },\n });\n }, \"[convex-auth] Storage event handler failed:\");\n };\n window.addEventListener(\"storage\", onStorage);\n registry[registryKey] = onStorage;\n disposeStorageListener = () => {\n if (registry[registryKey] === onStorage) {\n delete registry[registryKey];\n }\n window.removeEventListener(\"storage\", onStorage);\n };\n }\n\n // Auto-wire: feed our tokens into the Convex client so\n // queries and mutations are automatically authenticated.\n bindConvexAuth();\n\n // Auto-hydrate and handle code flow.\n if (typeof window !== \"undefined\") {\n if (proxy) {\n // Proxy mode: eagerly resolve auth once on startup so routes that only\n // read auth state (and do not issue Convex queries yet) don't stay in\n // the initial loading phase.\n if (!hasServerToken) {\n Fx.detach(\n () => fetchAccessToken({ forceRefreshToken: true }),\n \"[convex-auth] Proxy token refresh failed:\",\n );\n }\n } else {\n // SPA mode: hydrate from localStorage, then handle OAuth code flow.\n Fx.detach(async () => {\n await Fx.run(\n Fx.from({\n ok: async () => {\n await hydrateFromStorage();\n await handleCodeFlow();\n },\n err: (e) => e,\n }).pipe(\n Fx.inspect((error) =>\n Fx.sync(() =>\n console.error(\n \"[convex-auth] Client initialization failed:\",\n error,\n ),\n ),\n ),\n Fx.recover((_error) =>\n Fx.from({\n ok: () => setToken({ shouldStore: false, tokens: null }),\n err: (e) => e,\n }).pipe(Fx.recover(() => Fx.succeed(undefined))),\n ),\n ),\n );\n }, \"[convex-auth] SPA initialization failed:\");\n }\n }\n\n // ---------------------------------------------------------------------------\n // Passkey helpers\n // ---------------------------------------------------------------------------\n\n /**\n * Base64url encode/decode helpers for the WebAuthn credential API.\n * These run client-side only (browser context).\n */\n const base64urlEncode = (buffer: ArrayBuffer): string => {\n const bytes = new Uint8Array(buffer);\n let binary = \"\";\n for (let i = 0; i < bytes.byteLength; i++) {\n binary += String.fromCharCode(bytes[i]!);\n }\n return btoa(binary)\n .replace(/\\+/g, \"-\")\n .replace(/\\//g, \"_\")\n .replace(/=+$/, \"\");\n };\n\n const base64urlDecode = (str: string): Uint8Array => {\n const padded = str.replace(/-/g, \"+\").replace(/_/g, \"/\");\n const binary = atob(padded);\n const bytes = new Uint8Array(binary.length);\n for (let i = 0; i < binary.length; i++) {\n bytes[i] = binary.charCodeAt(i);\n }\n return bytes;\n };\n\n const passkey = {\n /**\n * Check if WebAuthn passkeys are supported in the current environment.\n */\n isSupported: (): boolean => {\n return (\n typeof window !== \"undefined\" &&\n typeof window.PublicKeyCredential !== \"undefined\"\n );\n },\n\n /**\n * Check if conditional UI (autofill-assisted passkey sign-in) is supported.\n *\n * ```ts\n * if (await auth.passkey.isAutofillSupported()) {\n * auth.passkey.authenticate({ autofill: true });\n * }\n * ```\n */\n isAutofillSupported: async (): Promise<boolean> => {\n if (typeof window === \"undefined\") return false;\n if (typeof window.PublicKeyCredential === \"undefined\") return false;\n if (\n typeof (window.PublicKeyCredential as any)\n .isConditionalMediationAvailable !== \"function\"\n ) {\n return false;\n }\n return (\n window.PublicKeyCredential as any\n ).isConditionalMediationAvailable();\n },\n\n /**\n * Register a new passkey for the current or new user.\n *\n * Performs the full two-round-trip WebAuthn registration ceremony:\n * 1. Requests creation options from the server (challenge, RP info)\n * 2. Calls `navigator.credentials.create()` with the options\n * 3. Sends the attestation back to the server for verification\n * 4. Server creates user + account + passkey records and returns tokens\n *\n * Works in both SPA and proxy (SSR) modes.\n *\n * ```ts\n * await auth.passkey.register({ name: \"MacBook Touch ID\" });\n * ```\n *\n * @param opts.name - Friendly name for this passkey\n * @param opts.email - Email to associate with the new account\n * @param opts.userName - Username for the credential (defaults to email)\n * @param opts.userDisplayName - Display name for the credential\n * @returns `{ kind: \"signedIn\" }` on success\n */\n register: async (opts?: {\n name?: string;\n email?: string;\n userName?: string;\n userDisplayName?: string;\n }): Promise<SignInResult> => {\n const phase1Params = {\n flow: \"registerOptions\",\n email: opts?.email,\n userName: opts?.userName,\n userDisplayName: opts?.userDisplayName,\n };\n\n // Phase 1: Get registration options from server\n let phase1Result: SignInActionResult;\n if (proxy) {\n phase1Result = (await proxyFetch({\n action: \"auth/session:start\",\n args: { provider: \"passkey\", params: phase1Params },\n })) as SignInActionResult;\n } else {\n phase1Result = (await convex.action(requireApiRefs().session.start, {\n provider: \"passkey\",\n params: phase1Params,\n })) as SignInActionResult;\n }\n\n if (phase1Result.kind !== \"passkeyOptions\") {\n throw new Error(\"Server did not return passkey registration options\");\n }\n\n const options = phase1Result.options;\n\n // Convert base64url strings to ArrayBuffers for the credential API\n const createOptions: CredentialCreationOptions = {\n publicKey: {\n rp: options.rp,\n user: {\n id: base64urlDecode(options.user.id).buffer as ArrayBuffer,\n name: options.user.name,\n displayName: options.user.displayName,\n },\n challenge: base64urlDecode(options.challenge).buffer as ArrayBuffer,\n pubKeyCredParams: options.pubKeyCredParams,\n timeout: options.timeout,\n attestation: options.attestation,\n authenticatorSelection: options.authenticatorSelection,\n excludeCredentials: (options.excludeCredentials ?? []).map(\n (cred: any) => ({\n type: cred.type ?? \"public-key\",\n id: base64urlDecode(cred.id).buffer as ArrayBuffer,\n transports: cred.transports,\n }),\n ),\n },\n };\n\n // Phase 2: Create credential via browser API\n const credential = (await navigator.credentials.create(\n createOptions,\n )) as PublicKeyCredential | null;\n if (!credential) {\n throw new Error(\"Passkey registration was cancelled\");\n }\n\n const response = credential.response as AuthenticatorAttestationResponse;\n\n // Extract transports if available\n const transports =\n typeof response.getTransports === \"function\"\n ? response.getTransports()\n : undefined;\n\n const phase2Params = {\n flow: \"registerVerify\",\n clientDataJSON: base64urlEncode(response.clientDataJSON),\n attestationObject: base64urlEncode(response.attestationObject),\n transports,\n passkeyName: opts?.name,\n email: opts?.email,\n };\n\n // Phase 3: Send attestation to server for verification\n let phase2Result: SignInActionResult;\n if (proxy) {\n // In proxy mode the verifier is stored in an httpOnly cookie by the proxy.\n // We pass it back explicitly so the proxy can forward it to Convex.\n phase2Result = (await proxyFetch({\n action: \"auth/session:start\",\n args: {\n provider: \"passkey\",\n params: phase2Params,\n verifier: phase1Result.verifier,\n },\n })) as SignInActionResult;\n } else {\n phase2Result = (await convex.action(requireApiRefs().session.start, {\n provider: \"passkey\",\n params: phase2Params,\n verifier: phase1Result.verifier,\n })) as SignInActionResult;\n }\n\n return Fx.run(\n Fx.match(phase2Result, phase2Result.kind, {\n signedIn: (signedInResult) =>\n Fx.from({\n ok: async () => {\n const signingIn = await setTokenAndMaybeWait(\n proxy\n ? {\n shouldStore: false as const,\n tokens:\n signedInResult.tokens === null\n ? null\n : { token: signedInResult.tokens.token },\n waitForHandshake: true,\n context: {\n provider: \"passkey\",\n flow: \"registerVerify\",\n },\n }\n : {\n shouldStore: true as const,\n tokens: signedInResult.tokens,\n waitForHandshake: true,\n context: {\n provider: \"passkey\",\n flow: \"registerVerify\",\n },\n },\n );\n return signingIn\n ? ({ kind: \"signedIn\" as const } as SignInResult)\n : ({ kind: \"started\" as const } as SignInResult);\n },\n err: (e) => e as never,\n }),\n redirect: (_redirectResult) =>\n Fx.succeed({ kind: \"started\" as const }),\n started: (_startedResult) => Fx.succeed({ kind: \"started\" as const }),\n passkeyOptions: (_passkeyOptionsResult) =>\n Fx.succeed({ kind: \"started\" as const }),\n totpRequired: (_totpRequiredResult) =>\n Fx.succeed({ kind: \"started\" as const }),\n totpSetup: (_totpSetupResult) =>\n Fx.succeed({ kind: \"started\" as const }),\n deviceCode: (_deviceCodeResult) =>\n Fx.succeed({ kind: \"started\" as const }),\n }),\n );\n },\n\n /**\n * Authenticate with an existing passkey.\n *\n * Performs the full two-round-trip WebAuthn authentication ceremony:\n * 1. Requests assertion options from the server (challenge, allowed credentials)\n * 2. Calls `navigator.credentials.get()` with the options\n * 3. Sends the assertion back to the server for signature verification\n * 4. Server verifies signature, updates counter, creates session, returns tokens\n *\n * Works in both SPA and proxy (SSR) modes.\n *\n * ```ts\n * // Discoverable credential (no email needed)\n * await auth.passkey.authenticate();\n *\n * // Scoped to a specific user's credentials\n * await auth.passkey.authenticate({ email: \"user@example.com\" });\n *\n * // Autofill-assisted (conditional UI)\n * await auth.passkey.authenticate({ autofill: true });\n * ```\n *\n * @param opts.email - Scope to credentials for this email's user\n * @param opts.autofill - Use conditional mediation (autofill UI)\n * @returns `{ kind: \"signedIn\" }` on success\n */\n authenticate: async (opts?: {\n email?: string;\n autofill?: boolean;\n }): Promise<SignInResult> => {\n const phase1Params = {\n flow: \"authOptions\",\n email: opts?.email,\n };\n\n // Phase 1: Get assertion options from server\n let phase1Result: SignInActionResult;\n if (proxy) {\n phase1Result = (await proxyFetch({\n action: \"auth/session:start\",\n args: { provider: \"passkey\", params: phase1Params },\n })) as SignInActionResult;\n } else {\n phase1Result = (await convex.action(requireApiRefs().session.start, {\n provider: \"passkey\",\n params: phase1Params,\n })) as SignInActionResult;\n }\n\n if (phase1Result.kind !== \"passkeyOptions\") {\n throw new Error(\"Server did not return passkey authentication options\");\n }\n\n const options = phase1Result.options;\n\n // Convert base64url strings to ArrayBuffers for the credential API\n const getOptions: CredentialRequestOptions = {\n publicKey: {\n challenge: base64urlDecode(options.challenge).buffer as ArrayBuffer,\n timeout: options.timeout,\n rpId: options.rpId,\n userVerification: options.userVerification,\n allowCredentials: (options.allowCredentials ?? []).map(\n (cred: any) => ({\n type: cred.type ?? \"public-key\",\n id: base64urlDecode(cred.id).buffer as ArrayBuffer,\n transports: cred.transports,\n }),\n ),\n },\n ...(opts?.autofill ? { mediation: \"conditional\" as any } : {}),\n };\n\n // Phase 2: Get credential via browser API\n const credential = (await navigator.credentials.get(\n getOptions,\n )) as PublicKeyCredential | null;\n if (!credential) {\n throw new Error(\"Passkey authentication was cancelled\");\n }\n\n const response = credential.response as AuthenticatorAssertionResponse;\n\n const phase2Params = {\n flow: \"authVerify\",\n credentialId: base64urlEncode(credential.rawId),\n clientDataJSON: base64urlEncode(response.clientDataJSON),\n authenticatorData: base64urlEncode(response.authenticatorData),\n signature: base64urlEncode(response.signature),\n };\n\n // Phase 3: Send assertion to server for verification\n let phase2Result: SignInActionResult;\n if (proxy) {\n phase2Result = (await proxyFetch({\n action: \"auth/session:start\",\n args: {\n provider: \"passkey\",\n params: phase2Params,\n verifier: phase1Result.verifier,\n },\n })) as SignInActionResult;\n } else {\n phase2Result = (await convex.action(requireApiRefs().session.start, {\n provider: \"passkey\",\n params: phase2Params,\n verifier: phase1Result.verifier,\n })) as SignInActionResult;\n }\n\n return Fx.run(\n Fx.match(phase2Result, phase2Result.kind, {\n signedIn: (signedInResult) =>\n Fx.from({\n ok: async () => {\n const signingIn = await setTokenAndMaybeWait(\n proxy\n ? {\n shouldStore: false as const,\n tokens:\n signedInResult.tokens === null\n ? null\n : { token: signedInResult.tokens.token },\n waitForHandshake: true,\n context: { provider: \"passkey\", flow: \"authVerify\" },\n }\n : {\n shouldStore: true as const,\n tokens: signedInResult.tokens,\n waitForHandshake: true,\n context: { provider: \"passkey\", flow: \"authVerify\" },\n },\n );\n return signingIn\n ? ({ kind: \"signedIn\" as const } as SignInResult)\n : ({ kind: \"started\" as const } as SignInResult);\n },\n err: (e) => e as never,\n }),\n redirect: (_redirectResult) =>\n Fx.succeed({ kind: \"started\" as const }),\n started: (_startedResult) => Fx.succeed({ kind: \"started\" as const }),\n passkeyOptions: (_passkeyOptionsResult) =>\n Fx.succeed({ kind: \"started\" as const }),\n totpRequired: (_totpRequiredResult) =>\n Fx.succeed({ kind: \"started\" as const }),\n totpSetup: (_totpSetupResult) =>\n Fx.succeed({ kind: \"started\" as const }),\n deviceCode: (_deviceCodeResult) =>\n Fx.succeed({ kind: \"started\" as const }),\n }),\n );\n },\n };\n\n const totp = {\n /**\n * Start TOTP enrollment. Must be authenticated.\n *\n * Returns a URI for QR code display and a base32 secret for manual entry.\n *\n * ```ts\n * const setup = await auth.totp.setup();\n * // Display QR code from setup.uri\n * // Or show setup.secret for manual entry\n * ```\n */\n setup: async (opts?: {\n name?: string;\n accountName?: string;\n }): Promise<{\n uri: string;\n secret: string;\n verifier: string;\n totpId: string;\n }> => {\n const params: Record<string, any> = { flow: \"setup\" };\n if (opts?.name) params.name = opts.name;\n if (opts?.accountName) params.accountName = opts.accountName;\n\n if (proxy) {\n const result = await proxyFetch({\n action: \"auth/session:start\",\n args: { provider: \"totp\", params },\n });\n return {\n uri: result.totpSetup.uri,\n secret: result.totpSetup.secret,\n verifier: result.verifier,\n totpId: result.totpSetup.totpId,\n };\n }\n\n const result = await convex.action(requireApiRefs().session.start, {\n provider: \"totp\",\n params,\n });\n return {\n uri: result.totpSetup.uri,\n secret: result.totpSetup.secret,\n verifier: result.verifier,\n totpId: result.totpSetup.totpId,\n };\n },\n\n /**\n * Complete TOTP enrollment by verifying the first code from the authenticator app.\n *\n * ```ts\n * await auth.totp.confirm({ code: \"123456\", verifier: setup.verifier, totpId: setup.totpId });\n * ```\n */\n confirm: async (opts: {\n code: string;\n verifier: string;\n totpId: string;\n }): Promise<void> => {\n const params: Record<string, any> = {\n flow: \"confirm\",\n code: opts.code,\n totpId: opts.totpId,\n };\n\n if (proxy) {\n const result = await proxyFetch({\n action: \"auth/session:start\",\n args: { provider: \"totp\", params, verifier: opts.verifier },\n });\n if (result.tokens) {\n await setTokenAndMaybeWait({\n shouldStore: false,\n tokens:\n result.tokens === null ? null : { token: result.tokens.token },\n waitForHandshake: true,\n context: { provider: \"totp\", flow: \"confirm\" },\n });\n }\n return;\n }\n\n const result = await convex.action(requireApiRefs().session.start, {\n provider: \"totp\",\n params,\n verifier: opts.verifier,\n });\n if (result.tokens) {\n await setTokenAndMaybeWait({\n shouldStore: true,\n tokens: (result.tokens as AuthSession | null) ?? null,\n waitForHandshake: true,\n context: { provider: \"totp\", flow: \"confirm\" },\n });\n }\n },\n\n /**\n * Complete 2FA verification during sign-in.\n *\n * Called after a credentials sign-in returns `kind: \"totpRequired\"`.\n *\n * ```ts\n * const result = await auth.signIn(\"password\", { email, password });\n * if (result.kind === \"totpRequired\") {\n * await auth.totp.verify({ code: \"123456\", verifier: result.verifier });\n * }\n * ```\n */\n verify: async (opts: { code: string; verifier: string }): Promise<void> => {\n const params: Record<string, any> = {\n flow: \"verify\",\n code: opts.code,\n };\n\n if (proxy) {\n const result = await proxyFetch({\n action: \"auth/session:start\",\n args: { provider: \"totp\", params, verifier: opts.verifier },\n });\n if (result.tokens) {\n await setTokenAndMaybeWait({\n shouldStore: false,\n tokens:\n result.tokens === null ? null : { token: result.tokens.token },\n waitForHandshake: true,\n context: { provider: \"totp\", flow: \"verify\" },\n });\n }\n return;\n }\n\n const result = await convex.action(requireApiRefs().session.start, {\n provider: \"totp\",\n params,\n verifier: opts.verifier,\n });\n if (result.tokens) {\n await setTokenAndMaybeWait({\n shouldStore: true,\n tokens: (result.tokens as AuthSession | null) ?? null,\n waitForHandshake: true,\n context: { provider: \"totp\", flow: \"verify\" },\n });\n }\n },\n };\n\n const device = {\n /**\n * Poll for device authorization status.\n *\n * The device calls this repeatedly (respecting `interval`) after\n * initiating a device flow via `signIn(\"device\")`. Returns when\n * the user authorizes, or throws on timeout/denial.\n *\n * ```ts\n * const result = await auth.signIn(\"device\");\n * const { deviceCode } = result;\n * // Display deviceCode.userCode to the user, then poll:\n * await auth.device.poll(deviceCode);\n * // User is now signed in\n * ```\n *\n * @param code - The {@link DeviceCodeResult} from `signIn(\"device\")`.\n * @returns Resolves when the device is authorized and tokens are stored.\n * @throws When the code expires, is denied, or polling encounters an error.\n */\n poll: async (code: DeviceCodeResult): Promise<void> => {\n const intervalMs = code.interval * 1000;\n const expiresAt = Date.now() + code.expiresIn * 1000;\n\n while (Date.now() < expiresAt) {\n await new Promise((resolve) => setTimeout(resolve, intervalMs));\n\n const pollResult = await Fx.run(\n Fx.from({\n ok: async () => {\n let result: any;\n const params: Record<string, any> = {\n flow: \"poll\",\n deviceCode: code.deviceCode,\n };\n\n if (proxy) {\n result = await proxyFetch({\n action: \"auth/session:start\",\n args: { provider: \"device\", params },\n });\n } else {\n result = await convex.action(requireApiRefs().session.start, {\n provider: \"device\",\n params,\n });\n }\n\n return result;\n },\n err: (e) => e,\n }).pipe(\n Fx.recover((e: unknown) => {\n const dispatch =\n e instanceof ConvexError\n ? {\n tag:\n (e.data as Record<string, unknown> | undefined)\n ?.code === \"DEVICE_AUTHORIZATION_PENDING\"\n ? \"continue\"\n : (e.data as Record<string, unknown> | undefined)\n ?.code === \"DEVICE_SLOW_DOWN\"\n ? \"slowDown\"\n : \"fatal\",\n }\n : ({ tag: \"fatal\" } as const);\n\n return Fx.match(dispatch, dispatch.tag, {\n continue: () => Fx.succeed({ _poll: \"continue\" as const }),\n slowDown: () => Fx.succeed({ _poll: \"slow_down\" as const }),\n fatal: () => Fx.fatal(e),\n });\n }),\n ),\n );\n\n if (\"_poll\" in pollResult) {\n if (pollResult._poll === \"slow_down\") {\n // Back off by adding one interval\n await new Promise((resolve) => setTimeout(resolve, intervalMs));\n }\n continue;\n }\n\n // Authorized — tokens received\n if (pollResult.tokens) {\n if (proxy) {\n await setTokenAndMaybeWait({\n shouldStore: false,\n tokens:\n pollResult.tokens === null\n ? null\n : { token: pollResult.tokens.token },\n waitForHandshake: true,\n context: { provider: \"device\", flow: \"poll\" },\n });\n } else {\n await setTokenAndMaybeWait({\n shouldStore: true,\n tokens: (pollResult.tokens as AuthSession | null) ?? null,\n waitForHandshake: true,\n context: { provider: \"device\", flow: \"poll\" },\n });\n }\n return;\n }\n }\n\n throw new Error(\"Device authorization timed out.\");\n },\n\n /**\n * Authorize a device from the verification page.\n *\n * Called by an authenticated user on the verification page after\n * they enter the user code displayed on the device.\n *\n * ```ts\n * // On the /device verification page:\n * await auth.device.verify(userCode);\n * ```\n *\n * @param userCode - The user code entered by the user (e.g. \"WDJB-MJHT\").\n */\n verify: async (userCode: string): Promise<void> => {\n const params: Record<string, any> = {\n flow: \"verify\",\n userCode,\n };\n\n if (proxy) {\n await proxyFetch({\n action: \"auth/session:start\",\n args: { provider: \"device\", params },\n });\n } else {\n await convex.action(requireApiRefs().session.start, {\n provider: \"device\",\n params,\n });\n }\n },\n };\n\n return {\n /** Current auth state snapshot. */\n get state(): AuthState {\n return snapshot;\n },\n /** Sign in with a provider. See {@link SignInResult} for return shape. */\n signIn,\n /** Sign out and clear all token state. */\n signOut,\n /** Subscribe to auth state changes. Returns an unsubscribe function. */\n onChange,\n /** Passkey (WebAuthn) authentication helpers. */\n passkey,\n /** TOTP two-factor authentication helpers. */\n totp,\n /** Device authorization (RFC 8628) helpers. */\n device,\n /** Remove global listeners when disposing this client instance. */\n destroy: () => {\n destroyed = true;\n settleHandshakeWaiters(authEpoch, {\n type: \"reject\",\n error: createHandshakeError(\"AUTH_HANDSHAKE_REJECTED\", {\n reason: \"destroyed\",\n }),\n });\n disposeStorageListener?.();\n subscribers.clear();\n },\n } as AuthClient<Api>;\n}\n\n// ---------------------------------------------------------------------------\n// Browser mutex — ensures only one tab refreshes a token at a time.\n// ---------------------------------------------------------------------------\n\nasync function browserMutex<T>(\n key: string,\n callback: () => Promise<T>,\n): Promise<T> {\n const lockManager = (globalThis as any)?.navigator?.locks;\n return lockManager !== undefined\n ? await lockManager.request(key, callback)\n : await manualMutex(key, callback);\n}\n\nfunction getStorageListenerRegistry(): Record<\n string,\n (event: StorageEvent) => void\n> {\n const globalAny = globalThis as any;\n if (globalAny.__convexAuthStorageListeners === undefined) {\n globalAny.__convexAuthStorageListeners = {} as Record<\n string,\n (event: StorageEvent) => void\n >;\n }\n return globalAny.__convexAuthStorageListeners as Record<\n string,\n (event: StorageEvent) => void\n >;\n}\n\nfunction getManualMutexTails(): Record<string, Promise<void>> {\n const globalAny = globalThis as any;\n if (globalAny.__convexAuthMutexTails === undefined) {\n globalAny.__convexAuthMutexTails = {} as Record<string, Promise<void>>;\n }\n return globalAny.__convexAuthMutexTails as Record<string, Promise<void>>;\n}\n\nasync function manualMutex<T>(\n key: string,\n callback: () => Promise<T>,\n): Promise<T> {\n const mutexTails = getManualMutexTails();\n const previousTail = mutexTails[key] ?? Promise.resolve();\n\n let releaseCurrent: (() => void) | undefined;\n const currentTail = new Promise<void>((resolve) => {\n releaseCurrent = resolve;\n });\n\n mutexTails[key] = previousTail.then(\n () => currentTail,\n () => currentTail,\n );\n\n await Fx.run(\n Fx.from({\n ok: () => previousTail,\n err: () => undefined,\n }).pipe(Fx.recover(() => Fx.succeed(undefined))),\n );\n let result: T;\n let threw = false;\n let thrownError: unknown;\n await Fx.run(\n Fx.from({\n ok: async () => {\n result = await callback();\n },\n err: (e) => e,\n }).pipe(\n Fx.recover((e) => {\n threw = true;\n thrownError = e;\n return Fx.succeed(undefined);\n }),\n ),\n );\n releaseCurrent?.();\n if (mutexTails[key] === currentTail) {\n delete mutexTails[key];\n }\n if (threw) {\n throw thrownError;\n }\n return result!;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":["url","key","options","result"],"sources":["../../src/client/index.ts"],"sourcesContent":["import { Fx } from \"@robelest/fx\";\nimport { ConvexHttpClient } from \"convex/browser\";\nimport type { FunctionReference } from \"convex/server\";\nimport { ConvexError, Value } from \"convex/values\";\n\nimport { AUTH_ERRORS } from \"../server/errors\";\n\n// Re-export error utilities so consumers can import from `@robelest/convex-auth/client`.\nexport {\n isAuthError,\n parseAuthError,\n AUTH_ERRORS,\n type AuthErrorCode,\n} from \"../server/errors\";\n\n/**\n * Structural interface for any Convex client.\n * Satisfied by `ConvexClient` (`convex/browser`),\n * `ConvexReactClient` (`convex/react`), and similar transports.\n *\n * `clearAuth` is present on `ConvexReactClient` and `BaseConvexClient`\n * but not on the simplified `ConvexClient`. When available we call it\n * during sign-out for a clean deauthentication.\n */\ninterface ConvexTransport {\n action(action: any, args: any): Promise<any>;\n setAuth(\n fetchToken: (args: {\n forceRefreshToken: boolean;\n }) => Promise<string | null | undefined>,\n onChange?: (isAuthenticated: boolean) => void,\n ): void;\n clearAuth?(): void;\n}\n\n/** Pluggable key-value storage (defaults to `localStorage`). */\nexport interface Storage {\n getItem(\n key: string,\n ): string | null | undefined | Promise<string | null | undefined>;\n setItem(key: string, value: string): void | Promise<void>;\n removeItem(key: string): void | Promise<void>;\n}\n\ntype AuthSession = {\n token: string;\n refreshToken: string;\n};\n\ntype SignInActionResult =\n | { kind: \"signedIn\"; tokens: AuthSession | null }\n | { kind: \"redirect\"; redirect: string; verifier: string }\n | { kind: \"started\" }\n | { kind: \"passkeyOptions\"; options: Record<string, any>; verifier: string }\n | { kind: \"totpRequired\"; verifier: string }\n | {\n kind: \"totpSetup\";\n totpSetup: { uri: string; secret: string; totpId: string };\n verifier: string;\n }\n | {\n kind: \"deviceCode\";\n deviceCode: {\n deviceCode: string;\n userCode: string;\n verificationUri: string;\n verificationUriComplete: string;\n expiresIn: number;\n interval: number;\n };\n };\n\n/**\n * Device code response returned when signing in with the `\"device\"` provider.\n *\n * The device displays the `userCode` (or `verification_uri_complete`) and\n * polls via `auth.device.poll()` until the user authorizes.\n */\nexport type DeviceCodeResult = {\n /** High-entropy device code used for polling (keep secret). */\n deviceCode: string;\n /** Short human-readable code the user enters (e.g. \"WDJB-MJHT\"). */\n userCode: string;\n /** Base verification URL (e.g. \"https://myapp.com/device\"). */\n verification_uri: string;\n /** Verification URL with user code pre-filled as `?code=XXXX-XXXX`. */\n verification_uri_complete: string;\n /** Lifetime of the codes in seconds. */\n expiresIn: number;\n /** Minimum polling interval in seconds. */\n interval: number;\n};\n\n/**\n * Result of a `signIn` call.\n *\n * - `kind: \"signedIn\"` — credentials were accepted and the user is authenticated.\n * - `kind: \"redirect\"` — OAuth flow initiated; redirect the user to `redirect.toString()`.\n * - `kind: \"totpRequired\"` — credentials valid but 2FA is needed; call `auth.totp.verify()`.\n * - `kind: \"deviceCode\"` — device flow initiated; display the code and poll via `auth.device.poll()`.\n * - `kind: \"started\"` — a non-immediate flow started (for example email/phone verification).\n */\nexport type SignInResult =\n | { kind: \"signedIn\" }\n | { kind: \"redirect\"; redirect: URL; verifier: string }\n | { kind: \"totpRequired\"; verifier: string }\n | { kind: \"deviceCode\"; deviceCode: DeviceCodeResult }\n | { kind: \"started\" };\n\n/** Reactive auth state snapshot returned by `auth.state` and `auth.onChange`. */\nexport type AuthState = {\n /** High-level auth phase for deterministic UI state handling. */\n phase: \"loading\" | \"handshake\" | \"authenticated\" | \"unauthenticated\";\n /** `true` during initial hydration before the first token is resolved. */\n isLoading: boolean;\n /** `true` only after Convex confirms authentication with the backend. */\n isAuthenticated: boolean;\n /** The raw JWT string, or `null` when not authenticated. */\n token: string | null;\n};\n\n/**\n * Typed Convex API references for the auth functions.\n * Pass these from your generated `api` object.\n */\nexport type AuthApiRefs<\n HasPasskey extends boolean = boolean,\n HasTotp extends boolean = boolean,\n HasDevice extends boolean = boolean,\n> = {\n signIn: FunctionReference<\"action\", \"public\", any, any>;\n signOut: FunctionReference<\"action\", \"public\", any, any>;\n store: FunctionReference<\"mutation\", \"public\", any, any>;\n /** @internal Set automatically by `createAuth` — do not set manually. */\n _capabilities?: {\n passkey: HasPasskey;\n totp: HasTotp;\n device: HasDevice;\n };\n};\n\n/** Passkey (WebAuthn) client-side helpers. */\nexport interface PasskeyClient {\n isSupported(): boolean;\n isAutofillSupported(): Promise<boolean>;\n register(opts?: Record<string, any>): Promise<SignInResult>;\n authenticate(opts?: Record<string, any>): Promise<SignInResult>;\n}\n\n/** TOTP two-factor authentication client-side helpers. */\nexport interface TotpClient {\n setup(opts?: Record<string, any>): Promise<Record<string, any>>;\n confirm(opts: Record<string, any>): Promise<void>;\n verify(opts: Record<string, any>): Promise<void>;\n}\n\n/** Device authorization (RFC 8628) client-side helpers. */\nexport interface DeviceClient {\n poll(code: any): Promise<void>;\n verify(userCode: string): Promise<void>;\n}\n\n/** Extract capability flags from an AuthApiRefs type. */\ntype InferCaps<Api extends AuthApiRefs<boolean, boolean, boolean>> =\n Api extends AuthApiRefs<infer P, infer T, infer D>\n ? { passkey: P; totp: T; device: D }\n : { passkey: boolean; totp: boolean; device: boolean };\n\n/** Base auth client — always present. */\nexport interface AuthClientBase {\n readonly state: AuthState;\n signIn: (\n provider: string,\n params?: Record<string, any>,\n ) => Promise<SignInResult>;\n signOut: () => Promise<void>;\n onChange: (callback: () => void) => () => void;\n destroy: () => void;\n}\n\n/**\n * Auth client return type — conditionally includes `passkey`, `totp`, and\n * `device` helpers based on the capabilities in the `AuthApiRefs` type.\n */\nexport type AuthClient<\n Api extends AuthApiRefs<boolean, boolean, boolean> = AuthApiRefs,\n> = AuthClientBase &\n (InferCaps<Api>[\"passkey\"] extends true ? { passkey: PasskeyClient } : {}) &\n (InferCaps<Api>[\"totp\"] extends true ? { totp: TotpClient } : {}) &\n (InferCaps<Api>[\"device\"] extends true ? { device: DeviceClient } : {});\n\n/** Options for {@link client}. */\nexport type ClientOptions<\n Api extends AuthApiRefs<boolean, boolean, boolean> = AuthApiRefs,\n> = {\n /** Any Convex client (`ConvexClient` or `ConvexReactClient`). */\n convex: ConvexTransport;\n /**\n * Typed Convex API references for the auth functions.\n * Required in SPA mode. Optional when `proxyPath` is set (proxy mode\n * routes through the SSR proxy instead of calling Convex directly).\n *\n * ```ts\n * import { api } from \"../convex/_generated/api\";\n * client({\n * convex,\n * api: api.auth,\n * });\n * ```\n */\n api?: Api;\n /**\n * Convex deployment URL. Derived automatically from the client internals\n * when omitted — pass explicitly only if auto-detection fails.\n */\n url?: string;\n /**\n * Key-value storage for persisting tokens.\n *\n * - Defaults to `localStorage` in SPA mode.\n * - Defaults to `null` (in-memory only) when `proxyPath` is set,\n * since httpOnly cookies handle persistence.\n */\n storage?: Storage | null;\n /** Override how the URL bar is updated after OAuth code exchange. */\n replaceUrl?: (relativeUrl: string) => void | Promise<void>;\n /**\n * SSR proxy endpoint (e.g. `\"/api/auth\"`).\n *\n * When set, `signIn`/`signOut`/token refresh POST to this URL\n * (with `credentials: \"include\"`) instead of calling Convex directly.\n * The server handles httpOnly cookies for token persistence.\n *\n * Pair with {@link ClientOptions.tokenSeed} for flash-free SSR hydration.\n */\n proxyPath?: string;\n /**\n * JWT from server-side hydration.\n *\n * In proxy mode the server reads the JWT from an httpOnly cookie\n * and passes it to the client during SSR. This avoids a loading\n * flash on first render — the client is immediately authenticated.\n */\n tokenSeed?: string | null;\n};\n\nconst VERIFIER_STORAGE_KEY = \"__convexAuthOAuthVerifier\";\nconst JWT_STORAGE_KEY = \"__convexAuthJWT\";\nconst REFRESH_TOKEN_STORAGE_KEY = \"__convexAuthRefreshToken\";\n\nconst RETRY_BASE_MS = 500;\nconst RETRY_MAX_RETRIES = 2;\nconst AUTH_HANDSHAKE_TIMEOUT_MS = 5000;\nconst NETWORK_ERROR_PATTERN = /(network|fetch|load failed|failed to fetch)/i;\n\ntype AuthHandshakeErrorCode =\n | \"AUTH_HANDSHAKE_TIMEOUT\"\n | \"AUTH_HANDSHAKE_REJECTED\";\n\ntype AuthFlowContext = {\n provider?: string;\n flow: string;\n};\n\ntype HandshakeWaiter = {\n epoch: number;\n context: AuthFlowContext;\n resolve: () => void;\n reject: (error: ConvexError<Value>) => void;\n timeoutId: ReturnType<typeof setTimeout>;\n};\n\n/**\n * Resolve the Convex deployment URL from the client.\n *\n * `ConvexReactClient` exposes `.url` directly.\n * `ConvexClient` exposes `.client.url` via `BaseConvexClient`.\n */\nfunction resolveUrl(convex: ConvexTransport, explicit?: string): string {\n if (explicit) return explicit;\n const c = convex as any;\n const url: unknown = c.url ?? c.client?.url;\n if (typeof url === \"string\") return url;\n throw new Error(\n \"Could not determine Convex deployment URL. Pass `url` explicitly.\",\n );\n}\n\nfunction isTransientNetworkError(error: unknown): boolean {\n return (\n error instanceof TypeError ||\n (error instanceof Error && NETWORK_ERROR_PATTERN.test(error.message || \"\"))\n );\n}\n\nfunction isRetriableProxyRefreshError(error: unknown): boolean {\n if (isTransientNetworkError(error)) {\n return true;\n }\n if (!(error instanceof Error)) {\n return false;\n }\n const statusMatch = error.message.match(/Proxy request failed:\\s*(\\d{3})/);\n if (statusMatch === null) {\n return false;\n }\n const statusCode = Number(statusMatch[1]);\n return statusCode >= 500 && statusCode < 600;\n}\n\n/**\n * Create a framework-agnostic auth client.\n *\n * Returns an object with `signIn`, `signOut`, `onChange`, `state`,\n * `passkey`, and `totp` — everything needed for client-side auth.\n *\n * ### SPA mode (default)\n *\n * ```ts\n * import { ConvexClient } from 'convex/browser';\n * import { client } from '@robelest/convex-auth/client';\n * import { api } from '../convex/_generated/api';\n *\n * const convex = new ConvexClient(CONVEX_URL);\n * const auth = client({ convex, api: api.auth });\n * ```\n *\n * ### SSR / proxy mode\n *\n * ```ts\n * const auth = client({\n * convex,\n * proxyPath: '/api/auth',\n * tokenSeed: tokenFromServer, // JWT read from httpOnly cookie during SSR\n * });\n * ```\n *\n * In proxy mode all auth operations go through the proxy URL.\n * Tokens are stored in httpOnly cookies server-side — the client\n * holds the JWT in memory only.\n *\n * @param options - Client configuration. See {@link ClientOptions}.\n * @returns Auth client with conditional `passkey`, `totp`, and `device` helpers.\n */\nexport function client<\n Api extends AuthApiRefs<boolean, boolean, boolean> = AuthApiRefs,\n>(options: ClientOptions<Api>): AuthClient<Api> {\n const { convex, proxyPath, api: apiRefs } = options;\n const proxy = proxyPath;\n\n function requireApiRefs() {\n if (!apiRefs) {\n throw new Error(\n \"The `api` option is required when `proxyPath` is not set. \" +\n \"Pass { api: api.auth }.\",\n );\n }\n return apiRefs;\n }\n\n // In proxy mode, default storage to null (cookies handle persistence).\n const storage =\n options.storage !== undefined\n ? options.storage\n : proxy\n ? null\n : typeof window === \"undefined\"\n ? null\n : window.localStorage;\n\n const replaceUrl =\n options.replaceUrl ??\n ((url: string) => {\n if (typeof window !== \"undefined\") {\n window.history.replaceState({}, \"\", url);\n }\n });\n\n const url = proxy ? undefined : resolveUrl(convex, options.url);\n const escapedNamespace = proxy\n ? proxy.replace(/[^a-zA-Z0-9]/g, \"\")\n : url!.replace(/[^a-zA-Z0-9]/g, \"\");\n const key = (name: string) => `${name}_${escapedNamespace}`;\n const subscribers = new Set<() => void>();\n let disposeStorageListener: (() => void) | null = null;\n\n // Unauthenticated HTTP client for code verification & OAuth exchange.\n // Only needed in SPA mode — proxy mode routes everything through the proxy.\n const httpClient = proxy ? null : new ConvexHttpClient(url!);\n\n // ---------------------------------------------------------------------------\n // State\n // ---------------------------------------------------------------------------\n\n // If a server-provided token was supplied (SSR hydration), treat it as\n // immediately authenticated to avoid a handshake-only loading screen.\n const serverToken =\n typeof options.tokenSeed === \"string\" && options.tokenSeed.trim().length > 0\n ? options.tokenSeed\n : null;\n const hasServerToken = serverToken !== null;\n\n let token: string | null = serverToken;\n let isLoading = !hasServerToken;\n let authConfirmed = hasServerToken;\n let handshakePending = false;\n let authEpoch = 0;\n let destroyed = false;\n const handshakeWaiters = new Set<HandshakeWaiter>();\n let snapshot: AuthState = {\n phase: hasServerToken\n ? \"authenticated\"\n : isLoading\n ? \"loading\"\n : \"unauthenticated\",\n isLoading,\n isAuthenticated: hasServerToken,\n token,\n };\n let handlingCodeFlow = false;\n\n const createHandshakeError = (\n code: AuthHandshakeErrorCode,\n context: Record<string, unknown>,\n ) => {\n return new ConvexError({\n code,\n message: AUTH_ERRORS[code],\n ...context,\n } as Value);\n };\n\n const settleHandshakeWaiters = (\n epoch: number,\n outcome:\n | { type: \"resolve\" }\n | { type: \"reject\"; error: ConvexError<Value> },\n ) => {\n for (const waiter of Array.from(handshakeWaiters)) {\n if (waiter.epoch !== epoch) {\n continue;\n }\n clearTimeout(waiter.timeoutId);\n handshakeWaiters.delete(waiter);\n if (outcome.type === \"resolve\") {\n waiter.resolve();\n } else {\n waiter.reject(outcome.error);\n }\n }\n };\n\n const rejectObsoleteHandshakeWaiters = (activeEpoch: number) => {\n for (const waiter of Array.from(handshakeWaiters)) {\n if (waiter.epoch >= activeEpoch) {\n continue;\n }\n clearTimeout(waiter.timeoutId);\n handshakeWaiters.delete(waiter);\n waiter.reject(\n createHandshakeError(\"AUTH_HANDSHAKE_REJECTED\", {\n ...waiter.context,\n reason: \"token_changed\",\n }),\n );\n }\n };\n\n const waitForAuthHandshake = async (context: AuthFlowContext) => {\n if (token === null) {\n return;\n }\n if (authConfirmed && !handshakePending) {\n return;\n }\n if (!handshakePending) {\n throw createHandshakeError(\"AUTH_HANDSHAKE_REJECTED\", {\n ...context,\n reason: \"auth_rejected\",\n });\n }\n\n const epoch = authEpoch;\n await new Promise<void>((resolve, reject) => {\n const waiterRef: { current: HandshakeWaiter | null } = { current: null };\n const timeoutId = setTimeout(() => {\n if (waiterRef.current !== null) {\n handshakeWaiters.delete(waiterRef.current);\n }\n reject(\n createHandshakeError(\"AUTH_HANDSHAKE_TIMEOUT\", {\n ...context,\n timeoutMs: AUTH_HANDSHAKE_TIMEOUT_MS,\n }),\n );\n }, AUTH_HANDSHAKE_TIMEOUT_MS);\n\n const waiter: HandshakeWaiter = {\n epoch,\n context,\n resolve,\n reject,\n timeoutId,\n };\n waiterRef.current = waiter;\n handshakeWaiters.add(waiter);\n });\n };\n\n const handleConvexAuthChange = (isAuthenticated: boolean) => {\n if (destroyed) {\n return;\n }\n\n if (isAuthenticated) {\n authConfirmed = true;\n handshakePending = false;\n settleHandshakeWaiters(authEpoch, { type: \"resolve\" });\n } else {\n authConfirmed = false;\n // Do not reject immediately while a handshake is pending.\n // Convex can transiently emit `false` while reauth is still in flight,\n // and a subsequent `true` confirms the same session.\n }\n\n if (updateSnapshot()) {\n notify();\n }\n };\n\n const notify = () => {\n for (const cb of subscribers) cb();\n };\n\n const updateSnapshot = () => {\n const phaseDispatch = {\n tag:\n token !== null && handshakePending\n ? \"handshake\"\n : isLoading\n ? \"loading\"\n : token !== null && authConfirmed\n ? \"authenticated\"\n : \"unauthenticated\",\n } as const;\n\n const phase = {\n handshake: \"handshake\",\n loading: \"loading\",\n authenticated: \"authenticated\",\n unauthenticated: \"unauthenticated\",\n }[phaseDispatch.tag] as AuthState[\"phase\"];\n\n const next: AuthState = {\n phase,\n isLoading: phase === \"loading\" || phase === \"handshake\",\n isAuthenticated: phase === \"authenticated\",\n token,\n };\n if (\n snapshot.phase === next.phase &&\n snapshot.isLoading === next.isLoading &&\n snapshot.isAuthenticated === next.isAuthenticated &&\n snapshot.token === next.token\n ) {\n return false;\n }\n snapshot = next;\n return true;\n };\n\n const finalizeLoadingState = () => {\n if (!isLoading) {\n return;\n }\n isLoading = false;\n if (updateSnapshot()) {\n notify();\n }\n };\n\n // ---------------------------------------------------------------------------\n // Storage helpers (SPA mode only)\n // ---------------------------------------------------------------------------\n\n const storageGet = async (name: string): Promise<string | null> => {\n if (!storage) {\n return null;\n }\n return Fx.run(\n Fx.from({\n ok: async () => (await storage.getItem(key(name))) ?? null,\n err: (e) => e,\n }).pipe(\n Fx.inspect((error) =>\n Fx.sync(() =>\n console.error(\n `[convex-auth] Failed to read ${name} from storage:`,\n error,\n ),\n ),\n ),\n Fx.recover(() => Fx.succeed(null)),\n ),\n );\n };\n\n const storageSet = async (name: string, value: string): Promise<void> => {\n if (!storage) {\n return;\n }\n await Fx.run(\n Fx.from({\n ok: () => storage.setItem(key(name), value),\n err: (e) => e,\n }).pipe(\n Fx.inspect((error) =>\n Fx.sync(() =>\n console.error(\n `[convex-auth] Failed to write ${name} to storage:`,\n error,\n ),\n ),\n ),\n Fx.recover(() => Fx.succeed(undefined)),\n ),\n );\n };\n\n const storageRemove = async (name: string): Promise<void> => {\n if (!storage) {\n return;\n }\n await Fx.run(\n Fx.from({\n ok: () => storage.removeItem(key(name)),\n err: (e) => e,\n }).pipe(\n Fx.inspect((error) =>\n Fx.sync(() =>\n console.error(\n `[convex-auth] Failed to remove ${name} from storage:`,\n error,\n ),\n ),\n ),\n Fx.recover(() => Fx.succeed(undefined)),\n ),\n );\n };\n\n // ---------------------------------------------------------------------------\n // Token management\n // ---------------------------------------------------------------------------\n\n const bindConvexAuth = () => {\n convex.setAuth(fetchAccessToken, handleConvexAuthChange);\n };\n\n const setToken = async (\n args:\n | {\n shouldStore: true;\n tokens: AuthSession | null;\n requireHandshake?: boolean;\n resyncConvexAuth?: boolean;\n }\n | {\n shouldStore: false;\n tokens: { token: string } | null;\n requireHandshake?: boolean;\n resyncConvexAuth?: boolean;\n },\n ) => {\n const previousToken = token;\n\n if (args.tokens === null) {\n token = null;\n if (args.shouldStore) {\n await storageRemove(JWT_STORAGE_KEY);\n await storageRemove(REFRESH_TOKEN_STORAGE_KEY);\n }\n } else {\n token = args.tokens.token;\n if (args.shouldStore && \"refreshToken\" in args.tokens) {\n await storageSet(JWT_STORAGE_KEY, args.tokens.token);\n await storageSet(REFRESH_TOKEN_STORAGE_KEY, args.tokens.refreshToken);\n }\n }\n\n if (token !== previousToken) {\n authEpoch += 1;\n rejectObsoleteHandshakeWaiters(authEpoch);\n }\n\n if (token === null) {\n authConfirmed = false;\n handshakePending = false;\n settleHandshakeWaiters(authEpoch, {\n type: \"reject\",\n error: createHandshakeError(\"AUTH_HANDSHAKE_REJECTED\", {\n reason: \"token_cleared\",\n }),\n });\n } else {\n const shouldEnterHandshake =\n args.requireHandshake === true || !authConfirmed;\n if (shouldEnterHandshake) {\n authConfirmed = false;\n handshakePending = true;\n } else {\n handshakePending = false;\n }\n }\n\n const hadPendingLoad = isLoading;\n isLoading = false;\n const changed = updateSnapshot();\n if (args.resyncConvexAuth !== false) {\n bindConvexAuth();\n }\n if (hadPendingLoad || changed) {\n notify();\n }\n };\n\n const setTokenAndMaybeWait = async (\n args:\n | {\n shouldStore: true;\n tokens: AuthSession | null;\n waitForHandshake: boolean;\n context: AuthFlowContext;\n }\n | {\n shouldStore: false;\n tokens: { token: string } | null;\n waitForHandshake: boolean;\n context: AuthFlowContext;\n },\n ): Promise<boolean> => {\n const { waitForHandshake, context, ...tokenArgs } = args;\n await setToken({\n ...(tokenArgs as\n | { shouldStore: true; tokens: AuthSession | null }\n | { shouldStore: false; tokens: { token: string } | null }),\n requireHandshake: waitForHandshake,\n });\n if (tokenArgs.tokens === null) {\n return false;\n }\n if (waitForHandshake) {\n await waitForAuthHandshake(context);\n }\n return true;\n };\n\n // ---------------------------------------------------------------------------\n // Proxy fetch helper\n // ---------------------------------------------------------------------------\n\n const resolveProxyUrl = () => {\n const origin =\n typeof window !== \"undefined\" &&\n typeof window.location?.origin === \"string\"\n ? window.location.origin\n : typeof location !== \"undefined\" && typeof location.origin === \"string\"\n ? location.origin\n : null;\n if (origin !== null) {\n return new URL(proxy!, origin).toString();\n }\n return Fx.run(\n Fx.from({\n ok: () => new URL(proxy!).toString(),\n err: () => proxy! as string,\n }).pipe(Fx.recover((fallback) => Fx.succeed(fallback))),\n );\n };\n\n const isAbsoluteUrl = (value: string) => {\n return Fx.run(\n Fx.from({\n ok: () => {\n new URL(value);\n return true;\n },\n err: () => false as const,\n }).pipe(Fx.recover((v) => Fx.succeed(v))),\n );\n };\n\n const proxyFetch = async (body: Record<string, unknown>) => {\n const proxyUrl = await resolveProxyUrl();\n if (typeof window === \"undefined\" && !(await isAbsoluteUrl(proxyUrl))) {\n throw new Error(\n `Cannot call relative proxy URL \\`${proxy!}\\` without a browser origin. ` +\n \"Pass an absolute proxy URL for server runtimes.\",\n );\n }\n\n const response = await fetch(proxyUrl, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n credentials: \"include\",\n body: JSON.stringify(body),\n });\n if (!response.ok) {\n const errorBody = await Fx.run(\n Fx.from({\n ok: () => response.json() as Promise<Record<string, unknown>>,\n err: () => ({}) as Record<string, unknown>,\n }).pipe(Fx.recover((fallback) => Fx.succeed(fallback))),\n );\n // Reconstruct ConvexError when the proxy forwards structured auth error data.\n if (\n typeof errorBody === \"object\" &&\n errorBody !== null &&\n \"authError\" in errorBody &&\n typeof (errorBody as Record<string, unknown>).authError === \"object\"\n ) {\n throw new ConvexError(\n (errorBody as Record<string, unknown>).authError as Value,\n );\n }\n throw new Error(\n ((errorBody as Record<string, unknown>).error as string) ??\n `Proxy request failed: ${response.status}`,\n );\n }\n return Fx.run(\n Fx.from({\n ok: () => response.json(),\n err: () => new Error(\"Proxy response was not valid JSON\"),\n }).pipe(Fx.recover((e) => Fx.fatal(e))),\n );\n };\n\n // ---------------------------------------------------------------------------\n // Code verification with retries (SPA mode only)\n // ---------------------------------------------------------------------------\n\n const verifyCode = async (\n args: { code: string; verifier?: string } | { refreshToken: string },\n ) => {\n const verifyCodeRetryPolicy = Fx.retry.while(\n Fx.retry.compose(\n Fx.retry.jittered(Fx.retry.exponential(RETRY_BASE_MS)),\n Fx.retry.recurs(RETRY_MAX_RETRIES),\n ),\n (meta) => isTransientNetworkError(meta.input),\n );\n\n return Fx.run(\n Fx.from({\n ok: () =>\n httpClient!.action(\n requireApiRefs().signIn,\n \"code\" in args\n ? { params: { code: args.code }, verifier: args.verifier }\n : args,\n ),\n err: (e) => e,\n }).pipe(\n Fx.retry(verifyCodeRetryPolicy),\n Fx.recover((e) => Fx.fatal(e)),\n ),\n );\n };\n\n const verifyCodeAndSetToken = async (\n args: { code: string; verifier?: string } | { refreshToken: string },\n opts?: { resyncConvexAuth?: boolean },\n ) => {\n const { tokens } = await verifyCode(args);\n await setToken({\n shouldStore: true,\n tokens: (tokens as AuthSession | null) ?? null,\n resyncConvexAuth: opts?.resyncConvexAuth,\n });\n return tokens !== null;\n };\n\n const normalizeDeviceCodeResult = (device_code: any): DeviceCodeResult => {\n return {\n deviceCode: device_code.deviceCode,\n userCode: device_code.userCode,\n verification_uri:\n device_code.verification_uri ?? device_code.verificationUri,\n verification_uri_complete:\n device_code.verification_uri_complete ??\n device_code.verificationUriComplete,\n expiresIn: device_code.expiresIn,\n interval: device_code.interval,\n };\n };\n\n // ---------------------------------------------------------------------------\n // signIn\n // ---------------------------------------------------------------------------\n\n /**\n * Sign in with a provider.\n *\n * @param provider - Provider ID (e.g. `\"email\"`, `\"password\"`, `\"google\"`).\n * Omit when exchanging an OAuth code (the code carries the provider info).\n * @param args - Provider-specific arguments. Pass a `Record<string, Value>`\n * or `FormData`. Common fields: `email`, `password`, `code`, `redirectTo`.\n * @returns A {@link SignInResult} indicating the outcome.\n *\n * @example Email magic link\n * ```ts\n * await auth.signIn('email', { email: 'user@example.com' });\n * ```\n *\n * @example Password\n * ```ts\n * const result = await auth.signIn('password', { email, password, flow: 'signIn' });\n * if (result.kind === 'totpRequired') {\n * await auth.totp.verify({ code: totpCode, verifier: result.verifier });\n * }\n * ```\n *\n * @example OAuth (triggers redirect)\n * ```ts\n * await auth.signIn('google'); // redirects to Google\n * ```\n */\n const signIn = async (\n provider?: string,\n args?: FormData | Record<string, Value>,\n ): Promise<SignInResult> => {\n const params =\n args instanceof FormData\n ? (() => {\n const formParams: Record<string, Value> = {};\n args.forEach((value, key) => {\n formParams[key] = typeof value === \"string\" ? value : value.name;\n });\n return formParams;\n })()\n : (args ?? {});\n const flow =\n typeof params.flow === \"string\" && params.flow.length > 0\n ? params.flow\n : \"signIn\";\n\n const handleSignInActionResult = async (\n result: SignInActionResult,\n options: { shouldStore: boolean; persistVerifier: boolean },\n ): Promise<SignInResult> =>\n Fx.run(\n Fx.match(result, result.kind, {\n redirect: (redirectResult) =>\n Fx.from({\n ok: async () => {\n const redirectUrl = new URL(redirectResult.redirect);\n if (options.persistVerifier) {\n await storageSet(\n VERIFIER_STORAGE_KEY,\n redirectResult.verifier,\n );\n }\n if (typeof window !== \"undefined\") {\n window.location.href = redirectUrl.toString();\n }\n return {\n kind: \"redirect\" as const,\n redirect: redirectUrl,\n verifier: redirectResult.verifier,\n };\n },\n err: (e) => e as never,\n }),\n totpRequired: (totpRequiredResult) =>\n Fx.succeed({\n kind: \"totpRequired\" as const,\n verifier: totpRequiredResult.verifier,\n }),\n deviceCode: (deviceCodeResult) =>\n Fx.succeed({\n kind: \"deviceCode\" as const,\n deviceCode: normalizeDeviceCodeResult(\n deviceCodeResult.deviceCode,\n ),\n }),\n signedIn: (signedInResult) =>\n Fx.from({\n ok: async () => {\n const signingIn = await setTokenAndMaybeWait(\n options.shouldStore\n ? {\n shouldStore: true as const,\n tokens: signedInResult.tokens,\n waitForHandshake: true,\n context: { provider, flow },\n }\n : {\n shouldStore: false as const,\n tokens:\n signedInResult.tokens === null\n ? null\n : { token: signedInResult.tokens.token },\n waitForHandshake: true,\n context: { provider, flow },\n },\n );\n return signingIn\n ? ({ kind: \"signedIn\" as const } as SignInResult)\n : ({ kind: \"started\" as const } as SignInResult);\n },\n err: (e) => e as never,\n }),\n started: (_startedResult) => Fx.succeed({ kind: \"started\" as const }),\n passkeyOptions: (_passkeyOptionsResult) =>\n Fx.succeed({ kind: \"started\" as const }),\n totpSetup: (_totpSetupResult) =>\n Fx.succeed({ kind: \"started\" as const }),\n }),\n );\n\n if (proxy) {\n const result = (await proxyFetch({\n action: \"auth:signIn\",\n args: { provider, params },\n })) as SignInActionResult;\n return handleSignInActionResult(result, {\n shouldStore: false,\n persistVerifier: false,\n });\n }\n\n // SPA mode: call Convex directly.\n const verifier = (await storageGet(VERIFIER_STORAGE_KEY)) ?? undefined;\n await storageRemove(VERIFIER_STORAGE_KEY);\n const result = (await convex.action(requireApiRefs().signIn, {\n provider,\n params,\n verifier,\n })) as SignInActionResult;\n return handleSignInActionResult(result, {\n shouldStore: true,\n persistVerifier: true,\n });\n };\n\n // ---------------------------------------------------------------------------\n // signOut\n // ---------------------------------------------------------------------------\n\n /**\n * Sign out the current user.\n *\n * Invalidates the server session and clears local token state.\n * Errors are silently caught — calling `signOut` on an already\n * signed-out user is a no-op.\n */\n const signOut = async () => {\n if (proxy) {\n await Fx.run(\n Fx.from({\n ok: () => proxyFetch({ action: \"auth:signOut\", args: {} }),\n err: () => undefined,\n }).pipe(Fx.recover(() => Fx.succeed(undefined))),\n );\n await setToken({ shouldStore: false, tokens: null });\n if (convex.clearAuth) convex.clearAuth();\n return;\n }\n\n // SPA mode.\n await Fx.run(\n Fx.from({\n ok: () => convex.action(requireApiRefs().signOut, {}),\n err: () => undefined,\n }).pipe(Fx.recover(() => Fx.succeed(undefined))),\n );\n await setToken({ shouldStore: true, tokens: null });\n if (convex.clearAuth) convex.clearAuth();\n };\n\n // ---------------------------------------------------------------------------\n // fetchAccessToken — called by convex.setAuth()\n // ---------------------------------------------------------------------------\n\n const fetchAccessToken = async ({\n forceRefreshToken,\n }: {\n forceRefreshToken: boolean;\n }): Promise<string | null> => {\n if (!forceRefreshToken) return token;\n\n if (proxy) {\n // Proxy mode: POST to the proxy to refresh.\n // The proxy reads the real refresh token from the httpOnly cookie.\n const resolvedProxyUrl = await resolveProxyUrl();\n if (\n typeof window === \"undefined\" &&\n !(await isAbsoluteUrl(resolvedProxyUrl))\n ) {\n finalizeLoadingState();\n return token;\n }\n\n const tokenBeforeRefresh = token;\n return await browserMutex(\"__convexAuthProxyRefresh\", async () => {\n // Another tab/call may have already refreshed.\n if (token !== tokenBeforeRefresh) return token;\n\n const proxyRefreshRetryPolicy = Fx.retry.while(\n Fx.retry.compose(\n Fx.retry.jittered(Fx.retry.exponential(RETRY_BASE_MS)),\n Fx.retry.recurs(RETRY_MAX_RETRIES),\n ),\n (meta) => isRetriableProxyRefreshError(meta.input),\n );\n\n await Fx.run(\n Fx.from({\n ok: () =>\n proxyFetch({\n action: \"auth:signIn\",\n args: { refreshToken: true },\n }),\n err: (e) => e,\n }).pipe(\n Fx.retry(proxyRefreshRetryPolicy),\n Fx.chain((result: any) =>\n Fx.from({\n ok: async () => {\n if (result.tokens) {\n await setToken({\n shouldStore: false,\n tokens: { token: result.tokens.token },\n resyncConvexAuth: false,\n });\n } else {\n await setToken({\n shouldStore: false,\n tokens: null,\n resyncConvexAuth: false,\n });\n }\n },\n err: (e) => e,\n }),\n ),\n Fx.inspect((error) =>\n Fx.sync(() =>\n console.error(\"[convex-auth] Proxy refresh failed:\", error),\n ),\n ),\n Fx.recover(() => {\n if (token === null) {\n finalizeLoadingState();\n }\n return Fx.succeed(undefined);\n }),\n ),\n );\n return token;\n });\n }\n\n // SPA mode: refresh via localStorage + httpClient.\n const tokenBeforeLockAcquisition = token;\n return await browserMutex(REFRESH_TOKEN_STORAGE_KEY, async () => {\n const tokenAfterLockAcquisition = token;\n if (tokenAfterLockAcquisition !== tokenBeforeLockAcquisition) {\n return tokenAfterLockAcquisition;\n }\n const refreshToken =\n (await storageGet(REFRESH_TOKEN_STORAGE_KEY)) ?? null;\n if (!refreshToken) {\n finalizeLoadingState();\n return null;\n }\n await verifyCodeAndSetToken(\n { refreshToken },\n { resyncConvexAuth: false },\n );\n return token;\n });\n };\n\n // ---------------------------------------------------------------------------\n // OAuth code flow (SPA mode only — server handles this in proxy mode)\n // ---------------------------------------------------------------------------\n\n const handleCodeFlow = async () => {\n if (typeof window === \"undefined\") return;\n if (handlingCodeFlow) return;\n const code = new URLSearchParams(window.location.search).get(\"code\");\n if (!code) return;\n handlingCodeFlow = true;\n await Fx.run(\n Fx.from({\n ok: async () => {\n await signIn(undefined, { code });\n const codeUrl = new URL(window.location.href);\n codeUrl.searchParams.delete(\"code\");\n await replaceUrl(codeUrl.pathname + codeUrl.search + codeUrl.hash);\n },\n err: (e) => e,\n }).pipe(\n Fx.recover(() => Fx.succeed(undefined)),\n Fx.tap(() =>\n Fx.sync(() => {\n handlingCodeFlow = false;\n }),\n ),\n Fx.inspect(() =>\n Fx.sync(() => {\n handlingCodeFlow = false;\n }),\n ),\n ),\n );\n // The flag is always reset — Fx.recover above ensures success path,\n // but reset defensively here too.\n handlingCodeFlow = false;\n };\n\n // ---------------------------------------------------------------------------\n // Hydrate from storage (SPA mode only)\n // ---------------------------------------------------------------------------\n\n const hydrateFromStorage = async () => {\n const storedToken = (await storageGet(JWT_STORAGE_KEY)) ?? null;\n await setToken({\n shouldStore: false,\n tokens: storedToken === null ? null : { token: storedToken },\n });\n };\n\n // ---------------------------------------------------------------------------\n // Subscribe\n // ---------------------------------------------------------------------------\n\n /**\n * Subscribe to auth state changes. Invokes the callback immediately\n * with the current state, then again on every state transition.\n *\n * ```ts\n * const unsub = auth.onChange(setState);\n * ```\n *\n * @param cb - Callback receiving the latest {@link AuthState}.\n * @returns An unsubscribe function.\n */\n const onChange = (cb: (state: AuthState) => void): (() => void) => {\n cb(snapshot);\n const wrapped = () => cb(snapshot);\n subscribers.add(wrapped);\n return () => {\n subscribers.delete(wrapped);\n };\n };\n\n // ---------------------------------------------------------------------------\n // Initialization\n // ---------------------------------------------------------------------------\n\n // Cross-tab sync via storage events (SPA mode only).\n if (!proxy && typeof window !== \"undefined\") {\n const registryKey = key(JWT_STORAGE_KEY);\n const registry = getStorageListenerRegistry();\n const existingListener = registry[registryKey];\n if (existingListener !== undefined) {\n window.removeEventListener(\"storage\", existingListener);\n }\n\n const onStorage = (event: StorageEvent) => {\n Fx.detach(async () => {\n if (event.key !== key(JWT_STORAGE_KEY)) return;\n await setToken({\n shouldStore: false,\n tokens: event.newValue === null ? null : { token: event.newValue },\n });\n }, \"[convex-auth] Storage event handler failed:\");\n };\n window.addEventListener(\"storage\", onStorage);\n registry[registryKey] = onStorage;\n disposeStorageListener = () => {\n if (registry[registryKey] === onStorage) {\n delete registry[registryKey];\n }\n window.removeEventListener(\"storage\", onStorage);\n };\n }\n\n // Auto-wire: feed our tokens into the Convex client so\n // queries and mutations are automatically authenticated.\n bindConvexAuth();\n\n // Auto-hydrate and handle code flow.\n if (typeof window !== \"undefined\") {\n if (proxy) {\n // Proxy mode: eagerly resolve auth once on startup so routes that only\n // read auth state (and do not issue Convex queries yet) don't stay in\n // the initial loading phase.\n if (!hasServerToken) {\n Fx.detach(\n () => fetchAccessToken({ forceRefreshToken: true }),\n \"[convex-auth] Proxy token refresh failed:\",\n );\n }\n } else {\n // SPA mode: hydrate from localStorage, then handle OAuth code flow.\n Fx.detach(async () => {\n await Fx.run(\n Fx.from({\n ok: async () => {\n await hydrateFromStorage();\n await handleCodeFlow();\n },\n err: (e) => e,\n }).pipe(\n Fx.inspect((error) =>\n Fx.sync(() =>\n console.error(\n \"[convex-auth] Client initialization failed:\",\n error,\n ),\n ),\n ),\n Fx.recover((_error) =>\n Fx.from({\n ok: () => setToken({ shouldStore: false, tokens: null }),\n err: (e) => e,\n }).pipe(Fx.recover(() => Fx.succeed(undefined))),\n ),\n ),\n );\n }, \"[convex-auth] SPA initialization failed:\");\n }\n }\n\n // ---------------------------------------------------------------------------\n // Passkey helpers\n // ---------------------------------------------------------------------------\n\n /**\n * Base64url encode/decode helpers for the WebAuthn credential API.\n * These run client-side only (browser context).\n */\n const base64urlEncode = (buffer: ArrayBuffer): string => {\n const bytes = new Uint8Array(buffer);\n let binary = \"\";\n for (let i = 0; i < bytes.byteLength; i++) {\n binary += String.fromCharCode(bytes[i]!);\n }\n return btoa(binary)\n .replace(/\\+/g, \"-\")\n .replace(/\\//g, \"_\")\n .replace(/=+$/, \"\");\n };\n\n const base64urlDecode = (str: string): Uint8Array => {\n const padded = str.replace(/-/g, \"+\").replace(/_/g, \"/\");\n const binary = atob(padded);\n const bytes = new Uint8Array(binary.length);\n for (let i = 0; i < binary.length; i++) {\n bytes[i] = binary.charCodeAt(i);\n }\n return bytes;\n };\n\n const passkey = {\n /**\n * Check if WebAuthn passkeys are supported in the current environment.\n */\n isSupported: (): boolean => {\n return (\n typeof window !== \"undefined\" &&\n typeof window.PublicKeyCredential !== \"undefined\"\n );\n },\n\n /**\n * Check if conditional UI (autofill-assisted passkey sign-in) is supported.\n *\n * ```ts\n * if (await auth.passkey.isAutofillSupported()) {\n * auth.passkey.authenticate({ autofill: true });\n * }\n * ```\n */\n isAutofillSupported: async (): Promise<boolean> => {\n if (typeof window === \"undefined\") return false;\n if (typeof window.PublicKeyCredential === \"undefined\") return false;\n if (\n typeof (window.PublicKeyCredential as any)\n .isConditionalMediationAvailable !== \"function\"\n ) {\n return false;\n }\n return (\n window.PublicKeyCredential as any\n ).isConditionalMediationAvailable();\n },\n\n /**\n * Register a new passkey for the current or new user.\n *\n * Performs the full two-round-trip WebAuthn registration ceremony:\n * 1. Requests creation options from the server (challenge, RP info)\n * 2. Calls `navigator.credentials.create()` with the options\n * 3. Sends the attestation back to the server for verification\n * 4. Server creates user + account + passkey records and returns tokens\n *\n * Works in both SPA and proxy (SSR) modes.\n *\n * ```ts\n * await auth.passkey.register({ name: \"MacBook Touch ID\" });\n * ```\n *\n * @param opts.name - Friendly name for this passkey\n * @param opts.email - Email to associate with the new account\n * @param opts.userName - Username for the credential (defaults to email)\n * @param opts.userDisplayName - Display name for the credential\n * @returns `{ kind: \"signedIn\" }` on success\n */\n register: async (opts?: {\n name?: string;\n email?: string;\n userName?: string;\n userDisplayName?: string;\n }): Promise<SignInResult> => {\n const phase1Params = {\n flow: \"registerOptions\",\n email: opts?.email,\n userName: opts?.userName,\n userDisplayName: opts?.userDisplayName,\n };\n\n // Phase 1: Get registration options from server\n let phase1Result: SignInActionResult;\n if (proxy) {\n phase1Result = (await proxyFetch({\n action: \"auth:signIn\",\n args: { provider: \"passkey\", params: phase1Params },\n })) as SignInActionResult;\n } else {\n phase1Result = (await convex.action(requireApiRefs().signIn, {\n provider: \"passkey\",\n params: phase1Params,\n })) as SignInActionResult;\n }\n\n if (phase1Result.kind !== \"passkeyOptions\") {\n throw new Error(\"Server did not return passkey registration options\");\n }\n\n const options = phase1Result.options;\n\n // Convert base64url strings to ArrayBuffers for the credential API\n const createOptions: CredentialCreationOptions = {\n publicKey: {\n rp: options.rp,\n user: {\n id: base64urlDecode(options.user.id).buffer as ArrayBuffer,\n name: options.user.name,\n displayName: options.user.displayName,\n },\n challenge: base64urlDecode(options.challenge).buffer as ArrayBuffer,\n pubKeyCredParams: options.pubKeyCredParams,\n timeout: options.timeout,\n attestation: options.attestation,\n authenticatorSelection: options.authenticatorSelection,\n excludeCredentials: (options.excludeCredentials ?? []).map(\n (cred: any) => ({\n type: cred.type ?? \"public-key\",\n id: base64urlDecode(cred.id).buffer as ArrayBuffer,\n transports: cred.transports,\n }),\n ),\n },\n };\n\n // Phase 2: Create credential via browser API\n const credential = (await navigator.credentials.create(\n createOptions,\n )) as PublicKeyCredential | null;\n if (!credential) {\n throw new Error(\"Passkey registration was cancelled\");\n }\n\n const response = credential.response as AuthenticatorAttestationResponse;\n\n // Extract transports if available\n const transports =\n typeof response.getTransports === \"function\"\n ? response.getTransports()\n : undefined;\n\n const phase2Params = {\n flow: \"registerVerify\",\n clientDataJSON: base64urlEncode(response.clientDataJSON),\n attestationObject: base64urlEncode(response.attestationObject),\n transports,\n passkeyName: opts?.name,\n email: opts?.email,\n };\n\n // Phase 3: Send attestation to server for verification\n let phase2Result: SignInActionResult;\n if (proxy) {\n // In proxy mode the verifier is stored in an httpOnly cookie by the proxy.\n // We pass it back explicitly so the proxy can forward it to Convex.\n phase2Result = (await proxyFetch({\n action: \"auth:signIn\",\n args: {\n provider: \"passkey\",\n params: phase2Params,\n verifier: phase1Result.verifier,\n },\n })) as SignInActionResult;\n } else {\n phase2Result = (await convex.action(requireApiRefs().signIn, {\n provider: \"passkey\",\n params: phase2Params,\n verifier: phase1Result.verifier,\n })) as SignInActionResult;\n }\n\n return Fx.run(\n Fx.match(phase2Result, phase2Result.kind, {\n signedIn: (signedInResult) =>\n Fx.from({\n ok: async () => {\n const signingIn = await setTokenAndMaybeWait(\n proxy\n ? {\n shouldStore: false as const,\n tokens:\n signedInResult.tokens === null\n ? null\n : { token: signedInResult.tokens.token },\n waitForHandshake: true,\n context: {\n provider: \"passkey\",\n flow: \"registerVerify\",\n },\n }\n : {\n shouldStore: true as const,\n tokens: signedInResult.tokens,\n waitForHandshake: true,\n context: {\n provider: \"passkey\",\n flow: \"registerVerify\",\n },\n },\n );\n return signingIn\n ? ({ kind: \"signedIn\" as const } as SignInResult)\n : ({ kind: \"started\" as const } as SignInResult);\n },\n err: (e) => e as never,\n }),\n redirect: (_redirectResult) =>\n Fx.succeed({ kind: \"started\" as const }),\n started: (_startedResult) => Fx.succeed({ kind: \"started\" as const }),\n passkeyOptions: (_passkeyOptionsResult) =>\n Fx.succeed({ kind: \"started\" as const }),\n totpRequired: (_totpRequiredResult) =>\n Fx.succeed({ kind: \"started\" as const }),\n totpSetup: (_totpSetupResult) =>\n Fx.succeed({ kind: \"started\" as const }),\n deviceCode: (_deviceCodeResult) =>\n Fx.succeed({ kind: \"started\" as const }),\n }),\n );\n },\n\n /**\n * Authenticate with an existing passkey.\n *\n * Performs the full two-round-trip WebAuthn authentication ceremony:\n * 1. Requests assertion options from the server (challenge, allowed credentials)\n * 2. Calls `navigator.credentials.get()` with the options\n * 3. Sends the assertion back to the server for signature verification\n * 4. Server verifies signature, updates counter, creates session, returns tokens\n *\n * Works in both SPA and proxy (SSR) modes.\n *\n * ```ts\n * // Discoverable credential (no email needed)\n * await auth.passkey.authenticate();\n *\n * // Scoped to a specific user's credentials\n * await auth.passkey.authenticate({ email: \"user@example.com\" });\n *\n * // Autofill-assisted (conditional UI)\n * await auth.passkey.authenticate({ autofill: true });\n * ```\n *\n * @param opts.email - Scope to credentials for this email's user\n * @param opts.autofill - Use conditional mediation (autofill UI)\n * @returns `{ kind: \"signedIn\" }` on success\n */\n authenticate: async (opts?: {\n email?: string;\n autofill?: boolean;\n }): Promise<SignInResult> => {\n const phase1Params = {\n flow: \"authOptions\",\n email: opts?.email,\n };\n\n // Phase 1: Get assertion options from server\n let phase1Result: SignInActionResult;\n if (proxy) {\n phase1Result = (await proxyFetch({\n action: \"auth:signIn\",\n args: { provider: \"passkey\", params: phase1Params },\n })) as SignInActionResult;\n } else {\n phase1Result = (await convex.action(requireApiRefs().signIn, {\n provider: \"passkey\",\n params: phase1Params,\n })) as SignInActionResult;\n }\n\n if (phase1Result.kind !== \"passkeyOptions\") {\n throw new Error(\"Server did not return passkey authentication options\");\n }\n\n const options = phase1Result.options;\n\n // Convert base64url strings to ArrayBuffers for the credential API\n const getOptions: CredentialRequestOptions = {\n publicKey: {\n challenge: base64urlDecode(options.challenge).buffer as ArrayBuffer,\n timeout: options.timeout,\n rpId: options.rpId,\n userVerification: options.userVerification,\n allowCredentials: (options.allowCredentials ?? []).map(\n (cred: any) => ({\n type: cred.type ?? \"public-key\",\n id: base64urlDecode(cred.id).buffer as ArrayBuffer,\n transports: cred.transports,\n }),\n ),\n },\n ...(opts?.autofill ? { mediation: \"conditional\" as any } : {}),\n };\n\n // Phase 2: Get credential via browser API\n const credential = (await navigator.credentials.get(\n getOptions,\n )) as PublicKeyCredential | null;\n if (!credential) {\n throw new Error(\"Passkey authentication was cancelled\");\n }\n\n const response = credential.response as AuthenticatorAssertionResponse;\n\n const phase2Params = {\n flow: \"authVerify\",\n credentialId: base64urlEncode(credential.rawId),\n clientDataJSON: base64urlEncode(response.clientDataJSON),\n authenticatorData: base64urlEncode(response.authenticatorData),\n signature: base64urlEncode(response.signature),\n };\n\n // Phase 3: Send assertion to server for verification\n let phase2Result: SignInActionResult;\n if (proxy) {\n phase2Result = (await proxyFetch({\n action: \"auth:signIn\",\n args: {\n provider: \"passkey\",\n params: phase2Params,\n verifier: phase1Result.verifier,\n },\n })) as SignInActionResult;\n } else {\n phase2Result = (await convex.action(requireApiRefs().signIn, {\n provider: \"passkey\",\n params: phase2Params,\n verifier: phase1Result.verifier,\n })) as SignInActionResult;\n }\n\n return Fx.run(\n Fx.match(phase2Result, phase2Result.kind, {\n signedIn: (signedInResult) =>\n Fx.from({\n ok: async () => {\n const signingIn = await setTokenAndMaybeWait(\n proxy\n ? {\n shouldStore: false as const,\n tokens:\n signedInResult.tokens === null\n ? null\n : { token: signedInResult.tokens.token },\n waitForHandshake: true,\n context: { provider: \"passkey\", flow: \"authVerify\" },\n }\n : {\n shouldStore: true as const,\n tokens: signedInResult.tokens,\n waitForHandshake: true,\n context: { provider: \"passkey\", flow: \"authVerify\" },\n },\n );\n return signingIn\n ? ({ kind: \"signedIn\" as const } as SignInResult)\n : ({ kind: \"started\" as const } as SignInResult);\n },\n err: (e) => e as never,\n }),\n redirect: (_redirectResult) =>\n Fx.succeed({ kind: \"started\" as const }),\n started: (_startedResult) => Fx.succeed({ kind: \"started\" as const }),\n passkeyOptions: (_passkeyOptionsResult) =>\n Fx.succeed({ kind: \"started\" as const }),\n totpRequired: (_totpRequiredResult) =>\n Fx.succeed({ kind: \"started\" as const }),\n totpSetup: (_totpSetupResult) =>\n Fx.succeed({ kind: \"started\" as const }),\n deviceCode: (_deviceCodeResult) =>\n Fx.succeed({ kind: \"started\" as const }),\n }),\n );\n },\n };\n\n const totp = {\n /**\n * Start TOTP enrollment. Must be authenticated.\n *\n * Returns a URI for QR code display and a base32 secret for manual entry.\n *\n * ```ts\n * const setup = await auth.totp.setup();\n * // Display QR code from setup.uri\n * // Or show setup.secret for manual entry\n * ```\n */\n setup: async (opts?: {\n name?: string;\n accountName?: string;\n }): Promise<{\n uri: string;\n secret: string;\n verifier: string;\n totpId: string;\n }> => {\n const params: Record<string, any> = { flow: \"setup\" };\n if (opts?.name) params.name = opts.name;\n if (opts?.accountName) params.accountName = opts.accountName;\n\n if (proxy) {\n const result = await proxyFetch({\n action: \"auth:signIn\",\n args: { provider: \"totp\", params },\n });\n return {\n uri: result.totpSetup.uri,\n secret: result.totpSetup.secret,\n verifier: result.verifier,\n totpId: result.totpSetup.totpId,\n };\n }\n\n const result = await convex.action(requireApiRefs().signIn, {\n provider: \"totp\",\n params,\n });\n return {\n uri: result.totpSetup.uri,\n secret: result.totpSetup.secret,\n verifier: result.verifier,\n totpId: result.totpSetup.totpId,\n };\n },\n\n /**\n * Complete TOTP enrollment by verifying the first code from the authenticator app.\n *\n * ```ts\n * await auth.totp.confirm({ code: \"123456\", verifier: setup.verifier, totpId: setup.totpId });\n * ```\n */\n confirm: async (opts: {\n code: string;\n verifier: string;\n totpId: string;\n }): Promise<void> => {\n const params: Record<string, any> = {\n flow: \"confirm\",\n code: opts.code,\n totpId: opts.totpId,\n };\n\n if (proxy) {\n const result = await proxyFetch({\n action: \"auth:signIn\",\n args: { provider: \"totp\", params, verifier: opts.verifier },\n });\n if (result.tokens) {\n await setTokenAndMaybeWait({\n shouldStore: false,\n tokens:\n result.tokens === null ? null : { token: result.tokens.token },\n waitForHandshake: true,\n context: { provider: \"totp\", flow: \"confirm\" },\n });\n }\n return;\n }\n\n const result = await convex.action(requireApiRefs().signIn, {\n provider: \"totp\",\n params,\n verifier: opts.verifier,\n });\n if (result.tokens) {\n await setTokenAndMaybeWait({\n shouldStore: true,\n tokens: (result.tokens as AuthSession | null) ?? null,\n waitForHandshake: true,\n context: { provider: \"totp\", flow: \"confirm\" },\n });\n }\n },\n\n /**\n * Complete 2FA verification during sign-in.\n *\n * Called after a credentials sign-in returns `kind: \"totpRequired\"`.\n *\n * ```ts\n * const result = await auth.signIn(\"password\", { email, password });\n * if (result.kind === \"totpRequired\") {\n * await auth.totp.verify({ code: \"123456\", verifier: result.verifier });\n * }\n * ```\n */\n verify: async (opts: { code: string; verifier: string }): Promise<void> => {\n const params: Record<string, any> = {\n flow: \"verify\",\n code: opts.code,\n };\n\n if (proxy) {\n const result = await proxyFetch({\n action: \"auth:signIn\",\n args: { provider: \"totp\", params, verifier: opts.verifier },\n });\n if (result.tokens) {\n await setTokenAndMaybeWait({\n shouldStore: false,\n tokens:\n result.tokens === null ? null : { token: result.tokens.token },\n waitForHandshake: true,\n context: { provider: \"totp\", flow: \"verify\" },\n });\n }\n return;\n }\n\n const result = await convex.action(requireApiRefs().signIn, {\n provider: \"totp\",\n params,\n verifier: opts.verifier,\n });\n if (result.tokens) {\n await setTokenAndMaybeWait({\n shouldStore: true,\n tokens: (result.tokens as AuthSession | null) ?? null,\n waitForHandshake: true,\n context: { provider: \"totp\", flow: \"verify\" },\n });\n }\n },\n };\n\n const device = {\n /**\n * Poll for device authorization status.\n *\n * The device calls this repeatedly (respecting `interval`) after\n * initiating a device flow via `signIn(\"device\")`. Returns when\n * the user authorizes, or throws on timeout/denial.\n *\n * ```ts\n * const result = await auth.signIn(\"device\");\n * const { deviceCode } = result;\n * // Display deviceCode.userCode to the user, then poll:\n * await auth.device.poll(deviceCode);\n * // User is now signed in\n * ```\n *\n * @param code - The {@link DeviceCodeResult} from `signIn(\"device\")`.\n * @returns Resolves when the device is authorized and tokens are stored.\n * @throws When the code expires, is denied, or polling encounters an error.\n */\n poll: async (code: DeviceCodeResult): Promise<void> => {\n const intervalMs = code.interval * 1000;\n const expiresAt = Date.now() + code.expiresIn * 1000;\n\n while (Date.now() < expiresAt) {\n await new Promise((resolve) => setTimeout(resolve, intervalMs));\n\n const pollResult = await Fx.run(\n Fx.from({\n ok: async () => {\n let result: any;\n const params: Record<string, any> = {\n flow: \"poll\",\n deviceCode: code.deviceCode,\n };\n\n if (proxy) {\n result = await proxyFetch({\n action: \"auth:signIn\",\n args: { provider: \"device\", params },\n });\n } else {\n result = await convex.action(requireApiRefs().signIn, {\n provider: \"device\",\n params,\n });\n }\n\n return result;\n },\n err: (e) => e,\n }).pipe(\n Fx.recover((e: unknown) => {\n const dispatch =\n e instanceof ConvexError\n ? {\n tag:\n (e.data as Record<string, unknown> | undefined)\n ?.code === \"DEVICE_AUTHORIZATION_PENDING\"\n ? \"continue\"\n : (e.data as Record<string, unknown> | undefined)\n ?.code === \"DEVICE_SLOW_DOWN\"\n ? \"slowDown\"\n : \"fatal\",\n }\n : ({ tag: \"fatal\" } as const);\n\n return Fx.match(dispatch, dispatch.tag, {\n continue: () => Fx.succeed({ _poll: \"continue\" as const }),\n slowDown: () => Fx.succeed({ _poll: \"slow_down\" as const }),\n fatal: () => Fx.fatal(e),\n });\n }),\n ),\n );\n\n if (\"_poll\" in pollResult) {\n if (pollResult._poll === \"slow_down\") {\n // Back off by adding one interval\n await new Promise((resolve) => setTimeout(resolve, intervalMs));\n }\n continue;\n }\n\n // Authorized — tokens received\n if (pollResult.tokens) {\n if (proxy) {\n await setTokenAndMaybeWait({\n shouldStore: false,\n tokens:\n pollResult.tokens === null\n ? null\n : { token: pollResult.tokens.token },\n waitForHandshake: true,\n context: { provider: \"device\", flow: \"poll\" },\n });\n } else {\n await setTokenAndMaybeWait({\n shouldStore: true,\n tokens: (pollResult.tokens as AuthSession | null) ?? null,\n waitForHandshake: true,\n context: { provider: \"device\", flow: \"poll\" },\n });\n }\n return;\n }\n }\n\n throw new Error(\"Device authorization timed out.\");\n },\n\n /**\n * Authorize a device from the verification page.\n *\n * Called by an authenticated user on the verification page after\n * they enter the user code displayed on the device.\n *\n * ```ts\n * // On the /device verification page:\n * await auth.device.verify(userCode);\n * ```\n *\n * @param userCode - The user code entered by the user (e.g. \"WDJB-MJHT\").\n */\n verify: async (userCode: string): Promise<void> => {\n const params: Record<string, any> = {\n flow: \"verify\",\n userCode,\n };\n\n if (proxy) {\n await proxyFetch({\n action: \"auth:signIn\",\n args: { provider: \"device\", params },\n });\n } else {\n await convex.action(requireApiRefs().signIn, {\n provider: \"device\",\n params,\n });\n }\n },\n };\n\n return {\n /** Current auth state snapshot. */\n get state(): AuthState {\n return snapshot;\n },\n /** Sign in with a provider. See {@link SignInResult} for return shape. */\n signIn,\n /** Sign out and clear all token state. */\n signOut,\n /** Subscribe to auth state changes. Returns an unsubscribe function. */\n onChange,\n /** Passkey (WebAuthn) authentication helpers. */\n passkey,\n /** TOTP two-factor authentication helpers. */\n totp,\n /** Device authorization (RFC 8628) helpers. */\n device,\n /** Remove global listeners when disposing this client instance. */\n destroy: () => {\n destroyed = true;\n settleHandshakeWaiters(authEpoch, {\n type: \"reject\",\n error: createHandshakeError(\"AUTH_HANDSHAKE_REJECTED\", {\n reason: \"destroyed\",\n }),\n });\n disposeStorageListener?.();\n subscribers.clear();\n },\n } as AuthClient<Api>;\n}\n\n// ---------------------------------------------------------------------------\n// Browser mutex — ensures only one tab refreshes a token at a time.\n// ---------------------------------------------------------------------------\n\nasync function browserMutex<T>(\n key: string,\n callback: () => Promise<T>,\n): Promise<T> {\n const lockManager = (globalThis as any)?.navigator?.locks;\n return lockManager !== undefined\n ? await lockManager.request(key, callback)\n : await manualMutex(key, callback);\n}\n\nfunction getStorageListenerRegistry(): Record<\n string,\n (event: StorageEvent) => void\n> {\n const globalAny = globalThis as any;\n if (globalAny.__convexAuthStorageListeners === undefined) {\n globalAny.__convexAuthStorageListeners = {} as Record<\n string,\n (event: StorageEvent) => void\n >;\n }\n return globalAny.__convexAuthStorageListeners as Record<\n string,\n (event: StorageEvent) => void\n >;\n}\n\nfunction getManualMutexTails(): Record<string, Promise<void>> {\n const globalAny = globalThis as any;\n if (globalAny.__convexAuthMutexTails === undefined) {\n globalAny.__convexAuthMutexTails = {} as Record<string, Promise<void>>;\n }\n return globalAny.__convexAuthMutexTails as Record<string, Promise<void>>;\n}\n\nasync function manualMutex<T>(\n key: string,\n callback: () => Promise<T>,\n): Promise<T> {\n const mutexTails = getManualMutexTails();\n const previousTail = mutexTails[key] ?? Promise.resolve();\n\n let releaseCurrent: (() => void) | undefined;\n const currentTail = new Promise<void>((resolve) => {\n releaseCurrent = resolve;\n });\n\n mutexTails[key] = previousTail.then(\n () => currentTail,\n () => currentTail,\n );\n\n await Fx.run(\n Fx.from({\n ok: () => previousTail,\n err: () => undefined,\n }).pipe(Fx.recover(() => Fx.succeed(undefined))),\n );\n let result: T;\n let threw = false;\n let thrownError: unknown;\n await Fx.run(\n Fx.from({\n ok: async () => {\n result = await callback();\n },\n err: (e) => e,\n }).pipe(\n Fx.recover((e) => {\n threw = true;\n thrownError = e;\n return Fx.succeed(undefined);\n }),\n ),\n );\n releaseCurrent?.();\n if (mutexTails[key] === currentTail) {\n delete mutexTails[key];\n }\n if (threw) {\n throw thrownError;\n }\n return result!;\n}\n"],"mappings":"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"}
|
|
@@ -1,13 +1,27 @@
|
|
|
1
1
|
import { functions_d_exports } from "../functions.js";
|
|
2
|
+
import { model_d_exports } from "../model.js";
|
|
2
3
|
import { index_d_exports } from "../index.js";
|
|
4
|
+
import { identity_d_exports } from "../public/identity.js";
|
|
5
|
+
import { factors_d_exports } from "../public/factors.js";
|
|
6
|
+
import { groups_d_exports } from "../public/groups.js";
|
|
7
|
+
import { enterprise_d_exports } from "../public/enterprise.js";
|
|
8
|
+
import { keys_d_exports } from "../public/keys.js";
|
|
3
9
|
import { public_d_exports } from "../public.js";
|
|
10
|
+
import { shared_d_exports } from "../public/shared.js";
|
|
4
11
|
import { ApiFromModules, FilterApi, FunctionReference } from "convex/server";
|
|
5
12
|
|
|
6
13
|
//#region src/component/_generated/api.d.ts
|
|
7
14
|
declare const fullApi: ApiFromModules<{
|
|
8
15
|
functions: typeof functions_d_exports;
|
|
9
16
|
index: typeof index_d_exports;
|
|
17
|
+
model: typeof model_d_exports;
|
|
10
18
|
public: typeof public_d_exports;
|
|
19
|
+
"public/enterprise": typeof enterprise_d_exports;
|
|
20
|
+
"public/factors": typeof factors_d_exports;
|
|
21
|
+
"public/groups": typeof groups_d_exports;
|
|
22
|
+
"public/identity": typeof identity_d_exports;
|
|
23
|
+
"public/keys": typeof keys_d_exports;
|
|
24
|
+
"public/shared": typeof shared_d_exports;
|
|
11
25
|
}>;
|
|
12
26
|
/**
|
|
13
27
|
* A utility for referencing Convex functions in your app's public API.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"api.d.ts","names":[],"sources":["../../../src/component/_generated/api.ts"],"mappings":"
|
|
1
|
+
{"version":3,"file":"api.d.ts","names":[],"sources":["../../../src/component/_generated/api.ts"],"mappings":";;;;;;;;;;;;;cA4BM,OAAA,EAAS,cAAA;EACb,SAAA,SAAkB,mBAAA;EAClB,KAAA,SAAc,eAAA;EACd,KAAA,SAAc,eAAA;EACd,MAAA,SAAe,gBAAA;EACf,mBAAA,SAA4B,oBAAA;EAC5B,gBAAA,SAAyB,iBAAA;EACzB,eAAA,SAAwB,gBAAA;EACxB,iBAAA,SAA0B,kBAAA;EAC1B,aAAA,SAAsB,cAAA;EACtB,eAAA,SAAwB,gBAAA;AAAA;;;;;;;;;cAWb,GAAA,EAAK,SAAA,QACT,OAAA,EACP,iBAAA;;;;;;;;;cAWW,QAAA,EAAU,SAAA,QACd,OAAA,EACP,iBAAA;AAAA,cAGW,UAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"api.js","names":[],"sources":["../../../src/component/_generated/api.ts"],"sourcesContent":["/* eslint-disable */\n/**\n * Generated `api` utility.\n *\n * THIS CODE IS AUTOMATICALLY GENERATED.\n *\n * To regenerate, run `npx convex dev`.\n * @module\n */\n\nimport type * as functions from \"../functions.js\";\nimport type * as index from \"../index.js\";\nimport type * as public_ from \"../public.js\";\n\nimport type {\n ApiFromModules,\n FilterApi,\n FunctionReference,\n} from \"convex/server\";\nimport { anyApi, componentsGeneric } from \"convex/server\";\n\nconst fullApi: ApiFromModules<{\n functions: typeof functions;\n index: typeof index;\n public: typeof public_;\n}> = anyApi as any;\n\n/**\n * A utility for referencing Convex functions in your app's public API.\n *\n * Usage:\n * ```js\n * const myFunctionReference = api.myModule.myFunction;\n * ```\n */\nexport const api: FilterApi<\n typeof fullApi,\n FunctionReference<any, \"public\">\n> = anyApi as any;\n\n/**\n * A utility for referencing Convex functions in your app's internal API.\n *\n * Usage:\n * ```js\n * const myFunctionReference = internal.myModule.myFunction;\n * ```\n */\nexport const internal: FilterApi<\n typeof fullApi,\n FunctionReference<any, \"internal\">\n> = anyApi as any;\n\nexport const components = componentsGeneric() as unknown as {};\n"],"mappings":";;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"api.js","names":[],"sources":["../../../src/component/_generated/api.ts"],"sourcesContent":["/* eslint-disable */\n/**\n * Generated `api` utility.\n *\n * THIS CODE IS AUTOMATICALLY GENERATED.\n *\n * To regenerate, run `npx convex dev`.\n * @module\n */\n\nimport type * as functions from \"../functions.js\";\nimport type * as index from \"../index.js\";\nimport type * as model from \"../model.js\";\nimport type * as public_ from \"../public.js\";\nimport type * as public_enterprise from \"../public/enterprise.js\";\nimport type * as public_factors from \"../public/factors.js\";\nimport type * as public_groups from \"../public/groups.js\";\nimport type * as public_identity from \"../public/identity.js\";\nimport type * as public_keys from \"../public/keys.js\";\nimport type * as public_shared from \"../public/shared.js\";\n\nimport type {\n ApiFromModules,\n FilterApi,\n FunctionReference,\n} from \"convex/server\";\nimport { anyApi, componentsGeneric } from \"convex/server\";\n\nconst fullApi: ApiFromModules<{\n functions: typeof functions;\n index: typeof index;\n model: typeof model;\n public: typeof public_;\n \"public/enterprise\": typeof public_enterprise;\n \"public/factors\": typeof public_factors;\n \"public/groups\": typeof public_groups;\n \"public/identity\": typeof public_identity;\n \"public/keys\": typeof public_keys;\n \"public/shared\": typeof public_shared;\n}> = anyApi as any;\n\n/**\n * A utility for referencing Convex functions in your app's public API.\n *\n * Usage:\n * ```js\n * const myFunctionReference = api.myModule.myFunction;\n * ```\n */\nexport const api: FilterApi<\n typeof fullApi,\n FunctionReference<any, \"public\">\n> = anyApi as any;\n\n/**\n * A utility for referencing Convex functions in your app's internal API.\n *\n * Usage:\n * ```js\n * const myFunctionReference = internal.myModule.myFunction;\n * ```\n */\nexport const internal: FilterApi<\n typeof fullApi,\n FunctionReference<any, \"internal\">\n> = anyApi as any;\n\nexport const components = componentsGeneric() as unknown as {};\n"],"mappings":";;;;;;;;;;;AAiDA,MAAa,MAGT;;;;;;;;;AAUJ,MAAa,WAGT;AAEJ,MAAa,aAAa,mBAAmB"}
|