@voltro/cli 0.50.0 → 0.51.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (111) hide show
  1. package/CHANGELOG.md +160 -0
  2. package/dist/{apiBuild-CFYXo06U.js → apiBuild-CPDHXF72.js} +2 -2
  3. package/dist/apiBuild-GDKuGOMV.js +2 -0
  4. package/dist/appGraph-CFmFKHb2.js +2 -0
  5. package/dist/appGraph-yRuKjOba.js +111 -0
  6. package/dist/bin.js +1 -1
  7. package/dist/{build-CnSH-zru.js → build-DETLZAFt.js} +271 -240
  8. package/dist/{checkCommand-OL41BMIb.js → checkCommand-CWcnDArJ.js} +1 -1
  9. package/dist/{checkCommand-Do3SQbLx.js → checkCommand-DNuPiWMc.js} +56 -46
  10. package/dist/{codegenCommand-BJzaRz6q.js → codegenCommand-BNBHcNNj.js} +2 -2
  11. package/dist/{codemodRunner-De3k0pRd.js → codemodRunner-BDVixlSw.js} +278 -136
  12. package/dist/{commands-By23Ljny.js → commands-B1OiS9bX.js} +24 -23
  13. package/dist/{dashboardCommand-DN1rAABE.js → dashboardCommand-C-vvPY1B.js} +5 -5
  14. package/dist/{dataCommand-B93TUBIx.js → dataCommand-C1GxXW5q.js} +458 -384
  15. package/dist/dbCommand-C27HIsGE.js +2 -0
  16. package/dist/{dbCommand-Bf7Cy0mn.js → dbCommand-If4Y1xQ-.js} +1 -1
  17. package/dist/{dev-BWwE0QjK.js → dev-CK522MV5.js} +1 -1
  18. package/dist/{dev-1yu42ubu.js → dev-kdAg9Q7l.js} +1246 -1246
  19. package/dist/doctorCommand-BK4l18eG.js +2 -0
  20. package/dist/{doctorCommand-y-EbP8st.js → doctorCommand-nKmeW78u.js} +42 -26
  21. package/dist/{doctorSourceRelations-Dd48LPvO.js → doctorSourceRelations-c5mlN5HI.js} +66 -34
  22. package/dist/{dormancyCommand-Dc7KRNCG.js → dormancyCommand-CY3wa_SW.js} +1 -1
  23. package/dist/{embeddingsCommand-kPs132bB.js → embeddingsCommand-BDLIgje_.js} +1 -1
  24. package/dist/{envCommand-E12zSt51.js → envCommand-C6V_xVlT.js} +13 -13
  25. package/dist/{evolveCommand-B3nagPVc.js → evolveCommand-D3c4DSfN.js} +2 -2
  26. package/dist/{generateCommand-CcyvH2ve.js → generateCommand-DTNPGjxo.js} +1 -1
  27. package/dist/index.js +1 -1
  28. package/dist/{infoCommand-Cq0Yz98u.js → infoCommand-BnRFEF1o.js} +1 -1
  29. package/dist/{inspect-B7U7Cl_Z.js → inspect-CtL_xTbu.js} +1 -0
  30. package/dist/inspect-CuGDYES0.js +2 -0
  31. package/dist/manifestBuild-CPjhvM62.js +2 -0
  32. package/dist/{manifestBuild-BK42hu0k.js → manifestBuild-CuU1VrSm.js} +2 -2
  33. package/dist/{migrate-D3MK9BpK.js → migrate-DehuBakM.js} +1 -1
  34. package/dist/{runtimeTrace-BpLUcrfy.js → runtimeTrace-ZsBU7Tkx.js} +1 -1
  35. package/dist/{sdkgen-dl4-WKF6.js → sdkgen-O4XqWOjM.js} +1 -1
  36. package/dist/serveCommand-BRnPCxVd.js +2 -0
  37. package/dist/{serveCommand-8CTzQCY0.js → serveCommand-DdiYNBBu.js} +4 -4
  38. package/dist/serveEntry.js +1 -1
  39. package/dist/{start-7HcSIKEp.js → start-BLNmWkLa.js} +331 -327
  40. package/dist/{start-DvlYDyAr.js → start-Dzicuyw8.js} +1 -1
  41. package/dist/startEntry.js +1 -1
  42. package/dist/{updateCommand-i8JbrLAA.js → updateCommand-Bs322Q78.js} +1 -1
  43. package/dist/updateCommand-eXB35SEv.js +2 -0
  44. package/dist/{webDev-B4IEMB0n.js → webDev-B-ubQEMX.js} +283 -224
  45. package/dist/webDev-DposiF3j.js +2 -0
  46. package/dist/{webhooksCommand-B0bdyuQ4.js → webhooksCommand-FLYY9IXh.js} +1 -1
  47. package/package.json +41 -17
  48. package/templates/AGENTS.core.md +15 -5
  49. package/templates/AGENTS.md +16 -6
  50. package/templates/agent-docs/_index.md +1 -1
  51. package/templates/agent-docs/cli.md +92 -3
  52. package/templates/agent-docs/data.md +36 -0
  53. package/templates/agent-docs/internationalization.md +131 -13
  54. package/templates/agent-docs/whats-new.md +73 -27
  55. package/templates/apps/api-ai/package.json +7 -7
  56. package/templates/apps/api-auth/package.json +8 -8
  57. package/templates/apps/api-backend/package.json +7 -7
  58. package/templates/apps/api-backend-deactivation/package.json +7 -7
  59. package/templates/apps/api-backend-mail/package.json +8 -8
  60. package/templates/apps/api-backend-mariadb/package.json +9 -9
  61. package/templates/apps/api-backend-sqlite/package.json +8 -8
  62. package/templates/apps/api-backend-storage/package.json +8 -8
  63. package/templates/apps/api-cms/package.json +10 -10
  64. package/templates/apps/api-collab/package.json +8 -8
  65. package/templates/apps/api-data-advanced/package.json +8 -8
  66. package/templates/apps/api-durable/package.json +8 -8
  67. package/templates/apps/api-feature-flags/package.json +9 -9
  68. package/templates/apps/api-governance/package.json +8 -8
  69. package/templates/apps/api-kv/package.json +8 -8
  70. package/templates/apps/api-moderation/package.json +8 -8
  71. package/templates/apps/api-observability/package.json +8 -8
  72. package/templates/apps/api-ratelimit/package.json +8 -8
  73. package/templates/apps/api-rbac/package.json +8 -8
  74. package/templates/apps/api-rest/package.json +7 -7
  75. package/templates/apps/api-saas/package.json +11 -11
  76. package/templates/apps/api-saas-starter/package.json +10 -10
  77. package/templates/apps/api-search/package.json +8 -8
  78. package/templates/apps/api-status/package.json +8 -8
  79. package/templates/apps/api-versioning/package.json +8 -8
  80. package/templates/apps/api-webhooks/package.json +9 -9
  81. package/templates/apps/changelog/package.json +6 -6
  82. package/templates/apps/edge-functions/package.json +2 -2
  83. package/templates/apps/frontend-admin/package.json +8 -8
  84. package/templates/apps/frontend-app/package.json +9 -9
  85. package/templates/apps/frontend-auth/package.json +8 -8
  86. package/templates/apps/frontend-blank/package.json +7 -7
  87. package/templates/apps/frontend-cms/package.json +9 -9
  88. package/templates/apps/frontend-collab/package.json +10 -10
  89. package/templates/apps/frontend-contact/package.json +7 -7
  90. package/templates/apps/frontend-dashboard/package.json +7 -7
  91. package/templates/apps/frontend-docs/package.json +7 -7
  92. package/templates/apps/frontend-i18n/package.json +6 -6
  93. package/templates/apps/frontend-landing/package.json +7 -7
  94. package/templates/apps/frontend-portal/package.json +8 -8
  95. package/templates/apps/frontend-saas/package.json +8 -8
  96. package/templates/apps/frontend-spa/package.json +7 -7
  97. package/templates/apps/frontend-ssr/package.json +7 -7
  98. package/templates/apps/frontend-ssr-api/package.json +8 -8
  99. package/templates/apps/frontend-static-blog/package.json +6 -6
  100. package/templates/apps/frontend-status/package.json +8 -8
  101. package/templates/apps/mobile-app/package.json +4 -4
  102. package/dist/apiBuild-BWo8KI6n.js +0 -2
  103. package/dist/appGraph-KGDPTuTy.js +0 -110
  104. package/dist/appGraph-zuMGKVYX.js +0 -2
  105. package/dist/dbCommand-Bnl7MSGC.js +0 -2
  106. package/dist/doctorCommand-BmovAwb7.js +0 -2
  107. package/dist/inspect-DUze25t0.js +0 -2
  108. package/dist/manifestBuild-j0n109tt.js +0 -2
  109. package/dist/serveCommand-C_WI4TTG.js +0 -2
  110. package/dist/updateCommand-D91-TZ7E.js +0 -2
  111. package/dist/webDev-B79ji8M5.js +0 -2
@@ -3,7 +3,7 @@ import { n as t } from "./loadEnv-D9nEOClM.js";
3
3
  import { t as n } from "./bootRefusal-pgvDxlrU.js";
4
4
  import { r } from "./appPort-B_HpJ_ck.js";
5
5
  import { A as i, _ as a, g as o, h as s, m as c, o as l } from "./fileConventions-Cof68_BL.js";
6
- import { A as u, D as d, a as f, h as p, j as m, k as h } from "./inspect-B7U7Cl_Z.js";
6
+ import { A as u, D as d, a as f, h as p, j as m, k as h } from "./inspect-CtL_xTbu.js";
7
7
  import { n as g } from "./agentsMd-D6yD7IQv.js";
8
8
  import { c as _, p as v, t as y } from "./renderModeScan-D7J1B7Kw.js";
9
9
  import { t as b } from "./pageConvention-cEiRxdab.js";
@@ -16,7 +16,7 @@ import { addSink as R, createLogger as z, printReadyBlock as ne } from "@voltro/
16
16
  import { createRequire as B } from "node:module";
17
17
  import { currentTraceContext as V, resolveSecret as re } from "@voltro/runtime";
18
18
  import { homedir as H } from "node:os";
19
- import { FRAMEWORK_ENV_CATALOG as U, appEnvEntries as ie, checkEnvNaming as W, formatEnvErrors as ae, installEnvSnapshot as G, isEnvContract as oe, pluginEnvEntries as se, renderDotEnvExample as ce, resolveEnv as le } from "@voltro/env";
19
+ import { FRAMEWORK_ENV_CATALOG as U, appEnvEntries as ie, checkEnvNaming as ae, formatEnvErrors as oe, installEnvSnapshot as W, isEnvContract as G, pluginEnvEntries as se, renderDotEnvExample as ce, resolveEnv as le } from "@voltro/env";
20
20
  import { __installPublicEnv as ue } from "@voltro/env/public";
21
21
  import { mkdir as de, writeFile as fe } from "node:fs/promises";
22
22
  import { createHash as pe } from "node:crypto";
