@voltro/cli 0.59.0 → 0.61.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 (96) hide show
  1. package/CHANGELOG.md +83 -0
  2. package/dist/apiBuild-5U7PxjLa.js +2 -0
  3. package/dist/{apiBuild-BU5cd-Fn.js → apiBuild-C5HhMAEm.js} +2 -2
  4. package/dist/bin.js +1 -1
  5. package/dist/{build-uRMZrT8z.js → build-DQr7SsKK.js} +21 -17
  6. package/dist/{checkCommand-C1CQc8lD.js → checkCommand-ByaOhdc8.js} +1 -1
  7. package/dist/{checkCommand-DC7k1_hP.js → checkCommand-CvSheSdb.js} +3 -3
  8. package/dist/{codegenCommand-kS3Twuc9.js → codegenCommand-CI0mpjxo.js} +1 -1
  9. package/dist/{codemodRunner-kNnh1I7_.js → codemodRunner-Drb-H-jr.js} +258 -159
  10. package/dist/{commands-cu34ENUT.js → commands-pCItjdHG.js} +21 -21
  11. package/dist/{dashboardCommand-gG1y4PFG.js → dashboardCommand-O-ToEgiH.js} +3 -3
  12. package/dist/{dataCommand-hNOGKz4K.js → dataCommand-mn1Zc88W.js} +1 -1
  13. package/dist/{dev-Ce2gEziv.js → dev-dSH-Pkb2.js} +1 -1
  14. package/dist/{dev-Dff_pdik.js → dev-kn9-7RXZ.js} +1 -1
  15. package/dist/doctorCommand-BVat2ejT.js +2 -0
  16. package/dist/{doctorCommand-CGjefPmk.js → doctorCommand-ClB7Ucz5.js} +13 -13
  17. package/dist/{dormancyCommand-DYgI0Kf-.js → dormancyCommand-DZupfuq-.js} +1 -1
  18. package/dist/{embeddingsCommand-yJivQSrI.js → embeddingsCommand-D8_GquVX.js} +1 -1
  19. package/dist/{envCommand-ORJUf8r_.js → envCommand-DRjVSXRp.js} +2 -2
  20. package/dist/{evolveCommand-8CuFBlbQ.js → evolveCommand-Cb0C2b3V.js} +2 -2
  21. package/dist/index.js +1 -1
  22. package/dist/{infoCommand-D02A4WI2.js → infoCommand-BlKnoY2D.js} +1 -1
  23. package/dist/{probeCommand-BUYzc0CT.js → probeCommand-DYsOFm62.js} +1 -1
  24. package/dist/{runtimeTrace-DDuKJgVi.js → runtimeTrace-BI3kdicc.js} +1 -1
  25. package/dist/{sdkgen-vq1fF9D_.js → sdkgen-DZ4zCtV4.js} +1 -1
  26. package/dist/serveCommand-CwK_6Wxt.js +2 -0
  27. package/dist/{serveCommand-Dr4KXmTS.js → serveCommand-DnxqCQ16.js} +3 -3
  28. package/dist/serveEntry.js +1 -1
  29. package/dist/{start-C75w6ftA.js → start-DE4ixCTi.js} +1 -1
  30. package/dist/{start-DNtIlBcn.js → start-bqT4GRH0.js} +286 -226
  31. package/dist/startEntry.js +1 -1
  32. package/dist/{updateCommand-Bw3mCUDT.js → updateCommand-B18ZQNFg.js} +1 -1
  33. package/dist/updateCommand-B4EgDD-m.js +2 -0
  34. package/dist/{webDev-CBN9KkyQ.js → webDev-CYjhmOTZ.js} +1 -1
  35. package/dist/{webDev-Bzb8ZFus.js → webDev-CuG3Ged-.js} +1 -1
  36. package/dist/{webhooksCommand-BPJQOGTe.js → webhooksCommand-Bs-HZ4wY.js} +1 -1
  37. package/package.json +37 -19
  38. package/templates/AGENTS.md +2 -2
  39. package/templates/agent-docs/_index.md +2 -2
  40. package/templates/agent-docs/_manifest.json +1 -1
  41. package/templates/agent-docs/data.md +10 -2
  42. package/templates/agent-docs/observability.md +7 -1
  43. package/templates/agent-docs/plugins/sentry.md +121 -17
  44. package/templates/agent-docs/schema-driven-ui.md +38 -10
  45. package/templates/agent-docs/whats-new.md +11 -41
  46. package/templates/apps/api-ai/package.json +6 -6
  47. package/templates/apps/api-auth/package.json +8 -8
  48. package/templates/apps/api-backend/package.json +7 -7
  49. package/templates/apps/api-backend-deactivation/package.json +7 -7
  50. package/templates/apps/api-backend-mail/package.json +8 -8
  51. package/templates/apps/api-backend-mariadb/package.json +9 -9
  52. package/templates/apps/api-backend-sqlite/package.json +8 -8
  53. package/templates/apps/api-backend-storage/package.json +8 -8
  54. package/templates/apps/api-cms/package.json +9 -9
  55. package/templates/apps/api-collab/package.json +8 -8
  56. package/templates/apps/api-data-advanced/package.json +8 -8
  57. package/templates/apps/api-durable/package.json +8 -8
  58. package/templates/apps/api-feature-flags/package.json +9 -9
  59. package/templates/apps/api-governance/package.json +8 -8
  60. package/templates/apps/api-kv/package.json +8 -8
  61. package/templates/apps/api-moderation/package.json +8 -8
  62. package/templates/apps/api-observability/package.json +8 -8
  63. package/templates/apps/api-ratelimit/package.json +8 -8
  64. package/templates/apps/api-rbac/package.json +8 -8
  65. package/templates/apps/api-rest/package.json +7 -7
  66. package/templates/apps/api-row-history/package.json +8 -8
  67. package/templates/apps/api-saas/package.json +11 -11
  68. package/templates/apps/api-saas-starter/package.json +10 -10
  69. package/templates/apps/api-search/package.json +8 -8
  70. package/templates/apps/api-status/package.json +8 -8
  71. package/templates/apps/api-webhooks/package.json +9 -9
  72. package/templates/apps/changelog/package.json +7 -7
  73. package/templates/apps/edge-functions/package.json +2 -2
  74. package/templates/apps/frontend-admin/package.json +7 -7
  75. package/templates/apps/frontend-app/package.json +8 -8
  76. package/templates/apps/frontend-auth/package.json +7 -7
  77. package/templates/apps/frontend-blank/package.json +6 -6
  78. package/templates/apps/frontend-cms/package.json +8 -8
  79. package/templates/apps/frontend-collab/package.json +9 -9
  80. package/templates/apps/frontend-contact/package.json +7 -7
  81. package/templates/apps/frontend-dashboard/package.json +6 -6
  82. package/templates/apps/frontend-docs/package.json +8 -8
  83. package/templates/apps/frontend-i18n/package.json +6 -6
  84. package/templates/apps/frontend-landing/package.json +7 -7
  85. package/templates/apps/frontend-portal/package.json +7 -7
  86. package/templates/apps/frontend-saas/package.json +7 -7
  87. package/templates/apps/frontend-spa/package.json +6 -6
  88. package/templates/apps/frontend-ssr/package.json +6 -6
  89. package/templates/apps/frontend-ssr-api/package.json +7 -7
  90. package/templates/apps/frontend-static-blog/package.json +8 -8
  91. package/templates/apps/frontend-status/package.json +7 -7
  92. package/templates/apps/mobile-app/package.json +4 -4
  93. package/dist/apiBuild-B9OvhITV.js +0 -2
  94. package/dist/doctorCommand-DXnNpKQT.js +0 -2
  95. package/dist/serveCommand-1R52mo6F.js +0 -2
  96. package/dist/updateCommand-inInBIAh.js +0 -2
@@ -1,5 +1,5 @@
1
1
  import { i as e, t } from "./nodeEnvironment-cGFAj1J8.js";
2
- import { $ as n, $t as r, A as i, B as a, D as o, E as s, Et as c, F as l, Ft as u, G as d, H as ee, I as f, It as p, J as m, K as te, L as h, Lt as g, M as _, N as v, O as y, P as b, Pt as x, Q as ne, Qt as S, R as C, Rt as w, T as re, U as ie, W as ae, X as T, Y as E, Yt as oe, Z as se, a as ce, bt as le, c as D, en as ue, et as de, ft as fe, h as O, it as pe, j as me, jt as k, k as he, lt as A, m as j, mt as ge, n as _e, nt as ve, ot as ye, q as M, rt as be, s as xe, st as Se, tn as Ce, tt as N, u as we, xt as Te, z as P } from "./webDev-CBN9KkyQ.js";
2
+ import { $ as n, $t as r, A as i, B as a, D as o, E as s, Et as c, F as l, Ft as u, G as d, H as ee, I as f, It as p, J as m, K as te, L as h, Lt as g, M as _, N as v, O as y, P as b, Pt as x, Q as S, Qt as C, R as ne, Rt as w, T as re, U as ie, W as ae, X as T, Y as E, Yt as oe, Z as se, a as ce, bt as le, c as D, en as ue, et as de, ft as fe, h as O, it as pe, j as me, jt as k, k as he, lt as A, m as j, mt as ge, n as _e, nt as ve, ot as ye, q as M, rt as be, s as xe, st as Se, tn as Ce, tt as N, u as we, xt as Te, z as P } from "./webDev-CYjhmOTZ.js";
3
3
  import { A as F, I as Ee, M as De, O as Oe, g as ke, j as Ae, o as je } from "./inspect-PcC5J-Dl.js";
4
4
  import { r as Me } from "./appPort-B_HpJ_ck.js";
5
5
  import { o as Ne, t as Pe } from "./connectionConfig-Bk9IC7D0.js";
@@ -16,13 +16,14 @@ import { createLogger as H, printReadyBlock as et } from "@voltro/logger";
16
16
  import { appMode as tt, frameworkVersion as nt, setProcessBootPath as rt } from "@voltro/protocol/identity";
17
17
  import { applyKeepAlive as it, maybeCompress as U, negotiateEncoding as at, resolveKeepAlive as ot, snapshotMetricsSync as st } from "@voltro/runtime";
18
18
  import { Effect as ct } from "effect";
19
- import { createHash as W } from "node:crypto";
20
- import { resolveBroadcastProvider as lt } from "@voltro/plugin-broadcast";
21
- import { createServer as ut } from "node:http";
19
+ import { createRequire as W } from "node:module";
20
+ import { createHash as lt } from "node:crypto";
21
+ import { resolveBroadcastProvider as ut } from "@voltro/plugin-broadcast";
22
+ import { createServer as dt } from "node:http";
22
23
  //#region src/inertPublicEnv.ts
