cauthy-auth 0.5.0 → 0.5.2

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.
@@ -225,13 +225,11 @@ interface CauthySystem {
225
225
  email: string;
226
226
  }>;
227
227
  /**
228
- * How the application looks on Cauthy's pages: read it, set it, or take it
229
- * back to Cauthy's own with `null`. Of its own sign-in client — this one,
230
- * unless another is named (a system whose identity is a separate client).
228
+ * How the application looks on Cauthy's pages, read. It is decided in
229
+ * Cauthy's dashboard, by a person: an application never changes it.
231
230
  */
232
231
  theme: {
233
232
  get(clientId?: string): Promise<CauthyTheme>;
234
- set(theme: CauthyTheme | null, clientId?: string): Promise<void>;
235
233
  };
236
234
  /** The public half of `key`, to serve at the address Cauthy was given (`jwks_uri`). Empty with a secret. */
237
235
  publicJwks(): Promise<{
package/dist/theme.d.mts CHANGED
@@ -32,6 +32,9 @@ interface CauthyTheme {
32
32
  /** Paragraphs, labels, small print. */
33
33
  textMuted?: string;
34
34
  border?: string;
35
+ /** The fields and the secondary buttons, when they are not the card's colours. */
36
+ inputBackground?: string;
37
+ inputBorder?: string;
35
38
  /** The main button, and what is written on it. */
36
39
  primary?: string;
37
40
  primaryText?: string;
package/dist/theme.d.ts CHANGED
@@ -32,6 +32,9 @@ interface CauthyTheme {
32
32
  /** Paragraphs, labels, small print. */
33
33
  textMuted?: string;
34
34
  border?: string;
35
+ /** The fields and the secondary buttons, when they are not the card's colours. */
36
+ inputBackground?: string;
37
+ inputBorder?: string;
35
38
  /** The main button, and what is written on it. */
36
39
  primary?: string;
37
40
  primaryText?: string;
package/dist/theme.js CHANGED
@@ -226,7 +226,9 @@ function toWire(theme) {
226
226
  panelColors: "panel_colors",
227
227
  panelText: "panel_text",
228
228
  panelIconUrl: "panel_icon_url",
229
- texts: "texts"
229
+ texts: "texts",
230
+ inputBackground: "input_background",
231
+ inputBorder: "input_border"
230
232
  };
231
233
  const wire = {};
232
234
  for (const [k, v] of Object.entries(theme)) {
@@ -258,7 +260,9 @@ function fromWire(wire) {
258
260
  panel_colors: "panelColors",
259
261
  panel_text: "panelText",
260
262
  panel_icon_url: "panelIconUrl",
261
- texts: "texts"
263
+ texts: "texts",
264
+ input_background: "inputBackground",
265
+ input_border: "inputBorder"
262
266
  };
263
267
  const theme = {};
264
268
  for (const [k, v] of Object.entries(wire ?? {})) if (names[k] && v !== void 0 && v !== null && v !== "") theme[names[k]] = v;
package/dist/theme.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/theme.ts"],"sourcesContent":["// 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 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\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 if (!scope.startsWith('@') && !/:root|^html\\b|^body\\b|\\[data-|^\\*$|:host/.test(scope)) return false\n }\n return true\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// ── 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',\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',\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"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAgGA,IAAM,aAAa;AAWnB,SAAS,aAAa,KAA4B;AAChD,QAAM,OAAO,IAAI,QAAQ,qBAAqB,EAAE;AAChD,QAAMA,OAAqB,CAAC;AAC5B,QAAM,SAAmB,CAAC;AAC1B,MAAI,QAAQ;AACZ,MAAI,QAAQ;AACZ,MAAI,QAAQ;AACZ,QAAM,QAAQ,MAAM;AAClB,UAAM,IAAI,sCAAsC,KAAK,KAAK;AAC1D,QAAI,EAAG,CAAAA,KAAI,KAAK,EAAE,MAAM,EAAE,CAAC,GAAG,OAAO,EAAE,CAAC,EAAE,QAAQ,QAAQ,GAAG,EAAE,QAAQ,kBAAkB,EAAE,GAAG,QAAQ,CAAC,GAAG,MAAM,EAAE,CAAC;AACnH,YAAQ;AAAA,EACV;AACA,aAAW,MAAM,MAAM;AACrB,QAAI,OAAO;AACT,eAAS;AACT,UAAI,OAAO,MAAO,SAAQ;AAC1B;AAAA,IACF;AACA,QAAI,OAAO,OAAO,OAAO,KAAK;AAC5B,cAAQ;AACR,eAAS;AAAA,IACX,WAAW,OAAO,KAAK;AACrB;AACA,eAAS;AAAA,IACX,WAAW,OAAO,KAAK;AACrB,cAAQ,KAAK,IAAI,GAAG,QAAQ,CAAC;AAC7B,eAAS;AAAA,IACX,WAAW,OAAO,OAAO,UAAU,GAAG;AACpC,aAAO,KAAK,MAAM,KAAK,EAAE,QAAQ,QAAQ,GAAG,CAAC;AAC7C,cAAQ;AAAA,IACV,WAAW,OAAO,OAAO,UAAU,GAAG;AACpC,YAAM;AACN,aAAO,IAAI;AAAA,IACb,WAAW,OAAO,OAAO,UAAU,GAAG;AACpC,YAAM;AAAA,IACR,OAAO;AACL,eAAS;AAAA,IACX;AAAA,EACF;AACA,SAAOA;AACT;AAEA,IAAM,OAAO;AACb,IAAM,QAAQ;AACd,IAAM,QAAQ;AAGd,SAAS,QAAQ,GAAgB,GAAgF;AAC/G,aAAW,SAAS,EAAE,QAAQ;AAC5B,QAAI,EAAE,SAAS,WAAW,KAAK,KAAK,KAAK,EAAG,QAAO;AACnD,QAAI,EAAE,SAAS,UAAU,MAAM,KAAK,KAAK,EAAG,QAAO;AACnD,UAAM,QAAQ,MAAM,KAAK,KAAK;AAC9B,QAAI,SAAS,CAAC,kBAAkB,KAAK,MAAM,CAAC,CAAC,KAAK,MAAM,CAAC,MAAM,EAAE,MAAO,QAAO;AAE/E,QAAI,CAAC,MAAM,WAAW,GAAG,KAAK,CAAC,2CAA2C,KAAK,KAAK,EAAG,QAAO;AAAA,EAChG;AACA,SAAO;AACT;AAIA,SAAS,QAAQ,OAAe,MAA2B,OAAO,GAAkB;AAClF,MAAI,OAAO,GAAI,QAAO;AACtB,MAAI,aAAa;AAEjB,MAAIA,OAAM;AACV,WAAS,QAAQ,GAAG,QAAQ,MAAM,QAAQ,KAAKA,IAAG,GAAG,SAAS;AAC5D,IAAAA,OAAMA,KAAI,QAAQ,iEAAiE,CAAC,IAAI,MAAc,aAAsB;AAC1H,YAAM,QAAQ,KAAK,IAAI,IAAI;AAC3B,YAAM,OAAO,UAAU,SAAY,QAAQ,OAAO,MAAM,OAAO,CAAC,IAAI,aAAa,SAAY,QAAQ,SAAS,KAAK,GAAG,MAAM,OAAO,CAAC,IAAI;AACxI,UAAI,SAAS,KAAM,cAAa;AAChC,aAAO,QAAQ;AAAA,IACjB,CAAC;AACD,QAAI,WAAY,QAAO;AAAA,EACzB;AACA,SAAO,QAAQ,KAAKA,IAAG,IAAI,OAAOA,KAAI,KAAK;AAC7C;AAEA,IAAM,UAAU,CAAC,MAAc,KAAK,IAAI,GAAG,KAAK,IAAI,GAAG,CAAC,CAAC;AACzD,IAAM,OAAO,CAAC,MAAc,KAAK,MAAM,QAAQ,CAAC,IAAI,GAAG,EAAE,SAAS,EAAE,EAAE,SAAS,GAAG,GAAG;AACrF,IAAM,QAAQ,CAAC,MAAe,KAAK,WAAY,QAAQ,IAAI,QAAQ,KAAK,IAAI,GAAG,IAAI,GAAG,IAAI;AAE1F,SAAS,IAAI,GAAW,GAAW,GAAW,IAAI,GAAW;AAC3D,MAAI,KAAK,EAAG,QAAO,IAAI,KAAK,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC;AAClD,SAAO,QAAQ,KAAK,MAAM,QAAQ,CAAC,IAAI,GAAG,CAAC,KAAK,KAAK,MAAM,QAAQ,CAAC,IAAI,GAAG,CAAC,KAAK,KAAK,MAAM,QAAQ,CAAC,IAAI,GAAG,CAAC,KAAK,KAAK,MAAM,QAAQ,CAAC,IAAI,GAAI,IAAI,GAAI;AACxJ;AAEA,IAAM,QAAQ,CAAC,MAA2B,MAAM,SAAY,IAAI,EAAE,SAAS,GAAG,IAAI,WAAW,CAAC,IAAI,MAAM,WAAW,CAAC;AAEpH,IAAM,WAAmC,EAAE,OAAO,WAAW,OAAO,UAAU;AAGvE,SAAS,QAAQ,OAA8B;AACpD,QAAM,IAAI,MAAM,KAAK,EAAE,YAAY;AACnC,MAAI,SAAS,CAAC,EAAG,QAAO,SAAS,CAAC;AAClC,MAAI,6CAA6C,KAAK,CAAC,EAAG,QAAO;AACjE,MAAI,IAAI,uFAAuF,KAAK,CAAC;AACrG,MAAI,GAAG;AACL,UAAM,KAAK,CAAC,MAAe,EAAE,SAAS,GAAG,IAAI,WAAW,CAAC,IAAI,MAAM,WAAW,CAAC,IAAI;AACnF,WAAO,IAAI,GAAG,EAAE,CAAC,CAAC,GAAG,GAAG,EAAE,CAAC,CAAC,GAAG,GAAG,EAAE,CAAC,CAAC,GAAG,MAAM,EAAE,CAAC,CAAC,CAAC;AAAA,EACtD;AACA,MAAI,2FAA2F,KAAK,CAAC;AACrG,MAAI,GAAG;AACL,UAAM,KAAM,WAAW,EAAE,CAAC,CAAC,IAAI,MAAO,OAAO;AAC7C,UAAM,IAAI,WAAW,EAAE,CAAC,CAAC,IAAI;AAC7B,UAAM,IAAI,WAAW,EAAE,CAAC,CAAC,IAAI;AAC7B,UAAM,IAAI,CAAC,MAAc;AACvB,YAAM,KAAK,IAAI,IAAI,MAAM;AACzB,aAAO,IAAI,IAAI,KAAK,IAAI,GAAG,IAAI,CAAC,IAAI,KAAK,IAAI,IAAI,KAAK,IAAI,IAAI,GAAG,IAAI,GAAG,CAAC,CAAC;AAAA,IAC5E;AACA,WAAO,IAAI,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,MAAM,EAAE,CAAC,CAAC,CAAC;AAAA,EAC1C;AACA,MAAI,qFAAqF,KAAK,CAAC;AAC/F,MAAI,GAAG;AACL,UAAM,IAAI,EAAE,CAAC,EAAE,SAAS,GAAG,IAAI,WAAW,EAAE,CAAC,CAAC,IAAI,MAAM,WAAW,EAAE,CAAC,CAAC;AACvE,UAAM,IAAI,EAAE,CAAC,EAAE,SAAS,GAAG,IAAK,WAAW,EAAE,CAAC,CAAC,IAAI,MAAO,MAAM,WAAW,EAAE,CAAC,CAAC;AAC/E,UAAM,IAAK,WAAW,EAAE,CAAC,CAAC,IAAI,KAAK,KAAM;AACzC,UAAM,IAAI,IAAI,KAAK,IAAI,CAAC;AACxB,UAAM,IAAI,IAAI,KAAK,IAAI,CAAC;AACxB,UAAM,IAAI,KAAK,IAAI,IAAI,eAAe,IAAI,eAAe,GAAG,CAAC;AAC7D,UAAM,KAAK,KAAK,IAAI,IAAI,eAAe,IAAI,eAAe,GAAG,CAAC;AAC9D,UAAM,IAAI,KAAK,IAAI,IAAI,eAAe,IAAI,cAAc,GAAG,CAAC;AAC5D,WAAO;AAAA,MACL,MAAM,eAAe,IAAI,eAAe,KAAK,eAAe,CAAC;AAAA,MAC7D,MAAM,gBAAgB,IAAI,eAAe,KAAK,eAAe,CAAC;AAAA,MAC9D,MAAM,gBAAgB,IAAI,eAAe,KAAK,cAAc,CAAC;AAAA,MAC7D,MAAM,EAAE,CAAC,CAAC;AAAA,IACZ;AAAA,EACF;AACA,SAAO;AACT;AAGA,SAAS,SAAS,OAA8B;AAC9C,QAAM,IAAI,yBAAyB,KAAK,MAAM,KAAK,CAAC;AACpD,MAAI,CAAC,EAAG,QAAO;AACf,QAAM,KAAK,WAAW,EAAE,CAAC,CAAC,KAAK,EAAE,CAAC,MAAM,SAAS,EAAE,CAAC,MAAM,OAAO,KAAK;AACtE,SAAO,OAAO,SAAS,EAAE,IAAI,KAAK,IAAI,YAAY,KAAK,IAAI,GAAG,KAAK,MAAM,EAAE,CAAC,CAAC,IAAI;AACnF;AAGA,SAAS,OAAO,OAA8B;AAC5C,QAAM,IAAI,MAAM,KAAK;AACrB,SAAO,6BAA6B,KAAK,CAAC,MAAM,EAAE,MAAM,IAAI,GAAG,UAAU,KAAK,MAAM,MAAM,EAAE,MAAM,IAAI,GAAG,UAAU,KAAK,MAAM,IAAI,IAAI;AACxI;AAKA,IAAM,SAA0C;AAAA,EAC9C,CAAC,cAAc,CAAC,mBAAmB,cAAc,CAAC;AAAA,EAClD,CAAC,WAAW,CAAC,0BAA0B,qBAAqB,CAAC;AAAA,EAC7D,CAAC,QAAQ,CAAC,qBAAqB,mBAAmB,CAAC;AAAA,EACnD,CAAC,aAAa,CAAC,qBAAqB,CAAC;AAAA,EACrC,CAAC,UAAU,CAAC,uBAAuB,qBAAqB,CAAC;AAAA,EACzD,CAAC,WAAW,CAAC,gBAAgB,qBAAqB,CAAC;AAAA,EACnD,CAAC,eAAe,CAAC,qBAAqB,mBAAmB,CAAC;AAAA,EAC1D,CAAC,UAAU,CAAC,mBAAmB,qBAAqB,aAAa,CAAC;AAAA,EAClE,CAAC,SAAS,CAAC,wBAAwB,YAAY,CAAC;AAAA,EAChD,CAAC,mBAAmB,CAAC,iBAAiB,CAAC;AAAA,EACvC,CAAC,WAAW,CAAC,0BAA0B,cAAc,CAAC;AAAA,EACtD,CAAC,qBAAqB,CAAC,mBAAmB,CAAC;AAC7C;AAWO,SAAS,mBAAmB,KAAwB,UAAiC,CAAC,GAAkB;AAC7G,QAAM,IAAI,EAAE,MAAM,QAAQ,QAAQ,SAAS,OAAO,QAAQ,MAAM;AAChE,QAAM,OAAO,oBAAI,IAAoB;AACrC,aAAW,SAAS,MAAM,QAAQ,GAAG,IAAI,MAAM,CAAC,GAAG,GAAG;AACpD,eAAW,KAAK,aAAa,KAAK,EAAG,KAAI,QAAQ,GAAG,CAAC,EAAG,MAAK,IAAI,EAAE,MAAM,EAAE,KAAK;AAAA,EAClF;AACA,QAAM,QAAqB,CAAC;AAC5B,QAAM,WAAqB,CAAC;AAE5B,QAAM,OAAO,CAAI,QAAkB,IAA6B,SAAgC;AAC9F,eAAW,SAAS,QAAQ;AAC1B,YAAM,MAAM,KAAK,IAAI,KAAK;AAC1B,UAAI,QAAQ,OAAW;AACvB,YAAM,QAAQ,QAAQ,KAAK,IAAI;AAC/B,YAAM,MAAM,UAAU,OAAO,OAAO,GAAG,KAAK;AAC5C,UAAI,QAAQ,KAAM,QAAO;AACzB,eAAS,KAAK,GAAG,KAAK,MAAM,GAAG,YAAY,IAAI,kBAAkB;AAAA,IACnE;AACA,WAAO;AAAA,EACT;AAEA,aAAW,CAAC,OAAO,MAAM,KAAK,QAAQ;AACpC,UAAM,IAAI,KAAK,QAAQ,SAAS,UAAU;AAC1C,QAAI,MAAM,OAAW,CAAC,MAAkC,KAAK,IAAI;AAAA,EACnE;AACA,QAAM,SAAS,KAAK,CAAC,yBAAyB,gBAAgB,GAAG,UAAU,UAAU;AACrF,MAAI,WAAW,OAAW,OAAM,SAAS;AACzC,QAAM,SAAS,KAAK,CAAC,2BAA2B,gBAAgB,GAAG,UAAU,UAAU;AACvF,MAAI,WAAW,OAAW,OAAM,eAAe;AAC/C,QAAM,OAAO,KAAK,CAAC,kBAAkB,GAAG,QAAQ,aAAa;AAC7D,MAAI,SAAS,OAAW,OAAM,aAAa;AAC3C,MAAI,QAAQ,QAAS,OAAM,UAAU,QAAQ;AAE7C,MAAI,KAAK,SAAS,EAAG,UAAS,KAAK,0FAA0F;AAAA,WACpH,CAAC,CAAC,GAAG,KAAK,KAAK,CAAC,EAAE,KAAK,CAAC,MAAM,EAAE,WAAW,OAAO,CAAC,EAAG,UAAS,KAAK,gDAAgD;AAC7H,SAAO,EAAE,OAAO,SAAS;AAC3B;AAKO,SAAS,OAAO,OAA6C;AAClE,QAAM,QAA2C;AAAA,IAC/C,YAAY;AAAA,IAAc,SAAS;AAAA,IAAW,MAAM;AAAA,IAAQ,WAAW;AAAA,IAAc,QAAQ;AAAA,IAC7F,SAAS;AAAA,IAAW,aAAa;AAAA,IAAgB,QAAQ;AAAA,IAAU,OAAO;AAAA,IAAS,iBAAiB;AAAA,IACpG,SAAS;AAAA,IAAW,mBAAmB;AAAA,IAAsB,QAAQ;AAAA,IAAU,cAAc;AAAA,IAC7F,YAAY;AAAA,IAAe,SAAS;AAAA,IAAY,OAAO;AAAA,IAAS,QAAQ;AAAA,IAAU,aAAa;AAAA,IAC/F,WAAW;AAAA,IAAc,cAAc;AAAA,IAAkB,OAAO;AAAA,EAClE;AACA,QAAM,OAAgC,CAAC;AACvC,aAAW,CAAC,GAAG,CAAC,KAAK,OAAO,QAAQ,KAAK,GAAG;AAC1C,QAAI,MAAM,UAAa,MAAM,MAAO,MAAM,QAAQ,CAAC,KAAK,EAAE,WAAW,EAAI;AACzE,SAAK,MAAM,CAAsB,CAAC,IAAI;AAAA,EACxC;AACA,SAAO;AACT;AAGO,SAAS,SAAS,MAA4C;AACnE,QAAM,QAA2C;AAAA,IAC/C,YAAY;AAAA,IAAc,SAAS;AAAA,IAAW,MAAM;AAAA,IAAQ,YAAY;AAAA,IAAa,QAAQ;AAAA,IAC7F,SAAS;AAAA,IAAW,cAAc;AAAA,IAAe,QAAQ;AAAA,IAAU,OAAO;AAAA,IAAS,kBAAkB;AAAA,IACrG,SAAS;AAAA,IAAW,oBAAoB;AAAA,IAAqB,QAAQ;AAAA,IAAU,eAAe;AAAA,IAC9F,aAAa;AAAA,IAAc,UAAU;AAAA,IAAW,OAAO;AAAA,IAAS,QAAQ;AAAA,IAAU,cAAc;AAAA,IAChG,YAAY;AAAA,IAAa,gBAAgB;AAAA,IAAgB,OAAO;AAAA,EAClE;AACA,QAAM,QAAiC,CAAC;AACxC,aAAW,CAAC,GAAG,CAAC,KAAK,OAAO,QAAQ,QAAQ,CAAC,CAAC,EAAG,KAAI,MAAM,CAAC,KAAK,MAAM,UAAa,MAAM,QAAQ,MAAM,GAAI,OAAM,MAAM,CAAC,CAAC,IAAI;AAC9H,SAAO;AACT;AAuBA,eAAsB,UAAU,GAAoC;AAClE,QAAM,MAAM,CAAC,MAAe,OAAO,YAAY,cAAc,QAAQ,MAAM,CAAC,IAAI;AAChF,QAAM,UAAU,EAAE,UAAU,IAAI,eAAe,KAAK,IAAI,QAAQ,QAAQ,EAAE;AAC1E,QAAM,WAAW,EAAE,YAAY,IAAI,kBAAkB,KAAK;AAC1D,QAAM,SAAS,EAAE,UAAU,IAAI,eAAe,KAAK;AACnD,QAAM,QAAQ,EAAE,SAAS,IAAI,cAAc,KAAK;AAChD,aAAW,CAAC,MAAM,CAAC,KAAK,OAAO,QAAQ,EAAE,eAAe,QAAQ,kBAAkB,UAAU,eAAe,QAAQ,cAAc,MAAM,CAAC,GAAG;AACzI,QAAI,MAAM,GAAI,OAAM,IAAI,MAAM,gBAAgB,IAAI,8BAA8B;AAAA,EAClF;AACA,QAAM,MAAM,OAAO,EAAE,SAAS,OAAO,GAAG,MAAM,qBAAqB,mBAAmB,QAAQ,CAAC,UAAU;AAAA,IACvG,QAAQ;AAAA,IACR,SAAS,EAAE,eAAe,UAAU,KAAK,IAAI,gBAAgB,QAAQ,gBAAgB,mBAAmB;AAAA,IACxG,MAAM,KAAK,UAAU,OAAO,EAAE,KAAK,CAAC;AAAA,EACtC,CAAC;AACD,MAAI,CAAC,IAAI,IAAI;AACX,UAAM,OAAQ,MAAM,IAAI,KAAK,EAAE,MAAM,MAAM,IAAI;AAC/C,UAAM,IAAI,MAAM,0CAA0C,IAAI,MAAM,MAAM,MAAM,SAAS,CAAC,GAAG,WAAW,IAAI,UAAU,EAAE;AAAA,EAC1H;AACF;","names":["out"]}
1
+ {"version":3,"sources":["../src/theme.ts"],"sourcesContent":["// 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\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 if (!scope.startsWith('@') && !/:root|^html\\b|^body\\b|\\[data-|^\\*$|:host/.test(scope)) return false\n }\n return true\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// ── 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',\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',\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"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAmGA,IAAM,aAAa;AAWnB,SAAS,aAAa,KAA4B;AAChD,QAAM,OAAO,IAAI,QAAQ,qBAAqB,EAAE;AAChD,QAAMA,OAAqB,CAAC;AAC5B,QAAM,SAAmB,CAAC;AAC1B,MAAI,QAAQ;AACZ,MAAI,QAAQ;AACZ,MAAI,QAAQ;AACZ,QAAM,QAAQ,MAAM;AAClB,UAAM,IAAI,sCAAsC,KAAK,KAAK;AAC1D,QAAI,EAAG,CAAAA,KAAI,KAAK,EAAE,MAAM,EAAE,CAAC,GAAG,OAAO,EAAE,CAAC,EAAE,QAAQ,QAAQ,GAAG,EAAE,QAAQ,kBAAkB,EAAE,GAAG,QAAQ,CAAC,GAAG,MAAM,EAAE,CAAC;AACnH,YAAQ;AAAA,EACV;AACA,aAAW,MAAM,MAAM;AACrB,QAAI,OAAO;AACT,eAAS;AACT,UAAI,OAAO,MAAO,SAAQ;AAC1B;AAAA,IACF;AACA,QAAI,OAAO,OAAO,OAAO,KAAK;AAC5B,cAAQ;AACR,eAAS;AAAA,IACX,WAAW,OAAO,KAAK;AACrB;AACA,eAAS;AAAA,IACX,WAAW,OAAO,KAAK;AACrB,cAAQ,KAAK,IAAI,GAAG,QAAQ,CAAC;AAC7B,eAAS;AAAA,IACX,WAAW,OAAO,OAAO,UAAU,GAAG;AACpC,aAAO,KAAK,MAAM,KAAK,EAAE,QAAQ,QAAQ,GAAG,CAAC;AAC7C,cAAQ;AAAA,IACV,WAAW,OAAO,OAAO,UAAU,GAAG;AACpC,YAAM;AACN,aAAO,IAAI;AAAA,IACb,WAAW,OAAO,OAAO,UAAU,GAAG;AACpC,YAAM;AAAA,IACR,OAAO;AACL,eAAS;AAAA,IACX;AAAA,EACF;AACA,SAAOA;AACT;AAEA,IAAM,OAAO;AACb,IAAM,QAAQ;AACd,IAAM,QAAQ;AAGd,SAAS,QAAQ,GAAgB,GAAgF;AAC/G,aAAW,SAAS,EAAE,QAAQ;AAC5B,QAAI,EAAE,SAAS,WAAW,KAAK,KAAK,KAAK,EAAG,QAAO;AACnD,QAAI,EAAE,SAAS,UAAU,MAAM,KAAK,KAAK,EAAG,QAAO;AACnD,UAAM,QAAQ,MAAM,KAAK,KAAK;AAC9B,QAAI,SAAS,CAAC,kBAAkB,KAAK,MAAM,CAAC,CAAC,KAAK,MAAM,CAAC,MAAM,EAAE,MAAO,QAAO;AAE/E,QAAI,CAAC,MAAM,WAAW,GAAG,KAAK,CAAC,2CAA2C,KAAK,KAAK,EAAG,QAAO;AAAA,EAChG;AACA,SAAO;AACT;AAIA,SAAS,QAAQ,OAAe,MAA2B,OAAO,GAAkB;AAClF,MAAI,OAAO,GAAI,QAAO;AACtB,MAAI,aAAa;AAEjB,MAAIA,OAAM;AACV,WAAS,QAAQ,GAAG,QAAQ,MAAM,QAAQ,KAAKA,IAAG,GAAG,SAAS;AAC5D,IAAAA,OAAMA,KAAI,QAAQ,iEAAiE,CAAC,IAAI,MAAc,aAAsB;AAC1H,YAAM,QAAQ,KAAK,IAAI,IAAI;AAC3B,YAAM,OAAO,UAAU,SAAY,QAAQ,OAAO,MAAM,OAAO,CAAC,IAAI,aAAa,SAAY,QAAQ,SAAS,KAAK,GAAG,MAAM,OAAO,CAAC,IAAI;AACxI,UAAI,SAAS,KAAM,cAAa;AAChC,aAAO,QAAQ;AAAA,IACjB,CAAC;AACD,QAAI,WAAY,QAAO;AAAA,EACzB;AACA,SAAO,QAAQ,KAAKA,IAAG,IAAI,OAAOA,KAAI,KAAK;AAC7C;AAEA,IAAM,UAAU,CAAC,MAAc,KAAK,IAAI,GAAG,KAAK,IAAI,GAAG,CAAC,CAAC;AACzD,IAAM,OAAO,CAAC,MAAc,KAAK,MAAM,QAAQ,CAAC,IAAI,GAAG,EAAE,SAAS,EAAE,EAAE,SAAS,GAAG,GAAG;AACrF,IAAM,QAAQ,CAAC,MAAe,KAAK,WAAY,QAAQ,IAAI,QAAQ,KAAK,IAAI,GAAG,IAAI,GAAG,IAAI;AAE1F,SAAS,IAAI,GAAW,GAAW,GAAW,IAAI,GAAW;AAC3D,MAAI,KAAK,EAAG,QAAO,IAAI,KAAK,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC;AAClD,SAAO,QAAQ,KAAK,MAAM,QAAQ,CAAC,IAAI,GAAG,CAAC,KAAK,KAAK,MAAM,QAAQ,CAAC,IAAI,GAAG,CAAC,KAAK,KAAK,MAAM,QAAQ,CAAC,IAAI,GAAG,CAAC,KAAK,KAAK,MAAM,QAAQ,CAAC,IAAI,GAAI,IAAI,GAAI;AACxJ;AAEA,IAAM,QAAQ,CAAC,MAA2B,MAAM,SAAY,IAAI,EAAE,SAAS,GAAG,IAAI,WAAW,CAAC,IAAI,MAAM,WAAW,CAAC;AAEpH,IAAM,WAAmC,EAAE,OAAO,WAAW,OAAO,UAAU;AAGvE,SAAS,QAAQ,OAA8B;AACpD,QAAM,IAAI,MAAM,KAAK,EAAE,YAAY;AACnC,MAAI,SAAS,CAAC,EAAG,QAAO,SAAS,CAAC;AAClC,MAAI,6CAA6C,KAAK,CAAC,EAAG,QAAO;AACjE,MAAI,IAAI,uFAAuF,KAAK,CAAC;AACrG,MAAI,GAAG;AACL,UAAM,KAAK,CAAC,MAAe,EAAE,SAAS,GAAG,IAAI,WAAW,CAAC,IAAI,MAAM,WAAW,CAAC,IAAI;AACnF,WAAO,IAAI,GAAG,EAAE,CAAC,CAAC,GAAG,GAAG,EAAE,CAAC,CAAC,GAAG,GAAG,EAAE,CAAC,CAAC,GAAG,MAAM,EAAE,CAAC,CAAC,CAAC;AAAA,EACtD;AACA,MAAI,2FAA2F,KAAK,CAAC;AACrG,MAAI,GAAG;AACL,UAAM,KAAM,WAAW,EAAE,CAAC,CAAC,IAAI,MAAO,OAAO;AAC7C,UAAM,IAAI,WAAW,EAAE,CAAC,CAAC,IAAI;AAC7B,UAAM,IAAI,WAAW,EAAE,CAAC,CAAC,IAAI;AAC7B,UAAM,IAAI,CAAC,MAAc;AACvB,YAAM,KAAK,IAAI,IAAI,MAAM;AACzB,aAAO,IAAI,IAAI,KAAK,IAAI,GAAG,IAAI,CAAC,IAAI,KAAK,IAAI,IAAI,KAAK,IAAI,IAAI,GAAG,IAAI,GAAG,CAAC,CAAC;AAAA,IAC5E;AACA,WAAO,IAAI,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,MAAM,EAAE,CAAC,CAAC,CAAC;AAAA,EAC1C;AACA,MAAI,qFAAqF,KAAK,CAAC;AAC/F,MAAI,GAAG;AACL,UAAM,IAAI,EAAE,CAAC,EAAE,SAAS,GAAG,IAAI,WAAW,EAAE,CAAC,CAAC,IAAI,MAAM,WAAW,EAAE,CAAC,CAAC;AACvE,UAAM,IAAI,EAAE,CAAC,EAAE,SAAS,GAAG,IAAK,WAAW,EAAE,CAAC,CAAC,IAAI,MAAO,MAAM,WAAW,EAAE,CAAC,CAAC;AAC/E,UAAM,IAAK,WAAW,EAAE,CAAC,CAAC,IAAI,KAAK,KAAM;AACzC,UAAM,IAAI,IAAI,KAAK,IAAI,CAAC;AACxB,UAAM,IAAI,IAAI,KAAK,IAAI,CAAC;AACxB,UAAM,IAAI,KAAK,IAAI,IAAI,eAAe,IAAI,eAAe,GAAG,CAAC;AAC7D,UAAM,KAAK,KAAK,IAAI,IAAI,eAAe,IAAI,eAAe,GAAG,CAAC;AAC9D,UAAM,IAAI,KAAK,IAAI,IAAI,eAAe,IAAI,cAAc,GAAG,CAAC;AAC5D,WAAO;AAAA,MACL,MAAM,eAAe,IAAI,eAAe,KAAK,eAAe,CAAC;AAAA,MAC7D,MAAM,gBAAgB,IAAI,eAAe,KAAK,eAAe,CAAC;AAAA,MAC9D,MAAM,gBAAgB,IAAI,eAAe,KAAK,cAAc,CAAC;AAAA,MAC7D,MAAM,EAAE,CAAC,CAAC;AAAA,IACZ;AAAA,EACF;AACA,SAAO;AACT;AAGA,SAAS,SAAS,OAA8B;AAC9C,QAAM,IAAI,yBAAyB,KAAK,MAAM,KAAK,CAAC;AACpD,MAAI,CAAC,EAAG,QAAO;AACf,QAAM,KAAK,WAAW,EAAE,CAAC,CAAC,KAAK,EAAE,CAAC,MAAM,SAAS,EAAE,CAAC,MAAM,OAAO,KAAK;AACtE,SAAO,OAAO,SAAS,EAAE,IAAI,KAAK,IAAI,YAAY,KAAK,IAAI,GAAG,KAAK,MAAM,EAAE,CAAC,CAAC,IAAI;AACnF;AAGA,SAAS,OAAO,OAA8B;AAC5C,QAAM,IAAI,MAAM,KAAK;AACrB,SAAO,6BAA6B,KAAK,CAAC,MAAM,EAAE,MAAM,IAAI,GAAG,UAAU,KAAK,MAAM,MAAM,EAAE,MAAM,IAAI,GAAG,UAAU,KAAK,MAAM,IAAI,IAAI;AACxI;AAKA,IAAM,SAA0C;AAAA,EAC9C,CAAC,cAAc,CAAC,mBAAmB,cAAc,CAAC;AAAA,EAClD,CAAC,WAAW,CAAC,0BAA0B,qBAAqB,CAAC;AAAA,EAC7D,CAAC,QAAQ,CAAC,qBAAqB,mBAAmB,CAAC;AAAA,EACnD,CAAC,aAAa,CAAC,qBAAqB,CAAC;AAAA,EACrC,CAAC,UAAU,CAAC,uBAAuB,qBAAqB,CAAC;AAAA,EACzD,CAAC,WAAW,CAAC,gBAAgB,qBAAqB,CAAC;AAAA,EACnD,CAAC,eAAe,CAAC,qBAAqB,mBAAmB,CAAC;AAAA,EAC1D,CAAC,UAAU,CAAC,mBAAmB,qBAAqB,aAAa,CAAC;AAAA,EAClE,CAAC,SAAS,CAAC,wBAAwB,YAAY,CAAC;AAAA,EAChD,CAAC,mBAAmB,CAAC,iBAAiB,CAAC;AAAA,EACvC,CAAC,WAAW,CAAC,0BAA0B,cAAc,CAAC;AAAA,EACtD,CAAC,qBAAqB,CAAC,mBAAmB,CAAC;AAC7C;AAWO,SAAS,mBAAmB,KAAwB,UAAiC,CAAC,GAAkB;AAC7G,QAAM,IAAI,EAAE,MAAM,QAAQ,QAAQ,SAAS,OAAO,QAAQ,MAAM;AAChE,QAAM,OAAO,oBAAI,IAAoB;AACrC,aAAW,SAAS,MAAM,QAAQ,GAAG,IAAI,MAAM,CAAC,GAAG,GAAG;AACpD,eAAW,KAAK,aAAa,KAAK,EAAG,KAAI,QAAQ,GAAG,CAAC,EAAG,MAAK,IAAI,EAAE,MAAM,EAAE,KAAK;AAAA,EAClF;AACA,QAAM,QAAqB,CAAC;AAC5B,QAAM,WAAqB,CAAC;AAE5B,QAAM,OAAO,CAAI,QAAkB,IAA6B,SAAgC;AAC9F,eAAW,SAAS,QAAQ;AAC1B,YAAM,MAAM,KAAK,IAAI,KAAK;AAC1B,UAAI,QAAQ,OAAW;AACvB,YAAM,QAAQ,QAAQ,KAAK,IAAI;AAC/B,YAAM,MAAM,UAAU,OAAO,OAAO,GAAG,KAAK;AAC5C,UAAI,QAAQ,KAAM,QAAO;AACzB,eAAS,KAAK,GAAG,KAAK,MAAM,GAAG,YAAY,IAAI,kBAAkB;AAAA,IACnE;AACA,WAAO;AAAA,EACT;AAEA,aAAW,CAAC,OAAO,MAAM,KAAK,QAAQ;AACpC,UAAM,IAAI,KAAK,QAAQ,SAAS,UAAU;AAC1C,QAAI,MAAM,OAAW,CAAC,MAAkC,KAAK,IAAI;AAAA,EACnE;AACA,QAAM,SAAS,KAAK,CAAC,yBAAyB,gBAAgB,GAAG,UAAU,UAAU;AACrF,MAAI,WAAW,OAAW,OAAM,SAAS;AACzC,QAAM,SAAS,KAAK,CAAC,2BAA2B,gBAAgB,GAAG,UAAU,UAAU;AACvF,MAAI,WAAW,OAAW,OAAM,eAAe;AAC/C,QAAM,OAAO,KAAK,CAAC,kBAAkB,GAAG,QAAQ,aAAa;AAC7D,MAAI,SAAS,OAAW,OAAM,aAAa;AAC3C,MAAI,QAAQ,QAAS,OAAM,UAAU,QAAQ;AAE7C,MAAI,KAAK,SAAS,EAAG,UAAS,KAAK,0FAA0F;AAAA,WACpH,CAAC,CAAC,GAAG,KAAK,KAAK,CAAC,EAAE,KAAK,CAAC,MAAM,EAAE,WAAW,OAAO,CAAC,EAAG,UAAS,KAAK,gDAAgD;AAC7H,SAAO,EAAE,OAAO,SAAS;AAC3B;AAKO,SAAS,OAAO,OAA6C;AAClE,QAAM,QAA2C;AAAA,IAC/C,YAAY;AAAA,IAAc,SAAS;AAAA,IAAW,MAAM;AAAA,IAAQ,WAAW;AAAA,IAAc,QAAQ;AAAA,IAC7F,SAAS;AAAA,IAAW,aAAa;AAAA,IAAgB,QAAQ;AAAA,IAAU,OAAO;AAAA,IAAS,iBAAiB;AAAA,IACpG,SAAS;AAAA,IAAW,mBAAmB;AAAA,IAAsB,QAAQ;AAAA,IAAU,cAAc;AAAA,IAC7F,YAAY;AAAA,IAAe,SAAS;AAAA,IAAY,OAAO;AAAA,IAAS,QAAQ;AAAA,IAAU,aAAa;AAAA,IAC/F,WAAW;AAAA,IAAc,cAAc;AAAA,IAAkB,OAAO;AAAA,IAAS,iBAAiB;AAAA,IAAoB,aAAa;AAAA,EAC7H;AACA,QAAM,OAAgC,CAAC;AACvC,aAAW,CAAC,GAAG,CAAC,KAAK,OAAO,QAAQ,KAAK,GAAG;AAC1C,QAAI,MAAM,UAAa,MAAM,MAAO,MAAM,QAAQ,CAAC,KAAK,EAAE,WAAW,EAAI;AACzE,SAAK,MAAM,CAAsB,CAAC,IAAI;AAAA,EACxC;AACA,SAAO;AACT;AAGO,SAAS,SAAS,MAA4C;AACnE,QAAM,QAA2C;AAAA,IAC/C,YAAY;AAAA,IAAc,SAAS;AAAA,IAAW,MAAM;AAAA,IAAQ,YAAY;AAAA,IAAa,QAAQ;AAAA,IAC7F,SAAS;AAAA,IAAW,cAAc;AAAA,IAAe,QAAQ;AAAA,IAAU,OAAO;AAAA,IAAS,kBAAkB;AAAA,IACrG,SAAS;AAAA,IAAW,oBAAoB;AAAA,IAAqB,QAAQ;AAAA,IAAU,eAAe;AAAA,IAC9F,aAAa;AAAA,IAAc,UAAU;AAAA,IAAW,OAAO;AAAA,IAAS,QAAQ;AAAA,IAAU,cAAc;AAAA,IAChG,YAAY;AAAA,IAAa,gBAAgB;AAAA,IAAgB,OAAO;AAAA,IAAS,kBAAkB;AAAA,IAAmB,cAAc;AAAA,EAC9H;AACA,QAAM,QAAiC,CAAC;AACxC,aAAW,CAAC,GAAG,CAAC,KAAK,OAAO,QAAQ,QAAQ,CAAC,CAAC,EAAG,KAAI,MAAM,CAAC,KAAK,MAAM,UAAa,MAAM,QAAQ,MAAM,GAAI,OAAM,MAAM,CAAC,CAAC,IAAI;AAC9H,SAAO;AACT;AAuBA,eAAsB,UAAU,GAAoC;AAClE,QAAM,MAAM,CAAC,MAAe,OAAO,YAAY,cAAc,QAAQ,MAAM,CAAC,IAAI;AAChF,QAAM,UAAU,EAAE,UAAU,IAAI,eAAe,KAAK,IAAI,QAAQ,QAAQ,EAAE;AAC1E,QAAM,WAAW,EAAE,YAAY,IAAI,kBAAkB,KAAK;AAC1D,QAAM,SAAS,EAAE,UAAU,IAAI,eAAe,KAAK;AACnD,QAAM,QAAQ,EAAE,SAAS,IAAI,cAAc,KAAK;AAChD,aAAW,CAAC,MAAM,CAAC,KAAK,OAAO,QAAQ,EAAE,eAAe,QAAQ,kBAAkB,UAAU,eAAe,QAAQ,cAAc,MAAM,CAAC,GAAG;AACzI,QAAI,MAAM,GAAI,OAAM,IAAI,MAAM,gBAAgB,IAAI,8BAA8B;AAAA,EAClF;AACA,QAAM,MAAM,OAAO,EAAE,SAAS,OAAO,GAAG,MAAM,qBAAqB,mBAAmB,QAAQ,CAAC,UAAU;AAAA,IACvG,QAAQ;AAAA,IACR,SAAS,EAAE,eAAe,UAAU,KAAK,IAAI,gBAAgB,QAAQ,gBAAgB,mBAAmB;AAAA,IACxG,MAAM,KAAK,UAAU,OAAO,EAAE,KAAK,CAAC;AAAA,EACtC,CAAC;AACD,MAAI,CAAC,IAAI,IAAI;AACX,UAAM,OAAQ,MAAM,IAAI,KAAK,EAAE,MAAM,MAAM,IAAI;AAC/C,UAAM,IAAI,MAAM,0CAA0C,IAAI,MAAM,MAAM,MAAM,SAAS,CAAC,GAAG,WAAW,IAAI,UAAU,EAAE;AAAA,EAC1H;AACF;","names":["out"]}
package/dist/theme.mjs CHANGED
@@ -198,7 +198,9 @@ function toWire(theme) {
198
198
  panelColors: "panel_colors",
199
199
  panelText: "panel_text",
200
200
  panelIconUrl: "panel_icon_url",
201
- texts: "texts"
201
+ texts: "texts",
202
+ inputBackground: "input_background",
203
+ inputBorder: "input_border"
202
204
  };
203
205
  const wire = {};
204
206
  for (const [k, v] of Object.entries(theme)) {
@@ -230,7 +232,9 @@ function fromWire(wire) {
230
232
  panel_colors: "panelColors",
231
233
  panel_text: "panelText",
232
234
  panel_icon_url: "panelIconUrl",
233
- texts: "texts"
235
+ texts: "texts",
236
+ input_background: "inputBackground",
237
+ input_border: "inputBorder"
234
238
  };
235
239
  const theme = {};
236
240
  for (const [k, v] of Object.entries(wire ?? {})) if (names[k] && v !== void 0 && v !== null && v !== "") theme[names[k]] = v;
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/theme.ts"],"sourcesContent":["// 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 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\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 if (!scope.startsWith('@') && !/:root|^html\\b|^body\\b|\\[data-|^\\*$|:host/.test(scope)) return false\n }\n return true\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// ── 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',\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',\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"],"mappings":"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","names":["out"]}
1
+ {"version":3,"sources":["../src/theme.ts"],"sourcesContent":["// 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\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 if (!scope.startsWith('@') && !/:root|^html\\b|^body\\b|\\[data-|^\\*$|:host/.test(scope)) return false\n }\n return true\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// ── 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',\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',\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"],"mappings":"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","names":["out"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cauthy-auth",
3
- "version": "0.5.0",
3
+ "version": "0.5.2",
4
4
  "description": "Sign in with Cauthy: one route to mount, getSession on the server, useSession in the browser. No database, no screens to build.",
5
5
  "license": "Apache-2.0",
6
6
  "main": "dist/index.js",