@@ -66,12 +66,12 @@ __installPublicEnv(publicEnvValues)
66
66
  `;
67
67
  await de(e, { recursive: !0 }), await fe(O(e, "env.public.ts"), n, "utf8");
68
68
  }, Ce = async (e) => {
69
- let t = oe(e.rawEnv) ? e.rawEnv : void 0, n = await le({
69
+ let t = G(e.rawEnv) ? e.rawEnv : void 0, n = await le({
70
70
  contract: t,
71
71
  resolveSecret: re
72
- }), r = [...n.errors, ...W(t, e.appType)];
73
- if (r.length > 0) throw Error(ae(r));
74
- G(n.values), e.appType === "web" && ue(n.publicValues);
72
+ }), r = [...n.errors, ...ae(t, e.appType)];
73
+ if (r.length > 0) throw Error(oe(r));
74
+ W(n.values), e.appType === "web" && ue(n.publicValues);
75
75
  let i = t ? Object.keys(t.vars).length : 0;
76
76
  if (i > 0) {
77
77
  let r = Object.keys(n.publicValues).length;
@@ -582,7 +582,7 @@ __installPublicEnv(publicEnvValues)
582
582
  if (!j(a)) continue;
583
583
  let s;
584
584
  try {
585
- let { pages: e } = await Jr(a);
585
+ let { pages: e } = await Xr(a);
586
586
  s = e.map((e) => ({
587
587
  pattern: e.pattern,
588
588
  params: at(e.pattern)
@@ -1442,15 +1442,18 @@ import {
1442
1442
  tail: `${Qn}${r.slice(i + 21)}`,
1443
1443
  bootstrapModules: n
1444
1444
  };
1445
- }, rr = (e, t) => (/<title>/i.test(t) ? e.replace(/[^\S\n]*<title>[\s\S]*?<\/title>\n?/i, "") : e).replace("</head>", ` ${t}\n </head>`), ir = (e) => rr(e.head, e.headInjection).replace(/<html(\s+lang="[^"]*")?/i, `<html lang="${e.htmlLang}"`), ar = (e) => {
1446
- let { res: t, shell: n, htmlLang: r, headInjection: i } = e, a = null, o = !1, s = !1, c = () => {
1445
+ }, rr = (e, t) => (/<title>/i.test(t) ? e.replace(/[^\S\n]*<title>[\s\S]*?<\/title>\n?/i, "") : e).replace("</head>", ` ${t}\n </head>`), ir = (e) => e.replace(/&/g, "&amp;").replace(/"/g, "&quot;").replace(/</g, "&lt;").replace(/>/g, "&gt;"), ar = (e, t) => {
1446
+ let n = [t.timeZone === void 0 ? "" : ` data-voltro-tz="${ir(t.timeZone)}"`, t.renderedAt === void 0 ? "" : ` data-voltro-now="${t.renderedAt}"`].join("");
1447
+ return e.replace(/<html(\s+lang="[^"]*")?/i, `<html lang="${ir(t.lang)}"${n}`);
1448
+ }, or = (e) => ar(rr(e.head, e.headInjection), e.documentAttrs), sr = (e) => {
1449
+ let { res: t, shell: n, documentAttrs: r, headInjection: i } = e, a = null, o = !1, s = !1, c = () => {
1447
1450
  if (s || !o || a === null) return;
1448
1451
  s = !0, t.statusCode = e.statusCode ?? 200;
1449
1452
  for (let [n, r] of Object.entries(e.headers ?? {})) t.setHeader(n, r);
1450
- t.flushHeaders?.(), t.write(ir({
1453
+ t.flushHeaders?.(), t.write(or({
1451
1454
  head: n.head,
1452
1455
  headInjection: i(a.meta),
1453
- htmlLang: r
1456
+ documentAttrs: r
1454
1457
  }));
1455
1458
  let c = new he();
1456
1459
  c.pipe(t, { end: !1 }), c.on("end", () => {
@@ -1477,16 +1480,16 @@ import {
1477
1480
  return;
1478
1481
  }
1479
1482
  c();
1480
- }, or = (e) => Array.isArray(e.preload) && e.preload.length > 0, sr = (e, t) => typeof e == "string" ? {
1483
+ }, cr = (e) => Array.isArray(e.preload) && e.preload.length > 0, lr = (e, t) => typeof e == "string" ? {
1481
1484
  tag: e,
1482
1485
  input: {}
1483
1486
  } : {
1484
1487
  tag: e.tag,
1485
1488
  input: e.input?.(t) ?? {}
1486
- }, cr = async (e) => {
1489
+ }, ur = async (e) => {
1487
1490
  let { pageMod: t, params: n, query: r, apiName: i, seed: a, seedFailure: o, onError: s } = e;
1488
- if (or(t) && r !== void 0 && i !== void 0) for (let e of t.preload) {
1489
- let { tag: t, input: c } = sr(e, n);
1491
+ if (cr(t) && r !== void 0 && i !== void 0) for (let e of t.preload) {
1492
+ let { tag: t, input: c } = lr(e, n);
1490
1493
  try {
1491
1494
  a(i, t, c, await r(t, c));
1492
1495
  } catch (e) {
@@ -1496,12 +1499,12 @@ import {
1496
1499
  }, e);
1497
1500
  }
1498
1501
  }
1499
- }, lr = (e) => a.test(e) || e.endsWith(".workflow.server.tsx") ? !1 : o.test(e) || l.test(e) || i.test(e), ur = /* @__PURE__ */ new Set([
1502
+ }, dr = (e) => a.test(e) || e.endsWith(".workflow.server.tsx") ? !1 : o.test(e) || l.test(e) || i.test(e), fr = /* @__PURE__ */ new Set([
1500
1503
  "node_modules",
1501
1504
  "dist",
1502
1505
  ".framework",
1503
1506
  ".git"
1504
- ]), dr = async (e) => {
1507
+ ]), pr = async (e) => {
1505
1508
  let t = [], n = async (e) => {
1506
1509
  let r;
1507
1510
  try {
@@ -1511,15 +1514,15 @@ import {
1511
1514
  }
1512
1515
  for (let i of r) if (!(i.name.startsWith(".") && i.isDirectory())) {
1513
1516
  if (i.isDirectory()) {
1514
- if (ur.has(i.name)) continue;
1517
+ if (fr.has(i.name)) continue;
1515
1518
  await n(O(e, i.name));
1516
- } else lr(i.name) && t.push(O(e, i.name));
1519
+ } else dr(i.name) && t.push(O(e, i.name));
1517
1520
  }
1518
1521
  };
1519
1522
  return await n(e), t.sort();
1520
- }, fr = async (e) => {
1523
+ }, mr = async (e) => {
1521
1524
  let t = pe("sha1");
1522
- for (let n of await dr(e)) {
1525
+ for (let n of await pr(e)) {
1523
1526
  t.update(n.slice(e.length)), t.update("\0");
1524
1527
  try {
1525
1528
  t.update(await M.readFile(n));
@@ -1530,28 +1533,28 @@ import {
1530
1533
  t.update(await M.readFile(O(e, "rpcGroup.generated.ts")));
1531
1534
  } catch {}
1532
1535
  return t.digest("hex");
1533
- }, pr = async (e) => {
1536
+ }, hr = async (e) => {
1534
1537
  if (e.length === 0) return;
1535
1538
  let t = [];
1536
- for (let n of [...e].sort()) t.push(await fr(n));
1539
+ for (let n of [...e].sort()) t.push(await mr(n));
1537
1540
  return pe("sha1").update(t.join("\0")).digest("hex");
1538
- }, mr = (e) => typeof e == "object" && !!e && e._tag === "VoltroMiddleware" && typeof e.run == "function", hr = ["middleware.ts", "middleware.tsx"], gr = (e) => {
1541
+ }, gr = (e) => typeof e == "object" && !!e && e._tag === "VoltroMiddleware" && typeof e.run == "function", _r = ["middleware.ts", "middleware.tsx"], vr = (e) => {
1539
1542
  let t = e.replace(/\/+$/, "");
1540
1543
  return t === "" ? "/" : t;
1541
1544
  }, Z = (e, t) => {
1542
- let n = gr(e);
1545
+ let n = vr(e);
1543
1546
  if (n === "/") return !0;
1544
- let r = gr(t);
1547
+ let r = vr(t);
1545
1548
  return r === n || r.startsWith(`${n}/`);
1546
- }, _r = (e) => e === void 0 ? [] : typeof e == "string" ? [e] : e, vr = (e, t) => {
1549
+ }, yr = (e) => e === void 0 ? [] : typeof e == "string" ? [e] : e, br = (e, t) => {
1547
1550
  if (e === void 0) return !0;
1548
- let n = _r(e.under), r = e.routes ?? [];
1551
+ let n = yr(e.under), r = e.routes ?? [];
1549
1552
  return n.length === 0 && r.length === 0 || r.includes(t) || n.some((e) => Z(e, t)) ? !(e.except ?? []).some((e) => e === t || Z(e, t)) : !1;
1550
- }, yr = (e) => {
1553
+ }, xr = (e) => {
1551
1554
  if (e?.assets !== !0) return [];
1552
- let t = _r(e.under);
1555
+ let t = yr(e.under);
1553
1556
  return t.length > 0 ? t : (e.routes ?? []).length > 0 ? [] : ["/"];
1554
- }, br = (e, t) => yr(e).some((e) => Z(e, t)) ? !(e?.except ?? []).some((e) => Z(e, t)) : !1, xr = (e, t) => e.find(({ middleware: e }) => t.route === void 0 ? br(e.match, t.pathname) : vr(e.match, t.route))?.middleware, Sr = (e, t) => {
1557
+ }, Sr = (e, t) => xr(e).some((e) => Z(e, t)) ? !(e?.except ?? []).some((e) => Z(e, t)) : !1, Cr = (e, t) => e.find(({ middleware: e }) => t.route === void 0 ? Sr(e.match, t.pathname) : br(e.match, t.route))?.middleware, wr = (e, t) => {
1555
1558
  let n = [];
1556
1559
  for (let { exportName: r, middleware: i } of e) {
1557
1560
  let e = i.match;
@@ -1559,13 +1562,13 @@ import {
1559
1562
  kind: "dead-matcher",
1560
1563
  message: `\`${r}\` matches routes: ['${i}'], which is not a route in this app. Route patterns are spelled as the router spells them, e.g. \`/notes/[id]\`.`
1561
1564
  });