23
- var dt = "VOLTRO_PUBLIC_", ft = (e, t) => {
24
+ var ft = "VOLTRO_PUBLIC_", pt = (e, t) => {
24
25
  let n = [];
25
- for (let [r, i] of Object.entries(e)) if (r.startsWith(dt) && i !== void 0 && i !== "") {
26
+ for (let [r, i] of Object.entries(e)) if (r.startsWith(ft) && i !== void 0 && i !== "") {
26
27
  if (t === void 0 || !(r in t)) {
27
28
  n.push({
28
29
  key: r,
@@ -36,15 +37,15 @@ var dt = "VOLTRO_PUBLIC_", ft = (e, t) => {
36
37
  });
37
38
  }
38
39
  return n.sort((e, t) => e.key.localeCompare(t.key));
39
- }, pt = (e) => {
40
+ }, mt = (e) => {
40
41
  let t = e.map((e) => e.baked === "absent" ? ` • ${e.key} — not in the bundle at all` : ` • ${e.key} — the bundle carries a DIFFERENT value; the built one wins`);
41
42
  return `${e.length} VOLTRO_PUBLIC_* variable${e.length === 1 ? "" : "s"} set in this process's environment cannot reach the browser:\n${t.join("\n")}\n Public values are BAKED into the bundle by \`voltro build\` — that is what makes them
42
43
  readable in a browser — so they must exist when the bundle is BUILT, not when it runs.
43
44
  → pass them to the build (a Docker build-arg / CI build step), not as deployment env.`;
44
- }, mt = (e) => `W/"${W("md5").update(e).digest("hex")}"`, ht = (e) => {
45
+ }, ht = (e) => `W/"${lt("md5").update(e).digest("hex")}"`, gt = (e) => {
45
46
  let { response: t, status: n, headers: r, body: i, requestHeaders: a } = e, o = r["cache-control"], s = (typeof o == "string" ? o : "").toLowerCase();
46
47
  if (i === void 0 || n !== 200 || s.includes("no-store")) return !1;
47
- let c = r["content-type"], l = typeof c == "string" ? c : void 0, u = r.etag, d = typeof u == "string" ? u : mt(i), ee = a["if-none-match"];
48
+ let c = r["content-type"], l = typeof c == "string" ? c : void 0, u = r.etag, d = typeof u == "string" ? u : ht(i), ee = a["if-none-match"];
48
49
  if (ee !== void 0 && ee.split(",").some((e) => e.trim() === d)) return t.writeHead(304, {
49
50
  ...r,
50
51
  etag: d
@@ -64,7 +65,7 @@ var dt = "VOLTRO_PUBLIC_", ft = (e, t) => {
64
65
  etag: d
65
66
  };
66
67
  return f.compressed && delete p["content-length"], t.writeHead(n, p), t.end(Buffer.from(f.bytes)), !0;
67
- }, G = H({ scope: "voltro:start:cdc" }), gt = (e) => (t) => {
68
+ }, G = H({ scope: "voltro:start:cdc" }), _t = (e) => (t) => {
68
69
  let n = 0;
69
70
  for (let [r, i] of e.tableSubscriptionsByPattern) {
70
71
  if (!i.includes(t)) continue;
@@ -75,13 +76,13 @@ var dt = "VOLTRO_PUBLIC_", ft = (e, t) => {
75
76
  }));
76
77
  }
77
78
  return n;
78
- }, K = () => Pe() ? Ne() : null, _t = (e) => {
79
- let t = e.channel ?? "framework_changes", n = e.revalidateChannel ?? "voltro_revalidate", r = gt(e), i = null, a = null;
79
+ }, vt = () => Pe() ? Ne() : null, yt = (e) => {
80
+ let t = e.channel ?? "framework_changes", n = e.revalidateChannel ?? "voltro_revalidate", r = _t(e), i = null, a = null;
80
81
  return {
81
82
  start: async () => {
82
83
  let o = e.tableSubscriptionsByPattern.size > 0, s = e.onRevalidate !== void 0;
83
84
  if (!o && !s) return G.debug("skipped — no pages declare cacheInvalidatesOn and no revalidation handler is wired"), !1;
84
- let c = K();
85
+ let c = vt();
85
86
  if (!c && !o) return G.debug("no database configured — the revalidation LISTEN line is unavailable"), !1;
86
87
  if (!c) return G.warn(`${e.tableSubscriptionsByPattern.size} route(s) declare \`cacheInvalidatesOn\` and will NOT be invalidated live — no database is configured for this web process. Set DB_URL (or DB_HOST / PG_HOST) so the CDC listener can connect; until then those routes go stale until their \`revalidate\` window expires.`, { routes: [...e.tableSubscriptionsByPattern.keys()] }), !1;
87
88
  i = new (await (import("pg"))).default.Client(c), await i.connect(), a = (i) => {
@@ -123,7 +124,7 @@ var dt = "VOLTRO_PUBLIC_", ft = (e, t) => {
123
124
  }
124
125
  }
125
126
  };
126
- }, vt = H({ scope: "voltro:start:isr-cache" }), q = "voltro_isr_cache", yt = (e) => `
127
+ }, K = H({ scope: "voltro:start:isr-cache" }), bt = "voltro_isr_cache", xt = (e) => `
127
128
  CREATE TABLE IF NOT EXISTS ${e} (
128
129
  cache_key TEXT PRIMARY KEY,
129
130
  html TEXT NOT NULL,
@@ -134,9 +135,9 @@ CREATE TABLE IF NOT EXISTS ${e} (
134
135
  stale_while_revalidate_ms BIGINT NOT NULL DEFAULT 0
135
136
  );
136
137
  CREATE INDEX IF NOT EXISTS ${e}_servable_until_idx ON ${e} (servable_until);
137
- `, bt = (e) => {
138
- let t = e.tableName ?? q, { client: n } = e, r = /* @__PURE__ */ new Map(), i = !1, a = (async () => {
139
- i || (i = !0, await n.query(yt(t)));
138
+ `, St = (e) => {
139
+ let t = e.tableName ?? bt, { client: n } = e, r = /* @__PURE__ */ new Map(), i = !1, a = (async () => {
140
+ i || (i = !0, await n.query(xt(t)));
140
141
  })().then(async () => {
141
142
  let e = await n.query(`SELECT * FROM ${t}`);
142
143
  for (let t of e.rows) r.set(t.cache_key, {
@@ -148,10 +149,10 @@ CREATE INDEX IF NOT EXISTS ${e}_servable_until_idx ON ${e} (servable_until);
148
149
  staleWhileRevalidateMs: Number(t.stale_while_revalidate_ms)
149
150
  });
150
151
  }).catch((e) => {
151
- vt.warn("postgres bootstrap failed", {}, e);
152
+ K.warn("postgres bootstrap failed", {}, e);
152
153
  }), o = (e, t) => {
153
154
  a.then(() => n.query(e, t)).catch((e) => {
154
- vt.warn("postgres write failed", {}, e);
155
+ K.warn("postgres write failed", {}, e);
155
156
  });
156
157
  }, s = /* @__PURE__ */ new Map(), c = (e) => {
157
158
  s.set(e, (s.get(e) ?? 0) + 1);
@@ -202,21 +203,21 @@ CREATE INDEX IF NOT EXISTS ${e}_servable_until_idx ON ${e} (servable_until);
202
203
  return Array.from(r.entries());
203
204
  }
204
205
  };
205
- }, J = H({ scope: "voltro:start:revalidate" }), xt = (e) => {
206
+ }, q = H({ scope: "voltro:start:revalidate" }), Ct = (e) => {
206
207
  try {
207
208
  let t = JSON.parse(e);
208
209
  return (t.kind === "path" || t.kind === "table" || t.kind === "tag") && typeof t.value == "string" && t.value.length > 0 && (t.tenant === void 0 || typeof t.tenant == "string") ? {
209
210
  kind: t.kind,
210
211
  value: t.value,
211
212
  ...t.tenant === void 0 ? {} : { tenant: t.tenant }
212
- } : (J.warn("bad revalidation payload (shape)", { payload: e }), null);
213
+ } : (q.warn("bad revalidation payload (shape)", { payload: e }), null);
213
214
  } catch {
214
- return J.warn("bad revalidation payload (not JSON)", { payload: e }), null;
215
+ return q.warn("bad revalidation payload (not JSON)", { payload: e }), null;
215
216
  }
216
- }, St = (e, t) => {
217
+ }, wt = (e, t) => {
217
218
  if (t.kind === "table" || t.kind === "tag") {
218
219
  let n = e.tableSink(t.value);
219
- return J.info(`revalidate ${t.kind} '${t.value}' → dropped ${n} cache entries`, {
220
+ return q.info(`revalidate ${t.kind} '${t.value}' → dropped ${n} cache entries`, {
220
221
  kind: t.kind,
221
222
  value: t.value,
222
223
  dropped: n
@@ -225,7 +226,7 @@ CREATE INDEX IF NOT EXISTS ${e}_servable_until_idx ON ${e} (servable_until);
225
226
  let n = t.value, r = (e) => t.tenant === void 0 || e.split("|").includes(`tenant=${t.tenant}`), i = e.regexByPattern.get(n);
226
227
  if (i !== void 0) {
227
228
  let a = e.renderModeByPattern.get(n);
228
- if (a !== "isr") return J.error(`revalidatePath('${n}') targets a '${a ?? "unknown"}' route — only \`renderMode: 'isr'\` routes have cache entries to drop. Static HTML is a build artifact this process never re-renders; rebuild to change it.`, {
229
+ if (a !== "isr") return q.error(`revalidatePath('${n}') targets a '${a ?? "unknown"}' route — only \`renderMode: 'isr'\` routes have cache entries to drop. Static HTML is a build artifact this process never re-renders; rebuild to change it.`, {
229
230
  path: n,
230
231
  renderMode: a ?? "unknown"
231
232
  }), 0;
@@ -233,27 +234,67 @@ CREATE INDEX IF NOT EXISTS ${e}_servable_until_idx ON ${e} (servable_until);
233
234
  let t = e.split("|")[0] ?? e;
234
235
  return i.test(t) && r(e);
235
236
  });
236
- return J.info(`revalidate path pattern '${n}' → dropped ${o} cache entries`, {
237
+ return q.info(`revalidate path pattern '${n}' → dropped ${o} cache entries`, {
237
238
  path: n,
238
239
  dropped: o,
239
240
  ...t.tenant === void 0 ? {} : { tenant: t.tenant }
240
241
  }), o;
241
242
  }
242
243
  let a = [...e.regexByPattern.entries()].find(([, e]) => e.test(n));
243
- if (a === void 0) return J.error(`revalidatePath('${n}') matches no declared route — nothing was dropped. Pass a declared route pattern (e.g. /blog/[slug]) or a concrete path of one.`, { path: n }), 0;
244
+ if (a === void 0) return q.error(`revalidatePath('${n}') matches no declared route — nothing was dropped. Pass a declared route pattern (e.g. /blog/[slug]) or a concrete path of one.`, { path: n }), 0;
244
245
  let o = e.renderModeByPattern.get(a[0]);
245
- if (o !== "isr") return J.error(`revalidatePath('${n}') targets a '${o ?? "unknown"}' route (${a[0]}) — only \`renderMode: 'isr'\` routes have cache entries to drop.`, {
246
+ if (o !== "isr") return q.error(`revalidatePath('${n}') targets a '${o ?? "unknown"}' route (${a[0]}) — only \`renderMode: 'isr'\` routes have cache entries to drop.`, {
246
247
  path: n,
247
248
  route: a[0],
248
249
  renderMode: o ?? "unknown"
249
250
  }), 0;
250
251
  let s = e.cache.invalidateBy((e) => (e.split("|")[0] ?? e) === n && r(e));
251
- return J.info(`revalidate path '${n}' → dropped ${s} cache entries`, {
252
+ return q.info(`revalidate path '${n}' → dropped ${s} cache entries`, {
252
253
  path: n,
253
254
  dropped: s,
254
255
  ...t.tenant === void 0 ? {} : { tenant: t.tenant }
255
256
  }), s;
256
- }, Y = H({ scope: "voltro:start" }), Ct = nt() ?? "unknown", X = (e) => e instanceof Error && e._voltroControl === "redirect" && typeof e.location == "string", wt = (e) => e instanceof Error && e._voltroControl === "not-found", Tt = {
257
+ }, Tt = async (e) => {
258
+ let t = W(R(e, "package.json")), n;
259
+ try {
260
+ n = t.resolve("@voltro/plugin-sentry/server");
261
+ } catch {
262
+ return { reason: "SENTRY_DSN is set but `@voltro/plugin-sentry` is not installed in this app — the web server cannot report SSR errors. → `pnpm add @voltro/plugin-sentry` in the web app." };
263
+ }
264
+ try {
265
+ return await import(V(n).href);
266
+ } catch (e) {
267
+ return { reason: `@voltro/plugin-sentry/server resolved but could not be loaded: ${e instanceof Error ? e.message : String(e)}` };
268
+ }
269
+ }, Et = async (e, t, n, r = {}) => {
270
+ let i = t.SENTRY_DSN;
271
+ if (i === void 0 || i === "") return;
272
+ let a = await (r.load ?? Tt)(e);
273
+ if ("reason" in a) {
274
+ n.warn(a.reason);
275
+ return;
276
+ }
277
+ let o = {
278
+ dsn: i,
279
+ environment: t.SENTRY_ENVIRONMENT,
280
+ release: t.SENTRY_RELEASE,
281
+ traces: !1
282
+ }, s = await a.initSentryServer(o, n);
283
+ if (s !== void 0) return n.info("sentry active", {
284
+ ...a.sentryActiveFields(s, o),
285
+ process: "web"
286
+ }), (e, t) => {
287
+ try {
288
+ s.sdk.captureException(e, {
289
+ tags: {
290
+ "voltro.process": "web",
291
+ "voltro.stage": t.stage
292
+ },
293
+ ...t.pathname === void 0 ? {} : { extra: { pathname: t.pathname } }
294
+ });
295
+ } catch {}
296
+ };
297
+ }, J = H({ scope: "voltro:start" }), Dt = nt() ?? "unknown", Ot = (e) => e instanceof Error && e._voltroControl === "redirect" && typeof e.location == "string", kt = (e) => e instanceof Error && e._voltroControl === "not-found", At = {
257
298
  ".html": "text/html; charset=utf-8",
258
299
  ".js": "application/javascript",
259
300
  ".mjs": "application/javascript",
@@ -271,13 +312,13 @@ CREATE INDEX IF NOT EXISTS ${e}_servable_until_idx ON ${e} (servable_until);
271
312
  ".woff": "font/woff",
272
313
  ".woff2": "font/woff2",
273
314
  ".txt": "text/plain; charset=utf-8"
274
- }, Et = (e) => Tt[L(e).toLowerCase()] ?? "application/octet-stream", Dt = (e) => e.replace(/<script\b(?=[^>]*\btype="module")(?:(?!<\/script>).)*<\/script>/gi, "").replace(/<script\b(?=[^>]*\bsrc=)(?:(?!<\/script>).)*<\/script>/gi, "").replace(/<link\b[^>]*\brel="modulepreload"[^>]*>/gi, ""), Z = async (e) => {
315
+ }, jt = (e) => At[L(e).toLowerCase()] ?? "application/octet-stream", Mt = (e) => e.replace(/<script\b(?=[^>]*\btype="module")(?:(?!<\/script>).)*<\/script>/gi, "").replace(/<script\b(?=[^>]*\bsrc=)(?:(?!<\/script>).)*<\/script>/gi, "").replace(/<link\b[^>]*\brel="modulepreload"[^>]*>/gi, ""), Y = async (e) => {
275
316
  try {
276
317
  return await B.stat(e), !0;
277
318
  } catch {
278
319
  return !1;
279
320
  }
280
- }, Ot = (e) => {
321
+ }, Nt = (e) => {
281
322
  let t = [], n = 0, r = e.split("/").filter(Boolean), i = [];
282
323
  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, "\\$&"));
283
324
  let a = i.join("/");
@@ -286,8 +327,8 @@ CREATE INDEX IF NOT EXISTS ${e}_servable_until_idx ON ${e} (servable_until);
286
327
  paramNames: t,
287
328
  priority: n
288
329
  };
289
- }, kt = (e) => e.map((e) => {
290
- let { regex: t, paramNames: n, priority: r } = Ot(e.pattern);
330
+ }, Pt = (e) => e.map((e) => {
331
+ let { regex: t, paramNames: n, priority: r } = Nt(e.pattern);
291
332
  return {
292
333
  pattern: e.pattern,
293
334
  file: e.file,
@@ -296,7 +337,7 @@ CREATE INDEX IF NOT EXISTS ${e}_servable_until_idx ON ${e} (servable_until);
296
337
  paramNames: n,
297
338
  priority: r
298
339
  };
299
- }).slice().sort((e, t) => e.priority - t.priority), At = (e, t) => {
340
+ }).slice().sort((e, t) => e.priority - t.priority), Ft = (e, t) => {
300
341
  for (let n of t) {
301
342
  let t = n.regex.exec(e);
302
343
  if (!t) continue;
@@ -308,7 +349,7 @@ CREATE INDEX IF NOT EXISTS ${e}_servable_until_idx ON ${e} (servable_until);
308
349
  };
309
350
  }
310
351
  return null;
311
- }, jt = null, Mt, Nt = (e, t) => t === void 0 ? Promise.resolve() : (Mt ??= (async () => {
352
+ }, X = null, It, Lt = (e, t) => t === void 0 ? Promise.resolve() : (It ??= (async () => {
312
353
  try {
313
354
  let n = await e.getHelpers(), r = n.apiDescriptors?.[t];
314
355
  if (r === void 0) return;
@@ -316,9 +357,9 @@ CREATE INDEX IF NOT EXISTS ${e}_servable_until_idx ON ${e} (servable_until);
316
357
  if (i === void 0) return;
317
358
  i(t, await r());
318
359
  } catch {}
319
- })(), Mt), Pt = async (e) => {
360
+ })(), It), Rt = async (e) => {
320
361
  let { provider: t, route: r, params: i, pathname: a, dirs: o, shellTemplate: s, requestHeaders: c, requestUrl: l = "", apiOrigin: u, apiName: d } = e;
321
- await Nt(t, d);
362
+ await Lt(t, d);
322
363
  let { search: p } = be(l), g = await ie(ae(e.middlewares ?? [], {
323
364
  route: r.pattern,
324
365
  pathname: a
@@ -328,9 +369,9 @@ CREATE INDEX IF NOT EXISTS ${e}_servable_until_idx ON ${e} (servable_until);
328
369
  headers: c,
329
370
  cookies: ee(c.cookie),
330
371
  route: r.pattern
331
- }, e.onCookieWarning), y = await t.getPage(r.pattern, r.file), x = e.forceSsrRender === !0 ? "ssr" : ze(y, r.file), ne = x === "isr" && y.ppr === !0, S = x === "isr" && e.holesOnly !== !0 ? h(g.headers) : g.headers, C = xe(u, S.cookie, {
372
+ }, e.onCookieWarning), y = await t.getPage(r.pattern, r.file), x = e.forceSsrRender === !0 ? "ssr" : ze(y, r.file), S = x === "isr" && y.ppr === !0, C = x === "isr" && e.holesOnly !== !0 ? h(g.headers) : g.headers, ne = xe(u, C.cookie, {
332
373
  apiName: d,
333
- headers: S
374
+ headers: C
334
375
  });
335
376
  if (e.holesOnly === !0) {
336
377
  if (typeof y.loader != "function") return null;
@@ -343,8 +384,8 @@ CREATE INDEX IF NOT EXISTS ${e}_servable_until_idx ON ${e} (servable_until);
343
384
  pathname: a,
344
385
  search: p,
345
386
  signal: e.signal,
346
- headers: S,
347
- query: C,
387
+ headers: C,
388
+ query: ne,
348
389
  isServer: !0
349
390
  },
350
391
  helpers: await t.getHelpers(),
@@ -355,7 +396,7 @@ CREATE INDEX IF NOT EXISTS ${e}_servable_until_idx ON ${e} (servable_until);
355
396
  }
356
397
  let w = x === "spa" && we(o, r.dirChain).some((e) => e.hasLayout);
357
398
  if (x !== "ssr" && x !== "isr" && !w) return null;
358
- let re = we(o, r.dirChain), oe = {}, ce = null, le, ue = new AbortController(), fe = ne ? b(S, r.pattern) : S;
399
+ let re = we(o, r.dirChain), oe = {}, ce = null, le, ue = new AbortController(), fe = S ? b(C, r.pattern) : C;
359
400
  try {
360
401
  (await t.getHelpers()).beginStoreSeeds(), {chain: le, segmentLoaderData: oe} = await D({
361
402
  entries: re,
@@ -368,7 +409,7 @@ CREATE INDEX IF NOT EXISTS ${e}_servable_until_idx ON ${e} (servable_until);
368
409
  search: p,
369
410
  signal: ue.signal,
370
411
  headers: fe,
371
- query: C,
412
+ query: ne,
372
413
  isServer: !0
373
414
  }
374
415
  }), typeof y.loader == "function" && !w && (ce = await y.loader({
@@ -377,18 +418,18 @@ CREATE INDEX IF NOT EXISTS ${e}_servable_until_idx ON ${e} (servable_until);
377
418
  search: p,
378
419
  signal: ue.signal,
379
420
  headers: fe,
380
- query: C,
421
+ query: ne,
381
422
  isServer: !0
382
423
  }));
383
424
  } catch (e) {
384
- if (X(e)) return {
425
+ if (Ot(e)) return {
385
426
  control: "redirect",
386
427
  status: e.status,
387
428
  location: e.location,
388
429
  setCookies: g.setCookies,
389
430
  responseHeaders: g.responseHeaders
390
431
  };
391
- if (wt(e)) return {
432
+ if (kt(e)) return {
392
433
  control: "not-found",
393
434
  setCookies: g.setCookies,
394
435
  responseHeaders: g.responseHeaders
@@ -399,11 +440,11 @@ CREATE INDEX IF NOT EXISTS ${e}_servable_until_idx ON ${e} (servable_until);
399
440
  w || await te({
400
441
  pageMod: y,
401
442
  params: i,
402
- query: C,
443
+ query: ne,
403
444
  apiName: d,
404
445
  seed: O.seedPreloadedSubscription,
405
446
  seedFailure: O.seedPreloadedSubscriptionFailure,
406
- onError: ({ tag: e, apiName: t }, n) => Y.warn("preload seed failed", {
447
+ onError: ({ tag: e, apiName: t }, n) => J.warn("preload seed failed", {
407
448
  tag: e,
408
449
  apiName: t,
409
450
  pathname: a
@@ -421,11 +462,11 @@ CREATE INDEX IF NOT EXISTS ${e}_servable_until_idx ON ${e} (servable_until);
421
462
  };
422
463
  if (x === "isr" && g.cspNonce !== void 0) throw Error(`page '${r.pattern}' is renderMode 'isr' while middleware.ts mints a cspNonce — an isr render is CACHED and a cached nonce is a lie the browser enforces. Use renderMode 'ssr' for nonce'd pages, or a hash-based CSP for isr.`);
423
464
  let me = {
424
- cookies: ne ? v(f(g.cookies), r.pattern) : x === "isr" ? f(g.cookies) : g.cookies,
465
+ cookies: S ? v(f(g.cookies), r.pattern) : x === "isr" ? f(g.cookies) : g.cookies,
425
466
  headers: fe,
426
467
  url: l,
427
468
  ...e.formFlash === void 0 ? {} : { formFlash: e.formFlash }
428
- }, k = O.i18n?.resolve(S.cookie, S["accept-language"]), he = {
469
+ }, k = O.i18n?.resolve(C.cookie, C["accept-language"]), he = {
429
470
  lang: k?.locale ?? me.cookies["voltro:locale"] ?? "en",
430
471
  ...k?.timeZone === void 0 ? {} : { timeZone: k.timeZone },
431
472
  renderedAt: Date.now()
@@ -478,7 +519,10 @@ CREATE INDEX IF NOT EXISTS ${e}_servable_until_idx ON ${e} (servable_until);
478
519
  ...g.cspNonce === void 0 ? {} : { nonce: g.cspNonce }
479
520
  }),
480
521
  onShellError: (e) => {
481
- Y.error("spa layout shell render failed", { pathname: a }, e), r.writeHead(500, { "content-type": "text/plain; charset=utf-8" }), r.end("server error");
522
+ J.error("spa layout shell render failed", { pathname: a }, e), Q?.(e, {
523
+ stage: "spa-layout-shell",
524
+ pathname: a
525
+ }), r.writeHead(500, { "content-type": "text/plain; charset=utf-8" }), r.end("server error");
482
526
  }
483
527
  })
484
528
  };
@@ -504,9 +548,9 @@ CREATE INDEX IF NOT EXISTS ${e}_servable_until_idx ON ${e} (servable_until);
504
548
  loaderData: ce,
505
549
  segmentLoaderData: oe,
506
550
  pageLoaderRan: typeof y.loader == "function",
507
- ...ne ? { ppr: !0 } : {}
551
+ ...S ? { ppr: !0 } : {}
508
552
  });
509
- ne && _(j.stateInput, r.pattern);
553
+ S && _(j.stateInput, r.pattern);
510
554
  let ge = {
511
555
  descriptor: pe,
512
556
  params: i,
@@ -520,8 +564,8 @@ CREATE INDEX IF NOT EXISTS ${e}_servable_until_idx ON ${e} (servable_until);
520
564
  locale: k.locale
521
565
  } : {}
522
566
  }, _e = (t) => {
523
- if (jt === null || x !== "ssr" && x !== "isr" || typeof y.ogImage != "function" || t.includes("og:image")) return "";
524
- let n = S["x-tenant"], i = jt.signOgUrl({
567
+ if (X === null || x !== "ssr" && x !== "isr" || typeof y.ogImage != "function" || t.includes("og:image")) return "";
568
+ let n = C["x-tenant"], i = X.signOgUrl({
525
569
  pattern: r.pattern,
526
570
  params: e.params,
527
571
  ...n === void 0 ? {} : { tenant: n }
@@ -556,13 +600,16 @@ CREATE INDEX IF NOT EXISTS ${e}_servable_until_idx ON ${e} (servable_until);
556
600
  ...g.cspNonce === void 0 ? {} : { nonce: g.cspNonce }
557
601
  }),
558
602
  onShellError: (e) => {
559
- Y.error("ssr shell render failed", { pathname: a }, e), t.writeHead(500, { "content-type": "text/plain; charset=utf-8" }), t.end("server error");
603
+ J.error("ssr shell render failed", { pathname: a }, e), Q?.(e, {
604
+ stage: "ssr-shell",
605
+ pathname: a
606
+ }), t.writeHead(500, { "content-type": "text/plain; charset=utf-8" }), t.end("server error");
560
607
  }
561
608
  })
562
609
  };
563
610
  }
564
611
  let { html: Se, meta: Ce } = O.renderPageToHtml(ge), Te = ye(Ce), F = M(m(s.replace("<div id=\"root\"></div>", `<div id="root">${Se}</div>`), Te), he);
565
- A === "none" && (F = Dt(F));
612
+ A === "none" && (F = Mt(F));
566
613
  let Ee = x === "isr" ? I(y.revalidate) : null;
567
614
  return {
568
615
  html: g.cspNonce === void 0 ? F : T(F, g.cspNonce),
@@ -571,7 +618,7 @@ CREATE INDEX IF NOT EXISTS ${e}_servable_until_idx ON ${e} (servable_until);
571
618
  setCookies: g.setCookies,
572
619
  responseHeaders: g.responseHeaders
573
620
  };
574
- }, Q = (e) => e === "" ? "/" : e, Ft = async (e) => {
621
+ }, Z = (e) => e === "" ? "/" : e, zt = async (e) => {
575
622
  let t = await import(V(e).href);
576
623
  return {
577
624
  kind: "bundle",
@@ -582,18 +629,18 @@ CREATE INDEX IF NOT EXISTS ${e}_servable_until_idx ON ${e} (servable_until);
582
629
  return typeof r == "function" ? await r() : r;
583
630
  },
584
631
  async getLayout(e) {
585
- let n = t.layouts[Q(e)];
586
- if (!n) throw Error(`[voltro start] ssr bundle missing layout for dir ${Q(e)}`);
632
+ let n = t.layouts[Z(e)];
633
+ if (!n) throw Error(`[voltro start] ssr bundle missing layout for dir ${Z(e)}`);
587
634
  return typeof n == "function" ? await n() : n;
588
635
  },
589
636
  async getError(e) {
590
- let n = t.errors[Q(e)];
591
- if (!n) throw Error(`[voltro start] ssr bundle missing error for dir ${Q(e)}`);
637
+ let n = t.errors[Z(e)];
638
+ if (!n) throw Error(`[voltro start] ssr bundle missing error for dir ${Z(e)}`);
592
639
  return typeof n == "function" ? await n() : n;
593
640
  },
594
641
  async getPending(e) {
595
- let n = t.pendings[Q(e)];
596
- if (!n) throw Error(`[voltro start] ssr bundle missing pending for dir ${Q(e)}`);
642
+ let n = t.pendings[Z(e)];
643
+ if (!n) throw Error(`[voltro start] ssr bundle missing pending for dir ${Z(e)}`);
597
644
  return typeof n == "function" ? await n() : n;
598
645
  },
599
646
  async getHelpers() {
@@ -601,8 +648,8 @@ CREATE INDEX IF NOT EXISTS ${e}_servable_until_idx ON ${e} (servable_until);
601
648
  },
602
649
  async close() {}
603
650
  };
604
- }, It = async (e, t) => {
605
- let n = await S("vite", () => import("vite")), r = (await import("@vitejs/plugin-react")).default, i = (await import("@tailwindcss/vite")).default, a = await n.createServer({
651
+ }, Bt = async (e, t) => {
652
+ let n = await C("vite", () => import("vite")), r = (await import("@vitejs/plugin-react")).default, i = (await import("@tailwindcss/vite")).default, a = await n.createServer({
606
653
  root: t,
607
654
  envPrefix: "__VOLTRO_VITE_ENV_DISABLED__",
608
655
  plugins: [r(), i()],
@@ -621,8 +668,8 @@ CREATE INDEX IF NOT EXISTS ${e}_servable_until_idx ON ${e} (servable_until);
621
668
  logLevel: "warn"
622
669
  }), o = R(e, "src", "pages"), s = (e) => e === "" ? o : R(o, e), c = g({
623
670
  limit: w(),
624
- onColdStart: (e) => Y.debug("ssr cold-compile start", { id: e }),
625
- onColdEnd: (e, { durationMs: t, failed: n }) => Y.debug(`ssr cold-compile ${n ? "FAILED" : "end"} ${t}ms`, {
671
+ onColdStart: (e) => J.debug("ssr cold-compile start", { id: e }),
672
+ onColdEnd: (e, { durationMs: t, failed: n }) => J.debug(`ssr cold-compile ${n ? "FAILED" : "end"} ${t}ms`, {
626
673
  id: e,
627
674
  ms: t,
628
675
  ...n ? { failed: !0 } : {}
@@ -649,19 +696,20 @@ CREATE INDEX IF NOT EXISTS ${e}_servable_until_idx ON ${e} (servable_until);
649
696
  await a.close();
650
697
  }
651
698
  };
652
- }, Lt = async (t) => {
699
+ }, Q, $ = async (t) => {
653
700
  let n = Ye(), f = await j(t);
654
701
  if (!f) return {
655
702
  ran: !1,
656
703
  exitCode: 0
657
704
  };
658
- if (f.type !== "web") return Y.error("only web apps are supported by `voltro start`"), {
705
+ if (f.type !== "web") return J.error("only web apps are supported by `voltro start`"), {
659
706
  ran: !0,
660
707
  exitCode: 1
661
708
  };
709
+ Q = await Et(t, process.env, J);
662
710
  {
663
711
  let e = s(f);
664
- if (e !== void 0) return Y.error(`voltro start: refusing to boot — ${e}`), {
712
+ if (e !== void 0) return J.error(`voltro start: refusing to boot — ${e}`), {
665
713
  ran: !0,
666
714
  exitCode: 1
667
715
  };
@@ -670,19 +718,19 @@ CREATE INDEX IF NOT EXISTS ${e}_servable_until_idx ON ${e} (servable_until);
670
718
  rawEnv: f.env,
671
719
  appType: "web",
672
720
  root: t,
673
- log: Y,
721
+ log: J,
674
722
  generateTypes: !1
675
723
  }), te = m.publicValues;
676
724
  n.mark("config");
677
725
  let h = ue();
678
- fe(h), Y.info("booting voltro start", { app: f.name ?? "(unnamed)" });
726
+ fe(h), J.info("booting voltro start", { app: f.name ?? "(unnamed)" });
679
727
  let g = Me({
680
728
  kind: "web",
681
729
  configPort: f.port,
682
730
  env: process.env,
683
731
  dashboardPin: process.env[pe] === "1"
684
732
  });
685
- for (let e of g.warnings) Y.warn(e);
733
+ for (let e of g.warnings) J.warn(e);
686
734
  let _ = g.port, v = R(t, ".framework");
687
735
  {
688
736
  let e;
@@ -691,11 +739,11 @@ CREATE INDEX IF NOT EXISTS ${e}_servable_until_idx ON ${e} (servable_until);
691
739
  } catch {
692
740
  e = void 0;
693
741
  }
694
- let t = ft(process.env, e);
695
- t.length > 0 && Y.warn(pt(t));
742
+ let t = pt(process.env, e);
743
+ t.length > 0 && J.warn(mt(t));
696
744
  }
697
- let b = R(v, "dist"), S = R(b, "index.html");
698
- if (!await Z(S)) return Y.error("no built dist found — run `voltro build` first", { distDir: b }), {
745
+ let b = R(v, "dist"), C = R(b, "index.html");
746
+ if (!await Y(C)) return J.error("no built dist found — run `voltro build` first", { distDir: b }), {
699
747
  ran: !0,
700
748
  exitCode: 1
701
749
  };
@@ -709,78 +757,78 @@ CREATE INDEX IF NOT EXISTS ${e}_servable_until_idx ON ${e} (servable_until);
709
757
  status: "booting",
710
758
  logFile: E.path
711
759
  }).catch(() => {});
712
- let se = R(b, "_voltro", "shell.html"), D = await Z(se) ? await B.readFile(se, "utf8") : await B.readFile(S, "utf8"), de = await O(t, f), ve = Fe(f), M = Xe(f), N = _e(de[0]), P = de[0]?.name, ze = /* @__PURE__ */ new Set(), I = (e) => {
713
- ze.has(e.name) || (ze.add(e.name), Y.warn(`middleware.ts wrote the cookie "${e.name}" with the HttpOnly default — a browser SDK cannot read it`, {
760
+ let se = R(b, "_voltro", "shell.html"), D = await Y(se) ? await B.readFile(se, "utf8") : await B.readFile(C, "utf8"), de = await O(t, f), ve = Fe(f), M = Xe(f), N = _e(de[0]), P = de[0]?.name, ze = /* @__PURE__ */ new Set(), I = (e) => {
761
+ ze.has(e.name) || (ze.add(e.name), J.warn(`middleware.ts wrote the cookie "${e.name}" with the HttpOnly default — a browser SDK cannot read it`, {
714
762
  cookie: e.name,
715
763
  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."
716
764
  }));
717
765
  }, L = await a(t);
718
- L.length > 0 && Y.info(`middleware.ts loaded — ${L.length} middleware(s): ` + L.map((e) => e.exportName).join(", "));
766
+ L.length > 0 && J.info(`middleware.ts loaded — ${L.length} middleware(s): ` + L.map((e) => e.exportName).join(", "));
719
767
  let z, V = null, H = process.env.SSR_CACHE === "postgres";
720
- if (H && Pe()) V = new (await (import("pg"))).default.Client(Ne()), await V.connect(), z = bt({ client: V }), Y.info("isr cache backend: postgres", { table: "voltro_isr_cache" });
768
+ if (H && Pe()) V = new (await (import("pg"))).default.Client(Ne()), await V.connect(), z = St({ client: V }), J.info("isr cache backend: postgres", { table: "voltro_isr_cache" });
721
769
  else if (H) {
722
770
  let t = "SSR_CACHE=postgres, but nothing in the environment names a database (looked for DB_URL, DB_PRIMARY_URL, DB_DIRECT_URL, DB_MIGRATE_URL, DB_HOST, PG_HOST).";
723
- if (e()) throw Y.fatal(`${t} Refusing to fall back to the per-process memory cache: it is not shared between instances and does not survive a restart, so the pages this process serves would differ from its replicas' with nothing to indicate it.`), Error("[voltro start] SSR_CACHE=postgres with no database configured");
724
- z = Ve(), Y.warn(`${t} Falling back to the per-process memory cache — this would be a hard failure in production.`);
725
- } else z = Ve(), Y.info("isr cache backend: memory (per-process)", { hint: "set SSR_CACHE=postgres for persistent storage" });
771
+ if (e()) throw J.fatal(`${t} Refusing to fall back to the per-process memory cache: it is not shared between instances and does not survive a restart, so the pages this process serves would differ from its replicas' with nothing to indicate it.`), Error("[voltro start] SSR_CACHE=postgres with no database configured");
772
+ z = Ve(), J.warn(`${t} Falling back to the per-process memory cache — this would be a hard failure in production.`);
773
+ } else z = Ve(), J.info("isr cache backend: memory (per-process)", { hint: "set SSR_CACHE=postgres for persistent storage" });
726
774
  await o(t, f, de, te);
727
- let nt = R(t, "src", "pages"), { pages: rt, dirs: U } = await re(nt), W = kt(rt);
728
- C(L, W.map((e) => e.pattern)), n.mark("scan");
729
- let dt = R(b, "server", "ssrEntry.js"), G = await Z(dt);
730
- if (!G && process.env.NODE_ENV === "production") throw Y.fatal(`production \`voltro start\` requires a precompiled SSR bundle at ${dt} but it is missing. Run \`voltro build\` before serving — production renders from the bundle and never compiles on demand.`), Error(`[voltro start] missing SSR bundle at ${dt}`);
731
- let K = G ? await Ft(dt) : await It(t, v);
732
- Y.info(`ssr loader: ${K.kind}`, {
733
- kind: K.kind,
734
- ...K.kind === "middleware" ? { hint: "no pre-built SSR bundle found; run `voltro build` to enable bundle mode" } : {}
775
+ let nt = R(t, "src", "pages"), { pages: rt, dirs: U } = await re(nt), W = Pt(rt);
776
+ ne(L, W.map((e) => e.pattern)), n.mark("scan");
777
+ let lt = R(b, "server", "ssrEntry.js"), ft = await Y(lt);
778
+ if (!ft && process.env.NODE_ENV === "production") throw J.fatal(`production \`voltro start\` requires a precompiled SSR bundle at ${lt} but it is missing. Run \`voltro build\` before serving — production renders from the bundle and never compiles on demand.`), Error(`[voltro start] missing SSR bundle at ${lt}`);
779
+ let G = ft ? await zt(lt) : await Bt(t, v);
780
+ J.info(`ssr loader: ${G.kind}`, {
781
+ kind: G.kind,
782
+ ...G.kind === "middleware" ? { hint: "no pre-built SSR bundle found; run `voltro build` to enable bundle mode" } : {}
735
783
  }), n.mark("provider");
736
- let vt = K.getPageMeta?.();
784
+ let vt = G.getPageMeta?.();
737
785
  c(t);
738
- let q = /* @__PURE__ */ new Map(), yt = 0;
786
+ let K = /* @__PURE__ */ new Map(), bt = 0;
739
787
  for (let e of rt) {
740
788
  let t = vt?.[e.pattern];
741
789
  if (t) {
742
- q.set(e.pattern, t);
790
+ K.set(e.pattern, t);
743
791
  continue;
744
792
  }
745
793
  try {
746
- let t = await K.getPage(e.pattern, e.file);
747
- q.set(e.pattern, Re(t, e.file)), yt++;
794
+ let t = await G.getPage(e.pattern, e.file);
795
+ K.set(e.pattern, Re(t, e.file)), bt++;
748
796
  } catch (t) {
749
- Y.warn("failed to load page metadata", { pattern: e.pattern }, t);
797
+ J.warn("failed to load page metadata", { pattern: e.pattern }, t);
750
798
  }
751
799
  }
752
- let J = /* @__PURE__ */ new Map();
753
- for (let [e, t] of q) {
800
+ let xt = /* @__PURE__ */ new Map();
801
+ for (let [e, t] of K) {
754
802
  if (t.interactive !== "islands") continue;
755
803
  let n = R(b, "island-shells", `${k(e)}.html`);
756
804
  try {
757
- J.set(e, await B.readFile(n, "utf8"));
805
+ xt.set(e, await B.readFile(n, "utf8"));
758
806
  } catch {
759
- Y.warn("islands page has no built per-page shell — serving the full app shell", {
807
+ J.warn("islands page has no built per-page shell — serving the full app shell", {
760
808
  pattern: e,
761
809
  expected: n
762
810
  });
763
811
  }
764
812
  }
765
- Y.info(`registered ${q.size} route(s)`, {
766
- count: q.size,
767
- fromManifest: q.size - yt,
768
- fromModules: yt
813
+ J.info(`registered ${K.size} route(s)`, {
814
+ count: K.size,
815
+ fromManifest: K.size - bt,
816
+ fromModules: bt
769
817
  }), n.mark("routes");
770
- let X = /* @__PURE__ */ new Set();
771
- for (let e of W) q.get(e.pattern)?.renderMode === "spa" && we(U, e.dirChain).some((e) => e.hasLayout) && X.add(e.pattern);
772
- X.size > 0 && Y.info(`${X.size} spa route(s) render an SSR layout shell`, { patterns: [...X] });
773
- let wt = /* @__PURE__ */ new Map();
774
- for (let [e, t] of q) t.cacheInvalidatesOn.length > 0 && wt.set(e, t.cacheInvalidatesOn);
818
+ let q = /* @__PURE__ */ new Set();
819
+ for (let e of W) K.get(e.pattern)?.renderMode === "spa" && we(U, e.dirChain).some((e) => e.hasLayout) && q.add(e.pattern);
820
+ q.size > 0 && J.info(`${q.size} spa route(s) render an SSR layout shell`, { patterns: [...q] });
775
821
  let Tt = /* @__PURE__ */ new Map();
776
- for (let e of W) Tt.set(e.pattern, e.regex);
822
+ for (let [e, t] of K) t.cacheInvalidatesOn.length > 0 && Tt.set(e, t.cacheInvalidatesOn);
823
+ let Ot = /* @__PURE__ */ new Map();
824
+ for (let e of W) Ot.set(e.pattern, e.regex);
777
825
  {
778
- let n = new Set([...q].filter(([, e]) => (e.renderMode === "ssr" || e.renderMode === "isr") && e.hasOgImage).map(([e]) => e));
826
+ let n = new Set([...K].filter(([, e]) => (e.renderMode === "ssr" || e.renderMode === "isr") && e.hasOgImage).map(([e]) => e));
779
827
  if (n.size > 0) {
780
828
  let { secret: r, fromEnv: i } = Te();
781
- if (!i && e()) throw Y.fatal(`${n.size} ssr route(s) export ogImage, but VOLTRO_OG_SECRET is unset. Behind a load balancer the signing replica and the fetching replica differ, so a per-boot secret would 403 every cross-replica image fetch. Set VOLTRO_OG_SECRET (any long random value, same on every replica).`), Error("[voltro start] ssr ogImage routes need VOLTRO_OG_SECRET in a deploy environment");
829
+ if (!i && e()) throw J.fatal(`${n.size} ssr route(s) export ogImage, but VOLTRO_OG_SECRET is unset. Behind a load balancer the signing replica and the fetching replica differ, so a per-boot secret would 403 every cross-replica image fetch. Set VOLTRO_OG_SECRET (any long random value, same on every replica).`), Error("[voltro start] ssr ogImage routes need VOLTRO_OG_SECRET in a deploy environment");
782
830
  let a = new Map(rt.map((e) => [e.pattern, e.file]));
783
- jt = le({
831
+ X = le({
784
832
  root: t,
785
833
  fonts: f.fonts,
786
834
  cache: z,
@@ -788,45 +836,45 @@ CREATE INDEX IF NOT EXISTS ${e}_servable_until_idx ON ${e} (servable_until);
788
836
  isOgSsrRoute: (e) => n.has(e),
789
837
  getPageModule: async (e) => {
790
838
  let t = a.get(e);
791
- return t === void 0 ? null : await K.getPage(e, t);
839
+ return t === void 0 ? null : await G.getPage(e, t);
792
840
  }
793
- }), Y.info(`og route active for ${n.size} ssr route(s)`, { secret: i ? "env" : "per-boot" });
841
+ }), J.info(`og route active for ${n.size} ssr route(s)`, { secret: i ? "env" : "per-boot" });
794
842
  }
795
843
  }
796
- let Dt = /* @__PURE__ */ new Map();
797
- for (let [e, t] of q) Dt.set(e, t.renderMode);
798
- let Ot = [...q.values()].some((e) => e.renderMode === "isr"), Mt = {
844
+ let kt = /* @__PURE__ */ new Map();
845
+ for (let [e, t] of K) kt.set(e, t.renderMode);
846
+ let At = [...K.values()].some((e) => e.renderMode === "isr"), Mt = {
799
847
  cache: z,
800
- tableSink: gt({
848
+ tableSink: _t({
801
849
  cache: z,
802
- tableSubscriptionsByPattern: wt,
803
- regexByPattern: Tt
850
+ tableSubscriptionsByPattern: Tt,
851
+ regexByPattern: Ot
804
852
  }),
805
- regexByPattern: Tt,
806
- renderModeByPattern: Dt
853
+ regexByPattern: Ot,
854
+ renderModeByPattern: kt
807
855
  }, Nt = (e) => {
808
- let t = xt(e);
809
- t && St(Mt, t);
810
- }, Q = _t({
856
+ let t = Ct(e);
857
+ t && wt(Mt, t);
858
+ }, It = yt({
811
859
  cache: z,
812
- tableSubscriptionsByPattern: wt,
813
- regexByPattern: Tt,
814
- ...Ot ? { onRevalidate: Nt } : {}
815
- }), Lt = await Q.start(), $ = null, Rt = null;
816
- if (Ot) {
817
- let e = lt({}, process.env);
860
+ tableSubscriptionsByPattern: Tt,
861
+ regexByPattern: Ot,
862
+ ...At ? { onRevalidate: Nt } : {}
863
+ }), Lt = await It.start(), Z = null, $ = null;
864
+ if (At) {
865
+ let e = ut({}, process.env);
818
866
  if (e.crossReplica) try {
819
- Rt = e.provider;
867
+ $ = e.provider;
820
868
  let t = Ie(process.env);
821
- $ = await ct.runPromise(e.provider.subscribe(t, Nt)), Y.info(`revalidation subscriber: broker (${e.provider.name})`, { channel: t });
869
+ Z = await ct.runPromise(e.provider.subscribe(t, Nt)), J.info(`revalidation subscriber: broker (${e.provider.name})`, { channel: t });
822
870
  } catch (e) {
823
- Y.warn("revalidation broker subscribe failed — broker leg disabled", {}, e), Rt = null;
871
+ J.warn("revalidation broker subscribe failed — broker leg disabled", {}, e), $ = null;
824
872
  }
825
- Lt && $ === null && Y.info("revalidation subscriber: postgres LISTEN (voltro_revalidate)"), !Lt && $ === null && Y.warn("isr routes exist, but this web process has NO revalidation transport: no database is configured for the LISTEN line and no broker is configured. `revalidatePath` / `revalidateTable` / `revalidateTag` from the api will not reach this process — cached pages stay until their own `revalidate` window expires. Set DB_URL (postgres) or BROADCAST_URL (redis:// or nats://) on BOTH the api and this web deployment.");
873
+ Lt && Z === null && J.info("revalidation subscriber: postgres LISTEN (voltro_revalidate)"), !Lt && Z === null && J.warn("isr routes exist, but this web process has NO revalidation transport: no database is configured for the LISTEN line and no broker is configured. `revalidatePath` / `revalidateTable` / `revalidateTag` from the api will not reach this process — cached pages stay until their own `revalidate` window expires. Set DB_URL (postgres) or BROADCAST_URL (redis:// or nats://) on BOTH the api and this web deployment.");
826
874
  }
827
875
  n.mark("cdc");
828
- let zt = Le(), Bt = rt.map((e) => {
829
- let t = q.get(e.pattern);
876
+ let Vt = Le(), Ht = rt.map((e) => {
877
+ let t = K.get(e.pattern);
830
878
  return {
831
879
  pattern: e.pattern,
832
880
  file: e.file,
@@ -841,17 +889,17 @@ CREATE INDEX IF NOT EXISTS ${e}_servable_until_idx ON ${e} (servable_until);
841
889
  hasMeta: t?.hasMeta ?? !1,
842
890
  hasGetStaticPaths: t?.hasGetStaticPaths ?? !1
843
891
  };
844
- }), Vt = U.map((e) => ({
892
+ }), Ut = U.map((e) => ({
845
893
  dir: e.dir,
846
894
  hasLayout: e.hasLayout,
847
895
  hasError: e.hasError,
848
896
  hasPending: e.hasPending,
849
897
  hasNotFound: e.hasNotFound
850
- })), Ht = V ? "postgres" : "memory", Ut = {
898
+ })), Wt = V ? "postgres" : "memory", Gt = {
851
899
  kind: "web",
852
900
  meta: {
853
901
  name: f.name ?? "(unnamed)",
854
- voltroVersion: Ct,
902
+ voltroVersion: Dt,
855
903
  port: _,
856
904
  mode: tt(),
857
905
  apis: Object.entries(f.apis ?? {}).map(([e, t]) => {
@@ -862,8 +910,8 @@ CREATE INDEX IF NOT EXISTS ${e}_servable_until_idx ON ${e} (servable_until);
862
910
  return t.url !== void 0 && (n.url = t.url), n;
863
911
  })
864
912
  },
865
- routes: Bt,
866
- dirs: Vt,
913
+ routes: Ht,
914
+ dirs: Ut,
867
915
  cache: () => {
868
916
  let e = Date.now(), t = z.snapshot().map(([t, n]) => ({
869
917
  key: t,
@@ -876,13 +924,13 @@ CREATE INDEX IF NOT EXISTS ${e}_servable_until_idx ON ${e} (servable_until);
876
924
  staleWhileRevalidateMs: n.staleWhileRevalidateMs
877
925
  }));
878
926
  return {
879
- backend: Ht,
927
+ backend: Wt,
880
928
  size: z.size(),
881
929
  entries: t
882
930
  };
883
931
  },
884
932
  metrics: () => st()
885
- }, Wt = async (e, n) => {
933
+ }, Kt = async (e, n) => {
886
934
  let r = e.split("?")[0] ?? "/";
887
935
  if (f.name === "voltroDashboard" && r === "/api/dashboard/registry") try {
888
936
  let e = await Ge();
@@ -927,8 +975,8 @@ CREATE INDEX IF NOT EXISTS ${e}_servable_until_idx ON ${e} (servable_until);
927
975
  body: JSON.stringify({ apps: t })
928
976
  };
929
977
  }
930
- if (jt !== null && r === "/_voltro/og") {
931
- let t = await jt.handle(new URL(e, "http://localhost"));
978
+ if (X !== null && r === "/_voltro/og") {
979
+ let t = await X.handle(new URL(e, "http://localhost"));
932
980
  if (t !== null) return {
933
981
  status: t.status,
934
982
  headers: { ...t.headers },
@@ -947,7 +995,7 @@ CREATE INDEX IF NOT EXISTS ${e}_servable_until_idx ON ${e} (servable_until);
947
995
  };
948
996
  }
949
997
  if (r !== "/_voltro/inspect/stream") {
950
- let t = ke(e, Ut, n);
998
+ let t = ke(e, Gt, n);
951
999
  if (t !== null) return {
952
1000
  status: t.status,
953
1001
  headers: {
@@ -957,7 +1005,7 @@ CREATE INDEX IF NOT EXISTS ${e}_servable_until_idx ON ${e} (servable_until);
957
1005
  body: t.body
958
1006
  };
959
1007
  }
960
- let i = At(r, W), a = i ? q.get(i.route.pattern)?.renderMode : void 0, o = a === "ssr" || a === "isr" || (i ? X.has(i.route.pattern) : !1), s = [];
1008
+ let i = Ft(r, W), a = i ? K.get(i.route.pattern)?.renderMode : void 0, o = a === "ssr" || a === "isr" || (i ? q.has(i.route.pattern) : !1), s = [];
961
1009
  if (!o && L.length > 0) {
962
1010
  let t = ae(L, {
963
1011
  route: void 0,
@@ -978,7 +1026,7 @@ CREATE INDEX IF NOT EXISTS ${e}_servable_until_idx ON ${e} (servable_until);
978
1026
  ...e,
979
1027
  "set-cookie": s.map(d)
980
1028
  }, u = r === "/" ? R(b, "index.html") : R(b, r.replace(/^\//, ""), "index.html");
981
- if (!o && await Z(u)) {
1029
+ if (!o && await Y(u)) {
982
1030
  let e = await B.readFile(u);
983
1031
  return {
984
1032
  status: 200,
@@ -996,18 +1044,18 @@ CREATE INDEX IF NOT EXISTS ${e}_servable_until_idx ON ${e} (servable_until);
996
1044
  };
997
1045
  if (/\.[a-z0-9]+$/i.test(r)) {
998
1046
  let e = R(b, r.replace(/^\//, ""));
999
- if (await Z(e)) {
1047
+ if (await Y(e)) {
1000
1048
  let t = $e(r, M), i = at(n["accept-encoding"]), a = i === "br" ? `${e}.br` : i === "gzip" ? `${e}.gz` : void 0;
1001
- if (a !== void 0 && await Z(a)) {
1049
+ if (a !== void 0 && await Y(a)) {
1002
1050
  let n = await B.readFile(e);
1003
1051
  return {
1004
1052
  status: 200,
1005
1053
  headers: c({
1006
- "content-type": Et(e),
1054
+ "content-type": jt(e),
1007
1055
  "cache-control": t,
1008
1056
  "content-encoding": i === "br" ? "br" : "gzip",
1009
1057
  vary: "Accept-Encoding",
1010
- etag: mt(n)
1058
+ etag: ht(n)
1011
1059
  }),
1012
1060
  body: await B.readFile(a)
1013
1061
  };
@@ -1016,19 +1064,19 @@ CREATE INDEX IF NOT EXISTS ${e}_servable_until_idx ON ${e} (servable_until);
1016
1064
  return {
1017
1065
  status: 200,
1018
1066
  headers: c({
1019
- "content-type": Et(e),
1067
+ "content-type": jt(e),
1020
1068
  "cache-control": t
1021
1069
  }),
1022
1070
  body: o
1023
1071
  };
1024
1072
  }
1025
1073
  }
1026
- let p = At(r, W);
1074
+ let p = Ft(r, W);
1027
1075
  if (!p) {
1028
1076
  let i = ce(U, r);
1029
1077
  if (i !== void 0) try {
1030
- let a = await Pt({
1031
- provider: K,
1078
+ let a = await Rt({
1079
+ provider: G,
1032
1080
  root: t,
1033
1081
  route: {
1034
1082
  pattern: "<not-found>",
@@ -1060,7 +1108,10 @@ CREATE INDEX IF NOT EXISTS ${e}_servable_until_idx ON ${e} (servable_until);
1060
1108
  body: a.html
1061
1109
  };
1062
1110
  } catch (e) {
1063
- Y.warn("not-found.tsx failed to render — serving the plain 404", { pathname: r }, e instanceof Error ? e : Error(String(e)));
1111
+ J.warn("not-found.tsx failed to render — serving the plain 404", { pathname: r }, e instanceof Error ? e : Error(String(e))), Q?.(e, {
1112
+ stage: "not-found-render",
1113
+ pathname: r
1114
+ });
1064
1115
  }
1065
1116
  return {
1066
1117
  status: 404,
@@ -1071,7 +1122,7 @@ CREATE INDEX IF NOT EXISTS ${e}_servable_until_idx ON ${e} (servable_until);
1071
1122
  body: "not found"
1072
1123
  };
1073
1124
  }
1074
- let m = q.get(p.route.pattern), te = n["x-tenant"] ?? "anonymous", g = (await K.getHelpers()).i18n?.resolve(n.cookie, n["accept-language"])?.locale, _ = He(r, {
1125
+ let m = K.get(p.route.pattern), te = n["x-tenant"] ?? "anonymous", g = (await G.getHelpers()).i18n?.resolve(n.cookie, n["accept-language"])?.locale, _ = He(r, {
1075
1126
  ...m?.tenantAware ? { tenant: te } : {},
1076
1127
  ...g ? { locale: g } : {}
1077
1128
  }), v = m?.ppr === !0 && m.renderMode === "isr", y = (i, a) => ({
@@ -1086,14 +1137,14 @@ CREATE INDEX IF NOT EXISTS ${e}_servable_until_idx ON ${e} (servable_until);
1086
1137
  ...a
1087
1138
  }), o.write(i), (async () => {
1088
1139
  try {
1089
- let i = await Pt({
1090
- provider: K,
1140
+ let i = await Rt({
1141
+ provider: G,
1091
1142
  root: t,
1092
1143
  route: p.route,
1093
1144
  params: p.params,
1094
1145
  pathname: r,
1095
1146
  dirs: U,
1096
- shellTemplate: J.get(p.route.pattern) ?? D,
1147
+ shellTemplate: xt.get(p.route.pattern) ?? D,
1097
1148
  requestHeaders: n,
1098
1149
  apiOrigin: N,
1099
1150
  apiName: P,
@@ -1108,23 +1159,26 @@ CREATE INDEX IF NOT EXISTS ${e}_servable_until_idx ON ${e} (servable_until);
1108
1159
  res: o,
1109
1160
  helpers: i.holes.helpers,
1110
1161
  page: i.holes.page,
1111
- log: Y
1162
+ log: J
1112
1163
  }) : o.writableEnded || o.end();
1113
1164
  } catch (e) {
1114
- Y.warn("ppr hole pass failed", { url: r }, e), o.writableEnded || o.end();
1165
+ J.warn("ppr hole pass failed", { url: r }, e), Q?.(e, {
1166
+ stage: "ppr-holes",
1167
+ pathname: r
1168
+ }), o.writableEnded || o.end();
1115
1169
  }
1116
1170
  })();
1117
1171
  }
1118
- }), x = z.get(_), S = Date.now();
1119
- if (x && Ue(x, S)) return h.emit("cache", {
1172
+ }), x = z.get(_), C = Date.now();
1173
+ if (x && Ue(x, C)) return h.emit("cache", {
1120
1174
  kind: "HIT",
1121
1175
  key: _,
1122
- ageMs: S - x.renderedAt
1176
+ ageMs: C - x.renderedAt
1123
1177
  }), v ? y(x.html, {
1124
1178
  "cache-control": Ze(M, x.revalidateMs, x.staleWhileRevalidateMs),
1125
1179
  "x-voltro-cache": "HIT",
1126
1180
  "x-voltro-cache-key": _,
1127
- "x-voltro-cache-age-ms": String(S - x.renderedAt)
1181
+ "x-voltro-cache-age-ms": String(C - x.renderedAt)
1128
1182
  }) : {
1129
1183
  status: 200,
1130
1184
  headers: {
@@ -1133,27 +1187,27 @@ CREATE INDEX IF NOT EXISTS ${e}_servable_until_idx ON ${e} (servable_until);
1133
1187
  "x-voltro-rendered-by": "isr",
1134
1188
  "x-voltro-cache": "HIT",
1135
1189
  "x-voltro-cache-key": _,
1136
- "x-voltro-cache-age-ms": String(S - x.renderedAt)
1190
+ "x-voltro-cache-age-ms": String(C - x.renderedAt)
1137
1191
  },
1138
1192
  body: x.html
1139
1193
  };
1140
- if (x && Be(x, S)) {
1194
+ if (x && Be(x, C)) {
1141
1195
  h.emit("cache", {
1142
1196
  kind: "STALE",
1143
1197
  key: _,
1144
- ageMs: S - x.renderedAt
1198
+ ageMs: C - x.renderedAt
1145
1199
  });
1146
1200
  let i = z.generation(_);
1147
1201
  return (async () => {
1148
1202
  try {
1149
- let a = await Pt({
1150
- provider: K,
1203
+ let a = await Rt({
1204
+ provider: G,
1151
1205
  root: t,
1152
1206
  route: p.route,
1153
1207
  params: p.params,
1154
1208
  pathname: r,
1155
1209
  dirs: U,
1156
- shellTemplate: J.get(p.route.pattern) ?? D,
1210
+ shellTemplate: xt.get(p.route.pattern) ?? D,
1157
1211
  requestHeaders: n,
1158
1212
  apiOrigin: N,
1159
1213
  apiName: P,
@@ -1163,7 +1217,7 @@ CREATE INDEX IF NOT EXISTS ${e}_servable_until_idx ON ${e} (servable_until);
1163
1217
  buffered: !0
1164
1218
  });
1165
1219
  if (a && "html" in a && a.renderMode === "isr" && a.revalidateMs !== null) {
1166
- let e = q.get(p.route.pattern)?.staleWhileRevalidateMs ?? 0, t = Date.now();
1220
+ let e = K.get(p.route.pattern)?.staleWhileRevalidateMs ?? 0, t = Date.now();
1167
1221
  z.set(_, {
1168
1222
  html: a.html,
1169
1223
  renderedAt: t,
@@ -1171,16 +1225,19 @@ CREATE INDEX IF NOT EXISTS ${e}_servable_until_idx ON ${e} (servable_until);
1171
1225
  servableUntil: t + a.revalidateMs + e,
1172
1226
  revalidateMs: a.revalidateMs,
1173
1227
  staleWhileRevalidateMs: e
1174
- }, { ifGeneration: i }) || Y.info("SWR refresh discarded — the entry was purged while it rendered", { key: _ });
1228
+ }, { ifGeneration: i }) || J.info("SWR refresh discarded — the entry was purged while it rendered", { key: _ });
1175
1229
  }
1176
1230
  } catch (e) {
1177
- Y.warn("background SWR refresh failed", { url: r }, e);
1231
+ J.warn("background SWR refresh failed", { url: r }, e), Q?.(e, {
1232
+ stage: "swr-refresh",
1233
+ pathname: r
1234
+ });
1178
1235
  }
1179
1236
  })(), v ? y(x.html, {
1180
1237
  "cache-control": Ze(M, x.revalidateMs, x.staleWhileRevalidateMs),
1181
1238
  "x-voltro-cache": "STALE",
1182
1239
  "x-voltro-cache-key": _,
1183
- "x-voltro-cache-age-ms": String(S - x.renderedAt)
1240
+ "x-voltro-cache-age-ms": String(C - x.renderedAt)
1184
1241
  }) : {
1185
1242
  status: 200,
1186
1243
  headers: {
@@ -1189,20 +1246,20 @@ CREATE INDEX IF NOT EXISTS ${e}_servable_until_idx ON ${e} (servable_until);
1189
1246
  "x-voltro-rendered-by": "isr",
1190
1247
  "x-voltro-cache": "STALE",
1191
1248
  "x-voltro-cache-key": _,
1192
- "x-voltro-cache-age-ms": String(S - x.renderedAt)
1249
+ "x-voltro-cache-age-ms": String(C - x.renderedAt)
1193
1250
  },
1194
1251
  body: x.html
1195
1252
  };
1196
1253
  }
1197
1254
  try {
1198
- let i = z.generation(_), a = await Pt({
1199
- provider: K,
1255
+ let i = z.generation(_), a = await Rt({
1256
+ provider: G,
1200
1257
  root: t,
1201
1258
  route: p.route,
1202
1259
  params: p.params,
1203
1260
  pathname: r,
1204
1261
  dirs: U,
1205
- shellTemplate: J.get(p.route.pattern) ?? D,
1262
+ shellTemplate: xt.get(p.route.pattern) ?? D,
1206
1263
  requestHeaders: n,
1207
1264
  apiOrigin: N,
1208
1265
  apiName: P,
@@ -1250,7 +1307,7 @@ CREATE INDEX IF NOT EXISTS ${e}_servable_until_idx ON ${e} (servable_until);
1250
1307
  "x-voltro-rendered-by": a.renderMode
1251
1308
  });
1252
1309
  if (a.renderMode === "isr" && a.revalidateMs !== null) {
1253
- let e = Date.now(), t = q.get(p.route.pattern)?.staleWhileRevalidateMs ?? 0;
1310
+ let e = Date.now(), t = K.get(p.route.pattern)?.staleWhileRevalidateMs ?? 0;
1254
1311
  z.set(_, {
1255
1312
  html: a.html,
1256
1313
  renderedAt: e,
@@ -1258,7 +1315,7 @@ CREATE INDEX IF NOT EXISTS ${e}_servable_until_idx ON ${e} (servable_until);
1258
1315
  servableUntil: e + a.revalidateMs + t,
1259
1316
  revalidateMs: a.revalidateMs,
1260
1317
  staleWhileRevalidateMs: t
1261
- }, { ifGeneration: i }) || Y.info("miss fill discarded — the entry was purged while it rendered", { key: _ }), l["x-voltro-cache"] = "MISS", l["x-voltro-cache-key"] = _, l["x-voltro-cache-revalidate-ms"] = String(a.revalidateMs), t > 0 && (l["x-voltro-cache-swr-ms"] = String(t)), h.emit("cache", {
1318
+ }, { ifGeneration: i }) || J.info("miss fill discarded — the entry was purged while it rendered", { key: _ }), l["x-voltro-cache"] = "MISS", l["x-voltro-cache-key"] = _, l["x-voltro-cache-revalidate-ms"] = String(a.revalidateMs), t > 0 && (l["x-voltro-cache-swr-ms"] = String(t)), h.emit("cache", {
1262
1319
  kind: "MISS",
1263
1320
  key: _,
1264
1321
  revalidateMs: a.revalidateMs,
@@ -1277,7 +1334,10 @@ CREATE INDEX IF NOT EXISTS ${e}_servable_until_idx ON ${e} (servable_until);
1277
1334
  body: a.html
1278
1335
  };
1279
1336
  } catch (e) {
1280
- return Y.error("render error", { url: r }, e), ne(e) ? {
1337
+ return J.error("render error", { url: r }, e), Q?.(e, {
1338
+ stage: "render",
1339
+ pathname: r
1340
+ }), S(e) ? {
1281
1341
  status: 500,
1282
1342
  headers: {
1283
1343
  "content-type": "text/plain; charset=utf-8",
@@ -1297,12 +1357,12 @@ CREATE INDEX IF NOT EXISTS ${e}_servable_until_idx ON ${e} (servable_until);
1297
1357
  body: "server error"
1298
1358
  };
1299
1359
  }
1300
- }, Gt = !1, Kt = i(f.health, () => Gt), qt = p({
1360
+ }, qt = !1, Jt = i(f.health, () => qt), Yt = p({
1301
1361
  apiName: P,
1302
1362
  apiOrigin: N,
1303
1363
  loadDescriptors: async () => {
1304
1364
  if (P === void 0) return;
1305
- let e = (await K.getHelpers()).apiDescriptors?.[P];
1365
+ let e = (await G.getHelpers()).apiDescriptors?.[P];
1306
1366
  return e === void 0 ? void 0 : await e();
1307
1367
  },
1308
1368
  rpcQuery: (e, t) => xe(N, e, {
@@ -1310,14 +1370,14 @@ CREATE INDEX IF NOT EXISTS ${e}_servable_until_idx ON ${e} (servable_until);
1310
1370
  headers: t
1311
1371
  }),
1312
1372
  resolveLocale: async (e, t) => {
1313
- let n = await K.getHelpers(), r = u(t, n.i18n?.locales);
1373
+ let n = await G.getHelpers(), r = u(t, n.i18n?.locales);
1314
1374
  return r === void 0 ? n.i18n?.resolve(e.cookie, e["accept-language"])?.locale ?? "en" : r;
1315
1375
  },
1316
1376
  renderErrorPage: async ({ path: e, headers: n, flash: r }) => {
1317
- let { pathname: i } = be(e), a = At(i, W);
1377
+ let { pathname: i } = be(e), a = Ft(i, W);
1318
1378
  if (!a) return;
1319
- let o = await Pt({
1320
- provider: K,
1379
+ let o = await Rt({
1380
+ provider: G,
1321
1381
  root: t,
1322
1382
  route: a.route,
1323
1383
  params: a.params,
@@ -1335,19 +1395,19 @@ CREATE INDEX IF NOT EXISTS ${e}_servable_until_idx ON ${e} (servable_until);
1335
1395
  });
1336
1396
  return o !== null && "html" in o ? o.html : void 0;
1337
1397
  }
1338
- }), Jt = ot(f), Yt = ut(async (e, t) => {
1398
+ }), Xt = ot(f), Zt = dt(async (e, t) => {
1339
1399
  let n = e.url ?? "/", i = Date.now(), a = {};
1340
1400
  for (let [t, n] of Object.entries(e.headers)) n !== void 0 && (a[t.toLowerCase()] = Array.isArray(n) ? n.join(", ") : n);
1341
- let o = n.split("?")[0] ?? "/", s = (e.method ?? "GET").toUpperCase(), c = he(Kt, o);
1401
+ let o = n.split("?")[0] ?? "/", s = (e.method ?? "GET").toUpperCase(), c = he(Jt, o);
1342
1402
  if (c !== void 0) {
1343
- let e = await y(Kt, c);
1403
+ let e = await y(Jt, c);
1344
1404
  t.writeHead(e.status, {
1345
1405
  "content-type": "text/plain",
1346
1406
  "cache-control": "no-store"
1347
1407
  }), t.end(e.body);
1348
1408
  return;
1349
1409
  }
1350
- if (!(o.startsWith(x) && await qt(e, t))) {
1410
+ if (!(o.startsWith(x) && await Yt(e, t))) {
1351
1411
  if (s === "OPTIONS" && o.startsWith("/_voltro/inspect")) {
1352
1412
  let e = Oe(a.origin);
1353
1413
  t.writeHead(204, e), t.end();
@@ -1475,8 +1535,8 @@ CREATE INDEX IF NOT EXISTS ${e}_servable_until_idx ON ${e} (servable_until);
1475
1535
  return;
1476
1536
  }
1477
1537
  try {
1478
- let e = await Wt(n, a);
1479
- if (e.stream ? e.stream(t) : ht({
1538
+ let e = await Kt(n, a);
1539
+ if (e.stream ? e.stream(t) : gt({
1480
1540
  response: t,
1481
1541
  status: e.status,
1482
1542
  headers: e.headers,
@@ -1492,8 +1552,8 @@ CREATE INDEX IF NOT EXISTS ${e}_servable_until_idx ON ${e} (servable_until);
1492
1552
  renderedBy: e.headers["x-voltro-rendered-by"],
1493
1553
  cache: e.headers["x-voltro-cache"]
1494
1554
  });
1495
- let n = At(o, W)?.route.pattern ?? (e.status === 404 ? "<unmatched>" : "<asset>");
1496
- zt.record({
1555
+ let n = Ft(o, W)?.route.pattern ?? (e.status === 404 ? "<unmatched>" : "<asset>");
1556
+ Vt.record({
1497
1557
  kind: "request",
1498
1558
  tag: n,
1499
1559
  durationMs: t,
@@ -1505,10 +1565,10 @@ CREATE INDEX IF NOT EXISTS ${e}_servable_until_idx ON ${e} (servable_until);
1505
1565
  }
1506
1566
  }
1507
1567
  });
1508
- await new Promise((e) => Yt.listen(_, "::", e)), Gt = !0, n.mark("ready"), it(Yt, Jt), Y.info(`listening on http://localhost:${_}`, {
1568
+ await new Promise((e) => Zt.listen(_, "::", e)), qt = !0, n.mark("ready"), it(Zt, Xt), J.info(`listening on http://localhost:${_}`, {
1509
1569
  port: _,
1510
1570
  distDir: b
1511
- }), Y.debug("dynamic + ssr/isr routes resolve via SSR loader");
1571
+ }), J.debug("dynamic + ssr/isr routes resolve via SSR loader");
1512
1572
  try {
1513
1573
  await We({
1514
1574
  id: T,
@@ -1522,7 +1582,7 @@ CREATE INDEX IF NOT EXISTS ${e}_servable_until_idx ON ${e} (servable_until);
1522
1582
  let e = Se(t);
1523
1583
  if (e) {
1524
1584
  let t = await ye({ dashboardAppPath: e });
1525
- t.status === "launched" ? Y.info(`dashboard launched at http://localhost:${t.port}`, { port: t.port }) : t.status === "already-running" && Y.debug(`dashboard already running on :${t.port}`, { port: t.port });
1585
+ t.status === "launched" ? J.info(`dashboard launched at http://localhost:${t.port}`, { port: t.port }) : t.status === "already-running" && J.debug(`dashboard already running on :${t.port}`, { port: t.port });
1526
1586
  }
1527
1587
  setInterval(() => {
1528
1588
  We({
@@ -1536,7 +1596,7 @@ CREATE INDEX IF NOT EXISTS ${e}_servable_until_idx ON ${e} (servable_until);
1536
1596
  }).catch(() => {});
1537
1597
  }, 1e4).unref();
1538
1598
  } catch (e) {
1539
- Y.warn("runtime-registry write failed", {}, e);
1599
+ J.warn("runtime-registry write failed", {}, e);
1540
1600
  }
1541
1601
  et({
1542
1602
  app: f.name ?? "unnamed",
@@ -1544,38 +1604,38 @@ CREATE INDEX IF NOT EXISTS ${e}_servable_until_idx ON ${e} (servable_until);
1544
1604
  url: `http://localhost:${_}`,
1545
1605
  bootMs: n.total()
1546
1606
  });
1547
- let Xt = n.phaseBreakdown();
1548
- Y.info(`start: ready in ${n.total()}ms`, {
1607
+ let Qt = n.phaseBreakdown();
1608
+ J.info(`start: ready in ${n.total()}ms`, {
1549
1609
  bootMs: n.total(),
1550
- ...Xt ? { phases: Xt } : {}
1610
+ ...Qt ? { phases: Qt } : {}
1551
1611
  });
1552
- let Zt = !1, Qt = (e) => async () => {
1553
- if (!Zt) {
1554
- if (Zt = !0, Y.info(`received ${e}, shutting down`, { signal: e }), Yt.close(), await Q.stop(), $) try {
1555
- $();
1612
+ let $t = !1, en = (e) => async () => {
1613
+ if (!$t) {
1614
+ if ($t = !0, J.info(`received ${e}, shutting down`, { signal: e }), Zt.close(), await It.stop(), Z) try {
1615
+ Z();
1556
1616
  } catch {}
1557
- if (Rt) try {
1558
- await ct.runPromise(Rt.close());
1617
+ if ($) try {
1618
+ await ct.runPromise($.close());
1559
1619
  } catch {}
1560
1620
  if (V) try {
1561
1621
  await V.end();
1562
1622
  } catch {}
1563
- await K.close(), await Ke(T), await E.dispose(), process.exit(0);
1623
+ await G.close(), await Ke(T), await E.dispose(), process.exit(0);
1564
1624
  }
1565
1625
  };
1566
- process.on("SIGINT", Qt("SIGINT")), process.on("SIGTERM", Qt("SIGTERM"));
1567
- let $t = process.ppid;
1568
- if ($t > 1) {
1626
+ process.on("SIGINT", en("SIGINT")), process.on("SIGTERM", en("SIGTERM"));
1627
+ let tn = process.ppid;
1628
+ if (tn > 1) {
1569
1629
  let e = setInterval(() => {
1570
- (process.ppid !== $t || process.ppid === 1) && (clearInterval(e), Qt("SIGTERM")());
1630
+ (process.ppid !== tn || process.ppid === 1) && (clearInterval(e), en("SIGTERM")());
1571
1631
  }, 2e3);
1572
1632
  e.unref();
1573
1633
  }
1574
1634
  return new Promise(() => {});
1575
- }, $ = async (e) => {
1635
+ }, Vt = async (e) => {
1576
1636
  rt("start"), t("start");
1577
- let n = e.find((e) => !e.startsWith("-")) ?? process.cwd(), r = await Lt(z(n));
1578
- return r.ran ? r.exitCode : (Y.error("no web app found at this path"), 1);
1637
+ let n = e.find((e) => !e.startsWith("-")) ?? process.cwd(), r = await $(z(n));
1638
+ return r.ran ? r.exitCode : (J.error("no web app found at this path"), 1);
1579
1639
  };
1580
1640
  //#endregion
1581
- export { Lt as n, $ as t };
1641
+ export { $ as n, Vt as t };