@voltro/cli 0.22.1 → 0.23.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 (65) hide show
  1. package/CHANGELOG.md +316 -0
  2. package/dist/apiBuild-CD-4JLLA.js +2 -0
  3. package/dist/{apiBuild-DiWxVz-M.js → apiBuild-JQtIhZPy.js} +2 -2
  4. package/dist/bin.js +3 -3
  5. package/dist/{commands-BxRaIOBG.js → commands-Bsu9Buln.js} +1767 -1501
  6. package/dist/dbCommand-CSguuUQn.js +2 -0
  7. package/dist/{dbCommand-DVASmZj2.js → dbCommand-GI7-BVZt.js} +440 -259
  8. package/dist/{dev-Dd3EZzj5.js → dev-DRxF_qOB.js} +1 -1
  9. package/dist/{dev-BRiPgbKw.js → dev-jM07kq_D.js} +1479 -1479
  10. package/dist/index.js +1 -1
  11. package/dist/{inspectMetrics-9ZSuDeqD.js → inspectMetrics-dcC7gnxu.js} +566 -552
  12. package/dist/{serveCommand-DXJOARkO.js → serveCommand-Cl8sicD5.js} +280 -279
  13. package/dist/serveEntry.js +2 -2
  14. package/dist/{start-CsIjcOi-.js → start-C_4VUDT8.js} +327 -325
  15. package/dist/startEntry.js +2 -2
  16. package/package.json +17 -17
  17. package/templates/AGENTS.md +1 -1
  18. package/templates/agent-docs/_index.md +1 -1
  19. package/templates/agent-docs/_manifest.json +1 -1
  20. package/templates/agent-docs/caching.md +21 -5
  21. package/templates/agent-docs/cli.md +44 -0
  22. package/templates/agent-docs/data.md +23 -5
  23. package/templates/agent-docs/database/migrations.md +94 -0
  24. package/templates/agent-docs/plugins.md +42 -0
  25. package/templates/agent-docs/routing.md +23 -1
  26. package/templates/agent-docs/templates/apibackends.md +2 -2
  27. package/templates/agent-docs/whats-new.md +281 -32
  28. package/templates/apps/api-ai/package.json +7 -7
  29. package/templates/apps/api-auth/package.json +8 -8
  30. package/templates/apps/api-backend/package.json +7 -7
  31. package/templates/apps/api-backend-deactivation/package.json +7 -7
  32. package/templates/apps/api-backend-mail/package.json +8 -8
  33. package/templates/apps/api-backend-mariadb/package.json +9 -9
  34. package/templates/apps/api-backend-storage/package.json +8 -8
  35. package/templates/apps/api-data-advanced/package.json +8 -8
  36. package/templates/apps/api-durable/package.json +8 -8
  37. package/templates/apps/api-feature-flags/package.json +9 -9
  38. package/templates/apps/api-governance/package.json +8 -8
  39. package/templates/apps/api-kv/package.json +8 -8
  40. package/templates/apps/api-moderation/package.json +8 -8
  41. package/templates/apps/api-observability/package.json +8 -8
  42. package/templates/apps/api-ratelimit/package.json +8 -8
  43. package/templates/apps/api-rbac/package.json +8 -8
  44. package/templates/apps/api-rest/package.json +7 -7
  45. package/templates/apps/api-saas/package.json +11 -11
  46. package/templates/apps/api-search/package.json +8 -8
  47. package/templates/apps/api-versioning/app.config.ts +6 -4
  48. package/templates/apps/api-versioning/package.json +8 -8
  49. package/templates/apps/api-webhooks/package.json +9 -9
  50. package/templates/apps/changelog/package.json +6 -6
  51. package/templates/apps/edge-functions/package.json +2 -2
  52. package/templates/apps/frontend-admin/package.json +8 -8
  53. package/templates/apps/frontend-app/package.json +8 -8
  54. package/templates/apps/frontend-blank/package.json +7 -7
  55. package/templates/apps/frontend-contact/package.json +7 -7
  56. package/templates/apps/frontend-dashboard/package.json +7 -7
  57. package/templates/apps/frontend-docs/package.json +7 -7
  58. package/templates/apps/frontend-i18n/package.json +6 -6
  59. package/templates/apps/frontend-landing/package.json +7 -7
  60. package/templates/apps/frontend-spa/package.json +7 -7
  61. package/templates/apps/frontend-ssr/package.json +7 -7
  62. package/templates/apps/frontend-ssr-api/package.json +8 -8
  63. package/templates/apps/frontend-static-blog/package.json +6 -6
  64. package/dist/apiBuild-COyPDf3R.js +0 -2
  65. package/dist/dbCommand-CO3eSAZR.js +0 -2
@@ -1,14 +1,14 @@
1
- import { $ as e, C as t, E as n, G as r, H as i, J as a, P as o, Q as s, R as c, U as l, V as u, W as d, _ as f, a as p, at as m, b as ee, c as h, ct as g, dt as _, et as te, f as v, ft as y, g as ne, h as b, i as re, j as ie, m as x, nt as S, o as ae, p as C, pt as w, q as T, r as E, s as D, t as O, tt as k, ut as A, v as j, w as oe, y as M } from "./inspectMetrics-9ZSuDeqD.js";
2
- import { D as se, E as ce, T as le, a as N, p as ue, w as de } from "./inspect-_ldwsAwH.js";
1
+ import { $ as e, D as t, F as n, G as r, H as i, J as a, K as o, M as s, T as c, U as l, W as u, Y as d, _ as ee, a as te, b as f, c as p, dt as m, et as h, f as g, ft as _, g as ne, h as v, i as re, lt as y, m as b, mt as x, nt as ie, o as S, ot as C, p as w, pt as ae, r as T, rt as E, s as D, t as O, tt as k, v as A, w as j, x as M, y as oe, z as se } from "./inspectMetrics-dcC7gnxu.js";
2
+ import { D as ce, E as le, T as ue, a as de, p as N, w as P } from "./inspect-_ldwsAwH.js";
3
3
  import { t as fe } from "./bootTiming-BdyP9nYw.js";
4
- import { dirname as pe, extname as P, join as F, resolve as I } from "node:path";
5
- import { fileURLToPath as L, pathToFileURL as R } from "node:url";
6
- import { createLogger as z, printReadyBlock as me } from "@voltro/logger";
7
- import { promises as B } from "node:fs";
8
- import { snapshotMetricsSync as he } from "@voltro/runtime";
9
- import { createServer as ge } from "node:http";
4
+ import { dirname as F, extname as I, join as L, resolve as R } from "node:path";
5
+ import { fileURLToPath as z, pathToFileURL as B } from "node:url";
6
+ import { createLogger as V, printReadyBlock as pe } from "@voltro/logger";
7
+ import { promises as H } from "node:fs";
8
+ import { snapshotMetricsSync as me } from "@voltro/runtime";
9
+ import { createServer as he } from "node:http";
10
10
  //#region src/isrCdcInvalidator.ts
11
- var V = z({ scope: "voltro:start:cdc" }), H = (e) => (t) => {
11
+ var U = V({ scope: "voltro:start:cdc" }), W = (e) => (t) => {
12
12
  let n = 0;
13
13
  for (let [r, i] of e.tableSubscriptionsByPattern) {
14
14
  if (!i.includes(t)) continue;
@@ -19,23 +19,23 @@ var V = z({ scope: "voltro:start:cdc" }), H = (e) => (t) => {
19
19
  }));
20
20
  }
21
21
  return n;
