cauthy-auth 0.5.2 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (72) hide show
  1. package/README.md +68 -3
  2. package/dist/{cauthy-BCTCqubt.d.ts → cauthy-Bn3iv50y.d.ts} +1 -1
  3. package/dist/{cauthy-hswMoS7B.d.mts → cauthy-C29HCvag.d.mts} +1 -1
  4. package/dist/cli.js +490 -25
  5. package/dist/client.d.mts +273 -0
  6. package/dist/client.d.ts +273 -0
  7. package/dist/client.js +342 -0
  8. package/dist/client.js.map +1 -0
  9. package/dist/client.mjs +308 -0
  10. package/dist/client.mjs.map +1 -0
  11. package/dist/express.d.mts +24 -0
  12. package/dist/express.d.ts +24 -0
  13. package/dist/express.js +102 -0
  14. package/dist/express.js.map +1 -0
  15. package/dist/express.mjs +76 -0
  16. package/dist/express.mjs.map +1 -0
  17. package/dist/fastify.d.mts +2 -2
  18. package/dist/fastify.d.ts +2 -2
  19. package/dist/fastify.js +3 -1
  20. package/dist/fastify.js.map +1 -1
  21. package/dist/fastify.mjs +3 -1
  22. package/dist/fastify.mjs.map +1 -1
  23. package/dist/hono.d.mts +23 -0
  24. package/dist/hono.d.ts +23 -0
  25. package/dist/hono.js +50 -0
  26. package/dist/hono.js.map +1 -0
  27. package/dist/hono.mjs +24 -0
  28. package/dist/hono.mjs.map +1 -0
  29. package/dist/index.d.mts +44 -6
  30. package/dist/index.d.ts +44 -6
  31. package/dist/index.js +713 -37
  32. package/dist/index.js.map +1 -1
  33. package/dist/index.mjs +701 -37
  34. package/dist/index.mjs.map +1 -1
  35. package/dist/next.d.mts +24 -0
  36. package/dist/next.d.ts +24 -0
  37. package/dist/next.js +77 -0
  38. package/dist/next.js.map +1 -0
  39. package/dist/next.mjs +52 -0
  40. package/dist/next.mjs.map +1 -0
  41. package/dist/react.d.mts +592 -7
  42. package/dist/react.d.ts +592 -7
  43. package/dist/react.js +1025 -14
  44. package/dist/react.js.map +1 -1
  45. package/dist/react.mjs +1013 -10
  46. package/dist/react.mjs.map +1 -1
  47. package/dist/styles.css +271 -0
  48. package/dist/svelte.d.mts +26 -0
  49. package/dist/svelte.d.ts +26 -0
  50. package/dist/svelte.js +413 -0
  51. package/dist/svelte.js.map +1 -0
  52. package/dist/svelte.mjs +384 -0
  53. package/dist/svelte.mjs.map +1 -0
  54. package/dist/{system-DvcQjORr.d.ts → system-DhRr_WxR.d.ts} +139 -1
  55. package/dist/{system-CR8p4BjB.d.mts → system-ZD_Wa8Bm.d.mts} +139 -1
  56. package/dist/theme.d.mts +56 -1
  57. package/dist/theme.d.ts +56 -1
  58. package/dist/theme.js +181 -5
  59. package/dist/theme.js.map +1 -1
  60. package/dist/theme.mjs +176 -4
  61. package/dist/theme.mjs.map +1 -1
  62. package/dist/validate-B_iC-4y8.d.mts +19 -0
  63. package/dist/validate-B_iC-4y8.d.ts +19 -0
  64. package/dist/vue.d.mts +28 -0
  65. package/dist/vue.d.ts +28 -0
  66. package/dist/vue.js +431 -0
  67. package/dist/vue.js.map +1 -0
  68. package/dist/vue.mjs +402 -0
  69. package/dist/vue.mjs.map +1 -0
  70. package/package.json +68 -7
  71. package/dist/permissions-B-a3eN0h.d.mts +0 -52
  72. package/dist/permissions-B-a3eN0h.d.ts +0 -52
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/react.tsx","../src/permissions.ts"],"sourcesContent":["// React: who is signed in, in the browser.\n//\n// <CauthyProvider> // once, at the root\n// <App />\n// </CauthyProvider>\n//\n// const { session, status, signIn, signOut } = useSession()\n//\n// The browser never holds a token: it asks the application's own server\n// (`/api/auth/session`), which answers who is signed in and their\n// organizations. The session is kept current by asking again a little before\n// it expires and when the window comes back into view.\n\nimport { createContext, useCallback, useContext, useEffect, useMemo, useRef, useState, type ReactNode } from 'react'\nimport type { PublicSession } from './types'\n\nexport type { JsonValue, PublicSession, SessionOrganization, SessionUser } from './types'\nexport { can } from './permissions'\n\nexport interface SessionContext {\n /** The signed-in person and their organizations, or null. */\n session: PublicSession | null\n status: 'loading' | 'authenticated' | 'unauthenticated'\n /** Sends the browser to sign in, and back to `returnTo` (default: where it is now). */\n signIn(options?: { returnTo?: string; locale?: string; prompt?: 'login' }): void\n /** Signs out of this application and of Cauthy in this browser. */\n signOut(): void\n /** Asks the server again who is signed in. */\n refresh(): Promise<PublicSession | null>\n /** Where the person looks after their account: password, second step, passkeys. */\n accountUrl(returnTo?: string): string\n}\n\nexport interface CauthyProviderProps {\n children: ReactNode\n /** Where the server mounted the routes. Default: `/api/auth`. */\n basePath?: string\n /**\n * The session the server already read while rendering (SSR): the first\n * paint is then right, with no \"loading\". `null` means \"nobody\"; leave it\n * out when the server did not look.\n */\n initialSession?: PublicSession | null\n}\n\nconst Ctx = createContext<SessionContext | null>(null)\n\n/** Ask again this long before the session's token runs out. */\nconst AHEAD_MS = 60_000\n\nexport function CauthyProvider({ children, basePath = '/api/auth', initialSession }: CauthyProviderProps) {\n const base = basePath.replace(/\\/+$/, '')\n const [session, setSession] = useState<PublicSession | null>(initialSession ?? null)\n const [status, setStatus] = useState<SessionContext['status']>(\n initialSession === undefined ? 'loading' : initialSession === null ? 'unauthenticated' : 'authenticated',\n )\n const asking = useRef<Promise<PublicSession | null> | null>(null)\n\n const refresh = useCallback((): Promise<PublicSession | null> => {\n asking.current ??= (async () => {\n try {\n const res = await fetch(`${base}/session`, { credentials: 'same-origin', headers: { accept: 'application/json' } })\n if (!res.ok) throw new Error(String(res.status))\n const body = (await res.json()) as { session: PublicSession | null; status: string }\n // \"expired\" is the server unable to reach Cauthy: what is on screen\n // stays, and the next ask settles it.\n if (body.status !== 'expired') {\n setSession(body.session)\n setStatus(body.session ? 'authenticated' : 'unauthenticated')\n }\n return body.session\n } catch {\n setStatus((s) => (s === 'loading' ? 'unauthenticated' : s))\n return null\n } finally {\n asking.current = null\n }\n })()\n return asking.current\n }, [base])\n\n useEffect(() => {\n if (initialSession === undefined) void refresh()\n }, [initialSession, refresh])\n\n useEffect(() => {\n if (!session) return\n const wait = Math.max(new Date(session.expiresAt).getTime() - Date.now() - AHEAD_MS, 5_000)\n const timer = setTimeout(() => void refresh(), wait)\n return () => clearTimeout(timer)\n }, [session, refresh])\n\n useEffect(() => {\n const onVisible = () => {\n if (document.visibilityState === 'visible') void refresh()\n }\n document.addEventListener('visibilitychange', onVisible)\n return () => document.removeEventListener('visibilitychange', onVisible)\n }, [refresh])\n\n const value = useMemo<SessionContext>(\n () => ({\n session,\n status,\n refresh,\n signIn(options = {}) {\n const q = new URLSearchParams({ return_to: options.returnTo ?? window.location.pathname + window.location.search })\n if (options.locale) q.set('locale', options.locale)\n if (options.prompt) q.set('prompt', options.prompt)\n window.location.assign(`${base}/login?${q}`)\n },\n signOut() {\n window.location.assign(`${base}/logout`)\n },\n accountUrl(returnTo) {\n const back = returnTo ?? (typeof window === 'undefined' ? '/' : window.location.pathname + window.location.search)\n return `${base}/account?return_to=${encodeURIComponent(back)}`\n },\n }),\n [session, status, refresh, base],\n )\n return <Ctx.Provider value={value}>{children}</Ctx.Provider>\n}\n\nexport function useSession(): SessionContext {\n const ctx = useContext(Ctx)\n if (ctx === null) throw new Error('cauthy-auth: useSession needs <CauthyProvider> above it')\n return ctx\n}\n","// What a person may do in an organization.\n//\n// When a system keeps its catalog of roles in Cauthy, each of a person's\n// organizations arrives with what their role — and anything given or denied to\n// them apart from it — lets them do. Checking is a lookup in that list: no\n// call to Cauthy, on the server or in the browser.\n\n/** The part of an organization that says what its member may do. */\nexport interface Permitted {\n /** \"resource:action\" entries the person is allowed; \"*\" is any. Absent when the system keeps no catalog in Cauthy. */\n permissions?: string[]\n /** Entries the person is denied whatever else allows them. */\n denied?: string[]\n}\n\nfunction matches(entry: string, resource: string, action: string): boolean {\n // The resource may itself hold a colon: the action is what follows the last one.\n const i = entry.lastIndexOf(':')\n if (i < 0) return false\n const r = entry.slice(0, i)\n const a = entry.slice(i + 1)\n return (r === '*' || r === resource) && (a === '*' || a === action)\n}\n\n/**\n * Whether the person may do an action on a resource in an organization:\n * allowed by some entry, and denied by none. A denial wins.\n *\n * An organization of a system that keeps no catalog in Cauthy carries no\n * permissions, and the answer is `false`: decide by its `role` instead.\n *\n * if (!can(organization, 'invoicing', 'write')) return forbidden()\n */\nexport function can(organization: Permitted | null | undefined, resource: string, action: string): boolean {\n if (!organization?.permissions) return false\n if ((organization.denied ?? []).some((d) => matches(d, resource, action))) return false\n return organization.permissions.some((p) => matches(p, resource, action))\n}\n\n// ── A system's catalog of roles ────────────────────────────────────────────\n\n/** Something a role may do: an action on a resource, in organizations of a kind (\"*\", the default, is every kind). */\nexport interface PolicyPermission {\n kind?: string\n resource: string\n action: string\n}\n\nexport interface PolicyRole {\n role: string\n name?: string\n description?: string\n /** Roles whose permissions this one has as well. */\n inherits?: string[]\n permissions?: PolicyPermission[]\n}\n\nexport interface PushPolicyOptions {\n /** The system whose catalog this is. Default: `CAUTHY_SYSTEM`. */\n system?: string\n roles: PolicyRole[]\n /** Cauthy's address. Default: `CAUTHY_ISSUER`. */\n issuer?: string\n /** The workspace's slug. Default: `CAUTHY_TENANT`. */\n tenant?: string\n /** A personal access token with `organizations:manage`. Default: `CAUTHY_TOKEN`. */\n token?: string\n fetch?: typeof fetch\n}\n\n/**\n * Gives Cauthy a system's catalog of roles, replacing the one it has. It is\n * the way to load a first catalog from what a system already had; from then on\n * the catalog is Cauthy's, edited in its dashboard, and pushing again would\n * overwrite what was edited there.\n */\nexport async function pushPolicy(o: PushPolicyOptions): Promise<void> {\n const env = (n: string) => (typeof process !== 'undefined' ? process.env?.[n] : undefined)\n const issuer = (o.issuer ?? env('CAUTHY_ISSUER') ?? '').replace(/\\/+$/, '')\n const system = o.system ?? env('CAUTHY_SYSTEM') ?? ''\n const tenant = o.tenant ?? env('CAUTHY_TENANT') ?? ''\n const token = o.token ?? env('CAUTHY_TOKEN') ?? ''\n for (const [name, v] of Object.entries({ CAUTHY_ISSUER: issuer, CAUTHY_SYSTEM: system, CAUTHY_TENANT: tenant, CAUTHY_TOKEN: token })) {\n if (v === '') throw new Error(`cauthy-auth: ${name} is required to push a policy`)\n }\n const res = await (o.fetch ?? fetch)(`${issuer}/v1/systems/${encodeURIComponent(system)}/policy`, {\n method: 'PUT',\n headers: { authorization: `Bearer ${token}`, 'x-tenant-key': tenant, 'content-type': 'application/json' },\n body: JSON.stringify({ roles: o.roles }),\n })\n if (!res.ok) {\n const body = (await res.json().catch(() => null)) as { errors?: { message?: string }[] } | null\n throw new Error(`cauthy-auth: Cauthy refused the policy (${res.status}): ${body?.errors?.[0]?.message ?? res.statusText}`)\n }\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/react.tsx","../src/theme.ts","../src/validate.ts","../src/client.ts","../src/permissions.ts","../src/components.tsx"],"sourcesContent":["// React: who is signed in, in the browser.\n//\n// <CauthyProvider> // once, at the root\n// <App />\n// </CauthyProvider>\n//\n// const { session, status, signIn, signOut } = useSession()\n//\n// The browser never holds a token: it asks the application's own server\n// (`/api/auth/session`), which answers who is signed in and their\n// organizations. The session is kept current by asking again a little before\n// it expires and when the window comes back into view.\n\nimport { createContext, useCallback, useContext, useEffect, useMemo, useRef, useState, type ReactNode } from 'react'\nimport { createAuthClient, type AuthClient } from './client'\nimport type { PublicSession } from './types'\n\nexport type { JsonValue, PublicSession, SessionOrganization, SessionUser } from './types'\nexport { can, definePolicy, type PermissionOf, type Policy, type RoleOf } from './permissions'\n\nexport interface SessionContext {\n /** The signed-in person and their organizations, or null. */\n session: PublicSession | null\n status: 'loading' | 'authenticated' | 'unauthenticated'\n /** Sends the browser to sign in, and back to `returnTo` (default: where it is now). */\n signIn(options?: { returnTo?: string; locale?: string; prompt?: 'login' }): void\n /** Signs out of this application and of Cauthy in this browser. */\n signOut(): void\n /** Asks the server again who is signed in. */\n refresh(): Promise<PublicSession | null>\n /** Where the person looks after their account: password, second step, passkeys. */\n accountUrl(returnTo?: string): string\n /** Where the server mounted the routes. */\n basePath: string\n}\n\nexport interface CauthyProviderProps {\n children: ReactNode\n /** Where the server mounted the routes. Default: `/api/auth`. */\n basePath?: string\n /**\n * The session the server already read while rendering (SSR): the first\n * paint is then right, with no \"loading\". `null` means \"nobody\"; leave it\n * out when the server did not look.\n */\n initialSession?: PublicSession | null\n}\n\nconst Ctx = createContext<SessionContext | null>(null)\n\n/** Ask again this long before the session's token runs out. */\nconst AHEAD_MS = 60_000\n\nexport function CauthyProvider({ children, basePath = '/api/auth', initialSession }: CauthyProviderProps) {\n const base = basePath.replace(/\\/+$/, '')\n const [session, setSession] = useState<PublicSession | null>(initialSession ?? null)\n const [status, setStatus] = useState<SessionContext['status']>(\n initialSession === undefined ? 'loading' : initialSession === null ? 'unauthenticated' : 'authenticated',\n )\n const asking = useRef<Promise<PublicSession | null> | null>(null)\n\n const refresh = useCallback((): Promise<PublicSession | null> => {\n asking.current ??= (async () => {\n try {\n const res = await fetch(`${base}/session`, { credentials: 'same-origin', headers: { accept: 'application/json' } })\n if (!res.ok) throw new Error(String(res.status))\n const body = (await res.json()) as { session: PublicSession | null; status: string }\n // \"expired\" is the server unable to reach Cauthy: what is on screen\n // stays, and the next ask settles it.\n if (body.status !== 'expired') {\n setSession(body.session)\n setStatus(body.session ? 'authenticated' : 'unauthenticated')\n }\n return body.session\n } catch {\n setStatus((s) => (s === 'loading' ? 'unauthenticated' : s))\n return null\n } finally {\n asking.current = null\n }\n })()\n return asking.current\n }, [base])\n\n useEffect(() => {\n if (initialSession === undefined) void refresh()\n }, [initialSession, refresh])\n\n useEffect(() => {\n if (!session) return\n const wait = Math.max(new Date(session.expiresAt).getTime() - Date.now() - AHEAD_MS, 5_000)\n const timer = setTimeout(() => void refresh(), wait)\n return () => clearTimeout(timer)\n }, [session, refresh])\n\n useEffect(() => {\n const onVisible = () => {\n if (document.visibilityState === 'visible') void refresh()\n }\n document.addEventListener('visibilitychange', onVisible)\n return () => document.removeEventListener('visibilitychange', onVisible)\n }, [refresh])\n\n const value = useMemo<SessionContext>(\n () => ({\n session,\n status,\n refresh,\n signIn(options = {}) {\n const q = new URLSearchParams({ return_to: options.returnTo ?? window.location.pathname + window.location.search })\n if (options.locale) q.set('locale', options.locale)\n if (options.prompt) q.set('prompt', options.prompt)\n window.location.assign(`${base}/login?${q}`)\n },\n signOut() {\n window.location.assign(`${base}/logout`)\n },\n accountUrl(returnTo) {\n const back = returnTo ?? (typeof window === 'undefined' ? '/' : window.location.pathname + window.location.search)\n return `${base}/account?return_to=${encodeURIComponent(back)}`\n },\n basePath: base,\n }),\n [session, status, refresh, base],\n )\n return <Ctx.Provider value={value}>{children}</Ctx.Provider>\n}\n\nexport function useSession(): SessionContext {\n const ctx = useContext(Ctx)\n if (ctx === null) throw new Error('cauthy-auth: useSession needs <CauthyProvider> above it')\n return ctx\n}\n\n/**\n * The application's own sign-in screens: the functions a form calls.\n *\n * const { signIn, signUp, forgotPassword, signOut, session } = useAuth()\n * const r = await signIn.email({ email, password })\n *\n * They are `createAuthClient()`'s, and what is on screen follows them: after\n * a sign-in or a sign-out, `session` is the new one with no reload.\n */\nexport function useAuth(): AuthClient & Pick<SessionContext, 'session' | 'status' | 'refresh'> {\n const { session, status, refresh, basePath } = useSession()\n return useMemo(() => {\n const client = createAuthClient({ basePath })\n const then = async <T,>(running: Promise<T>): Promise<T> => {\n const r = await running\n await refresh()\n return r\n }\n return {\n ...client,\n signIn: { ...client.signIn, email: (f) => then(client.signIn.email(f)), mfa: (f) => then(client.signIn.mfa(f)), magicLinkVerify: (f) => then(client.signIn.magicLinkVerify(f)), emailCode: (f) => then(client.signIn.emailCode(f)) },\n signUp: { email: (f) => then(client.signUp.email(f)) },\n signOut: () => then(client.signOut()),\n account: {\n ...client.account,\n // What is on screen says the new name, and knows when the session ended.\n update: (f) => then(client.account.update(f)),\n changePassword: (f) => then(client.account.changePassword(f)),\n signOutEverywhere: () => then(client.account.signOutEverywhere()),\n },\n session,\n status,\n refresh,\n }\n }, [basePath, refresh, session, status])\n}\n\nexport { createAuthClient, type Account as AccountDetails, type AccountClient, type AccountSession, type AuthClient, type AuthError, type AuthMethods, type AuthResult, type LinkedIdentity } from './client'\nexport { Account, ForgotPassword, ResetPassword, SignIn, SignUp, VerifyEmail, type AccountProps, type AuthFormProps, type AuthTexts } from './components'\n","// An application's look, for Cauthy's hosted pages.\n//\n// Cauthy's pages — sign-in, sign-up, the account page — can take the colours,\n// corners, typeface and logo of the application that sends its people there,\n// so signing in reads as a page of the application. A theme is a short list of\n// values, which Cauthy checks one by one; it is never CSS.\n//\n// An application built with Stackmyth already has those values, as its\n// `--sm-*` tokens. `themeFromStackmyth` reads them out of its stylesheets.\n\n/** How an application looks on Cauthy's hosted pages. Every value is optional. */\n/** One font file the application serves: a family in one weight (or a range) and one style. */\nexport interface ThemeFont {\n family: string\n /** An https address of a `.woff2` file. It must answer with `Access-Control-Allow-Origin` for Cauthy's origin. */\n url: string\n /** `400`, or `\"100 900\"` for a variable font. Default: 400. */\n weight?: number | string\n style?: 'normal' | 'italic'\n}\n\n/** What an application says on its sign-in page, in one language. */\nexport interface ThemeTexts {\n /** Replaces \"Sign in\". */\n heading?: string\n /** Replaces \"to continue to …\". */\n subheading?: string\n /** The messages of the split layout's panel, shown one at a time (up to 5). */\n panel?: string[]\n /** Links at the foot of the split layout: privacy, terms (up to 4). */\n links?: { label: string; url: string }[]\n}\n\nexport interface CauthyTheme {\n /** The page. Colours are `#rrggbb` or `rgba(r, g, b, a)`. */\n background?: string\n /** The card, and inputs. */\n surface?: string\n /** Headings and what is typed. */\n text?: string\n /** Paragraphs, labels, small print. */\n textMuted?: string\n border?: string\n /** The fields and the secondary buttons, when they are not the card's colours. */\n inputBackground?: string\n inputBorder?: string\n /** The main button, and what is written on it. */\n primary?: string\n primaryText?: string\n /** Links, and the focus ring. */\n accent?: string\n error?: string\n errorBackground?: string\n success?: string\n successBackground?: string\n /** Corners of cards and inputs, in pixels (0–40). */\n radius?: number\n /** Corners of buttons, in pixels (0–40). */\n buttonRadius?: number\n /** A CSS font-family list: the application's typeface first, a system font after it. */\n fontFamily?: string\n /** The files of the typefaces `fontFamily` names, for people who do not have them installed. */\n fonts?: ThemeFont[]\n /** An image shown where \"Cauthy\" is, over https. */\n logoUrl?: string\n /**\n * How the sign-in pages are laid out: `card` (the default, one card in the\n * middle) or `split` (the form on one side, a panel that presents the\n * application on the other).\n */\n layout?: 'card' | 'split'\n /** The colours the split layout's backdrop blends, one to four. */\n panelColors?: string[]\n /** The colour of what is written on the panel. */\n panelText?: string\n /** An https image shown over the panel's messages. */\n panelIconUrl?: string\n /** The application's own words on the sign-in page, by language (`en`, `es`). */\n texts?: Record<string, ThemeTexts>\n /**\n * The application's Stackmyth tokens (`--sm-*`), from `tokensFromStackmyth`.\n * Cauthy's pages are drawn with Stackmyth's components, so these make its\n * buttons and fields the application's own. They are laid over the named values.\n */\n tokens?: Record<string, string>\n}\n\nexport interface StackmythThemeOptions {\n /**\n * The named theme to read, when the stylesheet keeps several under\n * `[data-theme=…]` (`\"vennet\"`). Without it only what applies to every\n * page (`:root`) is read.\n */\n theme?: string\n /** Which of the application's two modes to take. Default: `light`. */\n mode?: 'light' | 'dark'\n logoUrl?: string\n}\n\nexport interface ImportedTheme {\n theme: CauthyTheme\n /** Tokens that were there and could not be carried over, and why. */\n warnings: string[]\n}\n\nconst MAX_RADIUS = 40\n\n// ── Reading custom properties out of CSS ───────────────────────────────────\n\ninterface Declaration {\n name: string\n value: string\n /** The selectors and at-rules it sits inside, outermost first. */\n within: string[]\n}\n\nfunction declarations(css: string): Declaration[] {\n const text = css.replace(/\\/\\*[\\s\\S]*?\\*\\//g, '')\n const out: Declaration[] = []\n const within: string[] = []\n let chunk = ''\n let quote = ''\n let depth = 0 // parentheses, so a `;` inside url(…) does not end anything\n const flush = () => {\n const m = /^\\s*(--[\\w-]+)\\s*:\\s*([\\s\\S]+?)\\s*$/.exec(chunk)\n if (m) out.push({ name: m[1], value: m[2].replace(/\\s+/g, ' ').replace(/\\s*!important$/, ''), within: [...within] })\n chunk = ''\n }\n for (const ch of text) {\n if (quote) {\n chunk += ch\n if (ch === quote) quote = ''\n continue\n }\n if (ch === '\"' || ch === \"'\") {\n quote = ch\n chunk += ch\n } else if (ch === '(') {\n depth++\n chunk += ch\n } else if (ch === ')') {\n depth = Math.max(0, depth - 1)\n chunk += ch\n } else if (ch === '{' && depth === 0) {\n within.push(chunk.trim().replace(/\\s+/g, ' '))\n chunk = ''\n } else if (ch === '}' && depth === 0) {\n flush()\n within.pop()\n } else if (ch === ';' && depth === 0) {\n flush()\n } else {\n chunk += ch\n }\n }\n return out\n}\n\nconst DARK = /prefers-color-scheme:\\s*dark|data-(mode|theme|color-scheme)=[\"']?dark|\\.dark\\b/i\nconst LIGHT = /prefers-color-scheme:\\s*light|data-(mode|theme|color-scheme)=[\"']?light|\\.light\\b/i\nconst NAMED = /data-theme=[\"']?([\\w-]+)/i\n\n/** Whether a declaration applies to the page being themed. */\nfunction applies(d: Declaration, o: Required<Pick<StackmythThemeOptions, 'mode'>> & { theme?: string }): boolean {\n for (const scope of d.within) {\n if (o.mode === 'light' && DARK.test(scope)) return false\n if (o.mode === 'dark' && LIGHT.test(scope)) return false\n const named = NAMED.exec(scope)\n if (named && !/^(dark|light)$/i.test(named[1]) && named[1] !== o.theme) return false\n // Component-level rules (`.btn { --sm-… }`) are not the page's theme;\n // the class a mode is switched with (`.dark`, as shadcn/ui does) is.\n if (!scope.startsWith('@') && !/:root|^html\\b|^body\\b|\\[data-|^\\*$|:host|^\\.(dark|light)\\b/.test(scope)) return false\n }\n return true\n}\n\n// ── Tokens ─────────────────────────────────────────────────────────────────\n\n/** What a token's value may be written with, as Cauthy checks it. */\nconst TOKEN_CHARS = /^[A-Za-z0-9 #%.,()/'\"_+*-]+$/\nconst TOKEN_FUNCS = new Set(['var', 'calc', 'min', 'max', 'clamp', 'rgb', 'rgba', 'hsl', 'hsla', 'hwb', 'lab', 'lch', 'oklab', 'oklch', 'color',\n 'color-mix', 'light-dark', 'cubic-bezier', 'steps', 'linear', 'linear-gradient', 'radial-gradient', 'conic-gradient',\n 'repeating-linear-gradient', 'repeating-radial-gradient', 'drop-shadow', 'blur', 'translate', 'translatex', 'translatey', 'scale', 'rotate'])\n\nfunction tokenValue(value: string): string | null {\n const v = value.replace(/\\s+/g, ' ').trim()\n if (v === '' || v.length > 400 || !TOKEN_CHARS.test(v)) return null\n for (const m of v.matchAll(/([A-Za-z-]+)\\(/g)) if (!TOKEN_FUNCS.has(m[1].toLowerCase())) return null\n if (/^\\(|[ ,(]\\(/.test(v)) return null\n return v\n}\n\n/** A scope that is the page's theme itself: the root, or the theme and mode attributes — never a component inside it. */\nconst THEME_SCOPE = /^(?:\\s*(?::root|html|body|\\[data-(?:theme|mode|color-scheme)(?:=[\"']?[\\w-]+[\"']?)?\\])\\s*,?)+$/i\n\nexport interface StackmythTokens {\n /** Every `--sm-*` token the stylesheets set for the page, ready for `theme.tokens`. */\n tokens: Record<string, string>\n /** Tokens that were there and Cauthy would not take, and why. */\n warnings: string[]\n}\n\n/**\n * Reads an application's Stackmyth tokens out of its stylesheets: every\n * `--sm-*` custom property its theme sets, in the order the sheets are given\n * (a later one wins). Its own names — a brand palette the tokens point at —\n * are written in, so what comes out stands on Stackmyth's names alone.\n *\n * Cauthy's sign-in pages are drawn with Stackmyth's components: these tokens\n * are what makes them look like the application.\n */\nexport function tokensFromStackmyth(css: string | string[], options: StackmythThemeOptions = {}): StackmythTokens {\n const mode = options.mode ?? 'light'\n const all = (Array.isArray(css) ? css : [css]).flatMap(declarations)\n const named = options.theme ?? all.map((d) => d.within.map((w) => NAMED.exec(w)?.[1]).find((n) => n && !/^(dark|light)$/i.test(n))).find(Boolean)\n const vars = new Map<string, string>()\n for (const d of all) {\n if (!applies(d, { mode, theme: named })) continue\n if (!d.within.every((w) => w.startsWith('@') || THEME_SCOPE.test(w))) continue\n vars.set(d.name, d.value)\n }\n // The application's own names are written in; Stackmyth's are left as references.\n const inline = (value: string, depth = 0): string | null => {\n if (depth > 16) return null\n let failed = false\n let out = value\n for (let guard = 0; guard < 64; guard++) {\n const next = out.replace(/var\\(\\s*(--(?!sm-)[\\w-]+)\\s*(?:,\\s*([^()]*(?:\\([^()]*\\)[^()]*)*))?\\)/, (_m, name: string, fallback?: string) => {\n const known = vars.get(name)\n const got = known !== undefined ? inline(known, depth + 1) : fallback !== undefined ? inline(fallback.trim(), depth + 1) : null\n if (got === null) failed = true\n return got ?? ''\n })\n if (failed) return null\n if (next === out) break\n out = next\n }\n return out\n }\n const tokens: Record<string, string> = {}\n const warnings: string[] = []\n for (const [name, raw] of vars) {\n if (!/^--sm-[a-z0-9]+(?:-[a-z0-9]+)*$/.test(name)) continue\n const written = inline(raw)\n const value = written === null ? null : tokenValue(written)\n if (value === null) warnings.push(`${name}: \"${raw.length > 60 ? raw.slice(0, 57) + '…' : raw}\" is not a value Cauthy takes`)\n else tokens[name] = value\n }\n if (Object.keys(tokens).length === 0) warnings.push('no --sm-* token was found in these stylesheets')\n return { tokens, warnings }\n}\n\n// ── Values ─────────────────────────────────────────────────────────────────\n\nfunction resolve(value: string, vars: Map<string, string>, seen = 0): string | null {\n if (seen > 16) return null\n let unresolved = false\n // Innermost var() first: fallbacks may hold another var().\n let out = value\n for (let guard = 0; guard < 32 && /var\\(/.test(out); guard++) {\n out = out.replace(/var\\(\\s*(--[\\w-]+)\\s*(?:,\\s*([^()]*(?:\\([^()]*\\)[^()]*)*))?\\)/, (_m, name: string, fallback?: string) => {\n const known = vars.get(name)\n const next = known !== undefined ? resolve(known, vars, seen + 1) : fallback !== undefined ? resolve(fallback.trim(), vars, seen + 1) : null\n if (next === null) unresolved = true\n return next ?? ''\n })\n if (unresolved) return null\n }\n return /var\\(/.test(out) ? null : out.trim()\n}\n\nconst clamp01 = (n: number) => Math.min(1, Math.max(0, n))\nconst hex2 = (n: number) => Math.round(clamp01(n) * 255).toString(16).padStart(2, '0')\nconst gamma = (c: number) => (c <= 0.0031308 ? 12.92 * c : 1.055 * Math.pow(c, 1 / 2.4) - 0.055)\n\nfunction out(r: number, g: number, b: number, a = 1): string {\n if (a >= 1) return `#${hex2(r)}${hex2(g)}${hex2(b)}`\n return `rgba(${Math.round(clamp01(r) * 255)}, ${Math.round(clamp01(g) * 255)}, ${Math.round(clamp01(b) * 255)}, ${Math.round(clamp01(a) * 1000) / 1000})`\n}\n\nconst alpha = (s: string | undefined) => (s === undefined ? 1 : s.endsWith('%') ? parseFloat(s) / 100 : parseFloat(s))\n\nconst KEYWORDS: Record<string, string> = { white: '#ffffff', black: '#000000' }\n\n/** A colour as Cauthy takes it — `#rrggbb` or `rgba(…)` — or null when it is none it can read. */\nexport function toColor(value: string): string | null {\n const v = value.trim().toLowerCase()\n if (KEYWORDS[v]) return KEYWORDS[v]\n if (/^#([0-9a-f]{3,4}|[0-9a-f]{6}|[0-9a-f]{8})$/.test(v)) return v\n let m = /^rgba?\\(\\s*([\\d.]+%?)[\\s,]+([\\d.]+%?)[\\s,]+([\\d.]+%?)(?:\\s*[,/]\\s*([\\d.]+%?))?\\s*\\)$/.exec(v)\n if (m) {\n const ch = (s: string) => (s.endsWith('%') ? parseFloat(s) / 100 : parseFloat(s) / 255)\n return out(ch(m[1]), ch(m[2]), ch(m[3]), alpha(m[4]))\n }\n m = /^hsla?\\(\\s*([\\d.]+)(?:deg)?[\\s,]+([\\d.]+)%[\\s,]+([\\d.]+)%(?:\\s*[,/]\\s*([\\d.]+%?))?\\s*\\)$/.exec(v)\n if (m) {\n const h = ((parseFloat(m[1]) % 360) + 360) % 360\n const s = parseFloat(m[2]) / 100\n const l = parseFloat(m[3]) / 100\n const f = (n: number) => {\n const k = (n + h / 30) % 12\n return l - s * Math.min(l, 1 - l) * Math.max(-1, Math.min(k - 3, 9 - k, 1))\n }\n return out(f(0), f(8), f(4), alpha(m[4]))\n }\n m = /^oklch\\(\\s*([\\d.]+%?)\\s+([\\d.]+%?)\\s+([\\d.]+)(?:deg)?(?:\\s*\\/\\s*([\\d.]+%?))?\\s*\\)$/.exec(v)\n if (m) {\n const L = m[1].endsWith('%') ? parseFloat(m[1]) / 100 : parseFloat(m[1])\n const C = m[2].endsWith('%') ? (parseFloat(m[2]) / 100) * 0.4 : parseFloat(m[2])\n const H = (parseFloat(m[3]) * Math.PI) / 180\n const a = C * Math.cos(H)\n const b = C * Math.sin(H)\n const l = Math.pow(L + 0.3963377774 * a + 0.2158037573 * b, 3)\n const mm = Math.pow(L - 0.1055613458 * a - 0.0638541728 * b, 3)\n const s = Math.pow(L - 0.0894841775 * a - 1.291485548 * b, 3)\n return out(\n gamma(4.0767416621 * l - 3.3077115913 * mm + 0.2309699292 * s),\n gamma(-1.2684380046 * l + 2.6097574011 * mm - 0.3413193965 * s),\n gamma(-0.0041960863 * l - 0.7034186147 * mm + 1.707614701 * s),\n alpha(m[4]),\n )\n }\n return null\n}\n\n/** A length in pixels, within what Cauthy takes, or null. */\nfunction toRadius(value: string): number | null {\n const m = /^([\\d.]+)(px|rem|em)?$/.exec(value.trim())\n if (!m) return null\n const px = parseFloat(m[1]) * (m[2] === 'rem' || m[2] === 'em' ? 16 : 1)\n return Number.isFinite(px) ? Math.min(MAX_RADIUS, Math.max(0, Math.round(px))) : null\n}\n\n/** A font list as Cauthy takes it, or null. */\nfunction toFont(value: string): string | null {\n const v = value.trim()\n return /^[A-Za-z0-9 ,'\"_-]{1,200}$/.test(v) && (v.match(/\"/g)?.length ?? 0) % 2 === 0 && (v.match(/'/g)?.length ?? 0) % 2 === 0 ? v : null\n}\n\n// ── Stackmyth ──────────────────────────────────────────────────────────────\n\n/** Which Stackmyth token each value of a theme is read from, first found wins. */\nconst COLORS: [keyof CauthyTheme, string[]][] = [\n ['background', ['--sm-bg-surface', '--sm-surface']],\n ['surface', ['--sm-bg-surface-raised', '--sm-surface-raised']],\n ['text', ['--sm-text-primary', '--sm-surface-text']],\n ['textMuted', ['--sm-text-secondary']],\n ['border', ['--sm-border-default', '--sm-surface-border']],\n ['primary', ['--sm-primary', '--sm-bg-interactive']],\n ['primaryText', ['--sm-primary-text', '--sm-text-inverse']],\n ['accent', ['--sm-text-brand', '--sm-border-focus', '--sm-accent']],\n ['error', ['--sm-error-soft-text', '--sm-error']],\n ['errorBackground', ['--sm-error-soft']],\n ['success', ['--sm-success-soft-text', '--sm-success']],\n ['successBackground', ['--sm-success-soft']],\n]\n\n/**\n * Reads an application's Stackmyth theme out of its stylesheets.\n *\n * Give it the CSS that declares the tokens, in the order the application\n * loads it — Stackmyth's own (`@stackmyth/core/core.vars.css`, or a theme\n * file) and then the application's brand file that re-points them. Tokens\n * that point at the application's own variables are followed. The\n * application's dark mode is left out unless asked for.\n */\nexport function themeFromStackmyth(css: string | string[], options: StackmythThemeOptions = {}): ImportedTheme {\n const o = { mode: options.mode ?? 'light', theme: options.theme }\n const vars = new Map<string, string>()\n for (const sheet of Array.isArray(css) ? css : [css]) {\n for (const d of declarations(sheet)) if (applies(d, o)) vars.set(d.name, d.value)\n }\n const theme: CauthyTheme = {}\n const warnings: string[] = []\n\n const read = <T>(tokens: string[], to: (v: string) => T | null, what: string): T | undefined => {\n for (const token of tokens) {\n const raw = vars.get(token)\n if (raw === undefined) continue\n const value = resolve(raw, vars)\n const got = value === null ? null : to(value)\n if (got !== null) return got\n warnings.push(`${token}: \"${raw}\" is not ${what} Cauthy can take`)\n }\n return undefined\n }\n\n for (const [field, tokens] of COLORS) {\n const c = read(tokens, toColor, 'a colour')\n if (c !== undefined) (theme as Record<string, unknown>)[field] = c\n }\n const radius = read(['--sm-radius-container', '--sm-radius-md'], toRadius, 'a length')\n if (radius !== undefined) theme.radius = radius\n const button = read(['--sm-radius-interactive', '--sm-radius-sm'], toRadius, 'a length')\n if (button !== undefined) theme.buttonRadius = button\n const font = read(['--sm-font-family'], toFont, 'a font list')\n if (font !== undefined) theme.fontFamily = font\n if (options.logoUrl) theme.logoUrl = options.logoUrl\n\n if (vars.size === 0) warnings.push('no custom properties were found: is this the stylesheet that declares the --sm-* tokens?')\n else if (![...vars.keys()].some((k) => k.startsWith('--sm-'))) warnings.push('no --sm-* token was found in these stylesheets')\n return { theme, warnings }\n}\n\n// ── Any stylesheet ─────────────────────────────────────────────────────────\n\n/** The values of a theme a stylesheet can say. */\nexport type ThemeField =\n | 'background' | 'surface' | 'text' | 'textMuted' | 'border' | 'inputBackground' | 'inputBorder'\n | 'primary' | 'primaryText' | 'accent' | 'error' | 'errorBackground' | 'success' | 'successBackground'\n | 'radius' | 'buttonRadius' | 'fontFamily'\n\n/** How a stylesheet names its look: Stackmyth's tokens, shadcn/ui's (and Tailwind's), or the application's own. */\nexport type CssFormat = 'stackmyth' | 'shadcn' | 'custom'\n\nexport interface CssThemeOptions {\n /** Which names to read. Default: `auto`, told from the stylesheet itself. */\n format?: CssFormat | 'auto'\n /** Which of the application's two modes to take. Default: `light`. */\n mode?: 'light' | 'dark'\n /** The named theme to read, when the stylesheet keeps several under `[data-theme=…]`. */\n theme?: string\n /** For `custom`: the variable each value is read from, `{ primary: '--brand' }`. */\n map?: Partial<Record<ThemeField, string>>\n}\n\nexport interface CssImportedTheme extends ImportedTheme {\n /** The names that were read. */\n format: CssFormat\n}\n\nconst RADII: ThemeField[] = ['radius', 'buttonRadius']\n\n/** shadcn/ui's names, as Tailwind 3 (`--primary`) and Tailwind 4 (`--color-primary`) write them. */\nconst SHADCN: [ThemeField, string[]][] = [\n ['background', ['--background', '--color-background']],\n ['surface', ['--card', '--color-card', '--popover', '--color-popover']],\n ['text', ['--foreground', '--color-foreground']],\n ['textMuted', ['--muted-foreground', '--color-muted-foreground']],\n ['border', ['--border', '--color-border']],\n ['inputBorder', ['--input', '--color-input']],\n ['primary', ['--primary', '--color-primary']],\n ['primaryText', ['--primary-foreground', '--color-primary-foreground']],\n ['accent', ['--ring', '--color-ring', '--primary', '--color-primary']],\n ['error', ['--destructive', '--color-destructive']],\n ['radius', ['--radius']],\n ['buttonRadius', ['--radius']],\n ['fontFamily', ['--font-sans', '--font-family']],\n]\n\n/** A colour as shadcn/ui writes it on Tailwind 3 — `222.2 84% 4.9%`, the inside of hsl() — or any other. */\nfunction shadcnColor(value: string): string | null {\n return /^[\\d.]+(?:deg)?\\s+[\\d.]+%\\s+[\\d.]+%(?:\\s*\\/\\s*[\\d.]+%?)?$/.test(value.trim()) ? toColor(`hsl(${value.trim()})`) : toColor(value)\n}\n\n/** Every custom property a stylesheet sets for the page, the last one winning. */\nfunction pageVariables(css: string | string[], mode: 'light' | 'dark', theme?: string): Map<string, string> {\n const vars = new Map<string, string>()\n for (const sheet of Array.isArray(css) ? css : [css]) {\n for (const d of declarations(sheet)) if (applies(d, { mode, theme })) vars.set(d.name, d.value)\n }\n return vars\n}\n\n/** The custom properties a stylesheet sets for the page, by name: what a person picks from to map their own. */\nexport function cssVariables(css: string | string[], options: Pick<CssThemeOptions, 'mode' | 'theme'> = {}): string[] {\n return [...pageVariables(css, options.mode ?? 'light', options.theme).keys()].sort()\n}\n\n/**\n * Reads an application's look out of its stylesheets, whatever names it uses:\n * Stackmyth's tokens, shadcn/ui's (`--primary`, `--radius`, on Tailwind 3 or\n * 4), or the application's own variables given in `map`. What comes out is a\n * theme of named values, never CSS.\n */\nexport function themeFromCss(css: string | string[], options: CssThemeOptions = {}): CssImportedTheme {\n const mode = options.mode ?? 'light'\n const vars = pageVariables(css, mode, options.theme)\n const names = [...vars.keys()]\n let format: CssFormat\n if (options.format && options.format !== 'auto') format = options.format\n else if (options.map && Object.keys(options.map).length > 0) format = 'custom'\n else if (names.some((n) => n.startsWith('--sm-'))) format = 'stackmyth'\n else if (names.some((n) => /^--(color-)?(primary|background|foreground)$/.test(n))) format = 'shadcn'\n else format = 'custom'\n\n if (format === 'stackmyth') return { ...themeFromStackmyth(css, { mode, theme: options.theme }), format }\n\n const spec: [ThemeField, string[]][] = format === 'shadcn'\n ? SHADCN\n : Object.entries(options.map ?? {}).filter(([, v]) => v).map(([k, v]) => [k as ThemeField, [String(v).startsWith('--') ? String(v) : `--${v}`]])\n const theme: CauthyTheme = {}\n const warnings: string[] = []\n for (const [field, tokens] of spec) {\n for (const token of tokens) {\n const raw = vars.get(token)\n if (raw === undefined) continue\n const value = resolve(raw, vars)\n const got = value === null ? null\n : RADII.includes(field) ? toRadius(value)\n : field === 'fontFamily' ? toFont(value)\n : format === 'shadcn' ? shadcnColor(value) : toColor(value)\n if (got !== null) {\n (theme as Record<string, unknown>)[field] = got\n break\n }\n warnings.push(`${token}: \"${raw.length > 60 ? raw.slice(0, 57) + '…' : raw}\" is not ${RADII.includes(field) ? 'a length' : field === 'fontFamily' ? 'a font list' : 'a colour'} Cauthy can take`)\n }\n }\n if (vars.size === 0) warnings.push('no custom properties were found in these stylesheets')\n else if (format === 'custom' && spec.length === 0) warnings.push('these stylesheets use names of their own: say which variable each value is read from')\n return { theme, warnings, format }\n}\n\n// ── On the application's own screens ───────────────────────────────────────\n\n/**\n * A theme as the CSS variables of `cauthy-auth/styles.css` (`--cauthy-*`), for\n * the forms an application shows on its own pages. The page's own background,\n * the layout and the words are Cauthy's pages' matter, and left out.\n */\nexport function themeVariables(theme: CauthyTheme): Record<string, string> {\n const vars: Record<string, string> = {}\n const put = (name: string, v: string | number | undefined) => {\n if (v === undefined || v === '') return\n vars[`--cauthy-${name}`] = typeof v === 'number' ? `${v}px` : v\n }\n put('surface', theme.surface)\n put('text', theme.text)\n put('text-muted', theme.textMuted)\n put('border', theme.border)\n put('input-background', theme.inputBackground)\n put('input-border', theme.inputBorder)\n put('primary', theme.primary)\n put('primary-text', theme.primaryText)\n put('accent', theme.accent)\n put('error', theme.error)\n put('error-background', theme.errorBackground)\n put('success', theme.success)\n put('success-background', theme.successBackground)\n put('radius', theme.radius)\n put('button-radius', theme.buttonRadius)\n put('font', theme.fontFamily)\n return vars\n}\n\n// ── Sending it to Cauthy ───────────────────────────────────────────────────\n\n/** A theme as Cauthy's API names its values. */\nexport function toWire(theme: CauthyTheme): Record<string, unknown> {\n const names: Record<keyof CauthyTheme, string> = {\n background: 'background', surface: 'surface', text: 'text', textMuted: 'text_muted', border: 'border',\n primary: 'primary', primaryText: 'primary_text', accent: 'accent', error: 'error', errorBackground: 'error_background',\n success: 'success', successBackground: 'success_background', radius: 'radius', buttonRadius: 'button_radius',\n fontFamily: 'font_family', logoUrl: 'logo_url', fonts: 'fonts', layout: 'layout', panelColors: 'panel_colors',\n panelText: 'panel_text', panelIconUrl: 'panel_icon_url', texts: 'texts', inputBackground: 'input_background', inputBorder: 'input_border', tokens: 'tokens',\n }\n const wire: Record<string, unknown> = {}\n for (const [k, v] of Object.entries(theme)) {\n if (v === undefined || v === '' || (Array.isArray(v) && v.length === 0)) continue\n wire[names[k as keyof CauthyTheme]] = v\n }\n return wire\n}\n\n/** A theme as Cauthy answers it, in this package's names. */\nexport function fromWire(wire: Record<string, unknown>): CauthyTheme {\n const names: Record<string, keyof CauthyTheme> = {\n background: 'background', surface: 'surface', text: 'text', text_muted: 'textMuted', border: 'border',\n primary: 'primary', primary_text: 'primaryText', accent: 'accent', error: 'error', error_background: 'errorBackground',\n success: 'success', success_background: 'successBackground', radius: 'radius', button_radius: 'buttonRadius',\n font_family: 'fontFamily', logo_url: 'logoUrl', fonts: 'fonts', layout: 'layout', panel_colors: 'panelColors',\n panel_text: 'panelText', panel_icon_url: 'panelIconUrl', texts: 'texts', input_background: 'inputBackground', input_border: 'inputBorder', tokens: 'tokens',\n }\n const theme: Record<string, unknown> = {}\n for (const [k, v] of Object.entries(wire ?? {})) if (names[k] && v !== undefined && v !== null && v !== '') theme[names[k]] = v\n return theme as CauthyTheme\n}\n\nexport interface PushThemeOptions {\n /** Cauthy's address. Default: `CAUTHY_ISSUER`. */\n issuer?: string\n /** The application's client id. Default: `CAUTHY_CLIENT_ID`. */\n clientId?: string\n /** The workspace's slug. Default: `CAUTHY_TENANT`. */\n tenant?: string\n /**\n * A personal access token with `oauth_clients:manage`. Default:\n * `CAUTHY_TOKEN`. It belongs in the deploy pipeline, never in the application.\n */\n token?: string\n theme: CauthyTheme\n fetch?: typeof fetch\n}\n\n/**\n * Gives the application its look on Cauthy's pages. It replaces the theme: a\n * value left out goes back to Cauthy's own. Run it when the brand changes —\n * from a script or the deploy — not on every request.\n */\nexport async function pushTheme(o: PushThemeOptions): Promise<void> {\n const env = (n: string) => (typeof process !== 'undefined' ? process.env?.[n] : undefined)\n const issuer = (o.issuer ?? env('CAUTHY_ISSUER') ?? '').replace(/\\/+$/, '')\n const clientId = o.clientId ?? env('CAUTHY_CLIENT_ID') ?? ''\n const tenant = o.tenant ?? env('CAUTHY_TENANT') ?? ''\n const token = o.token ?? env('CAUTHY_TOKEN') ?? ''\n for (const [name, v] of Object.entries({ CAUTHY_ISSUER: issuer, CAUTHY_CLIENT_ID: clientId, CAUTHY_TENANT: tenant, CAUTHY_TOKEN: token })) {\n if (v === '') throw new Error(`cauthy-auth: ${name} is required to push a theme`)\n }\n const res = await (o.fetch ?? fetch)(`${issuer}/v1/oauth/clients/${encodeURIComponent(clientId)}/theme`, {\n method: 'PUT',\n headers: { authorization: `Bearer ${token}`, 'x-tenant-key': tenant, 'content-type': 'application/json' },\n body: JSON.stringify(toWire(o.theme)),\n })\n if (!res.ok) {\n const body = (await res.json().catch(() => null)) as { errors?: { message?: string }[] } | null\n throw new Error(`cauthy-auth: Cauthy refused the theme (${res.status}): ${body?.errors?.[0]?.message ?? res.statusText}`)\n }\n}\n","// What a sign-in or sign-up form is checked for before anything is sent, in\n// the browser and again on the server: the same rules in both places, so the\n// form says what the server would.\n\nexport type AuthField = 'email' | 'password' | 'newPassword' | 'name' | 'code'\n\n/** A value of a form that cannot be sent as it is. */\nexport interface FieldProblem {\n field: AuthField\n /** Stable, for translating: `required`, `invalid_email`, `too_short`, `too_long`. */\n code: 'required' | 'invalid_email' | 'too_short' | 'too_long'\n message: string\n}\n\n/** The shortest password Cauthy takes for a new account. */\nexport const MIN_PASSWORD = 8\nconst MAX_PASSWORD = 256\nconst MAX_NAME = 120\n\n// One @, something on each side, a dot in the domain, no spaces: what catches\n// a typo. Whether the address exists is Cauthy's to find out.\nconst EMAIL = /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/\n\nexport function checkEmail(value: unknown): FieldProblem | null {\n const v = typeof value === 'string' ? value.trim() : ''\n if (v === '') return { field: 'email', code: 'required', message: 'Enter your email address.' }\n if (v.length > 254 || !EMAIL.test(v)) return { field: 'email', code: 'invalid_email', message: 'That does not look like an email address.' }\n return null\n}\n\n/** A password being typed to sign in: only that there is one. */\nexport function checkPassword(value: unknown): FieldProblem | null {\n if (typeof value !== 'string' || value === '') return { field: 'password', code: 'required', message: 'Enter your password.' }\n if (value.length > MAX_PASSWORD) return { field: 'password', code: 'too_long', message: 'That password is too long.' }\n return null\n}\n\n/** A password being chosen for a new account. */\nexport function checkNewPassword(value: unknown): FieldProblem | null {\n const basic = checkPassword(value)\n if (basic) return basic\n if ((value as string).length < MIN_PASSWORD) {\n return { field: 'password', code: 'too_short', message: `Use at least ${MIN_PASSWORD} characters.` }\n }\n return null\n}\n\nexport function checkName(value: unknown): FieldProblem | null {\n if (value === undefined || value === null || value === '') return null\n if (typeof value !== 'string' || value.trim().length > MAX_NAME) return { field: 'name', code: 'too_long', message: `Use at most ${MAX_NAME} characters.` }\n return null\n}\n\nexport function checkCode(value: unknown): FieldProblem | null {\n const v = typeof value === 'string' ? value.trim() : ''\n if (v === '') return { field: 'code', code: 'required', message: 'Enter the code.' }\n if (v.length > 40) return { field: 'code', code: 'too_long', message: 'That is not a code.' }\n return null\n}\n\n/** The first problem of a form, or null when it can be sent. */\nexport function firstProblem(...checks: (FieldProblem | null)[]): FieldProblem | null {\n return checks.find((c) => c !== null) ?? null\n}\n","// The application's own sign-in screens, in the browser.\n//\n// const auth = createAuthClient()\n// const r = await auth.signIn.email({ email, password })\n// if (!r.ok) show(r.error.message) // r.error.field says which input\n// else if (r.status === 'mfa_required') askForTheCode()\n//\n// Every call goes to the application's own server (`/api/auth/*`), never to\n// Cauthy: the browser holds no token, before or after. A form is checked here\n// before it is sent, with the rules the server checks again.\n\nimport { fromWire, type CauthyTheme } from './theme'\nimport type { PublicSession } from './types'\nimport { checkCode, checkEmail, checkName, checkNewPassword, checkPassword, firstProblem, type AuthField, type FieldProblem } from './validate'\n\nexport { checkCode, checkEmail, checkName, checkNewPassword, checkPassword, MIN_PASSWORD, type AuthField, type FieldProblem } from './validate'\n\n/** What went wrong, in a form the screen can show. */\nexport interface AuthError {\n /** Stable, for translating: `invalid_credentials`, `invalid_email`, `too_short`, `email_taken`, `unavailable`… */\n code: string\n message: string\n /** The input it is about, when it is about one. */\n field?: AuthField\n}\n\nexport type AuthResult<S extends string, More = unknown> = ({ ok: true; status: S } & More) | { ok: false; error: AuthError }\n\n/** What the screen may offer. */\nexport interface AuthMethods {\n /** The providers the workspace signs people in with: `{ id: 'google', name: 'Google' }`. */\n providers: { id: string; name: string }[]\n /** Whether people may create an account themselves. */\n signUp: boolean\n magicLink: boolean\n /** Whether to offer a passkey. It is asked for on Cauthy's page: the person goes there for that step and comes back signed in. */\n passkey: boolean\n}\n\n/** A person's own account, as their account screen shows it. */\nexport interface Account {\n id: string\n email: string\n name: string\n emailVerified: boolean\n /** False for an account that only signs in through a provider: it has no current password to ask for. */\n hasPassword: boolean\n mfaEnabled: boolean\n}\n\n/** Somewhere the person is signed in. Moments are UTC. */\nexport interface AccountSession {\n /** \"Mac · Chrome\", or \"\" when the browser did not say. */\n device: string\n ip: string\n createdAt: string\n expiresAt: string\n}\n\n/**\n * The signed-in person's own account. What weakens it — the password, the\n * second step, its recovery codes — asks for the current password again.\n */\n/** A provider the account can also sign in with. */\nexport interface LinkedIdentity {\n provider: string\n /** The address the provider has for the person, when it said. */\n email: string\n name: string\n /** When it was linked, in UTC (ISO 8601). */\n linkedAt: string\n}\n\nexport interface AccountClient {\n /** The account, or null when nobody is signed in. */\n get(): Promise<Account | null>\n update(form: { name: string }): Promise<AuthResult<'saved', { account: Account }>>\n /** Ends every other session of the account; this one stays signed in. */\n changePassword(form: { password: string; newPassword: string }): Promise<AuthResult<'changed', { signedIn: boolean }>>\n mfa: {\n /** Starts turning the second step on: show `secret` (or `otpauthUri` as a QR code) to add to an authenticator app, then call `verify`. */\n setup(form: { password: string }): Promise<AuthResult<'started', { secret: string; otpauthUri: string }>>\n /** Turns it on with a code from the app. `recoveryCodes` are shown this once. */\n verify(form: { code: string }): Promise<AuthResult<'enabled', { recoveryCodes: string[] }>>\n disable(form: { password: string }): Promise<AuthResult<'disabled'>>\n /** New recovery codes; the earlier ones stop working. */\n recoveryCodes(form: { password: string }): Promise<AuthResult<'renewed', { recoveryCodes: string[] }>>\n }\n /**\n * Asks to sign in with another address. Nothing changes yet: the new address\n * is mailed a link to confirm it, and once it is confirmed the old one is\n * told, with a link that undoes it. Both open Cauthy's own page.\n */\n changeEmail(form: { email: string; password: string }): Promise<AuthResult<'sent', { email: string }>>\n /** The providers (Google…) the account can also sign in with. */\n identities(): Promise<LinkedIdentity[]>\n /**\n * Sends the browser to the provider, to link it to the account; it comes back\n * at `returnTo` with `?linked=<provider>`, or `?auth_error=<code>`.\n */\n link(provider: string, options?: { returnTo?: string }): void\n /** Where `link` sends the browser, for a plain link. */\n linkUrl(provider: string, options?: { returnTo?: string }): string\n /** The account stops signing in with that provider. Refused when it would be left with no way to sign in. */\n unlink(provider: string): Promise<AuthResult<'unlinked', { provider: string }>>\n /** Where the account is signed in. */\n sessions(): Promise<AccountSession[]>\n /** Signs the account out everywhere, here too. */\n signOutEverywhere(): Promise<AuthResult<'signed_out'>>\n}\n\nexport interface AuthClient {\n signIn: {\n /** With address and password. `mfa_required`: ask for the code and call `signIn.mfa`. */\n email(form: { email: string; password: string }): Promise<AuthResult<'signed_in', { session: PublicSession }> | AuthResult<'mfa_required'>>\n /** The second step: the code of the authenticator app, or a recovery code. */\n mfa(form: { code: string }): Promise<AuthResult<'signed_in', { session: PublicSession }>>\n /** Mails a link that signs the person in. The answer is the same whether or not the address has an account. */\n magicLink(form: { email: string }): Promise<AuthResult<'sent'>>\n /** Signs in with the token the mailed link opened the page with (`ml_token`). */\n magicLinkVerify(form: { token: string }): Promise<AuthResult<'signed_in', { session: PublicSession }>>\n /** Signs in with the code that came in the same mail as the link, for somebody reading it on another device. */\n emailCode(form: { code: string }): Promise<AuthResult<'signed_in', { session: PublicSession }>>\n /** Sends the browser to Cauthy's page to use a passkey; it comes back signed in, at `returnTo`. */\n passkey(options?: { returnTo?: string; locale?: string }): void\n /** Where `passkey` sends the browser, for a plain link. */\n passkeyUrl(options?: { returnTo?: string; locale?: string }): string\n /** Sends the browser to the provider; it comes back signed in, at `returnTo`. */\n social(provider: string, options?: { returnTo?: string }): void\n /** Where `social` sends the browser, for a plain link. */\n socialUrl(provider: string, options?: { returnTo?: string }): string\n }\n signUp: {\n /** `verification_required`: the account exists and must open the link Cauthy mailed before it can sign in. */\n email(form: { email: string; password: string; name?: string }): Promise<AuthResult<'signed_in', { session: PublicSession }> | AuthResult<'verification_required', { email: string }>>\n }\n /** Mails a link to choose a new password. The answer is the same whether or not the address has an account. */\n forgotPassword(form: { email: string }): Promise<AuthResult<'sent'>>\n /** Sets the new password, with the token the mailed link opened the page with (`token`). */\n resetPassword(form: { token: string; password: string }): Promise<AuthResult<'changed'>>\n /** Confirms the address, with the token the mailed link opened the page with (`token`). */\n verifyEmail(form: { token: string }): Promise<AuthResult<'verified'>>\n signOut(): Promise<AuthResult<'signed_out'>>\n /** The signed-in person's own account. */\n account: AccountClient\n /** Who is signed in, or null. */\n getSession(): Promise<PublicSession | null>\n methods(): Promise<AuthMethods>\n /**\n * How the workspace's forms look — colours, corners, typeface — as a person\n * set it in Cauthy's dashboard. Read once per page; null when Cauthy cannot say.\n */\n look(): Promise<CauthyTheme | null>\n}\n\nexport interface AuthClientOptions {\n /** Where the server mounted the routes. Default: `/api/auth`. */\n basePath?: string\n fetch?: typeof fetch\n}\n\nconst UNAVAILABLE: AuthError = { code: 'unavailable', message: 'Sign-in is unavailable right now. Try again in a moment.' }\n\nexport function createAuthClient(options: AuthClientOptions = {}): AuthClient {\n const base = (options.basePath ?? '/api/auth').replace(/\\/+$/, '')\n const doFetch: typeof fetch = (...args) => (options.fetch ?? fetch)(...args)\n\n async function post(path: string, form: Record<string, unknown>, bad: FieldProblem | null): Promise<any> {\n if (bad) return { ok: false, error: { code: bad.code, message: bad.message, field: bad.field } }\n try {\n const res = await doFetch(`${base}${path}`, {\n method: 'POST',\n credentials: 'same-origin',\n headers: { 'content-type': 'application/json', accept: 'application/json' },\n body: JSON.stringify(form),\n })\n const body = (await res.json().catch(() => null)) as any\n if (res.ok && body && typeof body.status === 'string') return { ok: true, ...body }\n const e = body?.error\n return { ok: false, error: e && typeof e.code === 'string' ? { code: e.code, message: String(e.message ?? ''), ...(e.field ? { field: e.field } : {}) } : UNAVAILABLE }\n } catch {\n return { ok: false, error: UNAVAILABLE }\n }\n }\n\n let looked: Promise<CauthyTheme | null> | undefined\n\n async function read(path: string): Promise<any> {\n try {\n const res = await doFetch(`${base}${path}`, { credentials: 'same-origin', headers: { accept: 'application/json' } })\n return res.ok ? await res.json() : null\n } catch {\n return null\n }\n }\n\n const linkUrl = (provider: string, o: { returnTo?: string } = {}) =>\n `${base}/me/identities/link/${encodeURIComponent(provider)}${o.returnTo ? `?return_to=${encodeURIComponent(o.returnTo)}` : ''}`\n const socialUrl = (provider: string, o: { returnTo?: string } = {}) =>\n `${base}/sign-in/social/${encodeURIComponent(provider)}${o.returnTo ? `?return_to=${encodeURIComponent(o.returnTo)}` : ''}`\n\n const passkeyUrl = (o: { returnTo?: string; locale?: string } = {}) => {\n const q = new URLSearchParams({ method: 'passkey' })\n if (o.returnTo) q.set('return_to', o.returnTo)\n if (o.locale) q.set('locale', o.locale)\n return `${base}/login?${q}`\n }\n\n return {\n signIn: {\n email: (f) => post('/sign-in/email', { email: f.email, password: f.password }, firstProblem(checkEmail(f.email), checkPassword(f.password))),\n mfa: (f) => post('/sign-in/mfa', { code: f.code }, checkCode(f.code)),\n magicLink: (f) => post('/sign-in/magic-link', { email: f.email }, checkEmail(f.email)),\n magicLinkVerify: (f) => post('/sign-in/magic-link/verify', { token: f.token }, null),\n emailCode: (f) => post('/sign-in/email-code', { code: f.code }, checkCode(f.code)),\n passkeyUrl,\n passkey(o) {\n window.location.assign(passkeyUrl(o))\n },\n socialUrl,\n social(provider, o) {\n window.location.assign(socialUrl(provider, o))\n },\n },\n signUp: {\n email: (f) => post('/sign-up/email', { email: f.email, password: f.password, name: f.name }, firstProblem(checkName(f.name), checkEmail(f.email), checkNewPassword(f.password))),\n },\n forgotPassword: (f) => post('/forgot-password', { email: f.email }, checkEmail(f.email)),\n resetPassword: (f) => post('/reset-password', { token: f.token, password: f.password }, checkNewPassword(f.password)),\n verifyEmail: (f) => post('/verify-email', { token: f.token }, null),\n signOut: () => post('/sign-out', {}, null),\n account: {\n async get() {\n const body = await read('/me')\n return body && typeof body.account === 'object' ? (body.account as Account) : null\n },\n update: (f) => post('/me', { name: f.name }, checkName(f.name)),\n changePassword: (f) => {\n const bad = checkNewPassword(f.newPassword)\n return post('/me/password', { password: f.password, newPassword: f.newPassword }, bad ? { ...bad, field: 'newPassword' } : null)\n },\n mfa: {\n setup: (f) => post('/me/mfa/setup', { password: f.password }, null),\n verify: (f) => post('/me/mfa/verify', { code: f.code }, checkCode(f.code)),\n disable: (f) => post('/me/mfa/disable', { password: f.password }, null),\n recoveryCodes: (f) => post('/me/mfa/recovery-codes', { password: f.password }, null),\n },\n changeEmail: (f) => post('/me/email', { email: f.email, password: f.password }, checkEmail(f.email)),\n async identities() {\n const body = await read('/me/identities')\n return body && Array.isArray(body.identities) ? (body.identities as LinkedIdentity[]) : []\n },\n linkUrl,\n link(provider, o) {\n window.location.assign(linkUrl(provider, o))\n },\n unlink: (provider) => post('/me/identities/unlink', { provider }, null),\n async sessions() {\n const body = await read('/me/sessions')\n return body && Array.isArray(body.sessions) ? (body.sessions as AccountSession[]) : []\n },\n signOutEverywhere: () => post('/me/sessions/end', {}, null),\n },\n async getSession() {\n try {\n const res = await doFetch(`${base}/session`, { credentials: 'same-origin', headers: { accept: 'application/json' } })\n if (!res.ok) return null\n return ((await res.json()) as { session: PublicSession | null }).session\n } catch {\n return null\n }\n },\n look() {\n looked ??= read('/look').then((wire) => (wire && typeof wire === 'object' ? fromWire(wire) : null))\n return looked\n },\n async methods() {\n try {\n const res = await doFetch(`${base}/methods`, { credentials: 'same-origin', headers: { accept: 'application/json' } })\n if (res.ok) return (await res.json()) as AuthMethods\n } catch {\n // falls through\n }\n return { providers: [], signUp: true, magicLink: false, passkey: false }\n },\n }\n}\n\nexport { createSessionStore, type SessionState, type SessionStore, type SessionStoreOptions } from './store'\n","// What a person may do in an organization.\n//\n// When a system keeps its catalog of roles in Cauthy, each of a person's\n// organizations arrives with what their role — and anything given or denied to\n// them apart from it — lets them do. Checking is a lookup in that list: no\n// call to Cauthy, on the server or in the browser.\n\n/** The part of an organization that says what its member may do. */\nexport interface Permitted {\n /** \"resource:action\" entries the person is allowed; \"*\" is any. Absent when the system keeps no catalog in Cauthy. */\n permissions?: string[]\n /** Entries the person is denied whatever else allows them. */\n denied?: string[]\n}\n\nfunction matches(entry: string, resource: string, action: string): boolean {\n // The resource may itself hold a colon: the action is what follows the last one.\n const i = entry.lastIndexOf(':')\n if (i < 0) return false\n const r = entry.slice(0, i)\n const a = entry.slice(i + 1)\n return (r === '*' || r === resource) && (a === '*' || a === action)\n}\n\n/**\n * Whether the person may do an action on a resource in an organization:\n * allowed by some entry, and denied by none. A denial wins.\n *\n * An organization of a system that keeps no catalog in Cauthy carries no\n * permissions, and the answer is `false`: decide by its `role` instead.\n *\n * if (!can(organization, 'invoicing', 'write')) return forbidden()\n */\nexport function can(organization: Permitted | null | undefined, resource: string, action: string): boolean {\n if (!organization?.permissions) return false\n if ((organization.denied ?? []).some((d) => matches(d, resource, action))) return false\n return organization.permissions.some((p) => matches(p, resource, action))\n}\n\n// ── A system's catalog of roles ────────────────────────────────────────────\n\n/** Something a role may do: an action on a resource, in organizations of a kind (\"*\", the default, is every kind). */\nexport interface PolicyPermission {\n kind?: string\n resource: string\n action: string\n}\n\nexport interface PolicyRole {\n role: string\n name?: string\n description?: string\n /** Roles whose permissions this one has as well. */\n inherits?: string[]\n permissions?: PolicyPermission[]\n}\n\n// ── The catalog, with its types ────────────────────────────────────────────\n//\n// A catalog written down once gives the roles and the permissions their\n// names: `can(org, 'ledger:write')` then takes only a permission the catalog\n// has, the editor offers them, and a typo does not compile.\n//\n// export const policy = definePolicy([\n// { role: 'reader', permissions: [{ resource: 'ledger', action: 'read' }] },\n// { role: 'accountant', inherits: ['reader'], permissions: [{ resource: 'ledger', action: 'write' }] },\n// ])\n// export const { can, hasRole } = policy\n//\n// can(organization, 'ledger:write') // 'ledger:wirte' does not compile\n// hasRole(organization, 'accountant')\n//\n// Write it by hand, or let `cauthy-auth policy --pull` write it from the\n// catalog Cauthy has.\n\n/** A role as `definePolicy` reads it: any `PolicyRole`, kept as written. */\ntype RoleShape = {\n readonly role: string\n readonly name?: string\n readonly description?: string\n readonly inherits?: readonly string[]\n readonly permissions?: readonly { readonly kind?: string; readonly resource: string; readonly action: string }[]\n}\n\n// \"*\" in a catalog is \"any\": the name it stands for is any text.\ntype Named<S extends string> = S extends '*' ? string : S\n\ntype PermissionsIn<R> = R extends { readonly permissions: readonly (infer P)[] }\n ? P extends { readonly resource: infer Res extends string; readonly action: infer Act extends string } ? `${Named<Res>}:${Named<Act>}` : never\n : never\n\n/** The roles a catalog names: `RoleOf<typeof policy>`. */\nexport type RoleOf<P> = P extends Policy<infer R, string> ? R : never\n/** The \"resource:action\" permissions a catalog names: `PermissionOf<typeof policy>`. */\nexport type PermissionOf<P> = P extends Policy<string, infer X> ? X : never\n\nexport interface Policy<Role extends string = string, Permission extends string = string> {\n /** The catalog as Cauthy takes it: `pushPolicy({ roles: policy.roles })`. */\n roles: PolicyRole[]\n /** Every role's name. */\n roleNames: Role[]\n /** Every permission some role has, as \"resource:action\". */\n permissions: Permission[]\n /**\n * Whether the person may do this in the organization: `can(org, 'ledger:write')`.\n * It reads what Cauthy sent with the session, so a catalog edited in Cauthy\n * since this file was written is still what decides.\n */\n can(organization: Permitted | null | undefined, permission: Permission): boolean\n /** Whether the person's role in the organization is one of these. */\n hasRole(organization: { role: string } | null | undefined, ...roles: Role[]): boolean\n /**\n * What a role may do by this catalog, with what it inherits: for showing a\n * role, never for deciding about a person (their exceptions are not here).\n */\n permissionsOf(role: Role): Permission[]\n}\n\n/** Gives a catalog of roles its types. See the top of this section. */\nexport function definePolicy<const T extends readonly RoleShape[]>(roles: T): Policy<T[number]['role'], PermissionsIn<T[number]>> {\n type Role = T[number]['role']\n type Permission = PermissionsIn<T[number]>\n const entry = (p: { resource: string; action: string }) => `${p.resource}:${p.action}` as Permission\n const byName = new Map(roles.map((r) => [r.role, r]))\n const split = (permission: string): [string, string] => {\n const i = permission.lastIndexOf(':')\n return i < 0 ? [permission, ''] : [permission.slice(0, i), permission.slice(i + 1)]\n }\n return {\n roles: roles.map((r) => ({\n role: r.role,\n ...(r.name !== undefined ? { name: r.name } : {}),\n ...(r.description !== undefined ? { description: r.description } : {}),\n ...(r.inherits ? { inherits: [...r.inherits] } : {}),\n ...(r.permissions ? { permissions: r.permissions.map((p) => ({ ...p })) } : {}),\n })),\n roleNames: roles.map((r) => r.role),\n permissions: [...new Set(roles.flatMap((r) => (r.permissions ?? []).map(entry)))],\n can(organization, permission) {\n const [resource, action] = split(permission)\n return can(organization, resource, action)\n },\n hasRole(organization, ...wanted) {\n return organization != null && (wanted as string[]).includes(organization.role)\n },\n permissionsOf(role: Role) {\n const seen = new Set<string>()\n const out = new Set<Permission>()\n const walk = (name: string) => {\n if (seen.has(name)) return // a catalog that inherits in a circle still ends\n seen.add(name)\n const r = byName.get(name)\n for (const p of r?.permissions ?? []) out.add(entry(p))\n for (const parent of r?.inherits ?? []) walk(parent)\n }\n walk(role)\n return [...out]\n },\n }\n}\n\nconst IDENT = /^[A-Za-z_$][A-Za-z0-9_$]*$/\n\n/**\n * A TypeScript module that defines the catalog given, for `cauthy-auth policy\n * --pull` to write: the application's types then come from the catalog\n * Cauthy has.\n */\nexport function policySource(system: string, roles: PolicyRole[]): string {\n const text = (v: string) => JSON.stringify(v)\n const key = (k: string) => (IDENT.test(k) ? k : text(k))\n const one = (r: PolicyRole) => {\n const parts = [`role: ${text(r.role)}`]\n if (r.name) parts.push(`name: ${text(r.name)}`)\n if (r.description) parts.push(`description: ${text(r.description)}`)\n if (r.inherits?.length) parts.push(`inherits: [${r.inherits.map(text).join(', ')}]`)\n if (r.permissions?.length) {\n const list = r.permissions.map((p) => ` { ${[...(p.kind && p.kind !== '*' ? [`${key('kind')}: ${text(p.kind)}`] : []), `resource: ${text(p.resource)}`, `action: ${text(p.action)}`].join(', ')} },`)\n parts.push(`permissions: [\\n${list.join('\\n')}\\n ]`)\n }\n return ` {\\n ${parts.join(',\\n ')},\\n },`\n }\n return `// The catalog of roles of ${text(system)}, as Cauthy has it.\n// Written by \\`cauthy-auth policy --pull\\`: run it again after the catalog\n// changes, and do not edit this file by hand.\n\nimport { definePolicy, type PermissionOf, type RoleOf } from 'cauthy-auth'\n\nexport const policy = definePolicy([\n${roles.map(one).join('\\n')}\n])\n\nexport const { can, hasRole } = policy\nexport type Role = RoleOf<typeof policy>\nexport type Permission = PermissionOf<typeof policy>\n`\n}\n\n/** Reads a system's catalog of roles from Cauthy, with a personal access token. */\nexport async function pullPolicy(o: Omit<PushPolicyOptions, 'roles'> = {}): Promise<PolicyRole[]> {\n const env = (n: string) => (typeof process !== 'undefined' ? process.env?.[n] : undefined)\n const issuer = (o.issuer ?? env('CAUTHY_ISSUER') ?? '').replace(/\\/+$/, '')\n const system = o.system ?? env('CAUTHY_SYSTEM') ?? ''\n const tenant = o.tenant ?? env('CAUTHY_TENANT') ?? ''\n const token = o.token ?? env('CAUTHY_TOKEN') ?? ''\n for (const [name, v] of Object.entries({ CAUTHY_ISSUER: issuer, CAUTHY_SYSTEM: system, CAUTHY_TENANT: tenant, CAUTHY_TOKEN: token })) {\n if (v === '') throw new Error(`cauthy-auth: ${name} is required to read a policy`)\n }\n const res = await (o.fetch ?? fetch)(`${issuer}/v1/systems/${encodeURIComponent(system)}/policy`, {\n headers: { authorization: `Bearer ${token}`, 'x-tenant-key': tenant, accept: 'application/json' },\n })\n const body = (await res.json().catch(() => null)) as { data?: { roles?: PolicyRole[] }; errors?: { message?: string }[] } | null\n if (!res.ok) throw new Error(`cauthy-auth: Cauthy refused to give the policy (${res.status}): ${body?.errors?.[0]?.message ?? res.statusText}`)\n return body?.data?.roles ?? []\n}\n\nexport interface PushPolicyOptions {\n /** The system whose catalog this is. Default: `CAUTHY_SYSTEM`. */\n system?: string\n roles: PolicyRole[]\n /** Cauthy's address. Default: `CAUTHY_ISSUER`. */\n issuer?: string\n /** The workspace's slug. Default: `CAUTHY_TENANT`. */\n tenant?: string\n /** A personal access token with `organizations:manage`. Default: `CAUTHY_TOKEN`. */\n token?: string\n fetch?: typeof fetch\n}\n\n/**\n * Gives Cauthy a system's catalog of roles, replacing the one it has. It is\n * the way to load a first catalog from what a system already had; from then on\n * the catalog is Cauthy's, edited in its dashboard, and pushing again would\n * overwrite what was edited there.\n */\nexport async function pushPolicy(o: PushPolicyOptions): Promise<void> {\n const env = (n: string) => (typeof process !== 'undefined' ? process.env?.[n] : undefined)\n const issuer = (o.issuer ?? env('CAUTHY_ISSUER') ?? '').replace(/\\/+$/, '')\n const system = o.system ?? env('CAUTHY_SYSTEM') ?? ''\n const tenant = o.tenant ?? env('CAUTHY_TENANT') ?? ''\n const token = o.token ?? env('CAUTHY_TOKEN') ?? ''\n for (const [name, v] of Object.entries({ CAUTHY_ISSUER: issuer, CAUTHY_SYSTEM: system, CAUTHY_TENANT: tenant, CAUTHY_TOKEN: token })) {\n if (v === '') throw new Error(`cauthy-auth: ${name} is required to push a policy`)\n }\n const res = await (o.fetch ?? fetch)(`${issuer}/v1/systems/${encodeURIComponent(system)}/policy`, {\n method: 'PUT',\n headers: { authorization: `Bearer ${token}`, 'x-tenant-key': tenant, 'content-type': 'application/json' },\n body: JSON.stringify({ roles: o.roles }),\n })\n if (!res.ok) {\n const body = (await res.json().catch(() => null)) as { errors?: { message?: string }[] } | null\n throw new Error(`cauthy-auth: Cauthy refused the policy (${res.status}): ${body?.errors?.[0]?.message ?? res.statusText}`)\n }\n}\n","// The sign-in screens, ready to use.\n//\n// <SignIn onSuccess={() => navigate('/')} />\n// <SignUp locale=\"es\" />\n// <ForgotPassword />\n//\n// They are plain forms — a label, an input, a button. Import\n// `cauthy-auth/styles.css` once and they are drawn with the colours, corners and\n// typeface a person set for the workspace in Cauthy's dashboard, the same as\n// Cauthy's own sign-in page. Or give them the application's own button and\n// input (`components`), or a class for each part (`classNames`), and pass\n// `unstyled` to leave all of that out. Everything they do is `useAuth()`: an\n// application that wants another form writes it with the same functions.\n\nimport { useEffect, useId, useRef, useState, type ComponentType, type CSSProperties, type FormEvent, type ReactNode } from 'react'\nimport { createAuthClient, type Account as AccountDetails, type AccountSession, type AuthError, type AuthMethods, type LinkedIdentity } from './client'\nimport { useAuth, useSession } from './react'\nimport { themeVariables, type CauthyTheme, type ThemeFont } from './theme'\n\n/** Every sentence the forms show. Give any of them to change it. */\nexport interface AuthTexts {\n email: string\n password: string\n name: string\n code: string\n signIn: string\n signUp: string\n continueWith: string // \"Continue with\" + the provider's name\n orWithEmail: string\n forgotPassword: string\n noAccount: string\n createAccount: string\n haveAccount: string\n sendLink: string\n linkSent: string\n codeHelp: string\n verify: string\n checkEmail: string\n backToSignIn: string\n emailMeALink: string\n usePasskey: string\n codeFromMail: string\n signInLinkSent: string\n newPassword: string\n savePassword: string\n passwordChanged: string\n confirming: string\n emailConfirmed: string\n // The account screen.\n profile: string\n save: string\n saved: string\n currentPassword: string\n changePassword: string\n passwordChangedHere: string\n secondStep: string\n secondStepOn: string\n secondStepOff: string\n turnOn: string\n turnOff: string\n addToApp: string // above the secret to add to an authenticator app\n openInApp: string\n recoveryCodes: string\n newRecoveryCodes: string\n keepCodes: string\n passkeys: string\n managePasskeys: string\n sessions: string\n signOutEverywhere: string\n unknownDevice: string\n emailAddress: string\n newEmail: string\n changeEmail: string\n emailSent: string // after asking: \"{email}\" is replaced\n linkedAccounts: string\n noLinkedAccounts: string\n linkWith: string // + the provider's name\n unlink: string\n linked: string // after coming back linked\n /** By error code; one missing shows what the server said. */\n errors: Record<string, string>\n}\n\nconst TEXTS: Record<'en' | 'es', AuthTexts> = {\n en: {\n email: 'Email', password: 'Password', name: 'Name', code: 'Code', signIn: 'Sign in', signUp: 'Create account',\n continueWith: 'Continue with', orWithEmail: 'or with your email', forgotPassword: 'Forgot your password?',\n noAccount: 'No account yet?', createAccount: 'Create one', haveAccount: 'Already have an account?',\n sendLink: 'Send the link', linkSent: 'If that address has an account, a link to choose a new password is on its way.',\n codeHelp: 'Enter the code from your authenticator app, or a recovery code.', verify: 'Verify',\n checkEmail: 'Almost there: open the link we sent to confirm your address, then sign in.', backToSignIn: 'Back to sign in',\n emailMeALink: 'Email me a sign-in link', usePasskey: 'Sign in with a passkey', codeFromMail: 'Reading it on another device? Enter the code from the email.', signInLinkSent: 'If that address has an account, a link to sign in is on its way.',\n newPassword: 'New password', savePassword: 'Save the password', passwordChanged: 'Your password was changed. You can sign in with it now.',\n confirming: 'Confirming your address…', emailConfirmed: 'Your address is confirmed. You can sign in now.',\n profile: 'Profile', save: 'Save', saved: 'Saved.', currentPassword: 'Current password', changePassword: 'Change password',\n passwordChangedHere: 'Your password was changed. Every other session of your account was signed out.',\n secondStep: 'Second step', secondStepOn: 'On: signing in also asks for a code from your authenticator app.', secondStepOff: 'Off: signing in asks only for your password.',\n turnOn: 'Turn on', turnOff: 'Turn off', addToApp: 'Add this key to your authenticator app, then enter the code it shows.', openInApp: 'Open in an authenticator app',\n recoveryCodes: 'Recovery codes', newRecoveryCodes: 'New recovery codes', keepCodes: 'Keep these codes somewhere safe. Each works once, and they are not shown again.',\n passkeys: 'Passkeys', managePasskeys: 'Add or remove a passkey', sessions: 'Where you are signed in', signOutEverywhere: 'Sign out everywhere', unknownDevice: 'Unknown device',\n emailAddress: 'Email address', newEmail: 'New email address', changeEmail: 'Change email',\n emailSent: 'We sent a link to {email}. Your address changes once you open it.',\n linkedAccounts: 'Linked accounts', noLinkedAccounts: 'No account is linked.', linkWith: 'Link', unlink: 'Unlink', linked: 'The account was linked.',\n errors: {\n required: 'This is required.', invalid_email: 'That does not look like an email address.', too_short: 'Use at least 8 characters.',\n invalid_credentials: 'The address or the password is not right.', unavailable: 'Sign-in is unavailable right now. Try again in a moment.',\n state_mismatch: 'That sign-in could not be completed. Try again.', cancelled: 'The sign-in was cancelled.',\n email_taken: 'That address already has an account.', email_unchanged: 'That is already your address.',\n last_sign_in_method: 'Add a password or link another account first: it is your only way to sign in.',\n identity_already_linked: 'That account is linked to someone else.', manual_linking_disabled: 'Linking accounts is turned off for this workspace.',\n invalid_token: 'This link is not valid, or it has expired. Ask for a new one.', invalid_code: 'That code is not right, or it has expired.', wrong_password: 'The current password is not right.', step_up_required: 'Enter your current password.', weak_password: 'Choose a stronger password.', unauthenticated: 'Sign in first.',\n },\n },\n es: {\n email: 'Correo', password: 'Contraseña', name: 'Nombre', code: 'Código', signIn: 'Entrar', signUp: 'Crear cuenta',\n continueWith: 'Continuar con', orWithEmail: 'o con tu correo', forgotPassword: '¿Olvidaste tu contraseña?',\n noAccount: '¿No tienes cuenta?', createAccount: 'Crear una', haveAccount: '¿Ya tienes cuenta?',\n sendLink: 'Enviar el enlace', linkSent: 'Si ese correo tiene una cuenta, ya va en camino un enlace para elegir una contraseña nueva.',\n codeHelp: 'Escribe el código de tu aplicación de autenticación, o un código de recuperación.', verify: 'Verificar',\n checkEmail: 'Ya casi: abre el enlace que te enviamos para confirmar tu correo y luego entra.', backToSignIn: 'Volver a entrar',\n emailMeALink: 'Envíame un enlace para entrar', usePasskey: 'Entrar con una llave de acceso', codeFromMail: '¿Lo estás leyendo en otro dispositivo? Escribe el código que trae el correo.', signInLinkSent: 'Si ese correo tiene una cuenta, ya va en camino un enlace para entrar.',\n newPassword: 'Contraseña nueva', savePassword: 'Guardar la contraseña', passwordChanged: 'Tu contraseña se cambió. Ya puedes entrar con ella.',\n confirming: 'Confirmando tu correo…', emailConfirmed: 'Tu correo quedó confirmado. Ya puedes entrar.',\n profile: 'Perfil', save: 'Guardar', saved: 'Guardado.', currentPassword: 'Contraseña actual', changePassword: 'Cambiar contraseña',\n passwordChangedHere: 'Tu contraseña se cambió. Se cerraron todas las demás sesiones de tu cuenta.',\n secondStep: 'Segundo paso', secondStepOn: 'Activo: al entrar también se pide un código de tu aplicación de autenticación.', secondStepOff: 'Inactivo: al entrar solo se pide tu contraseña.',\n turnOn: 'Activar', turnOff: 'Desactivar', addToApp: 'Agrega esta clave a tu aplicación de autenticación y escribe el código que muestra.', openInApp: 'Abrir en una aplicación de autenticación',\n recoveryCodes: 'Códigos de recuperación', newRecoveryCodes: 'Nuevos códigos de recuperación', keepCodes: 'Guarda estos códigos en un lugar seguro. Cada uno sirve una vez y no se vuelven a mostrar.',\n passkeys: 'Llaves de acceso', managePasskeys: 'Agregar o quitar una llave de acceso', sessions: 'Dónde tienes la sesión abierta', signOutEverywhere: 'Cerrar sesión en todas partes', unknownDevice: 'Dispositivo desconocido',\n emailAddress: 'Correo', newEmail: 'Correo nuevo', changeEmail: 'Cambiar el correo',\n emailSent: 'Enviamos un enlace a {email}. Tu correo cambia cuando lo abras.',\n linkedAccounts: 'Cuentas vinculadas', noLinkedAccounts: 'No hay cuentas vinculadas.', linkWith: 'Vincular', unlink: 'Desvincular', linked: 'La cuenta quedó vinculada.',\n errors: {\n required: 'Este dato es obligatorio.', invalid_email: 'Eso no parece un correo.', too_short: 'Usa al menos 8 caracteres.',\n invalid_credentials: 'El correo o la contraseña no son correctos.', unavailable: 'No se puede entrar en este momento. Intenta de nuevo en un momento.',\n state_mismatch: 'No se pudo completar el ingreso. Intenta de nuevo.', cancelled: 'El ingreso se canceló.',\n email_taken: 'Ese correo ya tiene una cuenta.', email_unchanged: 'Ese ya es tu correo.',\n last_sign_in_method: 'Primero agrega una contraseña o vincula otra cuenta: es tu única forma de entrar.',\n identity_already_linked: 'Esa cuenta está vinculada a otra persona.', manual_linking_disabled: 'Vincular cuentas está desactivado en este workspace.',\n invalid_token: 'Este enlace no es válido o ya venció. Pide uno nuevo.', invalid_code: 'Ese código no es correcto o ya venció.', wrong_password: 'La contraseña actual no es correcta.', step_up_required: 'Escribe tu contraseña actual.', weak_password: 'Elige una contraseña más fuerte.', unauthenticated: 'Inicia sesión primero.',\n },\n },\n}\n\ntype Slot = 'form' | 'field' | 'label' | 'input' | 'button' | 'providerButton' | 'link' | 'error' | 'fieldError' | 'notice' | 'separator' | 'footer' | 'account' | 'section' | 'heading' | 'secret' | 'codes' | 'sessions' | 'session'\n\nexport interface AuthFormProps {\n /** The language of the built-in sentences. Default: `en`. */\n locale?: 'en' | 'es'\n /** Sentences of the application's own, over the built-in ones. */\n texts?: Partial<Omit<AuthTexts, 'errors'>> & { errors?: Record<string, string> }\n /** Called once the person is signed in. Default: go to `returnTo`. */\n onSuccess?: () => void\n /** Where to go after signing in, and where a provider returns to. Default: `/`. */\n returnTo?: string\n /** Paths of the application's other screens, for the links between them. */\n links?: { signIn?: string; signUp?: string; forgotPassword?: string }\n /** A class for each part the form renders. A part given one is left to it by `styles.css`. */\n classNames?: Partial<Record<Slot, string>>\n /**\n * No look of Cauthy's at all: `styles.css` leaves the form alone and the\n * workspace's colours are not read. For a form drawn wholly with the\n * application's own `components` or `classNames`.\n */\n unstyled?: boolean\n /**\n * Take the colours, corners and typeface a person set for the workspace in\n * Cauthy's dashboard. Default: true. False keeps `styles.css`'s own, and\n * whatever `--cauthy-*` variables the application sets.\n */\n workspaceLook?: boolean\n /**\n * The application's own button and input, to draw the form with. Each is\n * given what a `<button>` or an `<input>` would be.\n */\n components?: {\n Button?: ComponentType<{ type: 'submit' | 'button'; disabled?: boolean; className?: string; onClick?: () => void; children: ReactNode }>\n Input?: ComponentType<{\n id: string; name: string; type: string; value: string; autoComplete?: string; required?: boolean; className?: string\n 'aria-invalid'?: boolean; 'aria-describedby'?: string; onChange: (e: { target: { value: string } }) => void\n }>\n }\n}\n\n// Declared once: a component made anew on every render would be a different\n// input each time, and the one being typed in would lose its place.\nconst PlainButton: NonNullable<NonNullable<AuthFormProps['components']>['Button']> = (p) => <button {...p} />\nconst PlainInput: NonNullable<NonNullable<AuthFormProps['components']>['Input']> = (p) => <input {...p} />\n\n// The workspace's look, read once per page and per mount point of the routes.\nconst looks = new Map<string, Promise<CauthyTheme | null>>()\n\n// A typeface is loaded from where the workspace's look says, once per page.\nconst loaded = new Set<string>()\nfunction loadFonts(fonts: ThemeFont[] | undefined) {\n if (typeof document === 'undefined' || typeof FontFace === 'undefined') return\n for (const f of fonts ?? []) {\n const key = `${f.family}|${f.url}|${f.weight ?? ''}|${f.style ?? ''}`\n // The same checks Cauthy's pages make: a plain family name, an https .woff2.\n if (loaded.has(key) || !/^[A-Za-z0-9][A-Za-z0-9 _-]*$/.test(f.family) || !/^https:\\/\\/[^\\s\"'()]+\\.woff2$/i.test(f.url)) continue\n loaded.add(key)\n const face = new FontFace(f.family, `url(\"${f.url}\") format(\"woff2\")`, { weight: String(f.weight ?? '400'), style: f.style === 'italic' ? 'italic' : 'normal', display: 'swap' })\n void face.load().then((ready) => document.fonts.add(ready), () => loaded.delete(key))\n }\n}\n\n/**\n * What the outermost element of a form carries: the mark `styles.css` styles\n * (`data-cauthy`) and the workspace's look as its variables.\n */\nfunction useRoot(props: { unstyled?: boolean; workspaceLook?: boolean }): { 'data-cauthy'?: ''; style?: CSSProperties } {\n const { basePath } = useSession()\n const [vars, setVars] = useState<Record<string, string>>({})\n const wanted = !props.unstyled && props.workspaceLook !== false\n useEffect(() => {\n if (!wanted) return\n let live = true\n let look = looks.get(basePath)\n if (!look) {\n look = createAuthClient({ basePath }).look()\n looks.set(basePath, look)\n }\n void look.then((theme) => {\n if (!live || !theme) return\n setVars(themeVariables(theme))\n loadFonts(theme.fonts)\n })\n return () => { live = false }\n }, [basePath, wanted])\n if (props.unstyled) return {}\n return { 'data-cauthy': '', style: vars as CSSProperties }\n}\n\nfunction useForm(props: AuthFormProps) {\n const t: AuthTexts = { ...TEXTS[props.locale ?? 'en'], ...props.texts, errors: { ...TEXTS[props.locale ?? 'en'].errors, ...props.texts?.errors } }\n const cx = (slot: Slot) => props.classNames?.[slot] ?? `cauthy-${slot}`\n const Button = props.components?.Button ?? PlainButton\n const Input = props.components?.Input ?? PlainInput\n const [error, setError] = useState<AuthError | null>(null)\n const [busy, setBusy] = useState(false)\n const say = (e: AuthError) => t.errors[e.code] ?? e.message\n const done = () => {\n if (props.onSuccess) props.onSuccess()\n else window.location.assign(props.returnTo ?? '/')\n }\n const root = useRoot(props)\n return { t, cx, Button, Input, error, setError, busy, setBusy, say, done, root }\n}\n\nfunction Field(p: {\n f: ReturnType<typeof useForm>; name: 'email' | 'password' | 'newPassword' | 'name' | 'code'; type: string; label: string; value: string\n autoComplete: string; required?: boolean; onChange: (v: string) => void; aside?: ReactNode\n}) {\n const id = useId()\n const { f } = p\n const bad = f.error?.field === p.name ? f.error : null\n return (\n <div className={f.cx('field')}>\n <label className={f.cx('label')} htmlFor={id}>{p.label}{p.aside}</label>\n <f.Input id={id} name={p.name} type={p.type} value={p.value} autoComplete={p.autoComplete} required={p.required} className={f.cx('input')}\n aria-invalid={bad ? true : undefined} aria-describedby={bad ? `${id}-error` : undefined} onChange={(e) => p.onChange(e.target.value)} />\n {bad && <span id={`${id}-error`} role=\"alert\" className={f.cx('fieldError')}>{f.say(bad)}</span>}\n </div>\n )\n}\n\n/** The error a provider's trip came back with, read once from the address. */\nfunction returnedError(): AuthError | null {\n if (typeof window === 'undefined') return null\n const code = new URLSearchParams(window.location.search).get('auth_error')\n return code ? { code, message: 'That sign-in could not be completed. Try again.' } : null\n}\n\n/**\n * The token a mailed link opened this page with, taken out of the address so\n * it is not left in the history or sent on as a referrer.\n */\nfunction takeToken(name: string): string | null {\n if (typeof window === 'undefined') return null\n const url = new URL(window.location.href)\n const token = url.searchParams.get(name)\n if (token === null) return null\n url.searchParams.delete(name)\n window.history.replaceState(window.history.state, '', url.pathname + url.search + url.hash)\n return token\n}\n\n/**\n * Runs `open` once with the token this page was opened with, or with null.\n * Once per page, even where React runs an effect twice while developing: the\n * token is taken out of the address the first time and a link works once.\n */\nfunction useMailedToken(name: string, open: (token: string | null) => void): void {\n const opened = useRef(false)\n useEffect(() => {\n if (opened.current) return\n opened.current = true\n open(takeToken(name))\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [])\n}\n\nexport function SignIn(props: AuthFormProps) {\n const auth = useAuth()\n const f = useForm(props)\n const [methods, setMethods] = useState<AuthMethods | null>(null)\n const [email, setEmail] = useState('')\n const [password, setPassword] = useState('')\n const [code, setCode] = useState('')\n const [step, setStep] = useState<'password' | 'code' | 'opening' | 'sent'>('password')\n\n useEffect(() => {\n void auth.methods().then(setMethods)\n const back = returnedError()\n if (back) f.setError(back)\n // Once: what the workspace offers does not change while the form is open.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [])\n\n // Opened from a sign-in link: the token signs the person in.\n useMailedToken('ml_token', (token) => {\n if (!token) return\n setStep('opening')\n void auth.signIn.magicLinkVerify({ token }).then((r) => {\n if (r.ok) return f.done()\n f.setError(r.error)\n setStep('password')\n })\n })\n\n const submit = async (e: FormEvent) => {\n e.preventDefault()\n f.setBusy(true)\n f.setError(null)\n const r = step === 'code' ? await auth.signIn.mfa({ code }) : step === 'sent' ? await auth.signIn.emailCode({ code }) : await auth.signIn.email({ email, password })\n f.setBusy(false)\n if (!r.ok) return f.setError(r.error)\n if (r.status === 'mfa_required') return setStep('code')\n f.done()\n }\n const sendLink = async () => {\n f.setBusy(true)\n f.setError(null)\n const r = await auth.signIn.magicLink({ email })\n f.setBusy(false)\n if (!r.ok) return f.setError(r.error)\n setStep('sent')\n }\n const general = f.error && !f.error.field ? f.error : null\n\n if (step === 'opening') return <div className={f.cx('form')} {...f.root} aria-busy=\"true\" />\n if (step === 'sent') {\n return (\n <form className={f.cx('form')} {...f.root} onSubmit={submit} noValidate>\n <p className={f.cx('notice')}>{f.t.signInLinkSent}</p>\n {general && <p role=\"alert\" className={f.cx('error')}>{f.say(general)}</p>}\n <p className={f.cx('notice')}>{f.t.codeFromMail}</p>\n <Field f={f} name=\"code\" type=\"text\" label={f.t.code} value={code} autoComplete=\"one-time-code\" required onChange={setCode} />\n <f.Button type=\"submit\" disabled={f.busy} className={f.cx('button')}>{f.t.verify}</f.Button>\n </form>\n )\n }\n if (step === 'code') {\n return (\n <form className={f.cx('form')} {...f.root} onSubmit={submit} noValidate>\n <p className={f.cx('notice')}>{f.t.codeHelp}</p>\n {general && <p role=\"alert\" className={f.cx('error')}>{f.say(general)}</p>}\n <Field f={f} name=\"code\" type=\"text\" label={f.t.code} value={code} autoComplete=\"one-time-code\" required onChange={setCode} />\n <f.Button type=\"submit\" disabled={f.busy} className={f.cx('button')}>{f.t.verify}</f.Button>\n </form>\n )\n }\n return (\n <form className={f.cx('form')} {...f.root} onSubmit={submit} noValidate>\n {general && <p role=\"alert\" className={f.cx('error')}>{f.say(general)}</p>}\n {(methods?.providers ?? []).map((p) => (\n <f.Button key={p.id} type=\"button\" className={f.cx('providerButton')} onClick={() => auth.signIn.social(p.id, { returnTo: props.returnTo })}>\n {f.t.continueWith} {p.name}\n </f.Button>\n ))}\n {methods?.passkey && (\n <f.Button type=\"button\" className={f.cx('providerButton')} onClick={() => auth.signIn.passkey({ returnTo: props.returnTo, locale: props.locale })}>{f.t.usePasskey}</f.Button>\n )}\n {((methods?.providers.length ?? 0) > 0 || methods?.passkey) && <p className={f.cx('separator')}>{f.t.orWithEmail}</p>}\n <Field f={f} name=\"email\" type=\"email\" label={f.t.email} value={email} autoComplete=\"username\" required onChange={setEmail} />\n <Field f={f} name=\"password\" type=\"password\" label={f.t.password} value={password} autoComplete=\"current-password\" required onChange={setPassword}\n aside={props.links?.forgotPassword ? <a className={f.cx('link')} href={props.links.forgotPassword}>{f.t.forgotPassword}</a> : undefined} />\n <f.Button type=\"submit\" disabled={f.busy} className={f.cx('button')}>{f.t.signIn}</f.Button>\n {methods?.magicLink && (\n <f.Button type=\"button\" disabled={f.busy} className={f.cx('providerButton')} onClick={() => void sendLink()}>{f.t.emailMeALink}</f.Button>\n )}\n {methods?.signUp !== false && props.links?.signUp && (\n <p className={f.cx('footer')}>{f.t.noAccount} <a className={f.cx('link')} href={props.links.signUp}>{f.t.createAccount}</a></p>\n )}\n </form>\n )\n}\n\nexport function SignUp(props: AuthFormProps) {\n const auth = useAuth()\n const f = useForm(props)\n const [name, setName] = useState('')\n const [email, setEmail] = useState('')\n const [password, setPassword] = useState('')\n const [sent, setSent] = useState(false)\n\n const submit = async (e: FormEvent) => {\n e.preventDefault()\n f.setBusy(true)\n f.setError(null)\n const r = await auth.signUp.email({ name, email, password })\n f.setBusy(false)\n if (!r.ok) return f.setError(r.error)\n if (r.status === 'verification_required') return setSent(true)\n f.done()\n }\n const general = f.error && !f.error.field ? f.error : null\n\n if (sent) {\n return (\n <div className={f.cx('form')} {...f.root}>\n <p className={f.cx('notice')}>{f.t.checkEmail}</p>\n {props.links?.signIn && <a className={f.cx('link')} href={props.links.signIn}>{f.t.backToSignIn}</a>}\n </div>\n )\n }\n return (\n <form className={f.cx('form')} {...f.root} onSubmit={submit} noValidate>\n {general && <p role=\"alert\" className={f.cx('error')}>{f.say(general)}</p>}\n <Field f={f} name=\"name\" type=\"text\" label={f.t.name} value={name} autoComplete=\"name\" onChange={setName} />\n <Field f={f} name=\"email\" type=\"email\" label={f.t.email} value={email} autoComplete=\"username\" required onChange={setEmail} />\n <Field f={f} name=\"password\" type=\"password\" label={f.t.password} value={password} autoComplete=\"new-password\" required onChange={setPassword} />\n <f.Button type=\"submit\" disabled={f.busy} className={f.cx('button')}>{f.t.signUp}</f.Button>\n {props.links?.signIn && <p className={f.cx('footer')}>{f.t.haveAccount} <a className={f.cx('link')} href={props.links.signIn}>{f.t.signIn}</a></p>}\n </form>\n )\n}\n\nexport function ForgotPassword(props: AuthFormProps) {\n const auth = useAuth()\n const f = useForm(props)\n const [email, setEmail] = useState('')\n const [sent, setSent] = useState(false)\n\n const submit = async (e: FormEvent) => {\n e.preventDefault()\n f.setBusy(true)\n f.setError(null)\n const r = await auth.forgotPassword({ email })\n f.setBusy(false)\n if (!r.ok) return f.setError(r.error)\n setSent(true)\n }\n const general = f.error && !f.error.field ? f.error : null\n\n if (sent) {\n return (\n <div className={f.cx('form')} {...f.root}>\n <p className={f.cx('notice')}>{f.t.linkSent}</p>\n {props.links?.signIn && <a className={f.cx('link')} href={props.links.signIn}>{f.t.backToSignIn}</a>}\n </div>\n )\n }\n return (\n <form className={f.cx('form')} {...f.root} onSubmit={submit} noValidate>\n {general && <p role=\"alert\" className={f.cx('error')}>{f.say(general)}</p>}\n <Field f={f} name=\"email\" type=\"email\" label={f.t.email} value={email} autoComplete=\"username\" required onChange={setEmail} />\n <f.Button type=\"submit\" disabled={f.busy} className={f.cx('button')}>{f.t.sendLink}</f.Button>\n {props.links?.signIn && <p className={f.cx('footer')}><a className={f.cx('link')} href={props.links.signIn}>{f.t.backToSignIn}</a></p>}\n </form>\n )\n}\n\n/** The page a \"choose a new password\" link opens: `pages.resetPassword`. */\nexport function ResetPassword(props: AuthFormProps) {\n const auth = useAuth()\n const f = useForm(props)\n const [token, setToken] = useState<string | null>(null)\n const [password, setPassword] = useState('')\n const [changed, setChanged] = useState(false)\n\n useMailedToken('token', (t) => {\n setToken(t ?? '')\n if (!t) f.setError({ code: 'invalid_token', message: 'This link is not valid, or it has expired.' })\n })\n\n const submit = async (e: FormEvent) => {\n e.preventDefault()\n f.setBusy(true)\n f.setError(null)\n const r = await auth.resetPassword({ token: token ?? '', password })\n f.setBusy(false)\n if (!r.ok) return f.setError(r.error)\n setChanged(true)\n }\n const general = f.error && !f.error.field ? f.error : null\n const back = props.links?.signIn && <a className={f.cx('link')} href={props.links.signIn}>{f.t.backToSignIn}</a>\n\n if (changed) {\n return (\n <div className={f.cx('form')} {...f.root}>\n <p className={f.cx('notice')}>{f.t.passwordChanged}</p>\n {back}\n </div>\n )\n }\n if (token === '') {\n return (\n <div className={f.cx('form')} {...f.root}>\n {general && <p role=\"alert\" className={f.cx('error')}>{f.say(general)}</p>}\n {props.links?.forgotPassword && <a className={f.cx('link')} href={props.links.forgotPassword}>{f.t.forgotPassword}</a>}\n </div>\n )\n }\n return (\n <form className={f.cx('form')} {...f.root} onSubmit={submit} noValidate>\n {general && <p role=\"alert\" className={f.cx('error')}>{f.say(general)}</p>}\n <Field f={f} name=\"password\" type=\"password\" label={f.t.newPassword} value={password} autoComplete=\"new-password\" required onChange={setPassword} />\n <f.Button type=\"submit\" disabled={f.busy || token === null} className={f.cx('button')}>{f.t.savePassword}</f.Button>\n </form>\n )\n}\n\n/** The page a \"confirm your address\" link opens: `pages.verifyEmail`. It confirms as it opens. */\nexport function VerifyEmail(props: AuthFormProps) {\n const auth = useAuth()\n const f = useForm(props)\n const [state, setState] = useState<'confirming' | 'confirmed' | 'failed'>('confirming')\n\n useMailedToken('token', (token) => {\n if (!token) {\n f.setError({ code: 'invalid_token', message: 'This link is not valid, or it has expired.' })\n return setState('failed')\n }\n void auth.verifyEmail({ token }).then((r) => {\n if (r.ok) return setState('confirmed')\n f.setError(r.error)\n setState('failed')\n })\n })\n\n return (\n <div className={f.cx('form')} {...f.root} aria-busy={state === 'confirming'}>\n {state === 'confirming' && <p className={f.cx('notice')}>{f.t.confirming}</p>}\n {state === 'confirmed' && <p className={f.cx('notice')}>{f.t.emailConfirmed}</p>}\n {state === 'failed' && f.error && <p role=\"alert\" className={f.cx('error')}>{f.say(f.error)}</p>}\n {state !== 'confirming' && props.links?.signIn && <a className={f.cx('link')} href={props.links.signIn}>{f.t.backToSignIn}</a>}\n </div>\n )\n}\n\nexport interface AccountProps extends Omit<AuthFormProps, 'links' | 'returnTo' | 'onSuccess'> {\n /** Called after \"sign out everywhere\". Default: go to `/`. */\n onSignedOut?: () => void\n /** The moment of a session, as the application writes dates. Default: the browser's own way, in the reader's time zone. */\n formatDate?: (iso: string) => string\n}\n\n/** One part of the account screen: its own form, its own error, its own \"saved\". */\nfunction useSection(props: AccountProps) {\n // The look is the account screen's, around every part: not read again here.\n const f = useForm({ ...props, unstyled: true })\n const [done, setDone] = useState<string | null>(null)\n const run = async <T extends { ok: boolean }>(action: () => Promise<T>): Promise<T> => {\n f.setBusy(true)\n f.setError(null)\n setDone(null)\n const r = await action()\n f.setBusy(false)\n if (!r.ok) f.setError((r as unknown as { error: AuthError }).error)\n return r\n }\n const general = f.error && !f.error.field ? f.error : null\n return { f, done, setDone, run, general }\n}\n\n/**\n * The signed-in person's account, in the application: their name, their\n * password, the second step, and where they are signed in. Each part saves on\n * its own. Like the other forms, it carries no styles.\n */\nexport function Account(props: AccountProps) {\n const auth = useAuth()\n const { accountUrl } = useSession()\n const { t, root } = useForm(props)\n const cx = (slot: Slot) => props.classNames?.[slot] ?? `cauthy-${slot}`\n const [account, setAccount] = useState<AccountDetails | null>(null)\n const [sessions, setSessions] = useState<AccountSession[]>([])\n\n useEffect(() => {\n void auth.account.get().then(setAccount)\n void auth.account.sessions().then(setSessions)\n // Once: the account is read when the screen opens, and after each change below.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [])\n\n if (account === null) return <div className={cx('account')} {...root} aria-busy=\"true\" />\n const when = props.formatDate ?? ((iso: string) => new Date(iso).toLocaleString())\n\n return (\n <div className={cx('account')} {...root}>\n <ProfilePart props={props} account={account} onSaved={setAccount} />\n <EmailPart props={props} account={account} />\n {account.hasPassword && <PasswordPart props={props} />}\n <LinkedPart props={props} />\n <SecondStepPart props={props} account={account} onChanged={(mfaEnabled) => setAccount({ ...account, mfaEnabled })} />\n <section className={cx('section')}>\n <h2 className={cx('heading')}>{t.passkeys}</h2>\n {/* A passkey belongs to the site it was made on, which is Cauthy's. */}\n <a className={cx('link')} href={accountUrl()}>{t.managePasskeys}</a>\n </section>\n <section className={cx('section')}>\n <h2 className={cx('heading')}>{t.sessions}</h2>\n <ul className={cx('sessions')}>\n {sessions.map((s, i) => (\n <li key={i} className={cx('session')}>{s.device || t.unknownDevice} · {s.ip} · {when(s.createdAt)}</li>\n ))}\n </ul>\n <SignOutEverywhere props={props} />\n </section>\n </div>\n )\n}\n\nfunction ProfilePart({ props, account, onSaved }: { props: AccountProps; account: AccountDetails; onSaved: (a: AccountDetails) => void }) {\n const auth = useAuth()\n const { f, done, setDone, run, general } = useSection(props)\n const [name, setName] = useState(account.name)\n const submit = async (e: FormEvent) => {\n e.preventDefault()\n const r = await run(() => auth.account.update({ name }))\n if (!r.ok) return\n onSaved(r.account)\n setDone(f.t.saved)\n }\n return (\n <form className={f.cx('section')} onSubmit={submit} noValidate>\n <h2 className={f.cx('heading')}>{f.t.profile}</h2>\n <p className={f.cx('notice')}>{account.email}</p>\n {general && <p role=\"alert\" className={f.cx('error')}>{f.say(general)}</p>}\n <Field f={f} name=\"name\" type=\"text\" label={f.t.name} value={name} autoComplete=\"name\" onChange={setName} />\n <f.Button type=\"submit\" disabled={f.busy} className={f.cx('button')}>{f.t.save}</f.Button>\n {done && <p role=\"status\" className={f.cx('notice')}>{done}</p>}\n </form>\n )\n}\n\nfunction EmailPart({ props, account }: { props: AccountProps; account: AccountDetails }) {\n const auth = useAuth()\n const { f, done, setDone, run, general } = useSection(props)\n const [email, setEmail] = useState('')\n const [password, setPassword] = useState('')\n const submit = async (e: FormEvent) => {\n e.preventDefault()\n const r = await run(() => auth.account.changeEmail({ email, password }))\n if (!r.ok) return\n setPassword('')\n setDone(f.t.emailSent.replace('{email}', r.email))\n }\n return (\n <form className={f.cx('section')} onSubmit={submit} noValidate>\n <h2 className={f.cx('heading')}>{f.t.emailAddress}</h2>\n <p className={f.cx('notice')}>{account.email}</p>\n {general && <p role=\"alert\" className={f.cx('error')}>{f.say(general)}</p>}\n <Field f={f} name=\"email\" type=\"email\" label={f.t.newEmail} value={email} autoComplete=\"email\" required onChange={setEmail} />\n {account.hasPassword && (\n <Field f={f} name=\"password\" type=\"password\" label={f.t.currentPassword} value={password} autoComplete=\"current-password\" required onChange={setPassword} />\n )}\n <f.Button type=\"submit\" disabled={f.busy} className={f.cx('button')}>{f.t.changeEmail}</f.Button>\n {done && <p role=\"status\" className={f.cx('notice')}>{done}</p>}\n </form>\n )\n}\n\n/** The providers the account signs in with, and the ones the workspace offers to link. */\nfunction LinkedPart({ props }: { props: AccountProps }) {\n const auth = useAuth()\n const { f, run, general } = useSection(props)\n const [linked, setLinked] = useState<LinkedIdentity[] | null>(null)\n const [offered, setOffered] = useState<{ id: string; name: string }[]>([])\n const [came, setCame] = useState<string | null>(null)\n useEffect(() => {\n void auth.account.identities().then(setLinked)\n void auth.methods().then((m) => setOffered(m.providers))\n // Back from a provider: say how it went, once.\n const back = typeof window === 'undefined' ? null : new URLSearchParams(window.location.search)\n if (back?.get('linked')) setCame(back.get('linked'))\n else if (back?.get('auth_error')) f.setError({ code: back.get('auth_error') as string, message: 'That account could not be linked. Try again.' })\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [])\n if (linked === null) return null\n const name = (id: string) => offered.find((p) => p.id === id)?.name ?? id\n const unlink = async (provider: string) => {\n const r = await run(() => auth.account.unlink(provider))\n if (r.ok) setLinked(linked.filter((x) => x.provider !== provider))\n }\n const here = typeof window === 'undefined' ? undefined : window.location.pathname\n return (\n <section className={f.cx('section')}>\n <h2 className={f.cx('heading')}>{f.t.linkedAccounts}</h2>\n {came && <p role=\"status\" className={f.cx('notice')}>{f.t.linked}</p>}\n {general && <p role=\"alert\" className={f.cx('error')}>{f.say(general)}</p>}\n {linked.length === 0 ? <p className={f.cx('notice')}>{f.t.noLinkedAccounts}</p> : (\n <ul className={f.cx('sessions')}>\n {linked.map((x) => (\n <li key={x.provider} className={f.cx('session')}>\n {name(x.provider)}{x.email ? ` · ${x.email}` : ''}{' '}\n <f.Button type=\"button\" disabled={f.busy} className={f.cx('providerButton')} onClick={() => void unlink(x.provider)}>{f.t.unlink}</f.Button>\n </li>\n ))}\n </ul>\n )}\n {offered.filter((p) => !linked.some((x) => x.provider === p.id)).map((p) => (\n <f.Button key={p.id} type=\"button\" className={f.cx('providerButton')} onClick={() => auth.account.link(p.id, { returnTo: here })}>{f.t.linkWith} {p.name}</f.Button>\n ))}\n </section>\n )\n}\n\nfunction PasswordPart({ props }: { props: AccountProps }) {\n const auth = useAuth()\n const { f, done, setDone, run, general } = useSection(props)\n const [password, setPassword] = useState('')\n const [newPassword, setNewPassword] = useState('')\n const submit = async (e: FormEvent) => {\n e.preventDefault()\n const r = await run(() => auth.account.changePassword({ password, newPassword }))\n if (!r.ok) return\n setPassword('')\n setNewPassword('')\n setDone(f.t.passwordChangedHere)\n }\n return (\n <form className={f.cx('section')} onSubmit={submit} noValidate>\n <h2 className={f.cx('heading')}>{f.t.changePassword}</h2>\n {general && <p role=\"alert\" className={f.cx('error')}>{f.say(general)}</p>}\n <Field f={f} name=\"password\" type=\"password\" label={f.t.currentPassword} value={password} autoComplete=\"current-password\" required onChange={setPassword} />\n <Field f={f} name=\"newPassword\" type=\"password\" label={f.t.newPassword} value={newPassword} autoComplete=\"new-password\" required onChange={setNewPassword} />\n <f.Button type=\"submit\" disabled={f.busy} className={f.cx('button')}>{f.t.changePassword}</f.Button>\n {done && <p role=\"status\" className={f.cx('notice')}>{done}</p>}\n </form>\n )\n}\n\nfunction SecondStepPart({ props, account, onChanged }: { props: AccountProps; account: AccountDetails; onChanged: (on: boolean) => void }) {\n const auth = useAuth()\n const { f, run, general } = useSection(props)\n const [password, setPassword] = useState('')\n const [code, setCode] = useState('')\n const [setup, setSetup] = useState<{ secret: string; otpauthUri: string } | null>(null)\n const [codes, setCodes] = useState<string[] | null>(null)\n\n const start = async (e: FormEvent) => {\n e.preventDefault()\n const r = await run(() => auth.account.mfa.setup({ password }))\n if (r.ok) setSetup({ secret: r.secret, otpauthUri: r.otpauthUri })\n }\n const confirm = async (e: FormEvent) => {\n e.preventDefault()\n const r = await run(() => auth.account.mfa.verify({ code }))\n if (!r.ok) return\n setSetup(null)\n setCode('')\n setPassword('')\n setCodes(r.recoveryCodes)\n onChanged(true)\n }\n const turnOff = async (e: FormEvent) => {\n e.preventDefault()\n const r = await run(() => auth.account.mfa.disable({ password }))\n if (!r.ok) return\n setPassword('')\n setCodes(null)\n onChanged(false)\n }\n const renew = async () => {\n const r = await run(() => auth.account.mfa.recoveryCodes({ password }))\n if (r.ok) setCodes(r.recoveryCodes)\n }\n const passwordField = account.hasPassword && (\n <Field f={f} name=\"password\" type=\"password\" label={f.t.currentPassword} value={password} autoComplete=\"current-password\" required onChange={setPassword} />\n )\n const shown = codes && (\n <>\n <p className={f.cx('notice')}>{f.t.keepCodes}</p>\n <ul className={f.cx('codes')}>{codes.map((c) => <li key={c}><code>{c}</code></li>)}</ul>\n </>\n )\n\n if (setup) {\n return (\n <form className={f.cx('section')} onSubmit={confirm} noValidate>\n <h2 className={f.cx('heading')}>{f.t.secondStep}</h2>\n <p className={f.cx('notice')}>{f.t.addToApp}</p>\n <code className={f.cx('secret')}>{setup.secret}</code>\n <a className={f.cx('link')} href={setup.otpauthUri}>{f.t.openInApp}</a>\n {general && <p role=\"alert\" className={f.cx('error')}>{f.say(general)}</p>}\n <Field f={f} name=\"code\" type=\"text\" label={f.t.code} value={code} autoComplete=\"one-time-code\" required onChange={setCode} />\n <f.Button type=\"submit\" disabled={f.busy} className={f.cx('button')}>{f.t.verify}</f.Button>\n </form>\n )\n }\n return (\n <form className={f.cx('section')} onSubmit={account.mfaEnabled ? turnOff : start} noValidate>\n <h2 className={f.cx('heading')}>{f.t.secondStep}</h2>\n <p className={f.cx('notice')}>{account.mfaEnabled ? f.t.secondStepOn : f.t.secondStepOff}</p>\n {shown}\n {general && <p role=\"alert\" className={f.cx('error')}>{f.say(general)}</p>}\n {passwordField}\n <f.Button type=\"submit\" disabled={f.busy} className={f.cx('button')}>{account.mfaEnabled ? f.t.turnOff : f.t.turnOn}</f.Button>\n {account.mfaEnabled && (\n <f.Button type=\"button\" disabled={f.busy} className={f.cx('providerButton')} onClick={() => void renew()}>{f.t.newRecoveryCodes}</f.Button>\n )}\n </form>\n )\n}\n\nfunction SignOutEverywhere({ props }: { props: AccountProps }) {\n const auth = useAuth()\n const { f, run, general } = useSection(props)\n const end = async () => {\n const r = await run(() => auth.account.signOutEverywhere())\n if (!r.ok) return\n if (props.onSignedOut) props.onSignedOut()\n else window.location.assign('/')\n }\n return (\n <>\n {general && <p role=\"alert\" className={f.cx('error')}>{f.say(general)}</p>}\n <f.Button type=\"button\" disabled={f.busy} className={f.cx('button')} onClick={() => void end()}>{f.t.signOutEverywhere}</f.Button>\n </>\n )\n}\n"],"mappings":"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","names":["useEffect","useRef","useState","jsx","useState","useRef","useEffect"]}