1562
- if (e?.assets !== !0) for (let [i, a] of [["under", _r(e?.under)], ["except", e?.except ?? []]]) for (let e of a) t.some((t) => Z(e, t)) || n.push({
1565
+ if (e?.assets !== !0) for (let [i, a] of [["under", yr(e?.under)], ["except", e?.except ?? []]]) for (let e of a) t.some((t) => Z(e, t)) || n.push({
1563
1566
  kind: "dead-matcher",
1564
1567
  message: `\`${r}\` matches ${i}: ['${e}'], which covers no route in this app. ` + (i === "except" ? "An `except` that excludes nothing is a rule that reads as active and is not." : "Add `assets: true` if you meant a path the router does not serve.")
1565
1568
  });
1566
1569
  }
1567
1570
  for (let r = 0; r < e.length; r += 1) for (let i = r + 1; i < e.length; i += 1) {
1568
- let a = e[r], o = e[i], s = t.find((e) => vr(a.middleware.match, e) && vr(o.middleware.match, e));
1571
+ let a = e[r], o = e[i], s = t.find((e) => br(a.middleware.match, e) && br(o.middleware.match, e));
1569
1572
  if (s !== void 0) {
1570
1573
  n.push({
1571
1574
  kind: "overlap",
@@ -1574,7 +1577,7 @@ import {
1574
1577
  continue;
1575
1578
  }
1576
1579
  {
1577
- let e = yr(a.middleware.match), t = yr(o.middleware.match), r = e.some((e) => t.some((t) => Z(e, t) || Z(t, e))), i = (a.middleware.match?.except ?? []).some((e) => t.length > 0 && t.every((t) => Z(e, t))) || (o.middleware.match?.except ?? []).some((t) => e.length > 0 && e.every((e) => Z(t, e)));
1580
+ let e = xr(a.middleware.match), t = xr(o.middleware.match), r = e.some((e) => t.some((t) => Z(e, t) || Z(t, e))), i = (a.middleware.match?.except ?? []).some((e) => t.length > 0 && t.every((t) => Z(e, t))) || (o.middleware.match?.except ?? []).some((t) => e.length > 0 && e.every((e) => Z(t, e)));
1578
1581
  r && !i && n.push({
1579
1582
  kind: "overlap",
1580
1583
  message: `\`${a.exportName}\` and \`${o.exportName}\` both declare \`assets: true\` over overlapping paths. A non-page request would match both, and there is no route to tell them apart.`
@@ -1582,10 +1585,10 @@ import {
1582
1585
  }
1583
1586
  }
1584
1587
  return n;
1585
- }, Cr = (e, t) => {
1586
- let r = Sr(e, t);
1588
+ }, Tr = (e, t) => {
1589
+ let r = wr(e, t);
1587
1590
  if (r.length !== 0) throw n(`middleware.ts: ${r.length} problem(s)\n\n` + r.map((e) => ` • ${e.message}`).join("\n\n"));
1588
- }, wr = (e) => {
1591
+ }, Er = (e) => {
1589
1592
  let t = {};
1590
1593
  if (!e) return t;
1591
1594
  for (let n of e.split(";")) {
@@ -1599,11 +1602,11 @@ import {
1599
1602
  }
1600
1603
  }
1601
1604
  return t;
1602
- }, Tr = (e) => Object.entries(e).map(([e, t]) => `${e}=${encodeURIComponent(t)}`).join("; "), Er = /(^|[-_.])(auth[-_.]?token|session|access[-_.]?token)([-_.]|$)|^sb-.*-auth-token$/i, Dr = (e) => e.httpOnly === void 0 && Er.test(e.name), Or = (e) => {
1605
+ }, Dr = (e) => Object.entries(e).map(([e, t]) => `${e}=${encodeURIComponent(t)}`).join("; "), Or = /(^|[-_.])(auth[-_.]?token|session|access[-_.]?token)([-_.]|$)|^sb-.*-auth-token$/i, kr = (e) => e.httpOnly === void 0 && Or.test(e.name), Ar = (e) => {
1603
1606
  let t = [`${e.name}=${encodeURIComponent(e.value)}`];
1604
1607
  return t.push(`Path=${e.path ?? "/"}`), e.maxAge !== void 0 && t.push(`Max-Age=${Math.trunc(e.maxAge)}`), e.httpOnly !== !1 && t.push("HttpOnly"), e.secure === !0 && t.push("Secure"), t.push(`SameSite=${e.sameSite ?? "lax"}`), t.join("; ");
1605
- }, kr = (e) => e.length === 0 ? {} : { "set-cookie": e.map(Or) }, Ar = async (e, t = (e) => import(L(e).href)) => {
1606
- for (let r of hr) {
1608
+ }, jr = (e) => e.length === 0 ? {} : { "set-cookie": e.map(Ar) }, Mr = async (e, t = (e) => import(L(e).href)) => {
1609
+ for (let r of _r) {
1607
1610
  let i;
1608
1611
  try {
1609
1612
  i = await t(O(e, r));
@@ -1612,7 +1615,7 @@ import {
1612
1615
  if (t === "ERR_MODULE_NOT_FOUND" || t === "MODULE_NOT_FOUND") continue;
1613
1616
  throw e;
1614
1617
  }
1615
- let a = Object.entries(i ?? {}), o = a.filter((e) => mr(e[1])).map(([e, t]) => ({
1618
+ let a = Object.entries(i ?? {}), o = a.filter((e) => gr(e[1])).map(([e, t]) => ({
1616
1619
  exportName: e,
1617
1620
  middleware: t
1618
1621
  }));
@@ -1630,7 +1633,7 @@ The wrapper is what carries \`match\`, and what lets \`voltro doctor\` report wh
1630
1633
  return o;
1631
1634
  }
1632
1635
  return [];
1633
- }, jr = async (e, t, n) => {
1636
+ }, Nr = async (e, t, n) => {
1634
1637
  let r = {
1635
1638
  headers: t.headers,
1636
1639
  cookies: t.cookies,
@@ -1640,7 +1643,7 @@ The wrapper is what carries \`match\`, and what lets \`voltro doctor\` report wh
1640
1643
  let i = await e.run(t);
1641
1644
  if (!i) return r;
1642
1645
  let a = i.setCookies ?? [];
1643
- if (n !== void 0) for (let e of a) Dr(e) && n(e);
1646
+ if (n !== void 0) for (let e of a) kr(e) && n(e);
1644
1647
  let o = i.headers ? {
1645
1648
  ...t.headers,
1646
1649
  ...i.headers
@@ -1652,19 +1655,19 @@ The wrapper is what carries \`match\`, and what lets \`voltro doctor\` report wh
1652
1655
  };
1653
1656
  let s = { ...t.cookies };
1654
1657
  for (let e of a) e.maxAge !== void 0 && e.maxAge <= 0 ? delete s[e.name] : s[e.name] = e.value;
1655
- return i.headers?.cookie === void 0 && (o.cookie = Tr(s)), {
1658
+ return i.headers?.cookie === void 0 && (o.cookie = Dr(s)), {
1656
1659
  headers: o,
1657
1660
  cookies: s,
1658
1661
  setCookies: a
1659
1662
  };
1660
- }, Q = z({ scope: "voltro:dev:web" }), Mr = z({ scope: "vite" }), Nr = await (async () => {
1663
+ }, Q = z({ scope: "voltro:dev:web" }), Pr = z({ scope: "vite" }), Fr = await (async () => {
1661
1664
  try {
1662
1665
  let e = O(D(te(import.meta.url)), "..", "package.json"), t = await M.readFile(e, "utf8");
1663
1666
  return JSON.parse(t).version ?? "0.0.0";
1664
1667
  } catch {
1665
1668
  return "0.0.0";
1666
1669
  }
1667
- })(), Pr = async () => {
1670
+ })(), Ir = async () => {
1668
1671
  try {
1669
1672
  let e = D(te(import.meta.url)), t = A(e, "..", "..", "devtools");
1670
1673
  if (j(O(t, "package.json"))) return t;
@@ -1673,7 +1676,7 @@ The wrapper is what carries \`match\`, and what lets \`voltro doctor\` report wh
1673
1676
  } catch {
1674
1677
  return null;
1675
1678
  }
1676
- }, Fr = (e, t) => e.disableDevtools || !t ? [] : [
1679
+ }, Lr = (e, t) => e.disableDevtools || !t ? [] : [
1677
1680
  "",
1678
1681
  "// Dev-only in-page devtools overlay. The `import.meta.env.DEV` guard is a",
1679
1682
  "// compile-time constant, so prod builds strip this whole `if` block — the",
@@ -1683,12 +1686,12 @@ The wrapper is what carries \`match\`, and what lets \`voltro doctor\` report wh
1683
1686
  " await import('@voltro/devtools/styles.css')",
1684
1687
  " Devtools = (await import('@voltro/devtools')).VoltroDevtools",
1685
1688
  "}"
1686
- ], Ir = (e, t) => e.disableDevtools || !t ? [] : [" ...(Devtools ? { Devtools } : {}),"], Lr = (e) => e.sentry ? ["import { initSentryBrowser } from '@voltro/plugin-sentry/web'"] : [], Rr = (e) => e.sentry ? [
1689
+ ], Rr = (e, t) => e.disableDevtools || !t ? [] : [" ...(Devtools ? { Devtools } : {}),"], zr = (e) => e.sentry ? ["import { initSentryBrowser } from '@voltro/plugin-sentry/web'"] : [], Br = (e) => e.sentry ? [
1687
1690
  "",
1688
1691
  "// Browser-side Sentry (frontend half of the deep integration). Errors +",
1689
1692
  "// browser rpc spans flow to Sentry, sharing the server transactions' trace.",
1690
1693
  `await initSentryBrowser(${JSON.stringify(e.sentry)})`
1691
- ] : [], zr = (e) => e.env ? ["import './env.public'"] : [], Br = (e) => {
1694
+ ] : [], Vr = (e) => e.env ? ["import './env.public'"] : [], Hr = (e) => {
1692
1695
  let t = [], n = A(e);
1693
1696
  for (;;) {
1694
1697
  j(O(n, "pnpm-workspace.yaml")) && t.push(n);
@@ -1697,14 +1700,14 @@ The wrapper is what carries \`match\`, and what lets \`voltro doctor\` report wh
1697
1700
  n = e;
1698
1701
  }
1699
1702
  return t;
1700
- }, Vr = b, Hr = (e) => {
1703
+ }, Ur = b, Wr = (e) => {
1701
1704
  if (/\/node_modules\/(?:\.pnpm\/[^/]+\/node_modules\/)?(?:react|react-dom|scheduler)\//.test(e)) return "react";
1702
1705
  let t = /\/([^/]+)\.island\.tsx?$/.exec(e);
1703
1706
  if (t) return `island-${t[1]}`;
1704
- }, Ur = /export\s+(?:async\s+)?(?:const|function|let|var)\s+loader\b/, Wr = (e) => e.startsWith("(") && e.endsWith(")"), Gr = (e) => e.filter((e) => !Wr(e)), Kr = (e) => {
1705
- let t = e.replace(c, "").split("/").filter(Boolean).filter((e) => !Wr(e));
1707
+ }, Gr = /export\s+(?:async\s+)?(?:const|function|let|var)\s+loader\b/, Kr = (e) => e.startsWith("(") && e.endsWith(")"), qr = (e) => e.filter((e) => !Kr(e)), Jr = (e) => {
1708
+ let t = e.replace(c, "").split("/").filter(Boolean).filter((e) => !Kr(e));
1706
1709
  return t.length === 0 ? "/" : "/" + t.join("/");
1707
- }, qr = (e) => `${e.replace(c, "").split("/").filter(Boolean).map((e) => e.replace(/[()]/g, "").replace(/\[\.\.\./g, "_rest_").replace(/[[\]]/g, "_")).map((e) => e.charAt(0).toUpperCase() + e.slice(1)).join("").replace(/[^A-Za-z0-9_]/g, "_") || "Index"}Page`, $ = (e, t) => e === "" ? `Root${t}` : `${e.split("/").filter(Boolean).map((e) => e.replace(/[()]/g, "").replace(/\[\.\.\./g, "_rest_").replace(/[[\]]/g, "_")).map((e) => e.charAt(0).toUpperCase() + e.slice(1)).join("").replace(/[^A-Za-z0-9_]/g, "_") || "Root"}${t}`, Jr = async (e) => {
1710
+ }, Yr = (e) => `${e.replace(c, "").split("/").filter(Boolean).map((e) => e.replace(/[()]/g, "").replace(/\[\.\.\./g, "_rest_").replace(/[[\]]/g, "_")).map((e) => e.charAt(0).toUpperCase() + e.slice(1)).join("").replace(/[^A-Za-z0-9_]/g, "_") || "Index"}Page`, $ = (e, t) => e === "" ? `Root${t}` : `${e.split("/").filter(Boolean).map((e) => e.replace(/[()]/g, "").replace(/\[\.\.\./g, "_rest_").replace(/[[\]]/g, "_")).map((e) => e.charAt(0).toUpperCase() + e.slice(1)).join("").replace(/[^A-Za-z0-9_]/g, "_") || "Root"}${t}`, Xr = async (e) => {
1708
1711
  let t = [], n = [], r = async (e, i) => {
1709
1712
  let a = [];
1710
1713
  try {
@@ -1712,17 +1715,17 @@ The wrapper is what carries \`match\`, and what lets \`voltro doctor\` report wh
1712
1715
  } catch {
1713
1716
  return;
1714
1717
  }
1715
- let o = a.filter((e) => e.isDirectory()).map((e) => e.name).sort(), l = a.filter((e) => e.isFile() && e.name.endsWith(".tsx") && !Vr(e.name)).map((e) => e.name).sort(), u = new Set(l), d = i.join("/");
1718
+ let o = a.filter((e) => e.isDirectory()).map((e) => e.name).sort(), l = a.filter((e) => e.isFile() && e.name.endsWith(".tsx") && !Ur(e.name)).map((e) => e.name).sort(), u = new Set(l), d = i.join("/");
1716
1719
  if (l.some((e) => s.has(e))) {
1717
1720
  let t = u.has("layout.tsx"), r = !1;
1718
1721
  if (t) try {
1719
1722
  let t = await M.readFile(O(e, "layout.tsx"), "utf8");
1720
- r = Ur.test(t);
1723
+ r = Gr.test(t);
1721
1724
  } catch {}
1722
1725
  n.push({
1723
1726
  dir: d,
1724
1727
  chain: i,
1725
- contributesToUrl: i.length === 0 || !Wr(i[i.length - 1]),
1728
+ contributesToUrl: i.length === 0 || !Kr(i[i.length - 1]),
1726
1729
  hasLayout: t,
1727
1730
  hasLayoutLoader: r,
1728
1731
  hasError: u.has("error.tsx"),
@@ -1736,8 +1739,8 @@ The wrapper is what carries \`match\`, and what lets \`voltro doctor\` report wh
1736
1739
  let n = d ? `${d}/${e}` : e;
1737
1740
  t.push({
1738
1741
  file: n,
1739
- pattern: Kr(n),
1740
- ident: qr(n),
1742
+ pattern: Jr(n),
1743
+ ident: Yr(n),
1741
1744
  dirChain: i
1742
1745
  });
1743
1746
  }
@@ -1756,14 +1759,14 @@ The wrapper is what carries \`match\`, and what lets \`voltro doctor\` report wh
1756
1759
  dirs: a,
1757
1760
  orphanedSpecials: o
1758
1761
  };
1759
- }, Yr = (e, t) => {
1762
+ }, Zr = (e, t) => {
1760
1763
  let n = [];
1761
1764
  for (let r = 0; r <= t.length; r++) {
1762
1765
  let i = t.slice(0, r).join("/"), a = e.find((e) => e.dir === i);
1763
1766
  a && n.push(a);
1764
1767
  }
1765
1768
  return n;
1766
- }, Xr = async (e) => {
1769
+ }, Qr = async (e) => {
1767
1770
  let { entries: t, loadLayout: n, loadError: r, loadPending: i, ctx: a } = e, o = {};
1768
1771
  return {
1769
1772
  chain: await Promise.all(t.map(async (e, t) => {
@@ -1787,10 +1790,10 @@ The wrapper is what carries \`match\`, and what lets \`voltro doctor\` report wh
1787
1790
  })),
1788
1791
  segmentLoaderData: o
1789
1792
  };
1790
- }, Zr = (e) => {
1791
- let t = Gr(e);
1793
+ }, $r = (e) => {
1794
+ let t = qr(e);
1792
1795
  return t.length === 0 ? "" : "/" + t.join("/");
1793
- }, Qr = [
1796
+ }, ei = [
1794
1797
  "// Hot-reload bridge: keep SSR-injected <link rel=\"stylesheet\"> tags",
1795
1798
  "// in sync with Vite's CSS HMR. Without this, edits to .css files",
1796
1799
  "// only update the JS-injected <style> overlay; the underlying <link>",
@@ -1883,7 +1886,7 @@ The wrapper is what carries \`match\`, and what lets \`voltro doctor\` report wh
1883
1886
  " _vdtErrorStart('Build error')",
1884
1887
  " })",
1885
1888
  "}"
1886
- ].join("\n"), $r = (e) => {
1889
+ ].join("\n"), ti = (e) => {
1887
1890
  let t = [], n = 0, r = e.split("/").filter(Boolean), i = [];
1888
1891
  for (let e of r) e.startsWith("[[...") && e.endsWith("]]") ? (i.push("(.*)"), t.push(e.slice(5, -2)), n += 2) : e.startsWith("[...") && e.endsWith("]") ? (i.push("(.+)"), t.push(e.slice(4, -1)), n += 3) : e.startsWith("[") && e.endsWith("]") ? (i.push("([^/]+)"), t.push(e.slice(1, -1)), n += 1) : i.push(e.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"));
1889
1892
  let a = i.join("/");
@@ -1892,8 +1895,8 @@ The wrapper is what carries \`match\`, and what lets \`voltro doctor\` report wh
1892
1895
  paramNames: t,
1893
1896
  priority: n
1894
1897
  };
1895
- }, ei = (e) => e.map((e) => {
1896
- let { regex: t, paramNames: n, priority: r } = $r(e.pattern);
1898
+ }, ni = (e) => e.map((e) => {
1899
+ let { regex: t, paramNames: n, priority: r } = ti(e.pattern);
1897
1900
  return {
1898
1901
  pattern: e.pattern,
1899
1902
  file: e.file,
@@ -1902,7 +1905,7 @@ The wrapper is what carries \`match\`, and what lets \`voltro doctor\` report wh
1902
1905
  paramNames: n,
1903
1906
  priority: r
1904
1907
  };
1905
- }).slice().sort((e, t) => e.priority - t.priority), ti = (e, t) => {
1908
+ }).slice().sort((e, t) => e.priority - t.priority), ri = (e, t) => {
1906
1909
  for (let n of t) {
1907
1910
  let t = n.regex.exec(e);
1908
1911
  if (!t) continue;
@@ -1914,7 +1917,7 @@ The wrapper is what carries \`match\`, and what lets \`voltro doctor\` report wh
1914
1917
  };
1915
1918
  }
1916
1919
  return null;
1917
- }, ni = J, ri = async (e) => {
1920
+ }, ii = J, ai = async (e) => {
1918
1921
  try {
1919
1922
  let t = await import(L(O(e, "app.config.ts")).href), n = t.default?.port, i = r({
1920
1923
  kind: "api",
@@ -1930,7 +1933,7 @@ The wrapper is what carries \`match\`, and what lets \`voltro doctor\` report wh
1930
1933
  kind: "api",
1931
1934
  env: {}
1932
1935
  }).port };
1933
- }, ii = (e, t) => ({
1936
+ }, oi = (e, t) => ({
1934
1937
  name: e,
1935
1938
  pkg: t.package,
1936
1939
  browserWsUrl: t.url,
@@ -1938,7 +1941,7 @@ The wrapper is what carries \`match\`, and what lets \`voltro doctor\` report wh
1938
1941
  ...t.serverUrl ? { serverOrigin: t.serverUrl } : {},
1939
1942
  ...t.headers ? { headers: t.headers } : {},
1940
1943
  ...t.authHeaders ? { hasAuthHeaders: !0 } : {}
1941
- }), ai = (e, t, n) => {
1944
+ }), si = (e, t, n) => {
1942
1945
  let r = t.transport?.wsPath ?? n.wsPath;
1943
1946
  return {
1944
1947
  name: e,
@@ -1950,7 +1953,7 @@ The wrapper is what carries \`match\`, and what lets \`voltro doctor\` report wh
1950
1953
  ...t.headers ? { headers: t.headers } : {},
1951
1954
  ...t.authHeaders ? { hasAuthHeaders: !0 } : {}
1952
1955
  };
1953
- }, oi = (e) => {
1956
+ }, ci = (e) => {
1954
1957
  let t = /* @__PURE__ */ new Map();
1955
1958
  for (let n of e) {
1956
1959
  if (n.proxyTarget === void 0) continue;
@@ -1958,43 +1961,43 @@ The wrapper is what carries \`match\`, and what lets \`voltro doctor\` report wh
1958
1961
  if (e) throw Error(`[voltro] api ${JSON.stringify(n.name)} and ${JSON.stringify(e)} both resolve the same-origin WS path ${JSON.stringify(n.browserWsUrl)}. A custom transport.wsPath must be unique per origin (one api per origin may use a fixed path). Give each a distinct wsPath, or drop the override to use the default /ws/<name>.`);
1959
1962
  t.set(n.browserWsUrl, n.name);
1960
1963
  }
1961
- }, si = async (e, t) => {
1964
+ }, li = async (e, t) => {
1962
1965
  let n = Object.entries(t.apis ?? {}), r = [];
1963
1966
  for (let [t, i] of n) {
1964
1967
  if (i.url) {
1965
- r.push(ii(t, i));
1968
+ r.push(oi(t, i));
1966
1969
  continue;
1967
1970
  }
1968
- let n = await ni(e, i.package);
1971
+ let n = await ii(e, i.package);
1969
1972
  if (!n) throw Error(`[voltro dev] api ${JSON.stringify(t)} (package ${JSON.stringify(i.package)}) is not a workspace dep and has no \`url\` set in app.config.ts. External apis need an explicit \`url\` because the framework can't discover their dev port.`);
1970
- r.push(ai(t, i, await ri(n)));
1973
+ r.push(si(t, i, await ai(n)));
1971
1974
  }
1972
- return oi(r), r;
1973
- }, ci = (e) => {
1975
+ return ci(r), r;
1976
+ }, ui = (e) => {
1974
1977
  if (!(!/^wss?:\/\//.test(e) && !/^https?:\/\//.test(e))) try {
1975
1978
  let t = new URL(e);
1976
1979
  return t.protocol = t.protocol === "wss:" || t.protocol === "https:" ? "https:" : "http:", `${t.protocol}//${t.host}`;
1977
1980
  } catch {
1978
1981
  return;
1979
1982
  }
1980
- }, li = (e) => `VOLTRO_API_ORIGIN_${e.toUpperCase().replace(/[^A-Z0-9]/g, "_")}`, ui = (e) => process.env[li(e)] ?? process.env.VOLTRO_API_ORIGIN, di = (e, t) => {
1983
+ }, di = (e) => `VOLTRO_API_ORIGIN_${e.toUpperCase().replace(/[^A-Z0-9]/g, "_")}`, fi = (e) => process.env[di(e)] ?? process.env.VOLTRO_API_ORIGIN, pi = (e, t) => {
1981
1984
  if (!e) return;
1982
- let n = ui(e.name) ?? e.serverOrigin;
1985
+ let n = fi(e.name) ?? e.serverOrigin;
1983
1986
  if (n) {
1984
- let e = ci(n);
1987
+ let e = ui(n);
1985
1988
  if (e) return e;
1986
1989
  }
1987
1990
  if (t?.allowDevProxy && e.proxyTarget) {
1988
- let t = ci(e.proxyTarget);
1991
+ let t = ui(e.proxyTarget);
1989
1992
  if (t) return t;
1990
1993
  }
1991
- if (!e.proxyTarget && /^wss?:\/\//.test(e.browserWsUrl)) return ci(e.browserWsUrl);
1992
- }, fi = (e, t, n) => {
1994
+ if (!e.proxyTarget && /^wss?:\/\//.test(e.browserWsUrl)) return ui(e.browserWsUrl);
1995
+ }, mi = (e, t, n) => {
1993
1996
  if (!e) {
1994
1997
  if (n?.apiName === void 0) return;
1995
1998
  let e = n.apiName;
1996
1999
  return async () => {
1997
- throw Error(`[loader.query] api '${e}' has no server-side origin for SSR. In a split web/api deployment the web pod reaches the api by internal DNS, not the browser's relative wsPath — set ${li(e)} (or VOLTRO_API_ORIGIN, or apis.${e}.serverUrl in app.config.ts) to the api's internal origin, e.g. http://api.<namespace>.svc.cluster.local. The browser transport is unaffected.`);
2000
+ throw Error(`[loader.query] api '${e}' has no server-side origin for SSR. In a split web/api deployment the web pod reaches the api by internal DNS, not the browser's relative wsPath — set ${di(e)} (or VOLTRO_API_ORIGIN, or apis.${e}.serverUrl in app.config.ts) to the api's internal origin, e.g. http://api.<namespace>.svc.cluster.local. The browser transport is unaffected.`);
1998
2001
  };
1999
2002
  }
2000
2003
  return async (r, i) => {
@@ -2017,7 +2020,7 @@ The wrapper is what carries \`match\`, and what lets \`voltro doctor\` report wh
2017
2020
  });
2018
2021
  } catch (t) {
2019
2022
  let i = t?.cause?.code ?? String(t?.message ?? t);
2020
- throw Error(`[loader.query] ${r}: could not reach the api at ${e}/rpc (${i}). ${n?.apiName ? `Set ${li(n.apiName)} / VOLTRO_API_ORIGIN` : "Set the api server origin"} to the api's SSR-reachable origin (internal cluster DNS in a split deployment).`, { cause: t });
2023
+ throw Error(`[loader.query] ${r}: could not reach the api at ${e}/rpc (${i}). ${n?.apiName ? `Set ${di(n.apiName)} / VOLTRO_API_ORIGIN` : "Set the api server origin"} to the api's SSR-reachable origin (internal cluster DNS in a split deployment).`, { cause: t });
2021
2024
  }
2022
2025
  if (!o.ok) throw Error(`[loader.query] ${r}: HTTP ${o.status} ${await o.text()}`);
2023
2026
  let s = await o.json();
@@ -2047,8 +2050,8 @@ The wrapper is what carries \`match\`, and what lets \`voltro doctor\` report wh
2047
2050
  }
2048
2051
  if (u) return l;
2049
2052
  };
2050
- }, pi = async (e, t, n, r = {}) => {
2051
- let i = t.title ?? t.name ?? "app", a = t.theme === "dark" ? " class=\"dark\"" : t.theme === "light" ? " class=\"light\"" : "", o = j(O(e, "node_modules", "@voltro", "devtools", "package.json")) || await Pr() !== null, s = t.theme === "system" ? [
2053
+ }, hi = async (e, t, n, r = {}) => {
2054
+ let i = t.title ?? t.name ?? "app", a = t.theme === "dark" ? " class=\"dark\"" : t.theme === "light" ? " class=\"light\"" : "", o = j(O(e, "node_modules", "@voltro", "devtools", "package.json")) || await Ir() !== null, s = t.theme === "system" ? [
2052
2055
  " <script>",
2053
2056
  " (function () {",
2054
2057
  " var root = document.documentElement",
@@ -2069,7 +2072,19 @@ The wrapper is what carries \`match\`, and what lets \`voltro doctor\` report wh
2069
2072
  " }",
2070
2073
  " })()",
2071
2074
  " <\/script>"
2072
- ].join("\n") : "", c = [
2075
+ ].join("\n") : "", c = t.timeZone === "viewer" ? [
2076
+ " <script>",
2077
+ " (function () {",
2078
+ " try {",
2079
+ " if (/(?:^|;\\s*)voltro:tz=/.test(document.cookie)) return",
2080
+ " var tz = Intl.DateTimeFormat().resolvedOptions().timeZone",
2081
+ " if (!tz) return",
2082
+ " document.cookie = 'voltro:tz=' + encodeURIComponent(tz)",
2083
+ " + '; path=/; max-age=31536000; SameSite=Lax'",
2084
+ " } catch (e) {}",
2085
+ " })()",
2086
+ " <\/script>"
2087
+ ].join("\n") : "", l = [
2073
2088
  "<!doctype html>",
2074
2089
  "<!-- GENERATED BY `voltro dev` — do not edit; will be overwritten on next boot. -->",
2075
2090
  `<html lang="en"${a}>`,
@@ -2079,6 +2094,7 @@ The wrapper is what carries \`match\`, and what lets \`voltro doctor\` report wh
2079
2094
  ` <title>${i}</title>`,
2080
2095
  " <link rel=\"icon\" type=\"image/svg+xml\" href=\"/favicon.svg\" />",
2081
2096
  ...s ? [s] : [],
2097
+ ...c ? [c] : [],
2082
2098
  " </head>",
2083
2099
  " <body>",
2084
2100
  " <div id=\"root\"></div>",
@@ -2086,35 +2102,35 @@ The wrapper is what carries \`match\`, and what lets \`voltro doctor\` report wh
2086
2102
  " </body>",
2087
2103
  "</html>",
2088
2104
  ""
2089
- ].join("\n"), l = O(e, "src", "pages"), { pages: u, dirs: d, orphanedSpecials: f } = await Jr(l);
2090
- await y(l, u);
2091
- for (let e of f) Q.warn(`src/pages/${e.dir || "."}/ contains ${e.files.join(", ")} but no page.tsx at or below it — ${e.files.length > 1 ? "those files are" : "that file is"} inert. A layout/error/loading/not-found file only applies to routes in its own directory tree; if this is an ordinary component, rename it so it does not read as a route boundary.`);
2092
- let p = (e) => `${e.replace(/[^a-zA-Z0-9]/g, "_")}AppGroup`, m = (e) => `${e.replace(/[^a-zA-Z0-9]/g, "_")}AppDescriptors`, h = n.map((e) => `import { appGroup as ${p(e.name)}, appDescriptors as ${m(e.name)} } from '${e.pkg}/rpcGroup'`);
2093
- n.some((e) => e.hasAuthHeaders) && (h.push("import __voltroAppConfig from '../app.config'"), h.push("const __voltroAuthHeaders = (__voltroAppConfig as { readonly apis?: Record<string, { readonly authHeaders?: () => Record<string, string> | Promise<Record<string, string>> }> }).apis"));
2094
- let g = n.map((e) => {
2095
- let t = [`group: ${p(e.name)}`];
2096
- return t.push(`descriptors: ${m(e.name)}`), t.push(`wsUrl: ${JSON.stringify(e.browserWsUrl)}`), e.hasAuthHeaders ? t.push(`headers: __voltroAuthHeaders?.[${JSON.stringify(e.name)}]?.authHeaders`) : e.headers && t.push(`headers: ${JSON.stringify(e.headers)}`), ` ${JSON.stringify(e.name)}: { ${t.join(", ")} },`;
2097
- }), _, v, b;
2098
- if (u.length > 0) {
2099
- let n = u.map((e) => ` ${JSON.stringify(e.pattern)}: () => import('../src/pages/${e.file}'),`), r = [];
2100
- for (let e of d) {
2105
+ ].join("\n"), u = O(e, "src", "pages"), { pages: d, dirs: f, orphanedSpecials: p } = await Xr(u);
2106
+ await y(u, d);
2107
+ for (let e of p) Q.warn(`src/pages/${e.dir || "."}/ contains ${e.files.join(", ")} but no page.tsx at or below it — ${e.files.length > 1 ? "those files are" : "that file is"} inert. A layout/error/loading/not-found file only applies to routes in its own directory tree; if this is an ordinary component, rename it so it does not read as a route boundary.`);
2108
+ let m = (e) => `${e.replace(/[^a-zA-Z0-9]/g, "_")}AppGroup`, h = (e) => `${e.replace(/[^a-zA-Z0-9]/g, "_")}AppDescriptors`, g = n.map((e) => `import { appGroup as ${m(e.name)}, appDescriptors as ${h(e.name)} } from '${e.pkg}/rpcGroup'`);
2109
+ n.some((e) => e.hasAuthHeaders) && (g.push("import __voltroAppConfig from '../app.config'"), g.push("const __voltroAuthHeaders = (__voltroAppConfig as { readonly apis?: Record<string, { readonly authHeaders?: () => Record<string, string> | Promise<Record<string, string>> }> }).apis"));
2110
+ let _ = n.map((e) => {
2111
+ let t = [`group: ${m(e.name)}`];
2112
+ return t.push(`descriptors: ${h(e.name)}`), t.push(`wsUrl: ${JSON.stringify(e.browserWsUrl)}`), e.hasAuthHeaders ? t.push(`headers: __voltroAuthHeaders?.[${JSON.stringify(e.name)}]?.authHeaders`) : e.headers && t.push(`headers: ${JSON.stringify(e.headers)}`), ` ${JSON.stringify(e.name)}: { ${t.join(", ")} },`;
2113
+ }), v, b, x;
2114
+ if (d.length > 0) {
2115
+ let n = d.map((e) => ` ${JSON.stringify(e.pattern)}: () => import('../src/pages/${e.file}'),`), r = [];
2116
+ for (let e of f) {
2101
2117
  let t = e.dir === "" ? "../src/pages" : `../src/pages/${e.dir}`;
2102
2118
  e.hasLayout && e.hasLayoutLoader ? r.push(`import * as ${$(e.dir, "Layout")}Mod from '${t}/layout.tsx'`) : e.hasLayout && r.push(`import ${$(e.dir, "Layout")} from '${t}/layout.tsx'`), e.hasError && r.push(`import ${$(e.dir, "Error")} from '${t}/error.tsx'`), e.hasPending && r.push(`import ${$(e.dir, "Pending")} from '${t}/loading.tsx'`), e.hasNotFound && r.push(`import ${$(e.dir, "NotFound")} from '${t}/not-found.tsx'`);
2103
2119
  }
2104
- let i = u.map((e) => {
2105
- let t = Yr(d, e.dirChain).map((e) => {
2120
+ let i = d.map((e) => {
2121
+ let t = Zr(f, e.dirChain).map((e) => {
2106
2122
  let t = [`id: ${JSON.stringify(e.dir || "/")}`], n = JSON.stringify(e.dir);
2107
2123
  return e.hasLayout && t.push(`Layout: refs.layouts[${n}]`), e.hasLayoutLoader && t.push(`loader: refs.layoutLoaders[${n}]`), e.hasError && t.push(`Error: refs.errors[${n}]`), e.hasPending && t.push(`Pending: refs.pendings[${n}]`), ` { ${t.join(", ")} }`;
2108
2124
  }).join(",\n");
2109
2125
  return ` makePageRoute(${JSON.stringify(e.pattern)}, ${t.length > 0 ? `[\n${t},\n ]` : "undefined"}),`;
2110
- }), a = d.filter((e) => e.hasNotFound).map((e) => {
2111
- let t = Zr(e.chain), n = Yr(d, e.chain).map((e) => {
2126
+ }), a = f.filter((e) => e.hasNotFound).map((e) => {
2127
+ let t = $r(e.chain), n = Zr(f, e.chain).map((e) => {
2112
2128
  let t = [`id: ${JSON.stringify(e.dir || "/")}`], n = JSON.stringify(e.dir);
2113
2129
  return e.hasLayout && t.push(`Layout: refs.layouts[${n}]`), e.hasError && t.push(`Error: refs.errors[${n}]`), ` { ${t.join(", ")} }`;
2114
2130
  }).join(",\n"), r = n.length > 0 ? `\n chain: [\n${n},\n ],` : "";
2115
2131
  return ` {\n prefix: ${JSON.stringify(t)},\n Component: refs.notFounds[${JSON.stringify(e.dir)}],${r}\n },`;
2116
- }), s = [], c = [], l = [], f = [], p = [], m = [];
2117
- for (let e of d) {
2132
+ }), s = [], c = [], l = [], u = [], p = [], m = [];
2133
+ for (let e of f) {
2118
2134
  let t = e.dir === "" ? "../src/pages/layout.tsx" : `../src/pages/${e.dir}/layout.tsx`, n = e.dir === "" ? "../src/pages/error.tsx" : `../src/pages/${e.dir}/error.tsx`, r = e.dir === "" ? "../src/pages/loading.tsx" : `../src/pages/${e.dir}/loading.tsx`, i = e.dir === "" ? "../src/pages/not-found.tsx" : `../src/pages/${e.dir}/not-found.tsx`, a = JSON.stringify(e.dir);
2119
2135
  e.hasLayout && e.hasLayoutLoader ? (c.push(` ${a}: ${$(e.dir, "Layout")}Mod.default,`), l.push(` ${a}: ${$(e.dir, "Layout")}Mod.loader,`), s.push({
2120
2136
  relPath: t,
@@ -2124,7 +2140,7 @@ The wrapper is what carries \`match\`, and what lets \`voltro doctor\` report wh
2124
2140
  relPath: t,
2125
2141
  kind: "layout",
2126
2142
  slotKey: e.dir
2127
- })), e.hasError && (f.push(` ${a}: ${$(e.dir, "Error")},`), s.push({
2143
+ })), e.hasError && (u.push(` ${a}: ${$(e.dir, "Error")},`), s.push({
2128
2144
  relPath: n,
2129
2145
  kind: "error",
2130
2146
  slotKey: e.dir
@@ -2138,12 +2154,12 @@ The wrapper is what carries \`match\`, and what lets \`voltro doctor\` report wh
2138
2154
  slotKey: e.dir
2139
2155
  }));
2140
2156
  }
2141
- for (let e of u) s.push({
2157
+ for (let e of d) s.push({
2142
2158
  relPath: `../src/pages/${e.file}`,
2143
2159
  kind: "page",
2144
2160
  slotKey: e.pattern
2145
2161
  });
2146
- let y = s.map((e) => ` ${JSON.stringify(e.relPath)},`), x = s.map((e, t) => {
2162
+ let h = s.map((e) => ` ${JSON.stringify(e.relPath)},`), y = s.map((e, t) => {
2147
2163
  let n = JSON.stringify(e.slotKey);
2148
2164
  return e.kind === "page" ? ` if (newMods[${t}] && refs.pages[${n}] !== undefined) { refs.pages[${n}] = newMods[${t}]; changed = true }` : ` if (newMods[${t}]?.default) { refs.${e.kind === "layout" ? "layouts" : e.kind === "error" ? "errors" : e.kind === "pending" ? "pendings" : "notFounds"}[${n}] = newMods[${t}].default;${e.kind === "layout" ? ` refs.layoutLoaders[${n}] = newMods[${t}].loader;` : ""} changed = true }`;
2149
2165
  }), S = t.locales ?? [], C = S.length > 0 && S.every((t) => j(O(e, "src", "locales", `${t}.ts`)) || j(O(e, "src", "locales", `${t}.tsx`))), w = C, T = t.defaultLocale ?? S[0] ?? "en";
@@ -2154,7 +2170,7 @@ The wrapper is what carries \`match\`, and what lets \`voltro doctor\` report wh
2154
2170
  "import { useServerRequest } from '@voltro/web'",
2155
2171
  ...S.map((e) => `import i18nCatalog_${e} from '../src/locales/${e}'`)
2156
2172
  ] : [];
2157
- v = [
2173
+ b = [
2158
2174
  "// GENERATED BY `voltro dev` — do not edit; will be overwritten on next boot.",
2159
2175
  "// Routes + per-page chain + not-found scopes assembled from src/pages/.",
2160
2176
  "//",
@@ -2194,7 +2210,7 @@ The wrapper is what carries \`match\`, and what lets \`voltro doctor\` report wh
2194
2210
  ...l,
2195
2211
  " },",
2196
2212
  " errors: {",
2197
- ...f,
2213
+ ...u,
2198
2214
  " },",
2199
2215
  " pendings: {",
2200
2216
  ...p,
@@ -2265,17 +2281,17 @@ The wrapper is what carries \`match\`, and what lets \`voltro doctor\` report wh
2265
2281
  "if (import.meta.hot) {",
2266
2282
  " import.meta.hot.accept(",
2267
2283
  " [",
2268
- ...y,
2284
+ ...h,
2269
2285
  " ],",
2270
2286
  " (newMods: Array<Record<string, unknown> | undefined>) => {",
2271
2287
  " let changed = false",
2272
- ...x,
2288
+ ...y,
2273
2289
  " if (changed) bump()",
2274
2290
  " },",
2275
2291
  " )",
2276
2292
  "}",
2277
2293
  ""
2278
- ].join("\n"), _ = [
2294
+ ].join("\n"), v = [
2279
2295
  "// GENERATED BY `voltro dev` — do not edit; will be overwritten on next boot.",
2280
2296
  "// The app's root component. It exports `App` and NOTHING ELSE: react-refresh",
2281
2297
  "// only accepts a module whose every export is a component, and a module it",
@@ -2297,6 +2313,29 @@ The wrapper is what carries \`match\`, and what lets \`voltro doctor\` report wh
2297
2313
  `const I18N_SUPPORTED: ReadonlyArray<string> = [${S.map((e) => JSON.stringify(e)).join(", ")}]`,
2298
2314
  `const I18N_DEFAULT = ${JSON.stringify(T)}`,
2299
2315
  "",
2316
+ "// The zone + clock the SERVER decided for this document, read back off",
2317
+ "// <html>. Same contract as <html lang> below and for the same reason:",
2318
+ "// the browser could answer both of these itself, its answer would",
2319
+ "// differ from the server's, and a difference is a hydration mismatch.",
2320
+ "//",
2321
+ "// Reading the ATTRIBUTE rather than the browser is the whole point.",
2322
+ "// 'Intl.DateTimeFormat().resolvedOptions().timeZone' is the viewer's",
2323
+ "// TRUE zone and is therefore the wrong value here — the server could",
2324
+ "// not know it, so it did not render with it. The app makes the server",
2325
+ "// know it by writing the 'voltro:tz' cookie (the pre-paint script",
2326
+ "// seeds it from the browser; a login overwrites it with the user's",
2327
+ "// own), and then the server's answer IS the viewer's zone.",
2328
+ "const readPublishedDocumentAttrs = (): { timeZone?: string; renderedAt?: number } => {",
2329
+ " if (typeof document === 'undefined') return {}",
2330
+ " const el = document.documentElement",
2331
+ " const tz = el.getAttribute('data-voltro-tz')",
2332
+ " const now = Number(el.getAttribute('data-voltro-now'))",
2333
+ " return {",
2334
+ " ...(tz ? { timeZone: tz } : {}),",
2335
+ " ...(Number.isFinite(now) && now > 0 ? { renderedAt: now } : {}),",
2336
+ " }",
2337
+ "}",
2338
+ "",
2300
2339
  "const pickI18nLocale = (ssr: ReturnType<typeof useServerRequest>): string => {",
2301
2340
  " if (ssr) {",
2302
2341
  " return resolveLocale({",
@@ -2350,28 +2389,37 @@ The wrapper is what carries \`match\`, and what lets \`voltro doctor\` report wh
2350
2389
  " const ssr = useServerRequest()",
2351
2390
  " const locale = pickI18nLocale(ssr)",
2352
2391
  " const messages = I18N_CATALOGS[locale] ?? I18N_CATALOGS[I18N_DEFAULT]!",
2392
+ " // Read once per mount, not per render: the values are fixed for the",
2393
+ " // life of the document, and 'renderedAt' moving would defeat the",
2394
+ " // point of pinning it.",
2395
+ " const published = useMemo(readPublishedDocumentAttrs, [])",
2353
2396
  " return (",
2354
- " <I18nProvider locale={locale} messages={messages} defaultLocale={I18N_DEFAULT}>",
2397
+ " <I18nProvider",
2398
+ " locale={locale}",
2399
+ " messages={messages}",
2400
+ " defaultLocale={I18N_DEFAULT}",
2401
+ " {...published}",
2402
+ " >",
2355
2403
  " <Router routes={routes} notFounds={notFounds} />",
2356
2404
  " </I18nProvider>",
2357
2405
  " )"
2358
2406
  ] : [" return <Router routes={routes} notFounds={notFounds} />"],
2359
2407
  "}",
2360
2408
  ""
2361
- ].join("\n"), b = [
2409
+ ].join("\n"), x = [
2362
2410
  "// GENERATED BY `voltro dev` — do not edit; will be overwritten on next boot.",
2363
2411
  "// Entry: imports the generated App component and calls mount() with the",
2364
2412
  "// resolved apis map. Side-effect only — no local component definitions —",
2365
2413
  "// so downstream invalidations (user page edits) terminate at app.tsx.",
2366
2414
  "",
2367
- ...zr(t),
2415
+ ...Vr(t),
2368
2416
  "import { mount } from '@voltro/web'",
2369
- ...h,
2417
+ ...g,
2370
2418
  "import { App } from './app'",
2371
2419
  "import { preloadCurrentRoute } from './routeTable'",
2372
- ...Lr(t),
2373
- ...Fr(t, o),
2374
- ...Rr(t),
2420
+ ...zr(t),
2421
+ ...Lr(t, o),
2422
+ ...Br(t),
2375
2423
  "",
2376
2424
  "// Preload the current route's page chunk BEFORE hydration so the first",
2377
2425
  "// client render matches the SSG/SSR-prerendered HTML. Without it, a lazy",
@@ -2386,52 +2434,52 @@ The wrapper is what carries \`match\`, and what lets \`voltro doctor\` report wh
2386
2434
  "",
2387
2435
  "mount(App, {",
2388
2436
  " apis: {",
2389
- ...g,
2437
+ ..._,
2390
2438
  " },",
2391
- ...Ir(t, o),
2439
+ ...Rr(t, o),
2392
2440
  "})",
2393
2441
  "",
2394
- Qr
2442
+ ei
2395
2443
  ].join("\n");
2396
- } else _ = "", v = "", b = [
2444
+ } else v = "", b = "", x = [
2397
2445
  "// GENERATED BY `voltro dev` — do not edit; will be overwritten on next boot.",
2398
2446
  "// The user's root component lives at ../src/App.tsx; this file imports it",
2399
2447
  "// and calls mount(). Side-effect only, no component definitions, so the",
2400
2448
  "// user's component file remains the Fast Refresh boundary.",
2401
2449
  "",
2402
- ...zr(t),
2450
+ ...Vr(t),
2403
2451
  "import { mount } from '@voltro/web'",
2404
- ...h,
2452
+ ...g,
2405
2453
  "import App from '../src/App'",
2406
- ...Lr(t),
2407
- ...Fr(t, o),
2408
- ...Rr(t),
2454
+ ...zr(t),
2455
+ ...Lr(t, o),
2456
+ ...Br(t),
2409
2457
  "",
2410
2458
  "mount(App, {",
2411
2459
  " apis: {",
2412
- ...g,
2460
+ ..._,
2413
2461
  " },",
2414
- ...Ir(t, o),
2462
+ ...Rr(t, o),
2415
2463
  "})",
2416
2464
  "",
2417
- Qr
2465
+ ei
2418
2466
  ].join("\n");
2419
- let x = O(e, ".framework");
2420
- await M.mkdir(x, { recursive: !0 }), t.env ? await Se(x, r) : await M.rm(O(x, "env.public.ts"), { force: !0 }), await M.writeFile(O(x, "index.html"), c, "utf8"), await M.writeFile(O(x, "main.tsx"), b, "utf8"), _ ? (await M.writeFile(O(x, "app.tsx"), _, "utf8"), await M.writeFile(O(x, "routeTable.ts"), v, "utf8")) : (await M.rm(O(x, "app.tsx"), { force: !0 }), await M.rm(O(x, "routeTable.ts"), { force: !0 }));
2421
- let S = O(e, ".gitignore"), C = "";
2467
+ let S = O(e, ".framework");
2468
+ await M.mkdir(S, { recursive: !0 }), t.env ? await Se(S, r) : await M.rm(O(S, "env.public.ts"), { force: !0 }), await M.writeFile(O(S, "index.html"), l, "utf8"), await M.writeFile(O(S, "main.tsx"), x, "utf8"), v ? (await M.writeFile(O(S, "app.tsx"), v, "utf8"), await M.writeFile(O(S, "routeTable.ts"), b, "utf8")) : (await M.rm(O(S, "app.tsx"), { force: !0 }), await M.rm(O(S, "routeTable.ts"), { force: !0 }));
2469
+ let C = O(e, ".gitignore"), w = "";
2422
2470
  try {
2423
- C = await M.readFile(S, "utf8");
2471
+ w = await M.readFile(C, "utf8");
2424
2472
  } catch {}
2425
- let w = ["/.framework/"], T = new Set(C.split("\n").map((e) => e.trim())), E = w.filter((e) => !T.has(e));
2426
- if (E.length > 0) {
2427
- let e = C === "" || C.endsWith("\n") ? "" : "\n";
2473
+ let T = ["/.framework/"], E = new Set(w.split("\n").map((e) => e.trim())), D = T.filter((e) => !E.has(e));
2474
+ if (D.length > 0) {
2475
+ let e = w === "" || w.endsWith("\n") ? "" : "\n";
2428
2476
  try {
2429
- await M.appendFile(S, `${e}${E.join("\n")}\n`, "utf8");
2477
+ await M.appendFile(C, `${e}${D.join("\n")}\n`, "utf8");
2430
2478
  } catch (e) {
2431
- Q.warn(`could not add ${E.join(", ")} to ${S} — add it by hand so the generated directory stays out of git. The build is unaffected.`, { reason: e?.message ?? String(e) });
2479
+ Q.warn(`could not add ${D.join(", ")} to ${C} — add it by hand so the generated directory stays out of git. The build is unaffected.`, { reason: e?.message ?? String(e) });
2432
2480
  }
2433
2481
  }
2434
- }, mi = async (e, t) => {
2482
+ }, gi = async (e, t) => {
2435
2483
  try {
2436
2484
  let n = D(e), r = O(n, "project.json");
2437
2485
  if (!j(r)) return;
@@ -2444,16 +2492,16 @@ The wrapper is what carries \`match\`, and what lets \`voltro doctor\` report wh
2444
2492
  projectJson: r
2445
2493
  });
2446
2494
  } catch {}
2447
- }, hi = (e) => O(e, ".framework", "dist", "server", "appConfig.js"), gi = async (e, t = {}) => {
2448
- let n = hi(e), r = t.preferSource !== !0 && j(n) ? n : O(e, "app.config.ts");
2495
+ }, _i = (e) => O(e, ".framework", "dist", "server", "appConfig.js"), vi = async (e, t = {}) => {
2496
+ let n = _i(e), r = t.preferSource !== !0 && j(n) ? n : O(e, "app.config.ts");
2449
2497
  try {
2450
2498
  let e = (await import(L(r).href)).default;
2451
2499
  return typeof e == "object" && e && "type" in e && e.type === "web" ? e : null;
2452
2500
  } catch {
2453
2501
  return null;
2454
2502
  }
2455
- }, _i = async (e) => {
2456
- let n = await gi(e, { preferSource: !0 });
2503
+ }, yi = async (e) => {
2504
+ let n = await vi(e, { preferSource: !0 });
2457
2505
  if (!n) return {
2458
2506
  ran: !1,
2459
2507
  exitCode: 0
@@ -2461,7 +2509,7 @@ The wrapper is what carries \`match\`, and what lets \`voltro doctor\` report wh
2461
2509
  ln();
2462
2510
  let i = St();
2463
2511
  Bt(i), Q.info("booting voltro dev (web)", { app: n.name ?? "(unnamed)" }), We(e, Q);
2464
- let a = await si(e, n);
2512
+ let a = await li(e, n);
2465
2513
  for (let e of a) Q.info("api wired", {
2466
2514
  name: e.name,
2467
2515
  pkg: e.pkg,
@@ -2480,7 +2528,7 @@ The wrapper is what carries \`match\`, and what lets \`voltro doctor\` report wh
2480
2528
  log: Q,
2481
2529
  generateTypes: !0
2482
2530
  }), s = o.publicValues;
2483
- await pi(e, n, a, s), Q.debug("generated framework entry files", { files: [
2531
+ await hi(e, n, a, s), Q.debug("generated framework entry files", { files: [
2484
2532
  "index.html",
2485
2533
  ".framework/main.tsx",
2486
2534
  ...n.env ? [".framework/env.public.ts"] : []
@@ -2501,10 +2549,10 @@ The wrapper is what carries \`match\`, and what lets \`voltro doctor\` report wh
2501
2549
  pid: process.pid,
2502
2550
  status: "booting",
2503
2551
  logFile: D.path
2504
- }).catch(() => {}), await mi(e, l);
2505
- let { pages: N, dirs: P } = await Jr(O(e, "src", "pages")), F = {
2552
+ }).catch(() => {}), await gi(e, l);
2553
+ let { pages: N, dirs: P } = await Xr(O(e, "src", "pages")), F = {
2506
2554
  dirs: P,
2507
- ssrRoutes: ei(N)
2555
+ ssrRoutes: ni(N)
2508
2556
  }, ee = P.map((e) => ({
2509
2557
  dir: e.dir,
2510
2558
  hasLayout: e.hasLayout,
@@ -2536,31 +2584,31 @@ The wrapper is what carries \`match\`, and what lets \`voltro doctor\` report wh
2536
2584
  }
2537
2585
  for (let n of await De(e)) t.watcher.add(n.dir);
2538
2586
  }
2539
- }, H = O(e, "src", "pages"), U = (e) => e.endsWith(".tsx") && (e === H || e.startsWith(H + "/")), ie = (e) => e === H || e.startsWith(H + "/"), W = async (t) => {
2587
+ }, H = O(e, "src", "pages"), U = (e) => e.endsWith(".tsx") && (e === H || e.startsWith(H + "/")), ie = (e) => e === H || e.startsWith(H + "/"), ae = async (t) => {
2540
2588
  try {
2541
2589
  let r = Date.now();
2542
- await pi(e, n, a, s);
2543
- let { pages: i, dirs: o } = await Jr(H);
2590
+ await hi(e, n, a, s);
2591
+ let { pages: i, dirs: o } = await Xr(H);
2544
2592
  await mt({
2545
2593
  appRoot: e,
2546
2594
  pages: i
2547
- }), F.dirs = o, F.ssrRoutes = ei(i), Q.info("page tree regenerated", {
2595
+ }), F.dirs = o, F.ssrRoutes = ni(i), Q.info("page tree regenerated", {
2548
2596
  reason: t,
2549
2597
  ms: Date.now() - r,
2550
2598
  routes: F.ssrRoutes.length
2551
2599
  });
2552
- for (let e of Sr(X, F.ssrRoutes.map((e) => e.pattern))) Q.error(`middleware.ts: ${e.message}`);
2600
+ for (let e of wr(X, F.ssrRoutes.map((e) => e.pattern))) Q.error(`middleware.ts: ${e.message}`);
2553
2601
  } catch (e) {
2554
2602
  Q.error("page tree regen failed", { reason: t }, e);
2555
2603
  }
2556
- }, ae = {
2604
+ }, oe = {
2557
2605
  name: "framework:regenerate-on-page-tree-change",
2558
2606
  configureServer(t) {
2559
2607
  let n = null, r = [], i = (e) => {
2560
2608
  r.push(e), n && clearTimeout(n), n = setTimeout(() => {
2561
2609
  n = null;
2562
2610
  let e = r.length === 1 ? r[0] : `${r.length} events (${r[0]}, …)`;
2563
- r.length = 0, W(e);
2611
+ r.length = 0, ae(e);
2564
2612
  }, 50);
2565
2613
  };
2566
2614
  t.watcher.on("add", (t) => {
@@ -2573,14 +2621,14 @@ The wrapper is what carries \`match\`, and what lets \`voltro doctor\` report wh
2573
2621
  ie(t) && i(`unlinkDir ${k(e, t)}`);
2574
2622
  });
2575
2623
  }
2576
- }, G = O(e, "app.config.ts"), se = (e) => {
2577
- if (!oe(e.env)) return "";
2624
+ }, W = O(e, "app.config.ts"), se = (e) => {
2625
+ if (!G(e.env)) return "";
2578
2626
  let t = Object.entries(e.env.vars).map(([e, t]) => `${e}:${t.access}`).sort();
2579
2627
  return `${String(e.env.publicPrefix)}|${t.join(",")}`;
2580
2628
  }, ce = (e, t) => {
2581
2629
  let n = [];
2582
2630
  return e.port !== t.port && n.push(`port ${e.port ?? "(default)"} → ${t.port ?? "(default)"}`), JSON.stringify(e.proxies) !== JSON.stringify(t.proxies) && n.push("proxies"), JSON.stringify(e.allowedHosts) !== JSON.stringify(t.allowedHosts) && n.push("allowedHosts"), JSON.stringify(e.apis) !== JSON.stringify(t.apis) && n.push("apis"), se(e) !== se(t) && n.push("env"), n;
2583
- }, le = n, ue = A(G), de = () => {
2631
+ }, le = n, ue = A(W), de = () => {
2584
2632
  let e = me(process.execPath, [...process.execArgv, ...process.argv.slice(1)], {
2585
2633
  stdio: "inherit",
2586
2634
  env: process.env,
@@ -2596,8 +2644,8 @@ The wrapper is what carries \`match\`, and what lets \`voltro doctor\` report wh
2596
2644
  }, fe = {
2597
2645
  name: "framework:watch-app-config",
2598
2646
  async configureServer(n) {
2599
- n.watcher.add(G), Q.info("watching app.config.ts for changes", { path: k(e, G) });
2600
- let r = hr.map((t) => O(e, t)), i = new Set(r.map((e) => A(e)));
2647
+ n.watcher.add(W), Q.info("watching app.config.ts for changes", { path: k(e, W) });
2648
+ let r = _r.map((t) => O(e, t)), i = new Set(r.map((e) => A(e)));
2601
2649
  for (let e of r) n.watcher.add(e);
2602
2650
  n.watcher.on("all", (t, r) => {
2603
2651
  i.has(A(r)) && (Q.warn("middleware.ts changed — restarting (it is loaded once per boot)", { path: k(e, r) }), n.close().catch(() => void 0).then(() => {
@@ -2607,10 +2655,10 @@ The wrapper is what carries \`match\`, and what lets \`voltro doctor\` report wh
2607
2655
  let a = async () => {
2608
2656
  try {
2609
2657
  try {
2610
- let e = n.moduleGraph.getModuleById(G);
2658
+ let e = n.moduleGraph.getModuleById(W);
2611
2659
  e && n.moduleGraph.invalidateModule(e);
2612
2660
  } catch {}
2613
- let e = (await n.ssrLoadModule(G, { fixStacktrace: !0 })).default;
2661
+ let e = (await n.ssrLoadModule(W, { fixStacktrace: !0 })).default;
2614
2662
  return typeof e == "object" && e && "type" in e && e.type === "web" ? e : (Q.warn("app.config.ts re-load returned wrong shape", { hasDefault: e !== void 0 }), null);
2615
2663
  } catch (e) {
2616
2664
  return Q.warn("app.config.ts re-load failed — ignoring this change", {}, e), null;
@@ -2644,7 +2692,7 @@ The wrapper is what carries \`match\`, and what lets \`voltro doctor\` report wh
2644
2692
  }
2645
2693
  try {
2646
2694
  let r = Date.now();
2647
- await pi(e, t, await si(e, t)), le = t, n.ws && n.ws.send({
2695
+ await hi(e, t, await li(e, t)), le = t, n.ws && n.ws.send({
2648
2696
  type: "full-reload",
2649
2697
  path: "*"
2650
2698
  }), Q.info("app.config.ts soft-regen", {
@@ -2654,7 +2702,7 @@ The wrapper is what carries \`match\`, and what lets \`voltro doctor\` report wh
2654
2702
  } catch (e) {
2655
2703
  Q.error("app.config.ts soft-regen failed", {}, e);
2656
2704
  }
2657
- }, l = (e) => E(e) === "app.config.ts" ? e === G || A(e) === ue : !1;
2705
+ }, l = (e) => E(e) === "app.config.ts" ? e === W || A(e) === ue : !1;
2658
2706
  n.watcher.on("change", (e) => {
2659
2707
  l(e) && (Q.info("app.config.ts change event (chokidar)", { file: e }), s());
2660
2708
  }), n.watcher.on("add", (e) => {
@@ -2662,7 +2710,7 @@ The wrapper is what carries \`match\`, and what lets \`voltro doctor\` report wh
2662
2710
  });
2663
2711
  try {
2664
2712
  let { watchFile: e } = await import("node:fs");
2665
- e(G, { interval: 500 }, (e, t) => {
2713
+ e(W, { interval: 500 }, (e, t) => {
2666
2714
  e.mtimeMs !== t.mtimeMs && (Q.info("app.config.ts change event (poll)", { mtime: e.mtimeMs }), s());
2667
2715
  }), Q.info("app.config.ts polling watcher attached", { intervalMs: 500 });
2668
2716
  } catch (e) {
@@ -2683,21 +2731,21 @@ The wrapper is what carries \`match\`, and what lets \`voltro doctor\` report wh
2683
2731
  async configureServer(t) {
2684
2732
  let n = [];
2685
2733
  for (let r of a) {
2686
- let i = await ni(e, r.pkg);
2734
+ let i = await ii(e, r.pkg);
2687
2735
  if (i) {
2688
2736
  n.push(i);
2689
2737
  try {
2690
2738
  t.watcher.add(O(i, "rpcGroup.generated.ts"));
2691
2739
  } catch {}
2692
- for (let e of await dr(i)) try {
2740
+ for (let e of await pr(i)) try {
2693
2741
  t.watcher.add(e);
2694
2742
  } catch {}
2695
2743
  }
2696
2744
  }
2697
2745
  if (n.length === 0) return;
2698
- let r = await pr(n), i = null, o = !1, s = async () => {
2746
+ let r = await hr(n), i = null, o = !1, s = async () => {
2699
2747
  if (o) return;
2700
- let e = await pr(n);
2748
+ let e = await hr(n);
2701
2749
  if (e !== void 0 && e !== r) {
2702
2750
  r = e, o = !0, Q.info("the api surface changed — re-bundling the api client + reloading (descriptor edits propagate automatically; no manual restart needed)");
2703
2751
  try {
@@ -2711,7 +2759,7 @@ The wrapper is what carries \`match\`, and what lets \`voltro doctor\` report wh
2711
2759
  }
2712
2760
  }, c = (e) => {
2713
2761
  let t = A(e);
2714
- !lr(t) && !t.endsWith("rpcGroup.generated.ts") || (i && clearTimeout(i), i = setTimeout(() => {
2762
+ !dr(t) && !t.endsWith("rpcGroup.generated.ts") || (i && clearTimeout(i), i = setTimeout(() => {
2715
2763
  s();
2716
2764
  }, 120));
2717
2765
  };
@@ -2963,7 +3011,7 @@ The wrapper is what carries \`match\`, and what lets \`voltro doctor\` report wh
2963
3011
  kind: "web",
2964
3012
  meta: {
2965
3013
  name: n.name ?? "(unnamed)",
2966
- voltroVersion: Nr,
3014
+ voltroVersion: Fr,
2967
3015
  port: l,
2968
3016
  mode: "dev",
2969
3017
  apis: Object.entries(n.apis ?? {}).map(([e, t]) => {
@@ -2981,7 +3029,7 @@ The wrapper is what carries \`match\`, and what lets \`voltro doctor\` report wh
2981
3029
  size: 0,
2982
3030
  entries: []
2983
3031
  }),
2984
- env: () => Te(n.name ?? "app", { contract: oe(n.env) ? n.env : void 0 })
3032
+ env: () => Te(n.name ?? "app", { contract: G(n.env) ? n.env : void 0 })
2985
3033
  }, c = p(o, i, s, { method: e.method ?? "GET" });
2986
3034
  if (c === null) return r();
2987
3035
  t.statusCode = c.status, t.setHeader("content-type", c.contentType);
@@ -3039,29 +3087,36 @@ The wrapper is what carries \`match\`, and what lets \`voltro doctor\` report wh
3039
3087
  if (i !== void 0) return i;
3040
3088
  let t = n.locales ?? [], a = n.defaultLocale ?? t[0] ?? "en";
3041
3089
  return t.length === 0 ? (i = Promise.resolve(() => void 0), i) : (i = (async () => {
3042
- let [{ makeSsgWrap: n }, { makeSsrI18nResolver: i }] = await Promise.all([r("@voltro/i18n"), r("@voltro/i18n/server")]), s = {};
3043
- for (let i of t) if (j(O(e, "src", "locales", `${i}.ts`))) try {
3044
- let t = (await r(O(e, "src", "locales", `${i}.ts`))).default;
3045
- t !== void 0 && (s[i] = n(i, t, a));
3090
+ let [{ makeSsgWrap: i }, { makeSsrI18nResolver: s }] = await Promise.all([r("@voltro/i18n"), r("@voltro/i18n/server")]), c = {};
3091
+ for (let n of t) if (j(O(e, "src", "locales", `${n}.ts`))) try {
3092
+ let t = (await r(O(e, "src", "locales", `${n}.ts`))).default;
3093
+ t !== void 0 && (c[n] = i(n, t, a));
3046
3094
  } catch (e) {
3047
- Q.warn("locale catalog failed to load for SSR", { locale: i }, e);
3095
+ Q.warn("locale catalog failed to load for SSR", { locale: n }, e);
3048
3096
  }
3049
- if (o = Object.keys(s).length > 0, Object.keys(s).length === 0) {
3050
- let { resolveLocale: e } = await r("@voltro/i18n/server");
3051
- return (n, r) => ({
3097
+ if (o = Object.keys(c).length > 0, Object.keys(c).length === 0) {
3098
+ let { resolveLocale: e, resolveTimeZone: i } = await r("@voltro/i18n/server");
3099
+ return (r, o) => ({
3052
3100
  locale: e({
3053
- cookieHeader: n ?? null,
3054
- acceptLanguageHeader: r ?? null,
3101
+ cookieHeader: r ?? null,
3102
+ acceptLanguageHeader: o ?? null,
3055
3103
  supported: t,
3056
3104
  defaultLocale: a
3057
3105
  }),
3106
+ timeZone: i({
3107
+ cookieHeader: r ?? null,
3108
+ configured: n.timeZone ?? null,
3109
+ defaultTimeZone: n.defaultTimeZone ?? null
3110
+ }),
3058
3111
  outerWrap: (e) => e
3059
3112
  });
3060
3113
  }
3061
- return i({
3062
- wraps: s,
3114
+ return s({
3115
+ wraps: c,
3063
3116
  supported: t,
3064
- defaultLocale: a
3117
+ defaultLocale: a,
3118
+ timeZone: n.timeZone ?? null,
3119
+ defaultTimeZone: n.defaultTimeZone ?? null
3065
3120
  });
3066
3121
  })(), i);
3067
3122
  };
@@ -3073,24 +3128,24 @@ The wrapper is what carries \`match\`, and what lets \`voltro doctor\` report wh
3073
3128
  if (d.startsWith("/@") || d.startsWith("/node_modules/") || d.startsWith("/.framework/") || d.startsWith("/_voltro/") || d === "/main.tsx" || d === "/index.html" || d === "/sw.js" || d === "/favicon.ico" || d === "/robots.txt") return l();
3074
3129
  let p = async () => {
3075
3130
  if (X.length === 0) return;
3076
- let e = xr(X, {
3131
+ let e = Cr(X, {
3077
3132
  route: void 0,
3078
3133
  pathname: d
3079
3134
  });
3080
3135
  if (e === void 0) return;
3081
3136
  let t = {};
3082
3137
  for (let [e, n] of Object.entries(i.headers ?? {})) typeof n == "string" ? t[e] = n : Array.isArray(n) && (t[e] = n.join(", "));
3083
- let n = await jr(e, {
3138
+ let n = await Nr(e, {
3084
3139
  pathname: d,
3085
3140
  search: f,
3086
3141
  headers: t,
3087
- cookies: wr(t.cookie),
3142
+ cookies: Er(t.cookie),
3088
3143
  route: void 0
3089
3144
  });
3090
- for (let e of n.setCookies) c.appendHeader("set-cookie", Or(e));
3145
+ for (let e of n.setCookies) c.appendHeader("set-cookie", Ar(e));
3091
3146
  };
3092
3147
  if (/\.[a-z0-9]+$/i.test(d)) return await p(), l();
3093
- let m = ti(d, F.ssrRoutes);
3148
+ let m = ri(d, F.ssrRoutes);
3094
3149
  if (!m) return await p(), l();
3095
3150
  let h = !xe.has(m.route.pattern), g = Date.now();
3096
3151
  h && Q.info(`ssr compiling ${m.route.pattern}`, {
@@ -3112,29 +3167,29 @@ The wrapper is what carries \`match\`, and what lets \`voltro doctor\` report wh
3112
3167
  }
3113
3168
  }, x = !1;
3114
3169
  try {
3115
- let S = await y("loadPage", async () => await r(O(e, "src", "pages", m.route.file))), C = _(S, O("src", "pages", m.route.file)), w = Yr(F.dirs, m.route.dirChain), T = C === "spa" && w.some((e) => e.hasLayout);
3170
+ let S = await y("loadPage", async () => await r(O(e, "src", "pages", m.route.file))), C = _(S, O("src", "pages", m.route.file)), w = Zr(F.dirs, m.route.dirChain), T = C === "spa" && w.some((e) => e.hasLayout);
3116
3171
  if (C !== "ssr" && C !== "isr" && !T) return await p(), l();
3117
3172
  let E = {};
3118
3173
  for (let [e, t] of Object.entries(i.headers ?? {})) typeof t == "string" ? E[e] = t : Array.isArray(t) && (E[e] = t.join(", "));
3119
- let D = await jr(xr(X, {
3174
+ let D = await Nr(Cr(X, {
3120
3175
  route: m.route.pattern,
3121
3176
  pathname: d
3122
3177
  }), {
3123
3178
  pathname: d,
3124
3179
  search: f,
3125
3180
  headers: E,
3126
- cookies: wr(E.cookie),
3181
+ cookies: Er(E.cookie),
3127
3182
  route: m.route.pattern
3128
3183
  }, ze);
3129
- for (let e of D.setCookies) c.appendHeader("set-cookie", Or(e));
3130
- let k = D.headers, A = fi(di(a[0], { allowDevProxy: !0 }), D.headers.cookie, {
3184
+ for (let e of D.setCookies) c.appendHeader("set-cookie", Ar(e));
3185
+ let k = D.headers, A = mi(pi(a[0], { allowDevProxy: !0 }), D.headers.cookie, {
3131
3186
  apiName: a[0]?.name,
3132
3187
  headers: D.headers
3133
3188
  }), j = new AbortController(), M = () => j.abort();
3134
3189
  c.once("close", M);
3135
3190
  let N = null, P = [], ee = {};
3136
3191
  try {
3137
- (await r("@voltro/web/ssr")).beginStoreSeeds(), {chain: P, segmentLoaderData: ee} = await y("loadChain", () => Xr({
3192
+ (await r("@voltro/web/ssr")).beginStoreSeeds(), {chain: P, segmentLoaderData: ee} = await y("loadChain", () => Qr({
3138
3193
  entries: w,
3139
3194
  loadLayout: (t) => r(O(e, "src", "pages", t.dir, "layout.tsx")),
3140
3195
  loadError: (t) => r(O(e, "src", "pages", t.dir, "error.tsx")),
@@ -3163,7 +3218,7 @@ The wrapper is what carries \`match\`, and what lets \`voltro doctor\` report wh
3163
3218
  c.off("close", M);
3164
3219
  }
3165
3220
  let I = await y("loadSsrHelpers", async () => await r("@voltro/web/ssr"));
3166
- T || await cr({
3221
+ T || await ur({
3167
3222
  pageMod: S,
3168
3223
  params: m.params,
3169
3224
  query: A,
@@ -3230,7 +3285,11 @@ The wrapper is what carries \`match\`, and what lets \`voltro doctor\` report wh
3230
3285
  ];
3231
3286
  for (let e of n) await b(e, t, re);
3232
3287
  });
3233
- let H = await y("readShell", Oe), U = await y("transformShell", () => t.transformIndexHtml(u, H)), ie = re.map((e) => `<link rel="stylesheet" href="${e}?direct" />`).join("\n "), W = z?.locale ?? L.cookies["voltro:locale"] ?? n.defaultLocale ?? (n.locales ?? [])[0] ?? "en", ae = Date.now();
3288
+ let H = await y("readShell", Oe), U = await y("transformShell", () => t.transformIndexHtml(u, H)), ie = re.map((e) => `<link rel="stylesheet" href="${e}?direct" />`).join("\n "), ae = z?.locale ?? L.cookies["voltro:locale"] ?? n.defaultLocale ?? (n.locales ?? [])[0] ?? "en", oe = Date.now(), W = {
3289
+ lang: ae,
3290
+ ...z?.timeZone === void 0 ? {} : { timeZone: z.timeZone },
3291
+ renderedAt: oe
3292
+ };
3234
3293
  if (B) {
3235
3294
  let e = (e) => Vn({
3236
3295
  helpers: I,
@@ -3239,13 +3298,13 @@ The wrapper is what carries \`match\`, and what lets \`voltro doctor\` report wh
3239
3298
  interactive: R,
3240
3299
  extra: [ie]
3241
3300
  });
3242
- if (B.hasDeferred) ar({
3301
+ if (B.hasDeferred) sr({
3243
3302
  res: c,
3244
3303
  shell: nr({
3245
3304
  shell: U,
3246
3305
  inlineModuleScriptsAsync: !0
3247
3306
  }),
3248
- htmlLang: W,
3307
+ documentAttrs: W,
3249
3308
  headers: {
3250
3309
  "content-type": "text/html; charset=utf-8",
3251
3310
  "x-voltro-rendered-by": "spa-shell-dev"
@@ -3263,7 +3322,7 @@ The wrapper is what carries \`match\`, and what lets \`voltro doctor\` report wh
3263
3322
  let t = Bn({
3264
3323
  helpers: I,
3265
3324
  prepared: B
3266
- }), n = U.replace("<div id=\"root\"></div>", `<div id="root">${t.body}</div>`).replace("</head>", ` ${e(t.meta)}\n </head>`).replace(/<html(\s+lang="[^"]*")?/i, `<html lang="${W}"`);
3325
+ }), n = ar(U.replace("<div id=\"root\"></div>", `<div id="root">${t.body}</div>`).replace("</head>", ` ${e(t.meta)}\n </head>`), W);
3267
3326
  c.statusCode = 200, c.setHeader("content-type", "text/html; charset=utf-8"), c.setHeader("x-voltro-rendered-by", "spa-shell-dev"), c.end(n);
3268
3327
  }
3269
3328
  } else if (V) {
@@ -3283,13 +3342,13 @@ The wrapper is what carries \`match\`, and what lets \`voltro doctor\` report wh
3283
3342
  requestContext: L,
3284
3343
  ...ne
3285
3344
  };
3286
- if (C === "ssr" && R === "full") ar({
3345
+ if (C === "ssr" && R === "full") sr({
3287
3346
  res: c,
3288
3347
  shell: nr({
3289
3348
  shell: U,
3290
3349
  inlineModuleScriptsAsync: !0
3291
3350
  }),
3292
- htmlLang: W,
3351
+ documentAttrs: W,
3293
3352
  headers: {
3294
3353
  "content-type": "text/html; charset=utf-8",
3295
3354
  "x-voltro-rendered-by": "ssr-dev"
@@ -3304,11 +3363,11 @@ The wrapper is what carries \`match\`, and what lets \`voltro doctor\` report wh
3304
3363
  }
3305
3364
  });
3306
3365
  else {
3307
- let { html: n, meta: r } = I.renderPageToHtml(t), i = U.replace("<div id=\"root\"></div>", `<div id="root">${n}</div>`).replace("</head>", ` ${e(r)}\n </head>`).replace(/<html(\s+lang="[^"]*")?/i, `<html lang="${W}"`);
3366
+ let { html: n, meta: r } = I.renderPageToHtml(t), i = ar(U.replace("<div id=\"root\"></div>", `<div id="root">${n}</div>`).replace("</head>", ` ${e(r)}\n </head>`), W);
3308
3367
  c.statusCode = 200, c.setHeader("content-type", "text/html; charset=utf-8"), c.setHeader("x-voltro-rendered-by", "ssr-dev"), c.end(i);
3309
3368
  }
3310
3369
  }
3311
- v.render = Date.now() - ae;
3370
+ v.render = Date.now() - oe;
3312
3371
  let G = Date.now() - g;
3313
3372
  h ? (xe.add(m.route.pattern), Q.info(`ssr compiled ${m.route.pattern} in ${G}ms`, {
3314
3373
  pattern: m.route.pattern,
@@ -3342,13 +3401,13 @@ The wrapper is what carries \`match\`, and what lets \`voltro doctor\` report wh
3342
3401
  }
3343
3402
  });
3344
3403
  }
3345
- }, je = Date.now(), Me = te.version ?? "?", Ne = await Pr(), Fe = O(e, "node_modules", "@voltro", "ui-shadcn"), Y = j(O(Fe, "package.json")) ? Fe : null, Ie = [], Le = await (async () => {
3404
+ }, je = Date.now(), Me = te.version ?? "?", Ne = await Ir(), Fe = O(e, "node_modules", "@voltro", "ui-shadcn"), Y = j(O(Fe, "package.json")) ? Fe : null, Ie = [], Le = await (async () => {
3346
3405
  let t = [];
3347
3406
  for (let n of a) {
3348
- let r = await ni(e, n.pkg);
3407
+ let r = await ii(e, n.pkg);
3349
3408
  r && t.push(r);
3350
3409
  }
3351
- let n = await pr(t);
3410
+ let n = await hr(t);
3352
3411
  if (n === void 0) return !1;
3353
3412
  let r = O(z, ".voltro-rpcgroup-optimize"), i = "";
3354
3413
  try {
@@ -3364,8 +3423,8 @@ The wrapper is what carries \`match\`, and what lets \`voltro doctor\` report wh
3364
3423
  cookie: e.name,
3365
3424
  hint: "If your IdP client reads this from `document.cookie` (Supabase's `createBrowserClient` does), pass `httpOnly: false`. Otherwise the SSR render succeeds and the user is signed out at the first client-side call. Set `httpOnly: true` explicitly to silence this."
3366
3425
  }));
3367
- }, X = await Ar(e);
3368
- X.length > 0 && Q.info(`middleware.ts loaded — ${X.length} middleware(s): ` + X.map((e) => e.exportName).join(", ")), Cr(X, F.ssrRoutes.map((e) => e.pattern)), Le && Q.info("rpcGroup changed since last boot — forcing a dep re-optimize so the browser loads the current api client");
3426
+ }, X = await Mr(e);
3427
+ X.length > 0 && Q.info(`middleware.ts loaded — ${X.length} middleware(s): ` + X.map((e) => e.exportName).join(", ")), Tr(X, F.ssrRoutes.map((e) => e.pattern)), Le && Q.info("rpcGroup changed since last boot — forcing a dep re-optimize so the browser loads the current api client");
3369
3428
  try {
3370
3429
  await Pe(l, "voltro dev (web)");
3371
3430
  } catch (e) {
@@ -3421,7 +3480,7 @@ The wrapper is what carries \`match\`, and what lets \`voltro doctor\` report wh
3421
3480
  L(),
3422
3481
  R(),
3423
3482
  re,
3424
- ae,
3483
+ oe,
3425
3484
  fe,
3426
3485
  he,
3427
3486
  ge,
@@ -3435,12 +3494,12 @@ The wrapper is what carries \`match\`, and what lets \`voltro doctor\` report wh
3435
3494
  host: !0,
3436
3495
  allowedHosts: n.allowedHosts === !0 || [...n.allowedHosts ?? []],
3437
3496
  proxy: q,
3438
- fs: { allow: [e, ...Br(e)] }
3497
+ fs: { allow: [e, ...Hr(e)] }
3439
3498
  },
3440
3499
  appType: "spa",
3441
3500
  cacheDir: O(z, ".vite"),
3442
3501
  publicDir: O(e, "public")
3443
- })).listen(), Mr.info(`v${Me} ready in ${Date.now() - je}ms`, {
3502
+ })).listen(), Pr.info(`v${Me} ready in ${Date.now() - je}ms`, {
3444
3503
  version: Me,
3445
3504
  bootMs: Date.now() - je
3446
3505
  }), Q.info(`listening on http://localhost:${l}`, {
@@ -3490,23 +3549,23 @@ The wrapper is what carries \`match\`, and what lets \`voltro doctor\` report wh
3490
3549
  url: `http://localhost:${l}`,
3491
3550
  bootMs: Date.now() - je
3492
3551
  }), new Promise(() => {});
3493
- }, vi = async (t) => {
3552
+ }, bi = async (t) => {
3494
3553
  e("serve");
3495
- let n = await gi(t);
3554
+ let n = await vi(t);
3496
3555
  if (!n) return {
3497
3556
  ran: !1,
3498
3557
  exitCode: 0
3499
3558
  };
3500
3559
  let i = Date.now(), a = Q.child("serve");
3501
3560
  a.info("booting voltro serve (preview)", { app: n.name ?? "(unnamed)" });
3502
- let o = await si(t, n);
3561
+ let o = await li(t, n);
3503
3562
  for (let e of o) a.info("api wired", {
3504
3563
  name: e.name,
3505
3564
  pkg: e.pkg
3506
3565
  });
3507
- await pi(t, n, o);
3566
+ await hi(t, n, o);
3508
3567
  {
3509
- let { pages: e } = await Jr(O(t, "src", "pages"));
3568
+ let { pages: e } = await Xr(O(t, "src", "pages"));
3510
3569
  await mt({
3511
3570
  appRoot: t,
3512
3571
  pages: e
@@ -3530,7 +3589,7 @@ The wrapper is what carries \`match\`, and what lets \`voltro doctor\` report wh
3530
3589
  ] },
3531
3590
  build: {
3532
3591
  outDir: "dist",
3533
- rollupOptions: { output: { manualChunks: Hr } }
3592
+ rollupOptions: { output: { manualChunks: Wr } }
3534
3593
  },
3535
3594
  publicDir: O(t, "public")
3536
3595
  });
@@ -3552,4 +3611,4 @@ The wrapper is what carries \`match\`, and what lets \`voltro doctor\` report wh
3552
3611
  }), new Promise(() => {});
3553
3612
  };
3554
3613
  //#endregion
3555
- export { yt as $, rr as A, Cn as B, Ar as C, xr as D, jr as E, zn as F, Xt as G, wn as H, Bn as I, Ft as J, Jt as K, Vn as L, ar as M, In as N, Or as O, Rn as P, bt as Q, Hn as R, kr as S, wr as T, on as U, Pn as V, en as W, St as X, Ct as Y, wt as Z, vi as _, be as _t, Xr as a, He as at, pi as b, Kr as c, We as ct, gi as d, J as dt, mt as et, si as f, De as ft, _i as g, xe as gt, li as h, Ce as ht, fi as i, Be as it, nr as j, cr as k, $ as l, Pe as lt, ai as m, Ee as mt, di as n, nt, hi as o, Ve as ot, ii as p, Te as pt, Bt as q, oi as r, tt as rt, Yr as s, Ue as st, Ur as t, it as tt, qr as u, ke as ut, Hr as v, _e as vt, Sr as w, Cr as x, Jr as y, Tn as z };
3614
+ export { bt as $, ar as A, Tn as B, Mr as C, Cr as D, Nr as E, Rn as F, en as G, Pn as H, zn as I, Bt as J, Xt as K, Bn as L, nr as M, sr as N, Ar as O, In as P, wt as Q, Vn as R, jr as S, Er as T, wn as U, Cn as V, on as W, Ct as X, Ft as Y, St as Z, bi as _, xe as _t, Qr as a, Be as at, hi as b, Jr as c, Ue as ct, vi as d, ke as dt, yt as et, li as f, J as ft, yi as g, Ce as gt, di as h, Ee as ht, mi as i, tt as it, rr as j, ur as k, $ as l, We as lt, si as m, Te as mt, pi as n, it as nt, _i as o, He as ot, oi as p, De as pt, Jt as q, ci as r, nt as rt, Zr as s, Ve as st, Gr as t, mt as tt, Yr as u, Pe as ut, Wr as v, be as vt, wr as w, Tr as x, Xr as y, _e as yt, Hn as z };