cauthy-auth 0.3.0 → 0.4.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.
@@ -1,4 +1,4 @@
1
- import { J as JsonValue, S as Session, f as SessionStatus, e as SessionOrganization, c as CauthySystem, P as PublicSession, b as CauthyOptions } from './system-BWLddIt2.js';
1
+ import { J as JsonValue, S as Session, f as SessionStatus, e as SessionOrganization, c as CauthySystem, P as PublicSession, b as CauthyOptions } from './system-CL3Q30FT.js';
2
2
  import { JWTVerifyGetKey } from 'jose';
3
3
 
4
4
  /** Something that happened in Cauthy, as a subscriber is told. Moments are UTC. */
@@ -1,4 +1,4 @@
1
- import { J as JsonValue, S as Session, f as SessionStatus, e as SessionOrganization, c as CauthySystem, P as PublicSession, b as CauthyOptions } from './system-BWLddIt2.mjs';
1
+ import { J as JsonValue, S as Session, f as SessionStatus, e as SessionOrganization, c as CauthySystem, P as PublicSession, b as CauthyOptions } from './system-CdvktS7x.mjs';
2
2
  import { JWTVerifyGetKey } from 'jose';
3
3
 
4
4
  /** Something that happened in Cauthy, as a subscriber is told. Moments are UTC. */
package/dist/cli.js CHANGED
@@ -266,10 +266,14 @@ function toWire(theme) {
266
266
  radius: "radius",
267
267
  buttonRadius: "button_radius",
268
268
  fontFamily: "font_family",
269
- logoUrl: "logo_url"
269
+ logoUrl: "logo_url",
270
+ fonts: "fonts"
270
271
  };
271
272
  const wire = {};
272
- for (const [k, v] of Object.entries(theme)) if (v !== void 0 && v !== "") wire[names[k]] = v;
273
+ for (const [k, v] of Object.entries(theme)) {
274
+ if (v === void 0 || v === "" || Array.isArray(v) && v.length === 0) continue;
275
+ wire[names[k]] = v;
276
+ }
273
277
  return wire;
274
278
  }