22
- }, U = () => !process.env.PG_HOST && !process.env.PG_DATABASE ? null : {
22
+ }, G = () => !process.env.PG_HOST && !process.env.PG_DATABASE ? null : {
23
23
  host: process.env.PG_HOST ?? "localhost",
24
24
  port: Number(process.env.PG_PORT ?? 5432),
25
25
  user: process.env.PG_USER ?? "app",
26
26
  password: process.env.PG_PASSWORD ?? "app",
27
27
  database: process.env.PG_DATABASE ?? "app"
28
- }, _e = (e) => {
29
- let t = e.channel ?? "framework_changes", n = H(e), r = null, i = null;
28
+ }, ge = (e) => {
29
+ let t = e.channel ?? "framework_changes", n = W(e), r = null, i = null;
30
30
  return {
31
31
  start: async () => {
32
- let a = U();
32
+ let a = G();
33
33
  if (!a) {
34
- V.debug("skipped — no PG_* env vars set");
34
+ U.debug("skipped — no PG_* env vars set");
35
35
  return;
36
36
  }
37
37
  if (e.tableSubscriptionsByPattern.size === 0) {
38
- V.debug("skipped — no pages declare cacheInvalidatesOn");
38
+ U.debug("skipped — no pages declare cacheInvalidatesOn");
39
39
  return;
40
40
  }
41
41
  r = new (await (import("pg"))).default.Client(a), await r.connect(), i = (e) => {
@@ -44,16 +44,16 @@ var V = z({ scope: "voltro:start:cdc" }), H = (e) => (t) => {
44
44
  try {
45
45
  r = JSON.parse(e.payload);
46
46
  } catch (e) {
47
- V.warn("bad CDC payload", {}, e);
47
+ U.warn("bad CDC payload", {}, e);
48
48
  return;
49
49
  }
50
50
  let i = n(r.table);
51
- i > 0 && V.info(`${r.op} on '${r.table}' → dropped ${i} cache entries`, {
51
+ i > 0 && U.info(`${r.op} on '${r.table}' → dropped ${i} cache entries`, {
52
52
  op: r.op,
53
53
  table: r.table,
54
54
  dropped: i
55
55
  });
56
- }, r.on("notification", i), await r.query(`LISTEN ${t}`), V.info(`LISTEN ${t}`, {
56
+ }, r.on("notification", i), await r.query(`LISTEN ${t}`), U.info(`LISTEN ${t}`, {
57
57
  channel: t,
58
58
  host: a.host,
59
59
  port: a.port,
@@ -69,7 +69,7 @@ var V = z({ scope: "voltro:start:cdc" }), H = (e) => (t) => {
69
69
  }
70
70
  }
71
71
  };
72
- }, W = z({ scope: "voltro:start:isr-cache" }), G = "voltro_isr_cache", ve = (e) => `
72
+ }, K = V({ scope: "voltro:start:isr-cache" }), _e = "voltro_isr_cache", q = (e) => `
73
73
  CREATE TABLE IF NOT EXISTS ${e} (
74
74
  cache_key TEXT PRIMARY KEY,
75
75
  html TEXT NOT NULL,
@@ -80,9 +80,9 @@ CREATE TABLE IF NOT EXISTS ${e} (
80
80
  stale_while_revalidate_ms BIGINT NOT NULL DEFAULT 0
81
81
  );
82
82
  CREATE INDEX IF NOT EXISTS ${e}_servable_until_idx ON ${e} (servable_until);
83
- `, ye = (e) => {
84
- let t = e.tableName ?? G, { client: n } = e, r = /* @__PURE__ */ new Map(), i = !1, a = (async () => {
85
- i || (i = !0, await n.query(ve(t)));
83
+ `, ve = (e) => {
84
+ let t = e.tableName ?? _e, { client: n } = e, r = /* @__PURE__ */ new Map(), i = !1, a = (async () => {
85
+ i || (i = !0, await n.query(q(t)));
86
86
  })().then(async () => {
87
87
  let e = await n.query(`SELECT * FROM ${t}`);
88
88
  for (let t of e.rows) r.set(t.cache_key, {
@@ -94,10 +94,10 @@ CREATE INDEX IF NOT EXISTS ${e}_servable_until_idx ON ${e} (servable_until);
94
94
  staleWhileRevalidateMs: Number(t.stale_while_revalidate_ms)
95
95
  });
96
96
  }).catch((e) => {
97
- W.warn("postgres bootstrap failed", {}, e);
97
+ K.warn("postgres bootstrap failed", {}, e);
98
98
  }), o = (e, t) => {
99
99
  a.then(() => n.query(e, t)).catch((e) => {
100
- W.warn("postgres write failed", {}, e);
100
+ K.warn("postgres write failed", {}, e);
101
101
  });
102
102
  };
103
103
  return {
@@ -142,14 +142,14 @@ CREATE INDEX IF NOT EXISTS ${e}_servable_until_idx ON ${e} (servable_until);
142
142
  return Array.from(r.entries());
143
143
  }
144
144
  };
145
- }, K = z({ scope: "voltro:start" }), be = await (async () => {
145
+ }, J = V({ scope: "voltro:start" }), ye = await (async () => {
146
146
  try {
147
- let e = F(pe(L(import.meta.url)), "..", "package.json"), t = await B.readFile(e, "utf8");
147
+ let e = L(F(z(import.meta.url)), "..", "package.json"), t = await H.readFile(e, "utf8");
148
148
  return JSON.parse(t).version ?? "0.0.0";
149
149
  } catch {
150
150
  return "0.0.0";
151
151
  }
152
- })(), q = (e) => e instanceof Error && e._voltroControl === "redirect" && typeof e.location == "string", xe = (e) => e instanceof Error && e._voltroControl === "not-found", J = {
152
+ })(), be = (e) => e instanceof Error && e._voltroControl === "redirect" && typeof e.location == "string", Y = (e) => e instanceof Error && e._voltroControl === "not-found", X = {
153
153
  ".html": "text/html; charset=utf-8",
154
154
  ".js": "application/javascript",
155
155
  ".mjs": "application/javascript",
@@ -167,13 +167,13 @@ CREATE INDEX IF NOT EXISTS ${e}_servable_until_idx ON ${e} (servable_until);
167
167
  ".woff": "font/woff",
168
168
  ".woff2": "font/woff2",
169
169
  ".txt": "text/plain; charset=utf-8"
170
- }, Se = (e) => J[P(e).toLowerCase()] ?? "application/octet-stream", Y = (e) => e.replace(/<script\b(?=[^>]*\btype="module")(?:(?!<\/script>).)*<\/script>/gi, "").replace(/<script\b(?=[^>]*\bsrc=)(?:(?!<\/script>).)*<\/script>/gi, "").replace(/<link\b[^>]*\brel="modulepreload"[^>]*>/gi, ""), X = async (e) => {
170
+ }, xe = (e) => X[I(e).toLowerCase()] ?? "application/octet-stream", Z = (e) => e.replace(/<script\b(?=[^>]*\btype="module")(?:(?!<\/script>).)*<\/script>/gi, "").replace(/<script\b(?=[^>]*\bsrc=)(?:(?!<\/script>).)*<\/script>/gi, "").replace(/<link\b[^>]*\brel="modulepreload"[^>]*>/gi, ""), Q = async (e) => {
171
171
  try {
172
- return await B.stat(e), !0;
172
+ return await H.stat(e), !0;
173
173
  } catch {
174
174
  return !1;
175
175
  }
176
- }, Z = (e) => {
176
+ }, Se = (e) => {
177
177
  let t = [], n = 0, r = e.split("/").filter(Boolean), i = [];
178
178
  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, "\\$&"));
179
179
  let a = i.join("/");
@@ -183,7 +183,7 @@ CREATE INDEX IF NOT EXISTS ${e}_servable_until_idx ON ${e} (servable_until);
183
183
  priority: n
184
184
  };
185
185
  }, Ce = (e) => e.map((e) => {
186
- let { regex: t, paramNames: n, priority: r } = Z(e.pattern);
186
+ let { regex: t, paramNames: n, priority: r } = Se(e.pattern);
187
187
  return {
188
188
  pattern: e.pattern,
189
189
  file: e.file,
@@ -205,139 +205,141 @@ CREATE INDEX IF NOT EXISTS ${e}_servable_until_idx ON ${e} (servable_until);
205
205
  }
206
206
  return null;
207
207
  }, Te = async (e) => {
208
- let { provider: t, route: n, params: r, pathname: i, dirs: a, shellTemplate: s, requestHeaders: c, requestUrl: l = "", apiOrigin: u, apiName: d } = e, m = re(u, c.cookie, { apiName: d }), h = await t.getPage(n.pattern, n.file), g = o(h, n.file), _ = g === "spa" && ae(a, n.dirChain).some((e) => e.hasLayout);
208
+ let { provider: t, route: r, params: i, pathname: a, dirs: o, shellTemplate: s, requestHeaders: c, requestUrl: l = "", apiOrigin: u, apiName: d } = e, { search: p } = M(l), m = re(u, c.cookie, { apiName: d }), h = await t.getPage(r.pattern, r.file), g = n(h, r.file), _ = g === "spa" && S(o, r.dirChain).some((e) => e.hasLayout);
209
209
  if (g !== "ssr" && g !== "isr" && !_) return null;
210
- let te = ae(a, n.dirChain), v = {}, y = null, ne, ie = new AbortController();
210
+ let ne = S(o, r.dirChain), y = {}, x = null, ie, C = new AbortController();
211
211
  try {
212
- (await t.getHelpers()).beginStoreSeeds(), {chain: ne, segmentLoaderData: v} = await p({
213
- entries: te,
212
+ (await t.getHelpers()).beginStoreSeeds(), {chain: ie, segmentLoaderData: y} = await te({
213
+ entries: ne,
214
214
  loadLayout: (e) => t.getLayout(e.dir),
215
215
  loadError: (e) => t.getError(e.dir),
216
216
  loadPending: (e) => t.getPending(e.dir),
217
217
  ctx: {
218
- params: r,
219
- pathname: i,
220
- signal: ie.signal,
218
+ params: i,
219
+ pathname: a,
220
+ search: p,
221
+ signal: C.signal,
221
222
  headers: c,
222
223
  query: m
223
224
  }
224
- }), typeof h.loader == "function" && !_ && (y = await h.loader({
225
- params: r,
226
- pathname: i,
227
- signal: ie.signal,
225
+ }), typeof h.loader == "function" && !_ && (x = await h.loader({
226
+ params: i,
227
+ pathname: a,
228
+ search: p,
229
+ signal: C.signal,
228
230
  headers: c,
229
231
  query: m
230
232
  }));
231
233
  } catch (e) {
232
- if (q(e)) return {
234
+ if (be(e)) return {
233
235
  control: "redirect",
234
236
  status: e.status,
235
237
  location: e.location
236
238
  };
237
- if (xe(e)) return { control: "not-found" };
239
+ if (Y(e)) return { control: "not-found" };
238
240
  throw e;
239
241
  }
240
- let C = await t.getHelpers(), w = {
241
- pattern: n.pattern,
242
+ let w = await t.getHelpers(), ae = {
243
+ pattern: r.pattern,
242
244
  Component: h.default,
243
245
  meta: h.meta,
244
246
  loader: h.loader,
245
247
  ErrorBoundary: h.ErrorBoundary,
246
248
  Pending: h.Pending,
247
249
  renderMode: g,
248
- chain: ne
250
+ chain: ie
249
251
  }, T = {
250
- cookies: C.parseCookieHeader(c.cookie),
252
+ cookies: w.parseCookieHeader(c.cookie),
251
253
  headers: c,
252
254
  url: l
253
- }, E = C.i18n?.resolve(c.cookie, c["accept-language"]), D = h.interactive ?? "full";
255
+ }, D = w.i18n?.resolve(c.cookie, c["accept-language"]), O = h.interactive ?? "full";
254
256
  if (_) {
255
- let e = j({
256
- helpers: C,
257
- page: n.pattern,
258
- interactive: D,
257
+ let e = A({
258
+ helpers: w,
259
+ page: r.pattern,
260
+ interactive: O,
259
261
  delivery: "stream",
260
262
  renderInput: {
261
- descriptor: w,
262
- params: r,
263
- pathname: i,
264
- segmentLoaderData: v,
263
+ descriptor: ae,
264
+ params: i,
265
+ pathname: a,
266
+ segmentLoaderData: y,
265
267
  requestContext: T,
266
- ...E ? {
267
- outerWrap: E.outerWrap,
268
- locale: E.locale
268
+ ...D ? {
269
+ outerWrap: D.outerWrap,
270
+ locale: D.locale
269
271
  } : {}
270
272
  }
271
- }), t = E?.locale ?? T.cookies["voltro:lang"] ?? "en", a = (t) => ee({
272
- helpers: C,
273
+ }), t = D?.locale ?? T.cookies["voltro:lang"] ?? "en", n = (t) => f({
274
+ helpers: w,
273
275
  prepared: e,
274
276
  meta: t,
275
- interactive: D
277
+ interactive: O
276
278
  });
277
279
  if (e.hasDeferred) {
278
- let n = x({ shell: s });
280
+ let r = b({ shell: s });
279
281
  return {
280
282
  renderMode: "spa",
281
- stream: (r) => b({
282
- res: r,
283
- shell: n,
283
+ stream: (i) => v({
284
+ res: i,
285
+ shell: r,
284
286
  htmlLang: t,
285
287
  headers: {
286
288
  "content-type": "text/html; charset=utf-8",
287
289
  "x-voltro-rendered-by": "spa"
288
290
  },
289
- headInjection: a,
290
- render: (t) => C.renderPageToStream({
291
+ headInjection: n,
292
+ render: (t) => w.renderPageToStream({
291
293
  ...e.renderInput,
292
294
  ...t
293
295
  }),
294
296
  onShellError: (e) => {
295
- K.error("spa layout shell render failed", { pathname: i }, e), r.writeHead(500, { "content-type": "text/plain; charset=utf-8" }), r.end("server error");
297
+ J.error("spa layout shell render failed", { pathname: a }, e), i.writeHead(500, { "content-type": "text/plain; charset=utf-8" }), i.end("server error");
296
298
  }
297
299
  })
298
300
  };
299
301
  }
300
- let o = M({
301
- helpers: C,
302
+ let o = oe({
303
+ helpers: w,
302
304
  prepared: e
303
305
  });
304
306
  return {
305
- html: s.replace("<div id=\"root\"></div>", `<div id="root">${o.body}</div>`).replace("</head>", ` ${a(o.meta)}\n </head>`).replace(/<html(\s+lang="[^"]*")?/i, `<html lang="${t}"`),
307
+ html: s.replace("<div id=\"root\"></div>", `<div id="root">${o.body}</div>`).replace("</head>", ` ${n(o.meta)}\n </head>`).replace(/<html(\s+lang="[^"]*")?/i, `<html lang="${t}"`),
306
308
  renderMode: "spa",
307
309
  revalidateMs: null
308
310
  };
309
311
  }
310
- let O = f({
311
- helpers: C,
312
- page: n.pattern,
313
- pathname: i,
312
+ let k = ee({
313
+ helpers: w,
314
+ page: r.pattern,
315
+ pathname: a,
314
316
  renderMode: g,
315
- interactive: D,
316
- loaderData: y,
317
- segmentLoaderData: v,
317
+ interactive: O,
318
+ loaderData: x,
319
+ segmentLoaderData: y,
318
320
  pageLoaderRan: typeof h.loader == "function"
319
- }), k = {
320
- descriptor: w,
321
- params: r,
322
- pathname: i,
323
- loaderData: O.loaderData,
324
- segmentLoaderData: O.segmentLoaderData,
321
+ }), j = {
322
+ descriptor: ae,
323
+ params: i,
324
+ pathname: a,
325
+ loaderData: k.loaderData,
326
+ segmentLoaderData: k.segmentLoaderData,
325
327
  requestContext: T,
326
- ...E ? {
327
- outerWrap: E.outerWrap,
328
- locale: E.locale
328
+ ...D ? {
329
+ outerWrap: D.outerWrap,
330
+ locale: D.locale
329
331
  } : {}
330
- }, A = (e) => [
331
- C.renderMetaToHtml(e),
332
- `<meta name="voltro-interactive" content="${D}" />`,
333
- ...O.hasDeferred ? [C.renderDeferredRegistryScript()] : [],
334
- C.renderRouterStateScript(O.stateInput)
332
+ }, se = (e) => [
333
+ w.renderMetaToHtml(e),
334
+ `<meta name="voltro-interactive" content="${O}" />`,
335
+ ...k.hasDeferred ? [w.renderDeferredRegistryScript()] : [],
336
+ w.renderRouterStateScript(k.stateInput)
335
337
  ].filter((e) => e.length > 0).join("\n ");
336
- if (g === "ssr" && D === "full" && e.buffered !== !0) {
337
- let e = E?.locale ?? T.cookies["voltro:lang"] ?? "en", t = x({ shell: s });
338
+ if (g === "ssr" && O === "full" && e.buffered !== !0) {
339
+ let e = D?.locale ?? T.cookies["voltro:lang"] ?? "en", t = b({ shell: s });
338
340
  return {
339
341
  renderMode: "ssr",
340
- stream: (n) => b({
342
+ stream: (n) => v({
341
343
  res: n,
342
344
  shell: t,
343
345
  htmlLang: e,
@@ -345,27 +347,27 @@ CREATE INDEX IF NOT EXISTS ${e}_servable_until_idx ON ${e} (servable_until);
345
347
  "content-type": "text/html; charset=utf-8",
346
348
  "x-voltro-rendered-by": "ssr"
347
349
  },
348
- headInjection: A,
349
- render: (e) => C.renderPageToStream({
350
- ...k,
350
+ headInjection: se,
351
+ render: (e) => w.renderPageToStream({
352
+ ...j,
351
353
  ...e
352
354
  }),
353
355
  onShellError: (e) => {
354
- K.error("ssr shell render failed", { pathname: i }, e), n.writeHead(500, { "content-type": "text/plain; charset=utf-8" }), n.end("server error");
356
+ J.error("ssr shell render failed", { pathname: a }, e), n.writeHead(500, { "content-type": "text/plain; charset=utf-8" }), n.end("server error");
355
357
  }
356
358
  })
357
359
  };
358
360
  }
359
- let { html: oe, meta: se } = C.renderPageToHtml(k), ce = A(se), le = E?.locale ?? T.cookies["voltro:lang"] ?? "en", N = s.replace("<div id=\"root\"></div>", `<div id="root">${oe}</div>`).replace("</head>", ` ${ce}\n </head>`).replace(/<html(\s+lang="[^"]*")?/i, `<html lang="${le}"`);
360
- D === "none" && (N = Y(N));
361
- let ue = g === "isr" ? S(h.revalidate) : null;
361
+ let { html: ce, meta: le } = w.renderPageToHtml(j), ue = se(le), de = D?.locale ?? T.cookies["voltro:lang"] ?? "en", N = s.replace("<div id=\"root\"></div>", `<div id="root">${ce}</div>`).replace("</head>", ` ${ue}\n </head>`).replace(/<html(\s+lang="[^"]*")?/i, `<html lang="${de}"`);
362
+ O === "none" && (N = Z(N));
363
+ let P = g === "isr" ? E(h.revalidate) : null;
362
364
  return {
363
365
  html: N,
364
366
  renderMode: g,
365
- revalidateMs: ue
367
+ revalidateMs: P
366
368
  };
367
- }, Q = (e) => e === "" ? "/" : e, Ee = async (e) => {
368
- let t = await import(R(e).href);
369
+ }, $ = (e) => e === "" ? "/" : e, Ee = async (e) => {
370
+ let t = await import(B(e).href);
369
371
  return {
370
372
  kind: "bundle",
371
373
  getPageMeta: () => t.pageMeta,
@@ -375,18 +377,18 @@ CREATE INDEX IF NOT EXISTS ${e}_servable_until_idx ON ${e} (servable_until);
375
377
  return typeof r == "function" ? await r() : r;
376
378
  },
377
379
  async getLayout(e) {
378
- let n = t.layouts[Q(e)];
379
- if (!n) throw Error(`[voltro start] ssr bundle missing layout for dir ${Q(e)}`);
380
+ let n = t.layouts[$(e)];
381
+ if (!n) throw Error(`[voltro start] ssr bundle missing layout for dir ${$(e)}`);
380
382
  return typeof n == "function" ? await n() : n;
381
383
  },
382
384
  async getError(e) {
383
- let n = t.errors[Q(e)];
384
- if (!n) throw Error(`[voltro start] ssr bundle missing error for dir ${Q(e)}`);
385
+ let n = t.errors[$(e)];
386
+ if (!n) throw Error(`[voltro start] ssr bundle missing error for dir ${$(e)}`);
385
387
  return typeof n == "function" ? await n() : n;
386
388
  },
387
389
  async getPending(e) {
388
- let n = t.pendings[Q(e)];
389
- if (!n) throw Error(`[voltro start] ssr bundle missing pending for dir ${Q(e)}`);
390
+ let n = t.pendings[$(e)];
391
+ if (!n) throw Error(`[voltro start] ssr bundle missing pending for dir ${$(e)}`);
390
392
  return typeof n == "function" ? await n() : n;
391
393
  },
392
394
  async getHelpers() {
@@ -395,7 +397,7 @@ CREATE INDEX IF NOT EXISTS ${e}_servable_until_idx ON ${e} (servable_until);
395
397
  async close() {}
396
398
  };
397
399
  }, De = async (e, t) => {
398
- let n = await g("vite", () => import("vite")), r = (await import("@vitejs/plugin-react")).default, i = (await import("@tailwindcss/vite")).default, o = await n.createServer({
400
+ let n = await y("vite", () => import("vite")), r = (await import("@vitejs/plugin-react")).default, i = (await import("@tailwindcss/vite")).default, o = await n.createServer({
399
401
  root: t,
400
402
  envPrefix: "__VOLTRO_VITE_ENV_DISABLED__",
401
403
  plugins: [r(), i()],
@@ -407,10 +409,10 @@ CREATE INDEX IF NOT EXISTS ${e}_servable_until_idx ON ${e} (servable_until);
407
409
  },
408
410
  appType: "custom",
409
411
  logLevel: "warn"
410
- }), s = F(e, "src", "pages"), c = (e) => e === "" ? s : F(s, e), l = T({
411
- limit: a(),
412
- onColdStart: (e) => K.debug("ssr cold-compile start", { id: e }),
413
- onColdEnd: (e, { durationMs: t, failed: n }) => K.debug(`ssr cold-compile ${n ? "FAILED" : "end"} ${t}ms`, {
412
+ }), s = L(e, "src", "pages"), c = (e) => e === "" ? s : L(s, e), l = a({
413
+ limit: d(),
414
+ onColdStart: (e) => J.debug("ssr cold-compile start", { id: e }),
415
+ onColdEnd: (e, { durationMs: t, failed: n }) => J.debug(`ssr cold-compile ${n ? "FAILED" : "end"} ${t}ms`, {
414
416
  id: e,
415
417
  ms: t,
416
418
  ...n ? { failed: !0 } : {}
@@ -419,16 +421,16 @@ CREATE INDEX IF NOT EXISTS ${e}_servable_until_idx ON ${e} (servable_until);
419
421
  return {
420
422
  kind: "middleware",
421
423
  async getPage(e, t) {
422
- return u(F(s, t));
424
+ return u(L(s, t));
423
425
  },
424
426
  async getLayout(e) {
425
- return u(F(c(e), "layout.tsx"));
427
+ return u(L(c(e), "layout.tsx"));
426
428
  },
427
429
  async getError(e) {
428
- return u(F(c(e), "error.tsx"));
430
+ return u(L(c(e), "error.tsx"));
429
431
  },
430
432
  async getPending(e) {
431
- return u(F(c(e), "loading.tsx"));
433
+ return u(L(c(e), "loading.tsx"));
432
434
  },
433
435
  async getHelpers() {
434
436
  return await u("@voltro/web/ssr");
@@ -437,99 +439,99 @@ CREATE INDEX IF NOT EXISTS ${e}_servable_until_idx ON ${e} (servable_until);
437
439
  await o.close();
438
440
  }
439
441
  };
440
- }, Oe = async (a) => {
441
- let o = fe(), f = await D(a);
442
- if (!f) return {
442
+ }, Oe = async (n) => {
443
+ let a = fe(), d = await D(n);
444
+ if (!d) return {
443
445
  ran: !1,
444
446
  exitCode: 0
445
447
  };
446
- if (f.type !== "web") return K.error("only web apps are supported by `voltro start`"), {
448
+ if (d.type !== "web") return J.error("only web apps are supported by `voltro start`"), {
447
449
  ran: !0,
448
450
  exitCode: 1
449
451
  };
450
- let { resolved: p } = await m({
451
- rawEnv: f.env,
452
+ let { resolved: ee } = await C({
453
+ rawEnv: d.env,
452
454
  appType: "web",
453
- root: a,
454
- log: K,
455
+ root: n,
456
+ log: J,
455
457
  generateTypes: !1
456
- }), ee = p.publicValues;
457
- o.mark("config");
458
- let g = d();
459
- u(g), K.info("booting voltro start", { app: f.name ?? "(unnamed)" });
460
- let b = (() => {
458
+ }), te = ee.publicValues;
459
+ a.mark("config");
460
+ let f = r();
461
+ i(f), J.info("booting voltro start", { app: d.name ?? "(unnamed)" });
462
+ let v = (() => {
461
463
  if (process.env.VOLTRO_IS_DASHBOARD === "1" && process.env.VOLTRO_DASHBOARD_PORT) return Number(process.env.VOLTRO_DASHBOARD_PORT);
462
464
  if (process.env.PORT) {
463
465
  let e = Number(process.env.PORT);
464
466
  if (Number.isFinite(e) && e > 0) return e;
465
467
  }
466
- return f.port ?? 5173;
467
- })(), re = F(a, ".framework"), x = F(re, "dist"), S = F(x, "index.html");
468
- if (!await X(S)) return K.error("no built dist found — run `voltro build` first", { distDir: x }), {
468
+ return d.port ?? 5173;
469
+ })(), re = L(n, ".framework"), y = L(re, "dist"), b = L(y, "index.html");
470
+ if (!await Q(b)) return J.error("no built dist found — run `voltro build` first", { distDir: y }), {
469
471
  ran: !0,
470
472
  exitCode: 1
471
473
  };
472
- let T = f.name ?? "unnamed", j = A("web", T, b), M = n(T);
473
- await w({
474
- id: j,
475
- name: T,
474
+ let E = d.name ?? "unnamed", A = m("web", E, v), M = t(E);
475
+ await x({
476
+ id: A,
477
+ name: E,
476
478
  kind: "web",
477
- url: `http://localhost:${b}`,
479
+ url: `http://localhost:${v}`,
478
480
  pid: process.pid,
479
481
  status: "booting",
480
482
  logFile: M.path
481
483
  }).catch(() => {});
482
- let pe = F(x, "_voltro", "shell.html"), P = await X(pe) ? await B.readFile(pe, "utf8") : await B.readFile(S, "utf8"), I = await h(a, f), L = E(I[0]), R = I[0]?.name, z, V = null;
484
+ let oe = L(y, "_voltro", "shell.html"), F = await Q(oe) ? await H.readFile(oe, "utf8") : await H.readFile(b, "utf8"), I = await p(n, d), R = T(I[0]), z = I[0]?.name, B, V = null;
483
485
  process.env.SSR_CACHE === "postgres" && process.env.PG_HOST ? (V = new (await (import("pg"))).default.Client({
484
486
  host: process.env.PG_HOST,
485
487
  port: Number(process.env.PG_PORT ?? 5432),
486
488
  user: process.env.PG_USER ?? "app",
487
489
  password: process.env.PG_PASSWORD ?? "app",
488
490
  database: process.env.PG_DATABASE ?? "app"
489
- }), await V.connect(), z = ye({ client: V }), K.info("isr cache backend: postgres", { table: "voltro_isr_cache" })) : (z = k(), K.info("isr cache backend: memory (per-process)", { hint: "set SSR_CACHE=postgres for persistent storage" })), await C(a, f, I, ee);
490
- let { pages: H, dirs: U } = await v(F(a, "src", "pages")), W = Ce(H);
491
- o.mark("scan");
492
- let G = F(x, "server", "ssrEntry.js"), ve = await X(G);
493
- if (!ve && process.env.NODE_ENV === "production") throw K.fatal(`production \`voltro start\` requires a precompiled SSR bundle at ${G} 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 ${G}`);
494
- let q = ve ? await Ee(G) : await De(a, re);
495
- K.info(`ssr loader: ${q.kind}`, {
491
+ }), await V.connect(), B = ve({ client: V }), J.info("isr cache backend: postgres", { table: "voltro_isr_cache" })) : (B = ie(), J.info("isr cache backend: memory (per-process)", { hint: "set SSR_CACHE=postgres for persistent storage" })), await w(n, d, I, te);
492
+ let { pages: U, dirs: W } = await g(L(n, "src", "pages")), G = Ce(U);
493
+ a.mark("scan");
494
+ let K = L(y, "server", "ssrEntry.js"), _e = await Q(K);
495
+ if (!_e && process.env.NODE_ENV === "production") throw J.fatal(`production \`voltro start\` requires a precompiled SSR bundle at ${K} 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 ${K}`);
496
+ let q = _e ? await Ee(K) : await De(n, re);
497
+ J.info(`ssr loader: ${q.kind}`, {
496
498
  kind: q.kind,
497
499
  ...q.kind === "middleware" ? { hint: "no pre-built SSR bundle found; run `voltro build` to enable bundle mode" } : {}
498
- }), o.mark("provider");
499
- let xe = q.getPageMeta?.(), J = /* @__PURE__ */ new Map(), Y = 0;
500
- for (let e of H) {
501
- let t = xe?.[e.pattern];
500
+ }), a.mark("provider");
501
+ let be = q.getPageMeta?.(), Y = /* @__PURE__ */ new Map(), X = 0;
502
+ for (let e of U) {
503
+ let t = be?.[e.pattern];
502
504
  if (t) {
503
- J.set(e.pattern, t);
505
+ Y.set(e.pattern, t);
504
506
  continue;
505
507
  }
506
508
  try {
507
509
  let t = await q.getPage(e.pattern, e.file);
508
- J.set(e.pattern, ie(t, e.file)), Y++;
510
+ Y.set(e.pattern, s(t, e.file)), X++;
509
511
  } catch (t) {
510
- K.warn("failed to load page metadata", { pattern: e.pattern }, t);
512
+ J.warn("failed to load page metadata", { pattern: e.pattern }, t);
511
513
  }
512
514
  }
513
- K.info(`registered ${J.size} route(s)`, {
514
- count: J.size,
515
- fromManifest: J.size - Y,
516
- fromModules: Y
517
- }), o.mark("routes");
515
+ J.info(`registered ${Y.size} route(s)`, {
516
+ count: Y.size,
517
+ fromManifest: Y.size - X,
518
+ fromModules: X
519
+ }), a.mark("routes");
518
520
  let Z = /* @__PURE__ */ new Set();
519
- for (let e of W) J.get(e.pattern)?.renderMode === "spa" && ae(U, e.dirChain).some((e) => e.hasLayout) && Z.add(e.pattern);
520
- Z.size > 0 && K.info(`${Z.size} spa route(s) render an SSR layout shell`, { patterns: [...Z] });
521
- let Q = /* @__PURE__ */ new Map();
522
- for (let [e, t] of J) t.cacheInvalidatesOn.length > 0 && Q.set(e, t.cacheInvalidatesOn);
523
- let Oe = /* @__PURE__ */ new Map();
524
- for (let e of W) Oe.set(e.pattern, e.regex);
525
- let ke = _e({
526
- cache: z,
527
- tableSubscriptionsByPattern: Q,
528
- regexByPattern: Oe
521
+ for (let e of G) Y.get(e.pattern)?.renderMode === "spa" && S(W, e.dirChain).some((e) => e.hasLayout) && Z.add(e.pattern);
522
+ Z.size > 0 && J.info(`${Z.size} spa route(s) render an SSR layout shell`, { patterns: [...Z] });
523
+ let Se = /* @__PURE__ */ new Map();
524
+ for (let [e, t] of Y) t.cacheInvalidatesOn.length > 0 && Se.set(e, t.cacheInvalidatesOn);
525
+ let $ = /* @__PURE__ */ new Map();
526
+ for (let e of G) $.set(e.pattern, e.regex);
527
+ let Oe = ge({
528
+ cache: B,
529
+ tableSubscriptionsByPattern: Se,
530
+ regexByPattern: $
529
531
  });
530
- await ke.start(), o.mark("cdc");
531
- let Ae = O(), je = H.map((e) => {
532
- let t = J.get(e.pattern);
532
+ await Oe.start(), a.mark("cdc");
533
+ let ke = O(), Ae = U.map((e) => {
534
+ let t = Y.get(e.pattern);
533
535
  return {
534
536
  pattern: e.pattern,
535
537
  file: e.file,
@@ -544,20 +546,20 @@ CREATE INDEX IF NOT EXISTS ${e}_servable_until_idx ON ${e} (servable_until);
544
546
  hasMeta: t?.hasMeta ?? !1,
545
547
  hasGetStaticPaths: t?.hasGetStaticPaths ?? !1
546
548
  };
547
- }), Me = U.map((e) => ({
549
+ }), je = W.map((e) => ({
548
550
  dir: e.dir,
549
551
  hasLayout: e.hasLayout,
550
552
  hasError: e.hasError,
551
553
  hasPending: e.hasPending,
552
554
  hasNotFound: e.hasNotFound
553
- })), Ne = V ? "postgres" : "memory", Pe = {
555
+ })), Me = V ? "postgres" : "memory", Ne = {
554
556
  kind: "web",
555
557
  meta: {
556
- name: f.name ?? "(unnamed)",
557
- voltroVersion: be,
558
- port: b,
558
+ name: d.name ?? "(unnamed)",
559
+ voltroVersion: ye,
560
+ port: v,
559
561
  mode: "start",
560
- apis: Object.entries(f.apis ?? {}).map(([e, t]) => {
562
+ apis: Object.entries(d.apis ?? {}).map(([e, t]) => {
561
563
  let n = {
562
564
  name: e,
563
565
  package: t.package
@@ -565,10 +567,10 @@ CREATE INDEX IF NOT EXISTS ${e}_servable_until_idx ON ${e} (servable_until);
565
567
  return t.url !== void 0 && (n.url = t.url), n;
566
568
  })
567
569
  },
568
- routes: je,
569
- dirs: Me,
570
+ routes: Ae,
571
+ dirs: je,
570
572
  cache: () => {
571
- let e = Date.now(), t = z.snapshot().map(([t, n]) => ({
573
+ let e = Date.now(), t = B.snapshot().map(([t, n]) => ({
572
574
  key: t,
573
575
  renderedAt: n.renderedAt,
574
576
  expiresAt: n.expiresAt,
@@ -579,15 +581,15 @@ CREATE INDEX IF NOT EXISTS ${e}_servable_until_idx ON ${e} (servable_until);
579
581
  staleWhileRevalidateMs: n.staleWhileRevalidateMs
580
582
  }));
581
583
  return {
582
- backend: Ne,
583
- size: z.size(),
584
+ backend: Me,
585
+ size: B.size(),
584
586
  entries: t
585
587
  };
586
588
  },
587
- metrics: () => he()
588
- }, Fe = async (t, n) => {
589
- let r = t.split("?")[0] ?? "/";
590
- if (f.name === "voltroDashboard" && r === "/api/dashboard/registry") try {
589
+ metrics: () => me()
590
+ }, Pe = async (t, r) => {
591
+ let i = t.split("?")[0] ?? "/";
592
+ if (d.name === "voltroDashboard" && i === "/api/dashboard/registry") try {
591
593
  let e = await _();
592
594
  return {
593
595
  status: 200,
@@ -601,7 +603,7 @@ CREATE INDEX IF NOT EXISTS ${e}_servable_until_idx ON ${e} (servable_until);
601
603
  body: `registry read error: ${e.message}`
602
604
  };
603
605
  }
604
- if (f.name === "voltroDashboard" && r === "/api/dashboard/config") {
606
+ if (d.name === "voltroDashboard" && i === "/api/dashboard/config") {
605
607
  let e = process.env.VOLTRO_DASHBOARD_APPS, t = [];
606
608
  if (e && e.trim().length > 0) {
607
609
  let n;
@@ -630,19 +632,19 @@ CREATE INDEX IF NOT EXISTS ${e}_servable_until_idx ON ${e} (servable_until);
630
632
  body: JSON.stringify({ apps: t })
631
633
  };
632
634
  }
633
- if (r === "/_voltro/inspect/logs") {
634
- let e = c(t, i(), n);
635
+ if (i === "/_voltro/inspect/logs") {
636
+ let e = se(t, l(), r);
635
637
  return {
636
638
  status: e.status,
637
639
  headers: {
638
640
  "content-type": e.contentType,
639
- ...de(n.origin)
641
+ ...P(r.origin)
640
642
  },
641
643
  body: e.body
642
644
  };
643
645
  }
644
- if (r !== "/_voltro/inspect/stream") {
645
- let e = ue(t, Pe, n);
646
+ if (i !== "/_voltro/inspect/stream") {
647
+ let e = N(t, Ne, r);
646
648
  if (e !== null) return {
647
649
  status: e.status,
648
650
  headers: {
@@ -652,71 +654,71 @@ CREATE INDEX IF NOT EXISTS ${e}_servable_until_idx ON ${e} (servable_until);
652
654
  body: e.body
653
655
  };
654
656
  }
655
- let o = we(r, W), l = o ? J.get(o.route.pattern)?.renderMode : void 0, u = l === "ssr" || l === "isr" || (o ? Z.has(o.route.pattern) : !1), d = r === "/" ? F(x, "index.html") : F(x, r.replace(/^\//, ""), "index.html");
656
- if (!u && await X(d)) return {
657
+ let a = we(i, G), o = a ? Y.get(a.route.pattern)?.renderMode : void 0, s = o === "ssr" || o === "isr" || (a ? Z.has(a.route.pattern) : !1), c = i === "/" ? L(y, "index.html") : L(y, i.replace(/^\//, ""), "index.html");
658
+ if (!s && await Q(c)) return {
657
659
  status: 200,
658
660
  headers: { "content-type": "text/html; charset=utf-8" },
659
- body: await B.readFile(d)
661
+ body: await H.readFile(c)
660
662
  };
661
- if (/\.[a-z0-9]+$/i.test(r)) {
662
- let e = F(x, r.replace(/^\//, ""));
663
- if (await X(e)) {
664
- let t = await B.readFile(e);
663
+ if (/\.[a-z0-9]+$/i.test(i)) {
664
+ let e = L(y, i.replace(/^\//, ""));
665
+ if (await Q(e)) {
666
+ let t = await H.readFile(e);
665
667
  return {
666
668
  status: 200,
667
- headers: { "content-type": Se(e) },
669
+ headers: { "content-type": xe(e) },
668
670
  body: t
669
671
  };
670
672
  }
671
673
  }
672
- let p = we(r, W);
673
- if (!p) return {
674
+ let u = we(i, G);
675
+ if (!u) return {
674
676
  status: 404,
675
677
  headers: { "content-type": "text/plain" },
676
678
  body: "not found"
677
679
  };
678
- let m = J.get(p.route.pattern), ee = n["x-tenant"] ?? "anonymous", h = (await q.getHelpers()).i18n?.resolve(n.cookie, n["accept-language"])?.locale, v = s(r, {
679
- ...m?.tenantAware ? { tenant: ee } : {},
680
- ...h ? { locale: h } : {}
681
- }), y = z.get(v), b = Date.now();
682
- if (y && e(y, b)) return g.emit("cache", {
680
+ let ee = Y.get(u.route.pattern), te = r["x-tenant"] ?? "anonymous", p = (await q.getHelpers()).i18n?.resolve(r.cookie, r["accept-language"])?.locale, m = e(i, {
681
+ ...ee?.tenantAware ? { tenant: te } : {},
682
+ ...p ? { locale: p } : {}
683
+ }), g = B.get(m), v = Date.now();
684
+ if (g && h(g, v)) return f.emit("cache", {
683
685
  kind: "HIT",
684
- key: v,
685
- ageMs: b - y.renderedAt
686
+ key: m,
687
+ ageMs: v - g.renderedAt
686
688
  }), {
687
689
  status: 200,
688
690
  headers: {
689
691
  "content-type": "text/html; charset=utf-8",
690
692
  "x-voltro-rendered-by": "isr",
691
693
  "x-voltro-cache": "HIT",
692
- "x-voltro-cache-key": v,
693
- "x-voltro-cache-age-ms": String(b - y.renderedAt)
694
+ "x-voltro-cache-key": m,
695
+ "x-voltro-cache-age-ms": String(v - g.renderedAt)
694
696
  },
695
- body: y.html
697
+ body: g.html
696
698
  };
697
- if (y && te(y, b)) return g.emit("cache", {
699
+ if (g && k(g, v)) return f.emit("cache", {
698
700
  kind: "STALE",
699
- key: v,
700
- ageMs: b - y.renderedAt
701
+ key: m,
702
+ ageMs: v - g.renderedAt
701
703
  }), (async () => {
702
704
  try {
703
705
  let e = await Te({
704
706
  provider: q,
705
- root: a,
706
- route: p.route,
707
- params: p.params,
708
- pathname: r,
709
- dirs: U,
710
- shellTemplate: P,
711
- requestHeaders: n,
712
- apiOrigin: L,
713
- apiName: R,
707
+ root: n,
708
+ route: u.route,
709
+ params: u.params,
710
+ pathname: i,
711
+ dirs: W,
712
+ shellTemplate: F,
713
+ requestHeaders: r,
714
+ apiOrigin: R,
715
+ apiName: z,
714
716
  requestUrl: t,
715
717
  buffered: !0
716
718
  });
717
719
  if (e && "html" in e && e.renderMode === "isr" && e.revalidateMs !== null) {
718
- let t = J.get(p.route.pattern)?.staleWhileRevalidateMs ?? 0, n = Date.now();
719
- z.set(v, {
720
+ let t = Y.get(u.route.pattern)?.staleWhileRevalidateMs ?? 0, n = Date.now();
721
+ B.set(m, {
720
722
  html: e.html,
721
723
  renderedAt: n,
722
724
  expiresAt: n + e.revalidateMs,
@@ -726,7 +728,7 @@ CREATE INDEX IF NOT EXISTS ${e}_servable_until_idx ON ${e} (servable_until);
726
728
  });
727
729
  }
728
730
  } catch (e) {
729
- K.warn("background SWR refresh failed", { url: r }, e);
731
+ J.warn("background SWR refresh failed", { url: i }, e);
730
732
  }
731
733
  })(), {
732
734
  status: 200,
@@ -734,23 +736,23 @@ CREATE INDEX IF NOT EXISTS ${e}_servable_until_idx ON ${e} (servable_until);
734
736
  "content-type": "text/html; charset=utf-8",
735
737
  "x-voltro-rendered-by": "isr",
736
738
  "x-voltro-cache": "STALE",
737
- "x-voltro-cache-key": v,
738
- "x-voltro-cache-age-ms": String(b - y.renderedAt)
739
+ "x-voltro-cache-key": m,
740
+ "x-voltro-cache-age-ms": String(v - g.renderedAt)
739
741
  },
740
- body: y.html
742
+ body: g.html
741
743
  };
742
744
  try {
743
745
  let e = await Te({
744
746
  provider: q,
745
- root: a,
746
- route: p.route,
747
- params: p.params,
748
- pathname: r,
749
- dirs: U,
750
- shellTemplate: P,
751
- requestHeaders: n,
752
- apiOrigin: L,
753
- apiName: R,
747
+ root: n,
748
+ route: u.route,
749
+ params: u.params,
750
+ pathname: i,
751
+ dirs: W,
752
+ shellTemplate: F,
753
+ requestHeaders: r,
754
+ apiOrigin: R,
755
+ apiName: z,
754
756
  requestUrl: t
755
757
  });
756
758
  if (!e) return {
@@ -759,7 +761,7 @@ CREATE INDEX IF NOT EXISTS ${e}_servable_until_idx ON ${e} (servable_until);
759
761
  "content-type": "text/html; charset=utf-8",
760
762
  "x-voltro-rendered-by": "spa-fallback"
761
763
  },
762
- body: P
764
+ body: F
763
765
  };
764
766
  if ("stream" in e) return {
765
767
  status: 200,
@@ -782,36 +784,36 @@ CREATE INDEX IF NOT EXISTS ${e}_servable_until_idx ON ${e} (servable_until);
782
784
  },
783
785
  body: "not found"
784
786
  };
785
- let i = {
787
+ let a = {
786
788
  "content-type": "text/html; charset=utf-8",
787
789
  "x-voltro-rendered-by": e.renderMode
788
790
  };
789
791
  if (e.renderMode === "isr" && e.revalidateMs !== null) {
790
- let t = Date.now(), n = J.get(p.route.pattern)?.staleWhileRevalidateMs ?? 0;
791
- z.set(v, {
792
+ let t = Date.now(), n = Y.get(u.route.pattern)?.staleWhileRevalidateMs ?? 0;
793
+ B.set(m, {
792
794
  html: e.html,
793
795
  renderedAt: t,
794
796
  expiresAt: t + e.revalidateMs,
795
797
  servableUntil: t + e.revalidateMs + n,
796
798
  revalidateMs: e.revalidateMs,
797
799
  staleWhileRevalidateMs: n
798
- }), i["x-voltro-cache"] = "MISS", i["x-voltro-cache-key"] = v, i["x-voltro-cache-revalidate-ms"] = String(e.revalidateMs), n > 0 && (i["x-voltro-cache-swr-ms"] = String(n)), g.emit("cache", {
800
+ }), a["x-voltro-cache"] = "MISS", a["x-voltro-cache-key"] = m, a["x-voltro-cache-revalidate-ms"] = String(e.revalidateMs), n > 0 && (a["x-voltro-cache-swr-ms"] = String(n)), f.emit("cache", {
799
801
  kind: "MISS",
800
- key: v,
802
+ key: m,
801
803
  revalidateMs: e.revalidateMs,
802
804
  swrMs: n
803
805
  });
804
- } else e.renderMode === "isr" && (i["x-voltro-cache"] = "BYPASS", g.emit("cache", {
806
+ } else e.renderMode === "isr" && (a["x-voltro-cache"] = "BYPASS", f.emit("cache", {
805
807
  kind: "BYPASS",
806
- key: v
808
+ key: m
807
809
  }));
808
810
  return {
809
811
  status: 200,
810
- headers: i,
812
+ headers: a,
811
813
  body: e.html
812
814
  };
813
815
  } catch (e) {
814
- return K.error("render error", { url: r }, e), ne(e) ? {
816
+ return J.error("render error", { url: i }, e), ne(e) ? {
815
817
  status: 500,
816
818
  headers: {
817
819
  "content-type": "text/plain; charset=utf-8",
@@ -824,49 +826,49 @@ CREATE INDEX IF NOT EXISTS ${e}_servable_until_idx ON ${e} (servable_until);
824
826
  body: "server error"
825
827
  };
826
828
  }
827
- }, Ie = !1, Le = ge(async (e, t) => {
828
- let n = e.url ?? "/", i = Date.now(), a = {};
829
- for (let [t, n] of Object.entries(e.headers)) n !== void 0 && (a[t.toLowerCase()] = Array.isArray(n) ? n.join(", ") : n);
830
- let o = n.split("?")[0] ?? "/", s = (e.method ?? "GET").toUpperCase();
831
- if (o === "/internal/liveness") {
829
+ }, Fe = !1, Ie = he(async (e, t) => {
830
+ let n = e.url ?? "/", r = Date.now(), i = {};
831
+ for (let [t, n] of Object.entries(e.headers)) n !== void 0 && (i[t.toLowerCase()] = Array.isArray(n) ? n.join(", ") : n);
832
+ let a = n.split("?")[0] ?? "/", s = (e.method ?? "GET").toUpperCase();
833
+ if (a === "/internal/liveness") {
832
834
  t.writeHead(200, {
833
835
  "content-type": "text/plain",
834
836
  "cache-control": "no-store"
835
837
  }), t.end("ok");
836
838
  return;
837
839
  }
838
- if (o === "/internal/readiness") {
839
- let e = Ie ? 200 : 503;
840
+ if (a === "/internal/readiness") {
841
+ let e = Fe ? 200 : 503;
840
842
  t.writeHead(e, {
841
843
  "content-type": "text/plain",
842
844
  "cache-control": "no-store"
843
- }), t.end(Ie ? "ready" : "not-ready");
845
+ }), t.end(Fe ? "ready" : "not-ready");
844
846
  return;
845
847
  }
846
- if (s === "OPTIONS" && o.startsWith("/_voltro/inspect")) {
847
- let e = de(a.origin);
848
+ if (s === "OPTIONS" && a.startsWith("/_voltro/inspect")) {
849
+ let e = P(i.origin);
848
850
  t.writeHead(204, e), t.end();
849
851
  return;
850
852
  }
851
- if (f.name === "voltroDashboard" && o === "/api/dashboard/proxy") {
853
+ if (d.name === "voltroDashboard" && a === "/api/dashboard/proxy") {
852
854
  let r = new URL(n, "http://x").searchParams.get("target");
853
855
  if (!r) {
854
856
  t.writeHead(400, { "content-type": "text/plain" }), t.end("missing ?target=");
855
857
  return;
856
858
  }
857
- if (!le(r)) {
859
+ if (!ue(r)) {
858
860
  t.writeHead(400, { "content-type": "text/plain" }), t.end("target not allowed: must be loopback or an origin configured in VOLTRO_DASHBOARD_APPS");
859
861
  return;
860
862
  }
861
863
  try {
862
- let n = { accept: a.accept ?? "application/json" }, i = a.authorization;
863
- i ? n.authorization = Array.isArray(i) ? i[0] : i : se(r) && process.env.VOLTRO_INSPECT_TOKEN && (n.authorization = `Bearer ${process.env.VOLTRO_INSPECT_TOKEN}`);
864
+ let n = { accept: i.accept ?? "application/json" }, a = i.authorization;
865
+ a ? n.authorization = Array.isArray(a) ? a[0] : a : ce(r) && process.env.VOLTRO_INSPECT_TOKEN && (n.authorization = `Bearer ${process.env.VOLTRO_INSPECT_TOKEN}`);
864
866
  let o;
865
867
  if (s && s !== "GET" && s !== "HEAD") {
866
868
  let t = [];
867
869
  for await (let n of e) t.push(n);
868
870
  o = Buffer.concat(t);
869
- let r = a["content-type"];
871
+ let r = i["content-type"];
870
872
  r && (n["content-type"] = Array.isArray(r) ? r[0] : r);
871
873
  }
872
874
  let c = await fetch(r, {
@@ -884,27 +886,27 @@ CREATE INDEX IF NOT EXISTS ${e}_servable_until_idx ON ${e} (servable_until);
884
886
  }
885
887
  return;
886
888
  }
887
- if (f.name === "voltroDashboard" && o === "/api/dashboard/proxy/stream") {
889
+ if (d.name === "voltroDashboard" && a === "/api/dashboard/proxy/stream") {
888
890
  let r = new URL(n, "http://x").searchParams.get("target");
889
891
  if (!r) {
890
892
  t.writeHead(400, { "content-type": "text/plain" }), t.end("missing ?target=");
891
893
  return;
892
894
  }
893
- if (!le(r)) {
895
+ if (!ue(r)) {
894
896
  t.writeHead(400, { "content-type": "text/plain" }), t.end("target not allowed: must be loopback or an origin configured in VOLTRO_DASHBOARD_APPS");
895
897
  return;
896
898
  }
897
- let i = new AbortController();
898
- e.on("close", () => i.abort()), t.on("close", () => i.abort());
899
+ let a = new AbortController();
900
+ e.on("close", () => a.abort()), t.on("close", () => a.abort());
899
901
  try {
900
- let e = a.authorization ?? (se(r) && process.env.VOLTRO_INSPECT_TOKEN ? `Bearer ${process.env.VOLTRO_INSPECT_TOKEN}` : void 0), n = await fetch(r, {
902
+ let e = i.authorization ?? (ce(r) && process.env.VOLTRO_INSPECT_TOKEN ? `Bearer ${process.env.VOLTRO_INSPECT_TOKEN}` : void 0), n = await fetch(r, {
901
903
  redirect: "manual",
902
904
  method: "GET",
903
905
  headers: {
904
906
  accept: "text/event-stream",
905
907
  ...e ? { authorization: Array.isArray(e) ? e[0] : e } : {}
906
908
  },
907
- signal: i.signal
909
+ signal: a.signal
908
910
  });
909
911
  if (!n.ok || !n.body) {
910
912
  t.writeHead(n.status, { "content-type": "text/plain" }), t.end(`upstream ${n.status}`);
@@ -931,23 +933,23 @@ CREATE INDEX IF NOT EXISTS ${e}_servable_until_idx ON ${e} (servable_until);
931
933
  }
932
934
  return;
933
935
  }
934
- if (o === "/_voltro/inspect/stream") {
935
- let n = de(a.origin);
936
- if (ce()) {
936
+ if (a === "/_voltro/inspect/stream") {
937
+ let n = P(i.origin);
938
+ if (le()) {
937
939
  t.writeHead(503, {
938
940
  "content-type": "application/json",
939
941
  ...n
940
942
  }), t.end(JSON.stringify({ error: "inspect disabled (VOLTRO_INSPECT=off)" }));
941
943
  return;
942
944
  }
943
- let i = N(a, "GET");
944
- if (!i.ok) {
945
+ let r = de(i, "GET");
946
+ if (!r.ok) {
945
947
  t.writeHead(401, {
946
948
  "content-type": "application/json",
947
949
  ...n
948
950
  }), t.end(JSON.stringify({
949
951
  error: "unauthorized",
950
- reason: i.reason
952
+ reason: r.reason
951
953
  }));
952
954
  return;
953
955
  }
@@ -958,30 +960,30 @@ CREATE INDEX IF NOT EXISTS ${e}_servable_until_idx ON ${e} (servable_until);
958
960
  "x-accel-buffering": "no",
959
961
  ...n
960
962
  }), t.flushHeaders(), t.write("retry: 5000\n\n");
961
- for (let e of g.buffered()) t.write(l(e));
962
- let o = g.subscribe((e) => {
963
- t.write(l(e));
963
+ for (let e of f.buffered()) t.write(u(e));
964
+ let a = f.subscribe((e) => {
965
+ t.write(u(e));
964
966
  }), s = setInterval(() => {
965
- t.write(r());
967
+ t.write(o());
966
968
  }, 15e3), c = () => {
967
- clearInterval(s), o();
969
+ clearInterval(s), a();
968
970
  };
969
971
  e.on("close", c), t.on("close", c);
970
972
  return;
971
973
  }
972
974
  try {
973
- let e = await Fe(n, a);
974
- if (e.stream ? e.stream(t) : (t.writeHead(e.status, e.headers), t.end(e.body)), !o.startsWith("/_voltro/inspect")) {
975
- let t = Date.now() - i;
976
- g.emit("request", {
977
- url: o,
975
+ let e = await Pe(n, i);
976
+ if (e.stream ? e.stream(t) : (t.writeHead(e.status, e.headers), t.end(e.body)), !a.startsWith("/_voltro/inspect")) {
977
+ let t = Date.now() - r;
978
+ f.emit("request", {
979
+ url: a,
978
980
  status: e.status,
979
981
  durationMs: t,
980
982
  renderedBy: e.headers["x-voltro-rendered-by"],
981
983
  cache: e.headers["x-voltro-cache"]
982
984
  });
983
- let n = we(o, W)?.route.pattern ?? (e.status === 404 ? "<unmatched>" : "<asset>");
984
- Ae.record({
985
+ let n = we(a, G)?.route.pattern ?? (e.status === 404 ? "<unmatched>" : "<asset>");
986
+ ke.record({
985
987
  kind: "request",
986
988
  tag: n,
987
989
  durationMs: t,
@@ -992,71 +994,71 @@ CREATE INDEX IF NOT EXISTS ${e}_servable_until_idx ON ${e} (servable_until);
992
994
  t.writeHead(500, { "content-type": "text/plain" }), t.end(`internal error: ${e.message}`);
993
995
  }
994
996
  });
995
- await new Promise((e) => Le.listen(b, "::", e)), Ie = !0, o.mark("ready"), K.info(`listening on http://localhost:${b}`, {
996
- port: b,
997
- distDir: x
998
- }), K.debug("dynamic + ssr/isr routes resolve via SSR loader");
997
+ await new Promise((e) => Ie.listen(v, "::", e)), Fe = !0, a.mark("ready"), J.info(`listening on http://localhost:${v}`, {
998
+ port: v,
999
+ distDir: y
1000
+ }), J.debug("dynamic + ssr/isr routes resolve via SSR loader");
999
1001
  try {
1000
- await w({
1001
- id: j,
1002
- name: T,
1002
+ await x({
1003
+ id: A,
1004
+ name: E,
1003
1005
  kind: "web",
1004
- url: `http://localhost:${b}`,
1006
+ url: `http://localhost:${v}`,
1005
1007
  pid: process.pid,
1006
1008
  status: "live",
1007
1009
  logFile: M.path
1008
1010
  });
1009
- let e = oe(a);
1011
+ let e = c(n);
1010
1012
  if (e) {
1011
- let n = await t({ dashboardAppPath: e });
1012
- n.status === "launched" ? K.info(`dashboard launched at http://localhost:${n.port}`, { port: n.port }) : n.status === "already-running" && K.debug(`dashboard already running on :${n.port}`, { port: n.port });
1013
+ let t = await j({ dashboardAppPath: e });
1014
+ 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 });
1013
1015
  }
1014
1016
  setInterval(() => {
1015
- w({
1016
- id: j,
1017
- name: T,
1017
+ x({
1018
+ id: A,
1019
+ name: E,
1018
1020
  kind: "web",
1019
- url: `http://localhost:${b}`,
1021
+ url: `http://localhost:${v}`,
1020
1022
  pid: process.pid,
1021
1023
  status: "live",
1022
1024
  logFile: M.path
1023
1025
  }).catch(() => {});
1024
1026
  }, 1e4).unref();
1025
1027
  } catch (e) {
1026
- K.warn("runtime-registry write failed", {}, e);
1028
+ J.warn("runtime-registry write failed", {}, e);
1027
1029
  }
1028
- me({
1029
- app: f.name ?? "unnamed",
1030
+ pe({
1031
+ app: d.name ?? "unnamed",
1030
1032
  kind: "web",
1031
- url: `http://localhost:${b}`,
1032
- bootMs: o.total()
1033
+ url: `http://localhost:${v}`,
1034
+ bootMs: a.total()
1033
1035
  });
1034
- let Re = o.phaseBreakdown();
1035
- K.info(`start: ready in ${o.total()}ms`, {
1036
- bootMs: o.total(),
1037
- ...Re ? { phases: Re } : {}
1036
+ let Le = a.phaseBreakdown();
1037
+ J.info(`start: ready in ${a.total()}ms`, {
1038
+ bootMs: a.total(),
1039
+ ...Le ? { phases: Le } : {}
1038
1040
  });
1039
- let ze = !1, $ = (e) => async () => {
1040
- if (!ze) {
1041
- if (ze = !0, K.info(`received ${e}, shutting down`, { signal: e }), Le.close(), await ke.stop(), V) try {
1041
+ let Re = !1, ze = (e) => async () => {
1042
+ if (!Re) {
1043
+ if (Re = !0, J.info(`received ${e}, shutting down`, { signal: e }), Ie.close(), await Oe.stop(), V) try {
1042
1044
  await V.end();
1043
1045
  } catch {}
1044
- await q.close(), await y(j), await M.dispose(), process.exit(0);
1046
+ await q.close(), await ae(A), await M.dispose(), process.exit(0);
1045
1047
  }
1046
1048
  };
1047
- process.on("SIGINT", $("SIGINT")), process.on("SIGTERM", $("SIGTERM"));
1049
+ process.on("SIGINT", ze("SIGINT")), process.on("SIGTERM", ze("SIGTERM"));
1048
1050
  let Be = process.ppid;
1049
1051
  if (Be > 1) {
1050
1052
  let e = setInterval(() => {
1051
- (process.ppid !== Be || process.ppid === 1) && (clearInterval(e), $("SIGTERM")());
1053
+ (process.ppid !== Be || process.ppid === 1) && (clearInterval(e), ze("SIGTERM")());
1052
1054
  }, 2e3);
1053
1055
  e.unref();
1054
1056
  }
1055
1057
  return new Promise(() => {});
1056
1058
  }, ke = async (e) => {
1057
1059
  process.env.NODE_ENV || (process.env.NODE_ENV = "production");
1058
- let t = await Oe(I(e.find((e) => !e.startsWith("-")) ?? process.cwd()));
1059
- return t.ran ? t.exitCode : (K.error("no web app found at this path"), 1);
1060
+ let t = await Oe(R(e.find((e) => !e.startsWith("-")) ?? process.cwd()));
1061
+ return t.ran ? t.exitCode : (J.error("no web app found at this path"), 1);
1060
1062
  };
1061
1063
  //#endregion
1062
1064
  export { ke as t };