275
279
  async function pushTheme(o) {
@@ -1,7 +1,8 @@
1
1
  import { FastifyReply, FastifyPluginAsync } from 'fastify';
2
- import { C as Cauthy } from './cauthy-mNADGlNl.mjs';
3
- import { S as Session } from './system-BWLddIt2.mjs';
2
+ import { C as Cauthy } from './cauthy-Dg-DNIo9.mjs';
3
+ import { S as Session } from './system-CdvktS7x.mjs';
4
4
  import 'jose';
5
+ import './theme.mjs';
5
6
 
6
7
  declare module 'fastify' {
7
8
  interface FastifyRequest {
package/dist/fastify.d.ts CHANGED
@@ -1,7 +1,8 @@
1
1
  import { FastifyReply, FastifyPluginAsync } from 'fastify';
2
- import { C as Cauthy } from './cauthy-C5_lopMQ.js';
3
- import { S as Session } from './system-BWLddIt2.js';
2
+ import { C as Cauthy } from './cauthy--iqtLWNa.js';
3
+ import { S as Session } from './system-CL3Q30FT.js';
4
4
  import 'jose';
5
+ import './theme.js';
5
6
 
6
7
  declare module 'fastify' {
7
8
  interface FastifyRequest {
package/dist/index.d.mts CHANGED
@@ -1,6 +1,6 @@
1
- export { C as Cauthy, a as CauthyEvent, b as CauthyWebhookError, R as Resolved, V as VerifyWebhookOptions, c as createCauthy, v as verifyWebhook } from './cauthy-mNADGlNl.mjs';
2
- export { C as CauthyApiError, a as CauthyConfigError, b as CauthyOptions, c as CauthySystem, J as JsonValue, N as NewMember, O as Organization, d as OrganizationMember, P as PublicSession, S as Session, e as SessionOrganization, f as SessionStatus, g as SessionUser, h as SystemKey, i as SystemOptions, j as createSystem } from './system-BWLddIt2.mjs';
3
- export { CauthyTheme, ImportedTheme, PushThemeOptions, StackmythThemeOptions, pushTheme, themeFromStackmyth } from './theme.mjs';
1
+ export { C as Cauthy, a as CauthyEvent, b as CauthyWebhookError, R as Resolved, V as VerifyWebhookOptions, c as createCauthy, v as verifyWebhook } from './cauthy-Dg-DNIo9.mjs';
2
+ export { C as CauthyApiError, a as CauthyConfigError, b as CauthyOptions, c as CauthySystem, J as JsonValue, N as NewMember, O as Organization, d as OrganizationMember, P as PublicSession, S as Session, e as SessionOrganization, f as SessionStatus, g as SessionUser, h as SystemKey, i as SystemOptions, j as createSystem } from './system-CdvktS7x.mjs';
3
+ export { CauthyTheme, ImportedTheme, PushThemeOptions, StackmythThemeOptions, ThemeFont, pushTheme, themeFromStackmyth } from './theme.mjs';
4
4
  export { P as Permitted, a as PolicyPermission, b as PolicyRole, c as PushPolicyOptions, d as can, p as pushPolicy } from './permissions-B-a3eN0h.mjs';
5
5
  import 'jose';
6
6
 
package/dist/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
- export { C as Cauthy, a as CauthyEvent, b as CauthyWebhookError, R as Resolved, V as VerifyWebhookOptions, c as createCauthy, v as verifyWebhook } from './cauthy-C5_lopMQ.js';
2
- export { C as CauthyApiError, a as CauthyConfigError, b as CauthyOptions, c as CauthySystem, J as JsonValue, N as NewMember, O as Organization, d as OrganizationMember, P as PublicSession, S as Session, e as SessionOrganization, f as SessionStatus, g as SessionUser, h as SystemKey, i as SystemOptions, j as createSystem } from './system-BWLddIt2.js';
3
- export { CauthyTheme, ImportedTheme, PushThemeOptions, StackmythThemeOptions, pushTheme, themeFromStackmyth } from './theme.js';
1
+ export { C as Cauthy, a as CauthyEvent, b as CauthyWebhookError, R as Resolved, V as VerifyWebhookOptions, c as createCauthy, v as verifyWebhook } from './cauthy--iqtLWNa.js';
2
+ export { C as CauthyApiError, a as CauthyConfigError, b as CauthyOptions, c as CauthySystem, J as JsonValue, N as NewMember, O as Organization, d as OrganizationMember, P as PublicSession, S as Session, e as SessionOrganization, f as SessionStatus, g as SessionUser, h as SystemKey, i as SystemOptions, j as createSystem } from './system-CL3Q30FT.js';
3
+ export { CauthyTheme, ImportedTheme, PushThemeOptions, StackmythThemeOptions, ThemeFont, pushTheme, themeFromStackmyth } from './theme.js';
4
4
  export { P as Permitted, a as PolicyPermission, b as PolicyRole, c as PushPolicyOptions, d as can, p as pushPolicy } from './permissions-B-a3eN0h.js';
5
5
  import 'jose';
6
6
 
package/dist/index.js CHANGED
@@ -93,6 +93,254 @@ async function unseal(sealed, key) {
93
93
  // src/system.ts
94
94
  var import_jose2 = require("jose");
95
95
 
96
+ // src/theme.ts
97
+ var MAX_RADIUS = 40;
98
+ function declarations(css) {
99
+ const text = css.replace(/\/\*[\s\S]*?\*\//g, "");
100
+ const out2 = [];
101
+ const within = [];
102
+ let chunk = "";
103
+ let quote = "";
104
+ let depth = 0;
105
+ const flush = () => {
106
+ const m = /^\s*(--[\w-]+)\s*:\s*([\s\S]+?)\s*$/.exec(chunk);
107
+ if (m) out2.push({ name: m[1], value: m[2].replace(/\s+/g, " ").replace(/\s*!important$/, ""), within: [...within] });
108
+ chunk = "";
109
+ };
110
+ for (const ch of text) {
111
+ if (quote) {
112
+ chunk += ch;
113
+ if (ch === quote) quote = "";
114
+ continue;
115
+ }
116
+ if (ch === '"' || ch === "'") {
117
+ quote = ch;
118
+ chunk += ch;
119
+ } else if (ch === "(") {
120
+ depth++;
121
+ chunk += ch;
122
+ } else if (ch === ")") {
123
+ depth = Math.max(0, depth - 1);
124
+ chunk += ch;
125
+ } else if (ch === "{" && depth === 0) {
126
+ within.push(chunk.trim().replace(/\s+/g, " "));
127
+ chunk = "";
128
+ } else if (ch === "}" && depth === 0) {
129
+ flush();
130
+ within.pop();
131
+ } else if (ch === ";" && depth === 0) {
132
+ flush();
133
+ } else {
134
+ chunk += ch;
135
+ }
136
+ }
137
+ return out2;
138
+ }
139
+ var DARK = /prefers-color-scheme:\s*dark|data-(mode|theme|color-scheme)=["']?dark|\.dark\b/i;
140
+ var LIGHT = /prefers-color-scheme:\s*light|data-(mode|theme|color-scheme)=["']?light|\.light\b/i;
141
+ var NAMED = /data-theme=["']?([\w-]+)/i;
142
+ function applies(d, o) {
143
+ for (const scope of d.within) {
144
+ if (o.mode === "light" && DARK.test(scope)) return false;
145
+ if (o.mode === "dark" && LIGHT.test(scope)) return false;
146
+ const named = NAMED.exec(scope);
147
+ if (named && !/^(dark|light)$/i.test(named[1]) && named[1] !== o.theme) return false;
148
+ if (!scope.startsWith("@") && !/:root|^html\b|^body\b|\[data-|^\*$|:host/.test(scope)) return false;
149
+ }
150
+ return true;
151
+ }
152
+ function resolve(value, vars, seen = 0) {
153
+ if (seen > 16) return null;
154
+ let unresolved = false;
155
+ let out2 = value;
156
+ for (let guard = 0; guard < 32 && /var\(/.test(out2); guard++) {
157
+ out2 = out2.replace(/var\(\s*(--[\w-]+)\s*(?:,\s*([^()]*(?:\([^()]*\)[^()]*)*))?\)/, (_m, name, fallback) => {
158
+ const known = vars.get(name);
159
+ const next = known !== void 0 ? resolve(known, vars, seen + 1) : fallback !== void 0 ? resolve(fallback.trim(), vars, seen + 1) : null;
160
+ if (next === null) unresolved = true;
161
+ return next ?? "";
162
+ });
163
+ if (unresolved) return null;
164
+ }
165
+ return /var\(/.test(out2) ? null : out2.trim();
166
+ }
167
+ var clamp01 = (n) => Math.min(1, Math.max(0, n));
168
+ var hex2 = (n) => Math.round(clamp01(n) * 255).toString(16).padStart(2, "0");
169
+ var gamma = (c) => c <= 31308e-7 ? 12.92 * c : 1.055 * Math.pow(c, 1 / 2.4) - 0.055;
170
+ function out(r, g, b, a = 1) {
171
+ if (a >= 1) return `#${hex2(r)}${hex2(g)}${hex2(b)}`;
172
+ return `rgba(${Math.round(clamp01(r) * 255)}, ${Math.round(clamp01(g) * 255)}, ${Math.round(clamp01(b) * 255)}, ${Math.round(clamp01(a) * 1e3) / 1e3})`;
173
+ }
174
+ var alpha = (s) => s === void 0 ? 1 : s.endsWith("%") ? parseFloat(s) / 100 : parseFloat(s);
175
+ var KEYWORDS = { white: "#ffffff", black: "#000000" };
176
+ function toColor(value) {
177
+ const v = value.trim().toLowerCase();
178
+ if (KEYWORDS[v]) return KEYWORDS[v];
179
+ if (/^#([0-9a-f]{3,4}|[0-9a-f]{6}|[0-9a-f]{8})$/.test(v)) return v;
180
+ let m = /^rgba?\(\s*([\d.]+%?)[\s,]+([\d.]+%?)[\s,]+([\d.]+%?)(?:\s*[,/]\s*([\d.]+%?))?\s*\)$/.exec(v);
181
+ if (m) {
182
+ const ch = (s) => s.endsWith("%") ? parseFloat(s) / 100 : parseFloat(s) / 255;
183
+ return out(ch(m[1]), ch(m[2]), ch(m[3]), alpha(m[4]));
184
+ }
185
+ m = /^hsla?\(\s*([\d.]+)(?:deg)?[\s,]+([\d.]+)%[\s,]+([\d.]+)%(?:\s*[,/]\s*([\d.]+%?))?\s*\)$/.exec(v);
186
+ if (m) {
187
+ const h = (parseFloat(m[1]) % 360 + 360) % 360;
188
+ const s = parseFloat(m[2]) / 100;
189
+ const l = parseFloat(m[3]) / 100;
190
+ const f = (n) => {
191
+ const k = (n + h / 30) % 12;
192
+ return l - s * Math.min(l, 1 - l) * Math.max(-1, Math.min(k - 3, 9 - k, 1));
193
+ };
194
+ return out(f(0), f(8), f(4), alpha(m[4]));
195
+ }
196
+ m = /^oklch\(\s*([\d.]+%?)\s+([\d.]+%?)\s+([\d.]+)(?:deg)?(?:\s*\/\s*([\d.]+%?))?\s*\)$/.exec(v);
197
+ if (m) {
198
+ const L = m[1].endsWith("%") ? parseFloat(m[1]) / 100 : parseFloat(m[1]);
199
+ const C = m[2].endsWith("%") ? parseFloat(m[2]) / 100 * 0.4 : parseFloat(m[2]);
200
+ const H = parseFloat(m[3]) * Math.PI / 180;
201
+ const a = C * Math.cos(H);
202
+ const b = C * Math.sin(H);
203
+ const l = Math.pow(L + 0.3963377774 * a + 0.2158037573 * b, 3);
204
+ const mm = Math.pow(L - 0.1055613458 * a - 0.0638541728 * b, 3);
205
+ const s = Math.pow(L - 0.0894841775 * a - 1.291485548 * b, 3);
206
+ return out(
207
+ gamma(4.0767416621 * l - 3.3077115913 * mm + 0.2309699292 * s),
208
+ gamma(-1.2684380046 * l + 2.6097574011 * mm - 0.3413193965 * s),
209
+ gamma(-0.0041960863 * l - 0.7034186147 * mm + 1.707614701 * s),
210
+ alpha(m[4])
211
+ );
212
+ }
213
+ return null;
214
+ }
215
+ function toRadius(value) {
216
+ const m = /^([\d.]+)(px|rem|em)?$/.exec(value.trim());
217
+ if (!m) return null;
218
+ const px = parseFloat(m[1]) * (m[2] === "rem" || m[2] === "em" ? 16 : 1);
219
+ return Number.isFinite(px) ? Math.min(MAX_RADIUS, Math.max(0, Math.round(px))) : null;
220
+ }
221
+ function toFont(value) {
222
+ const v = value.trim();
223
+ 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;
224
+ }
225
+ var COLORS = [
226
+ ["background", ["--sm-bg-surface", "--sm-surface"]],
227
+ ["surface", ["--sm-bg-surface-raised", "--sm-surface-raised"]],
228
+ ["text", ["--sm-text-primary", "--sm-surface-text"]],
229
+ ["textMuted", ["--sm-text-secondary"]],
230
+ ["border", ["--sm-border-default", "--sm-surface-border"]],
231
+ ["primary", ["--sm-primary", "--sm-bg-interactive"]],
232
+ ["primaryText", ["--sm-primary-text", "--sm-text-inverse"]],
233
+ ["accent", ["--sm-text-brand", "--sm-border-focus", "--sm-accent"]],
234
+ ["error", ["--sm-error-soft-text", "--sm-error"]],
235
+ ["errorBackground", ["--sm-error-soft"]],
236
+ ["success", ["--sm-success-soft-text", "--sm-success"]],
237
+ ["successBackground", ["--sm-success-soft"]]
238
+ ];
239
+ function themeFromStackmyth(css, options = {}) {
240
+ const o = { mode: options.mode ?? "light", theme: options.theme };
241
+ const vars = /* @__PURE__ */ new Map();
242
+ for (const sheet of Array.isArray(css) ? css : [css]) {
243
+ for (const d of declarations(sheet)) if (applies(d, o)) vars.set(d.name, d.value);
244
+ }
245
+ const theme = {};
246
+ const warnings = [];
247
+ const read = (tokens, to, what) => {
248
+ for (const token of tokens) {
249
+ const raw = vars.get(token);
250
+ if (raw === void 0) continue;
251
+ const value = resolve(raw, vars);
252
+ const got = value === null ? null : to(value);
253
+ if (got !== null) return got;
254
+ warnings.push(`${token}: "${raw}" is not ${what} Cauthy can take`);
255
+ }
256
+ return void 0;
257
+ };
258
+ for (const [field, tokens] of COLORS) {
259
+ const c = read(tokens, toColor, "a colour");
260
+ if (c !== void 0) theme[field] = c;
261
+ }
262
+ const radius = read(["--sm-radius-container", "--sm-radius-md"], toRadius, "a length");
263
+ if (radius !== void 0) theme.radius = radius;
264
+ const button = read(["--sm-radius-interactive", "--sm-radius-sm"], toRadius, "a length");
265
+ if (button !== void 0) theme.buttonRadius = button;
266
+ const font = read(["--sm-font-family"], toFont, "a font list");
267
+ if (font !== void 0) theme.fontFamily = font;
268
+ if (options.logoUrl) theme.logoUrl = options.logoUrl;
269
+ if (vars.size === 0) warnings.push("no custom properties were found: is this the stylesheet that declares the --sm-* tokens?");
270
+ else if (![...vars.keys()].some((k) => k.startsWith("--sm-"))) warnings.push("no --sm-* token was found in these stylesheets");
271
+ return { theme, warnings };
272
+ }
273
+ function toWire(theme) {
274
+ const names = {
275
+ background: "background",
276
+ surface: "surface",
277
+ text: "text",
278
+ textMuted: "text_muted",
279
+ border: "border",
280
+ primary: "primary",
281
+ primaryText: "primary_text",
282
+ accent: "accent",
283
+ error: "error",
284
+ errorBackground: "error_background",
285
+ success: "success",
286
+ successBackground: "success_background",
287
+ radius: "radius",
288
+ buttonRadius: "button_radius",
289
+ fontFamily: "font_family",
290
+ logoUrl: "logo_url",
291
+ fonts: "fonts"
292
+ };
293
+ const wire = {};
294
+ for (const [k, v] of Object.entries(theme)) {
295
+ if (v === void 0 || v === "" || Array.isArray(v) && v.length === 0) continue;
296
+ wire[names[k]] = v;
297
+ }
298
+ return wire;
299
+ }
300
+ function fromWire(wire) {
301
+ const names = {
302
+ background: "background",
303
+ surface: "surface",
304
+ text: "text",
305
+ text_muted: "textMuted",
306
+ border: "border",
307
+ primary: "primary",
308
+ primary_text: "primaryText",
309
+ accent: "accent",
310
+ error: "error",
311
+ error_background: "errorBackground",
312
+ success: "success",
313
+ success_background: "successBackground",
314
+ radius: "radius",
315
+ button_radius: "buttonRadius",
316
+ font_family: "fontFamily",
317
+ logo_url: "logoUrl",
318
+ fonts: "fonts"
319
+ };
320
+ const theme = {};
321
+ for (const [k, v] of Object.entries(wire ?? {})) if (names[k] && v !== void 0 && v !== null && v !== "") theme[names[k]] = v;
322
+ return theme;
323
+ }
324
+ async function pushTheme(o) {
325
+ const env3 = (n) => typeof process !== "undefined" ? process.env?.[n] : void 0;
326
+ const issuer = (o.issuer ?? env3("CAUTHY_ISSUER") ?? "").replace(/\/+$/, "");
327
+ const clientId = o.clientId ?? env3("CAUTHY_CLIENT_ID") ?? "";
328
+ const tenant = o.tenant ?? env3("CAUTHY_TENANT") ?? "";
329
+ const token = o.token ?? env3("CAUTHY_TOKEN") ?? "";
330
+ for (const [name, v] of Object.entries({ CAUTHY_ISSUER: issuer, CAUTHY_CLIENT_ID: clientId, CAUTHY_TENANT: tenant, CAUTHY_TOKEN: token })) {
331
+ if (v === "") throw new Error(`cauthy-auth: ${name} is required to push a theme`);
332
+ }
333
+ const res = await (o.fetch ?? fetch)(`${issuer}/v1/oauth/clients/${encodeURIComponent(clientId)}/theme`, {
334
+ method: "PUT",
335
+ headers: { authorization: `Bearer ${token}`, "x-tenant-key": tenant, "content-type": "application/json" },
336
+ body: JSON.stringify(toWire(o.theme))
337
+ });
338
+ if (!res.ok) {
339
+ const body = await res.json().catch(() => null);
340
+ throw new Error(`cauthy-auth: Cauthy refused the theme (${res.status}): ${body?.errors?.[0]?.message ?? res.statusText}`);
341
+ }
342
+ }
343
+
96
344
  // src/types.ts
97
345
  var CauthyConfigError = class extends Error {
98
346
  constructor(message) {
@@ -253,6 +501,15 @@ function createSystem(given = {}) {
253
501
  const u = await data("POST", "/v1/users", { ...person, client_id: clientId });
254
502
  return { id: u.id, email: u.email };
255
503
  },
504
+ theme: {
505
+ async get(of = clientId) {
506
+ return fromWire(await data("GET", `/v1/oauth/clients/${id(of)}/theme`));
507
+ },
508
+ async set(theme, of = clientId) {
509
+ if (theme === null) await call("DELETE", `/v1/oauth/clients/${id(of)}/theme`);
510
+ else await call("PUT", `/v1/oauth/clients/${id(of)}/theme`, toWire(theme));
511
+ }
512
+ },
256
513
  async publicJwks() {
257
514
  if (!key) return { keys: [] };
258
515
  const { kty, n, e } = asJwk(key) ?? await (0, import_jose2.exportJWK)(await signingKey());
@@ -649,226 +906,6 @@ function createCauthy(given = {}) {
649
906
  };
650
907
  }
651
908
 
652
- // src/theme.ts
653
- var MAX_RADIUS = 40;
654
- function declarations(css) {
655
- const text = css.replace(/\/\*[\s\S]*?\*\//g, "");
656
- const out2 = [];
657
- const within = [];
658
- let chunk = "";
659
- let quote = "";
660
- let depth = 0;
661
- const flush = () => {
662
- const m = /^\s*(--[\w-]+)\s*:\s*([\s\S]+?)\s*$/.exec(chunk);
663
- if (m) out2.push({ name: m[1], value: m[2].replace(/\s+/g, " ").replace(/\s*!important$/, ""), within: [...within] });
664
- chunk = "";
665
- };
666
- for (const ch of text) {
667
- if (quote) {
668
- chunk += ch;
669
- if (ch === quote) quote = "";
670
- continue;
671
- }
672
- if (ch === '"' || ch === "'") {
673
- quote = ch;
674
- chunk += ch;
675
- } else if (ch === "(") {
676
- depth++;
677
- chunk += ch;
678
- } else if (ch === ")") {
679
- depth = Math.max(0, depth - 1);
680
- chunk += ch;
681
- } else if (ch === "{" && depth === 0) {
682
- within.push(chunk.trim().replace(/\s+/g, " "));
683
- chunk = "";
684
- } else if (ch === "}" && depth === 0) {
685
- flush();
686
- within.pop();
687
- } else if (ch === ";" && depth === 0) {
688
- flush();
689
- } else {
690
- chunk += ch;
691
- }
692
- }
693
- return out2;
694
- }
695
- var DARK = /prefers-color-scheme:\s*dark|data-(mode|theme|color-scheme)=["']?dark|\.dark\b/i;
696
- var LIGHT = /prefers-color-scheme:\s*light|data-(mode|theme|color-scheme)=["']?light|\.light\b/i;
697
- var NAMED = /data-theme=["']?([\w-]+)/i;
698
- function applies(d, o) {
699
- for (const scope of d.within) {
700
- if (o.mode === "light" && DARK.test(scope)) return false;
701
- if (o.mode === "dark" && LIGHT.test(scope)) return false;
702
- const named = NAMED.exec(scope);
703
- if (named && !/^(dark|light)$/i.test(named[1]) && named[1] !== o.theme) return false;
704
- if (!scope.startsWith("@") && !/:root|^html\b|^body\b|\[data-|^\*$|:host/.test(scope)) return false;
705
- }
706
- return true;
707
- }
708
- function resolve(value, vars, seen = 0) {
709
- if (seen > 16) return null;
710
- let unresolved = false;
711
- let out2 = value;
712
- for (let guard = 0; guard < 32 && /var\(/.test(out2); guard++) {
713
- out2 = out2.replace(/var\(\s*(--[\w-]+)\s*(?:,\s*([^()]*(?:\([^()]*\)[^()]*)*))?\)/, (_m, name, fallback) => {
714
- const known = vars.get(name);
715
- const next = known !== void 0 ? resolve(known, vars, seen + 1) : fallback !== void 0 ? resolve(fallback.trim(), vars, seen + 1) : null;
716
- if (next === null) unresolved = true;
717
- return next ?? "";
718
- });
719
- if (unresolved) return null;
720
- }
721
- return /var\(/.test(out2) ? null : out2.trim();
722
- }
723
- var clamp01 = (n) => Math.min(1, Math.max(0, n));
724
- var hex2 = (n) => Math.round(clamp01(n) * 255).toString(16).padStart(2, "0");
725
- var gamma = (c) => c <= 31308e-7 ? 12.92 * c : 1.055 * Math.pow(c, 1 / 2.4) - 0.055;
726
- function out(r, g, b, a = 1) {
727
- if (a >= 1) return `#${hex2(r)}${hex2(g)}${hex2(b)}`;
728
- return `rgba(${Math.round(clamp01(r) * 255)}, ${Math.round(clamp01(g) * 255)}, ${Math.round(clamp01(b) * 255)}, ${Math.round(clamp01(a) * 1e3) / 1e3})`;
729
- }
730
- var alpha = (s) => s === void 0 ? 1 : s.endsWith("%") ? parseFloat(s) / 100 : parseFloat(s);
731
- var KEYWORDS = { white: "#ffffff", black: "#000000" };
732
- function toColor(value) {
733
- const v = value.trim().toLowerCase();
734
- if (KEYWORDS[v]) return KEYWORDS[v];
735
- if (/^#([0-9a-f]{3,4}|[0-9a-f]{6}|[0-9a-f]{8})$/.test(v)) return v;
736
- let m = /^rgba?\(\s*([\d.]+%?)[\s,]+([\d.]+%?)[\s,]+([\d.]+%?)(?:\s*[,/]\s*([\d.]+%?))?\s*\)$/.exec(v);
737
- if (m) {
738
- const ch = (s) => s.endsWith("%") ? parseFloat(s) / 100 : parseFloat(s) / 255;
739
- return out(ch(m[1]), ch(m[2]), ch(m[3]), alpha(m[4]));
740
- }
741
- m = /^hsla?\(\s*([\d.]+)(?:deg)?[\s,]+([\d.]+)%[\s,]+([\d.]+)%(?:\s*[,/]\s*([\d.]+%?))?\s*\)$/.exec(v);
742
- if (m) {
743
- const h = (parseFloat(m[1]) % 360 + 360) % 360;
744
- const s = parseFloat(m[2]) / 100;
745
- const l = parseFloat(m[3]) / 100;
746
- const f = (n) => {
747
- const k = (n + h / 30) % 12;
748
- return l - s * Math.min(l, 1 - l) * Math.max(-1, Math.min(k - 3, 9 - k, 1));
749
- };
750
- return out(f(0), f(8), f(4), alpha(m[4]));
751
- }
752
- m = /^oklch\(\s*([\d.]+%?)\s+([\d.]+%?)\s+([\d.]+)(?:deg)?(?:\s*\/\s*([\d.]+%?))?\s*\)$/.exec(v);
753
- if (m) {
754
- const L = m[1].endsWith("%") ? parseFloat(m[1]) / 100 : parseFloat(m[1]);
755
- const C = m[2].endsWith("%") ? parseFloat(m[2]) / 100 * 0.4 : parseFloat(m[2]);
756
- const H = parseFloat(m[3]) * Math.PI / 180;
757
- const a = C * Math.cos(H);
758
- const b = C * Math.sin(H);
759
- const l = Math.pow(L + 0.3963377774 * a + 0.2158037573 * b, 3);
760
- const mm = Math.pow(L - 0.1055613458 * a - 0.0638541728 * b, 3);
761
- const s = Math.pow(L - 0.0894841775 * a - 1.291485548 * b, 3);
762
- return out(
763
- gamma(4.0767416621 * l - 3.3077115913 * mm + 0.2309699292 * s),
764
- gamma(-1.2684380046 * l + 2.6097574011 * mm - 0.3413193965 * s),
765
- gamma(-0.0041960863 * l - 0.7034186147 * mm + 1.707614701 * s),
766
- alpha(m[4])
767
- );
768
- }
769
- return null;
770
- }
771
- function toRadius(value) {
772
- const m = /^([\d.]+)(px|rem|em)?$/.exec(value.trim());
773
- if (!m) return null;
774
- const px = parseFloat(m[1]) * (m[2] === "rem" || m[2] === "em" ? 16 : 1);
775
- return Number.isFinite(px) ? Math.min(MAX_RADIUS, Math.max(0, Math.round(px))) : null;
776
- }
777
- function toFont(value) {
778
- const v = value.trim();
779
- 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;
780
- }
781
- var COLORS = [
782
- ["background", ["--sm-bg-surface", "--sm-surface"]],
783
- ["surface", ["--sm-bg-surface-raised", "--sm-surface-raised"]],
784
- ["text", ["--sm-text-primary", "--sm-surface-text"]],
785
- ["textMuted", ["--sm-text-secondary"]],
786
- ["border", ["--sm-border-default", "--sm-surface-border"]],
787
- ["primary", ["--sm-primary", "--sm-bg-interactive"]],
788
- ["primaryText", ["--sm-primary-text", "--sm-text-inverse"]],
789
- ["accent", ["--sm-text-brand", "--sm-border-focus", "--sm-accent"]],
790
- ["error", ["--sm-error-soft-text", "--sm-error"]],
791
- ["errorBackground", ["--sm-error-soft"]],
792
- ["success", ["--sm-success-soft-text", "--sm-success"]],
793
- ["successBackground", ["--sm-success-soft"]]
794
- ];
795
- function themeFromStackmyth(css, options = {}) {
796
- const o = { mode: options.mode ?? "light", theme: options.theme };
797
- const vars = /* @__PURE__ */ new Map();
798
- for (const sheet of Array.isArray(css) ? css : [css]) {
799
- for (const d of declarations(sheet)) if (applies(d, o)) vars.set(d.name, d.value);
800
- }
801
- const theme = {};
802
- const warnings = [];
803
- const read = (tokens, to, what) => {
804
- for (const token of tokens) {
805
- const raw = vars.get(token);
806
- if (raw === void 0) continue;
807
- const value = resolve(raw, vars);
808
- const got = value === null ? null : to(value);
809
- if (got !== null) return got;
810
- warnings.push(`${token}: "${raw}" is not ${what} Cauthy can take`);
811
- }
812
- return void 0;
813
- };
814
- for (const [field, tokens] of COLORS) {
815
- const c = read(tokens, toColor, "a colour");
816
- if (c !== void 0) theme[field] = c;
817
- }
818
- const radius = read(["--sm-radius-container", "--sm-radius-md"], toRadius, "a length");
819
- if (radius !== void 0) theme.radius = radius;
820
- const button = read(["--sm-radius-interactive", "--sm-radius-sm"], toRadius, "a length");
821
- if (button !== void 0) theme.buttonRadius = button;
822
- const font = read(["--sm-font-family"], toFont, "a font list");
823
- if (font !== void 0) theme.fontFamily = font;
824
- if (options.logoUrl) theme.logoUrl = options.logoUrl;
825
- if (vars.size === 0) warnings.push("no custom properties were found: is this the stylesheet that declares the --sm-* tokens?");
826
- else if (![...vars.keys()].some((k) => k.startsWith("--sm-"))) warnings.push("no --sm-* token was found in these stylesheets");
827
- return { theme, warnings };
828
- }
829
- function toWire(theme) {
830
- const names = {
831
- background: "background",
832
- surface: "surface",
833
- text: "text",
834
- textMuted: "text_muted",
835
- border: "border",
836
- primary: "primary",
837
- primaryText: "primary_text",
838
- accent: "accent",
839
- error: "error",
840
- errorBackground: "error_background",
841
- success: "success",
842
- successBackground: "success_background",
843
- radius: "radius",
844
- buttonRadius: "button_radius",
845
- fontFamily: "font_family",
846
- logoUrl: "logo_url"
847
- };
848
- const wire = {};
849
- for (const [k, v] of Object.entries(theme)) if (v !== void 0 && v !== "") wire[names[k]] = v;
850
- return wire;
851
- }
852
- async function pushTheme(o) {
853
- const env3 = (n) => typeof process !== "undefined" ? process.env?.[n] : void 0;
854
- const issuer = (o.issuer ?? env3("CAUTHY_ISSUER") ?? "").replace(/\/+$/, "");
855
- const clientId = o.clientId ?? env3("CAUTHY_CLIENT_ID") ?? "";
856
- const tenant = o.tenant ?? env3("CAUTHY_TENANT") ?? "";
857
- const token = o.token ?? env3("CAUTHY_TOKEN") ?? "";
858
- for (const [name, v] of Object.entries({ CAUTHY_ISSUER: issuer, CAUTHY_CLIENT_ID: clientId, CAUTHY_TENANT: tenant, CAUTHY_TOKEN: token })) {
859
- if (v === "") throw new Error(`cauthy-auth: ${name} is required to push a theme`);
860
- }
861
- const res = await (o.fetch ?? fetch)(`${issuer}/v1/oauth/clients/${encodeURIComponent(clientId)}/theme`, {
862
- method: "PUT",
863
- headers: { authorization: `Bearer ${token}`, "x-tenant-key": tenant, "content-type": "application/json" },
864
- body: JSON.stringify(toWire(o.theme))
865
- });
866
- if (!res.ok) {
867
- const body = await res.json().catch(() => null);
868
- throw new Error(`cauthy-auth: Cauthy refused the theme (${res.status}): ${body?.errors?.[0]?.message ?? res.statusText}`);
869
- }
870
- }
871
-
872
909
  // src/permissions.ts
873
910
  function matches(entry, resource, action) {
874
911
  const i = entry.lastIndexOf(":");