@voltro/cli 0.8.0 → 0.9.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 (54) hide show
  1. package/CHANGELOG.md +19 -0
  2. package/THIRD-PARTY-NOTICES.md +2 -2
  3. package/dist/apiBuild-Ba4njm9m.js +2 -0
  4. package/dist/{apiBuild-OrDkXGFX.js → apiBuild-eInHm_bJ.js} +2 -2
  5. package/dist/bin.js +2 -2
  6. package/dist/{commands-DT4PipBz.js → commands-Cxs97AFp.js} +1685 -1592
  7. package/dist/{dev-Ga65K4jc.js → dev-63Ehpw2p.js} +179 -179
  8. package/dist/dev-CXsR8Zgo.js +2 -0
  9. package/dist/index.js +1 -1
  10. package/dist/{inspectMetrics-EK0CcHyu.js → inspectMetrics-DVCKKSPk.js} +930 -839
  11. package/dist/{serveCommand-CR5xnYZt.js → serveCommand-Cq7BhtpB.js} +5 -5
  12. package/dist/serveEntry.js +3 -3
  13. package/dist/{start-DuyBQxW3.js → start-CYe-7ueh.js} +296 -267
  14. package/dist/startEntry.js +2 -2
  15. package/package.json +18 -17
  16. package/templates/agent-docs/cli.md +49 -1
  17. package/templates/agent-docs/routing.md +26 -2
  18. package/templates/apps/api-ai/package.json +7 -7
  19. package/templates/apps/api-auth/package.json +8 -8
  20. package/templates/apps/api-backend/package.json +7 -7
  21. package/templates/apps/api-backend-deactivation/package.json +7 -7
  22. package/templates/apps/api-backend-mail/package.json +8 -8
  23. package/templates/apps/api-backend-mariadb/package.json +9 -9
  24. package/templates/apps/api-backend-storage/package.json +8 -8
  25. package/templates/apps/api-data-advanced/package.json +8 -8
  26. package/templates/apps/api-durable/package.json +8 -8
  27. package/templates/apps/api-feature-flags/package.json +9 -9
  28. package/templates/apps/api-governance/package.json +8 -8
  29. package/templates/apps/api-kv/package.json +8 -8
  30. package/templates/apps/api-moderation/package.json +8 -8
  31. package/templates/apps/api-observability/package.json +8 -8
  32. package/templates/apps/api-ratelimit/package.json +8 -8
  33. package/templates/apps/api-rbac/package.json +8 -8
  34. package/templates/apps/api-rest/package.json +7 -7
  35. package/templates/apps/api-saas/package.json +11 -11
  36. package/templates/apps/api-search/package.json +8 -8
  37. package/templates/apps/api-versioning/package.json +8 -8
  38. package/templates/apps/api-webhooks/package.json +8 -8
  39. package/templates/apps/changelog/package.json +6 -6
  40. package/templates/apps/edge-functions/package.json +2 -2
  41. package/templates/apps/frontend-admin/package.json +8 -8
  42. package/templates/apps/frontend-app/package.json +8 -8
  43. package/templates/apps/frontend-blank/package.json +7 -7
  44. package/templates/apps/frontend-contact/package.json +7 -7
  45. package/templates/apps/frontend-dashboard/package.json +7 -7
  46. package/templates/apps/frontend-docs/package.json +7 -7
  47. package/templates/apps/frontend-i18n/package.json +6 -6
  48. package/templates/apps/frontend-landing/package.json +7 -7
  49. package/templates/apps/frontend-spa/package.json +7 -7
  50. package/templates/apps/frontend-ssr/package.json +7 -7
  51. package/templates/apps/frontend-ssr-api/package.json +8 -8
  52. package/templates/apps/frontend-static-blog/package.json +6 -6
  53. package/dist/apiBuild-CmtI6Ygh.js +0 -2
  54. package/dist/dev-Ca1jdwnt.js +0 -2
@@ -1,22 +1,22 @@
1
- import { A as e, B as t, D as n, E as r, H as i, L as a, M as o, O as s, S as c, T as l, U as u, V as d, W as f, a as p, b as m, d as h, f as g, ft as _, g as v, h as y, i as b, j as x, k as S, m as ee, n as te, o as C, p as w, pt as T, q as E, r as D, s as O, t as k, tt as ne, vt as re, w as ie, xt as A, y as ae } from "./inspectMetrics-EK0CcHyu.js";
2
- import { dirname as j, extname as M, join as N, resolve as P } from "node:path";
3
- import { fileURLToPath as F, pathToFileURL as I } from "node:url";
4
- import { createLogger as L, printReadyBlock as oe } from "@voltro/logger";
5
- import { promises as R } from "node:fs";
6
- import { snapshotMetricsSync as se } from "@voltro/runtime";
7
- import { createServer as ce } from "node:http";
1
+ import { A as e, D as t, E as n, G as r, H as i, K as a, M as o, N as s, O as c, P as l, S as u, St as d, Tt as f, U as p, W as m, Y as h, _ as g, a as _, bt as v, c as y, f as ee, g as b, h as x, ht as S, i as C, j as te, k as w, m as ne, mt as T, o as E, p as D, r as O, rt as k, s as re, t as ie, v as A, w as ae, x as oe, xt as j, z as M } from "./inspectMetrics-DVCKKSPk.js";
2
+ import { dirname as N, extname as P, join as F, resolve as I } from "node:path";
3
+ import { fileURLToPath as L, pathToFileURL as R } from "node:url";
4
+ import { createLogger as z, printReadyBlock as se } from "@voltro/logger";
5
+ import { promises as B } from "node:fs";
6
+ import { snapshotMetricsSync as ce } from "@voltro/runtime";
7
+ import { createServer as le } from "node:http";
8
8
  //#region src/routeMeta.ts
9
- var z = (e) => typeof e.renderMode == "string" ? e.renderMode : e.dynamic === "force-dynamic" ? "ssr" : (e.dynamic, "static"), le = (e) => ({
10
- renderMode: z(e),
9
+ var V = (e) => typeof e.renderMode == "string" ? e.renderMode : e.dynamic === "force-dynamic" ? "ssr" : (e.dynamic, "static"), ue = (e) => ({
10
+ renderMode: V(e),
11
11
  tenantAware: e.tenantAware === !0,
12
- revalidateMs: o(e.revalidate),
13
- staleWhileRevalidateMs: o(e.staleWhileRevalidate) ?? 0,
12
+ revalidateMs: l(e.revalidate),
13
+ staleWhileRevalidateMs: l(e.staleWhileRevalidate) ?? 0,
14
14
  cacheInvalidatesOn: Array.isArray(e.cacheInvalidatesOn) ? e.cacheInvalidatesOn : [],
15
15
  interactive: e.interactive ?? "full",
16
16
  hasLoader: typeof e.loader == "function",
17
17
  hasMeta: e.meta != null,
18
18
  hasGetStaticPaths: typeof e.getStaticPaths == "function"
19
- }), B = L({ scope: "voltro:start:cdc" }), V = (e) => (t) => {
19
+ }), H = z({ scope: "voltro:start:cdc" }), U = (e) => (t) => {
20
20
  let n = 0;
21
21
  for (let [r, i] of e.tableSubscriptionsByPattern) {
22
22
  if (!i.includes(t)) continue;
@@ -27,23 +27,23 @@ var z = (e) => typeof e.renderMode == "string" ? e.renderMode : e.dynamic === "f
27
27
  }));
28
28
  }
29
29
  return n;
30
- }, H = () => !process.env.PG_HOST && !process.env.PG_DATABASE ? null : {
30
+ }, W = () => !process.env.PG_HOST && !process.env.PG_DATABASE ? null : {
31
31
  host: process.env.PG_HOST ?? "localhost",
32
32
  port: Number(process.env.PG_PORT ?? 5432),
33
33
  user: process.env.PG_USER ?? "app",
34
34
  password: process.env.PG_PASSWORD ?? "app",
35
35
  database: process.env.PG_DATABASE ?? "app"
36
- }, ue = (e) => {
37
- let t = e.channel ?? "framework_changes", n = V(e), r = null, i = null;
36
+ }, de = (e) => {
37
+ let t = e.channel ?? "framework_changes", n = U(e), r = null, i = null;
38
38
  return {
39
39
  start: async () => {
40
- let a = H();
40
+ let a = W();
41
41
  if (!a) {
42
- B.debug("skipped — no PG_* env vars set");
42
+ H.debug("skipped — no PG_* env vars set");
43
43
  return;
44
44
  }
45
45
  if (e.tableSubscriptionsByPattern.size === 0) {
46
- B.debug("skipped — no pages declare cacheInvalidatesOn");
46
+ H.debug("skipped — no pages declare cacheInvalidatesOn");
47
47
  return;
48
48
  }
49
49
  r = new (await (import("pg"))).default.Client(a), await r.connect(), i = (e) => {
@@ -52,16 +52,16 @@ var z = (e) => typeof e.renderMode == "string" ? e.renderMode : e.dynamic === "f
52
52
  try {
53
53
  r = JSON.parse(e.payload);
54
54
  } catch (e) {
55
- B.warn("bad CDC payload", {}, e);
55
+ H.warn("bad CDC payload", {}, e);
56
56
  return;
57
57
  }
58
58
  let i = n(r.table);
59
- i > 0 && B.info(`${r.op} on '${r.table}' → dropped ${i} cache entries`, {
59
+ i > 0 && H.info(`${r.op} on '${r.table}' → dropped ${i} cache entries`, {
60
60
  op: r.op,
61
61
  table: r.table,
62
62
  dropped: i
63
63
  });
64
- }, r.on("notification", i), await r.query(`LISTEN ${t}`), B.info(`LISTEN ${t}`, {
64
+ }, r.on("notification", i), await r.query(`LISTEN ${t}`), H.info(`LISTEN ${t}`, {
65
65
  channel: t,
66
66
  host: a.host,
67
67
  port: a.port,
@@ -77,7 +77,7 @@ var z = (e) => typeof e.renderMode == "string" ? e.renderMode : e.dynamic === "f
77
77
  }
78
78
  }
79
79
  };
80
- }, U = L({ scope: "voltro:start:isr-cache" }), W = "voltro_isr_cache", G = (e) => `
80
+ }, G = z({ scope: "voltro:start:isr-cache" }), K = "voltro_isr_cache", q = (e) => `
81
81
  CREATE TABLE IF NOT EXISTS ${e} (
82
82
  cache_key TEXT PRIMARY KEY,
83
83
  html TEXT NOT NULL,
@@ -88,9 +88,9 @@ CREATE TABLE IF NOT EXISTS ${e} (
88
88
  stale_while_revalidate_ms BIGINT NOT NULL DEFAULT 0
89
89
  );
90
90
  CREATE INDEX IF NOT EXISTS ${e}_servable_until_idx ON ${e} (servable_until);
91
- `, de = (e) => {
92
- let t = e.tableName ?? W, { client: n } = e, r = /* @__PURE__ */ new Map(), i = !1, a = (async () => {
93
- i || (i = !0, await n.query(G(t)));
91
+ `, fe = (e) => {
92
+ let t = e.tableName ?? K, { client: n } = e, r = /* @__PURE__ */ new Map(), i = !1, a = (async () => {
93
+ i || (i = !0, await n.query(q(t)));
94
94
  })().then(async () => {
95
95
  let e = await n.query(`SELECT * FROM ${t}`);
96
96
  for (let t of e.rows) r.set(t.cache_key, {
@@ -102,10 +102,10 @@ CREATE INDEX IF NOT EXISTS ${e}_servable_until_idx ON ${e} (servable_until);
102
102
  staleWhileRevalidateMs: Number(t.stale_while_revalidate_ms)
103
103
  });
104
104
  }).catch((e) => {
105
- U.warn("postgres bootstrap failed", {}, e);
105
+ G.warn("postgres bootstrap failed", {}, e);
106
106
  }), o = (e, t) => {
107
107
  a.then(() => n.query(e, t)).catch((e) => {
108
- U.warn("postgres write failed", {}, e);
108
+ G.warn("postgres write failed", {}, e);
109
109
  });
110
110
  };
111
111
  return {
@@ -150,14 +150,14 @@ CREATE INDEX IF NOT EXISTS ${e}_servable_until_idx ON ${e} (servable_until);
150
150
  return Array.from(r.entries());
151
151
  }
152
152
  };
153
- }, K = L({ scope: "voltro:start" }), fe = await (async () => {
153
+ }, J = z({ scope: "voltro:start" }), pe = await (async () => {
154
154
  try {
155
- let e = N(j(F(import.meta.url)), "..", "package.json"), t = await R.readFile(e, "utf8");
155
+ let e = F(N(L(import.meta.url)), "..", "package.json"), t = await B.readFile(e, "utf8");
156
156
  return JSON.parse(t).version ?? "0.0.0";
157
157
  } catch {
158
158
  return "0.0.0";
159
159
  }
160
- })(), q = (e) => e instanceof Error && e._voltroControl === "redirect" && typeof e.location == "string", J = (e) => e instanceof Error && e._voltroControl === "not-found", pe = {
160
+ })(), me = (e) => e instanceof Error && e._voltroControl === "redirect" && typeof e.location == "string", Y = (e) => e instanceof Error && e._voltroControl === "not-found", he = {
161
161
  ".html": "text/html; charset=utf-8",
162
162
  ".js": "application/javascript",
163
163
  ".mjs": "application/javascript",
@@ -175,13 +175,13 @@ CREATE INDEX IF NOT EXISTS ${e}_servable_until_idx ON ${e} (servable_until);
175
175
  ".woff": "font/woff",
176
176
  ".woff2": "font/woff2",
177
177
  ".txt": "text/plain; charset=utf-8"
178
- }, me = (e) => pe[M(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) => {
178
+ }, ge = (e) => he[P(e).toLowerCase()] ?? "application/octet-stream", X = (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) => {
179
179
  try {
180
- return await R.stat(e), !0;
180
+ return await B.stat(e), !0;
181
181
  } catch {
182
182
  return !1;
183
183
  }
184
- }, he = (e) => {
184
+ }, Q = (e) => {
185
185
  let t = [], n = 0, r = e.split("/").filter(Boolean), i = [];
186
186
  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, "\\$&"));
187
187
  let a = i.join("/");
@@ -190,8 +190,8 @@ CREATE INDEX IF NOT EXISTS ${e}_servable_until_idx ON ${e} (servable_until);
190
190
  paramNames: t,
191
191
  priority: n
192
192
  };
193
- }, ge = (e) => e.map((e) => {
194
- let { regex: t, paramNames: n, priority: r } = he(e.pattern);
193
+ }, _e = (e) => e.map((e) => {
194
+ let { regex: t, paramNames: n, priority: r } = Q(e.pattern);
195
195
  return {
196
196
  pattern: e.pattern,
197
197
  file: e.file,
@@ -200,7 +200,7 @@ CREATE INDEX IF NOT EXISTS ${e}_servable_until_idx ON ${e} (servable_until);
200
200
  paramNames: n,
201
201
  priority: r
202
202
  };
203
- }).slice().sort((e, t) => e.priority - t.priority), _e = (e, t) => {
203
+ }).slice().sort((e, t) => e.priority - t.priority), ve = (e, t) => {
204
204
  for (let n of t) {
205
205
  let t = n.regex.exec(e);
206
206
  if (!t) continue;
@@ -212,12 +212,12 @@ CREATE INDEX IF NOT EXISTS ${e}_servable_until_idx ON ${e} (servable_until);
212
212
  };
213
213
  }
214
214
  return null;
215
- }, ve = async (e) => {
216
- let { provider: t, route: n, params: r, pathname: i, dirs: a, shellTemplate: s, requestHeaders: c, requestUrl: l = "", apiOrigin: u } = e, d = D(u, c.cookie), f = await t.getPage(n.pattern, n.file), m = z(f);
217
- if (m !== "ssr" && m !== "isr") return null;
218
- let h = p(a, n.dirChain), g = {}, _ = null, y, x = new AbortController();
215
+ }, ye = async (e) => {
216
+ let { provider: t, route: n, params: r, pathname: i, dirs: a, shellTemplate: o, requestHeaders: s, requestUrl: c = "", apiOrigin: u } = e, d = C(u, s.cookie), f = await t.getPage(n.pattern, n.file), p = V(f), m = p === "spa" && E(a, n.dirChain).some((e) => e.hasLayout);
217
+ if (p !== "ssr" && p !== "isr" && !m) return null;
218
+ let h = E(a, n.dirChain), v = {}, y = null, ee, b = new AbortController();
219
219
  try {
220
- ({chain: y, segmentLoaderData: g} = await b({
220
+ ({chain: ee, segmentLoaderData: v} = await _({
221
221
  entries: h,
222
222
  loadLayout: (e) => t.getLayout(e.dir),
223
223
  loadError: (e) => t.getError(e.dir),
@@ -225,24 +225,24 @@ CREATE INDEX IF NOT EXISTS ${e}_servable_until_idx ON ${e} (servable_until);
225
225
  ctx: {
226
226
  params: r,
227
227
  pathname: i,
228
- signal: x.signal,
229
- headers: c,
228
+ signal: b.signal,
229
+ headers: s,
230
230
  query: d
231
231
  }
232
- })), typeof f.loader == "function" && (_ = await f.loader({
232
+ })), typeof f.loader == "function" && !m && (y = await f.loader({
233
233
  params: r,
234
234
  pathname: i,
235
- signal: x.signal,
236
- headers: c,
235
+ signal: b.signal,
236
+ headers: s,
237
237
  query: d
238
238
  }));
239
239
  } catch (e) {
240
- if (q(e)) return {
240
+ if (me(e)) return {
241
241
  control: "redirect",
242
242
  status: e.status,
243
243
  location: e.location
244
244
  };
245
- if (J(e)) return { control: "not-found" };
245
+ if (Y(e)) return { control: "not-found" };
246
246
  throw e;
247
247
  }
248
248
  let S = await t.getHelpers(), te = {
@@ -252,19 +252,45 @@ CREATE INDEX IF NOT EXISTS ${e}_servable_until_idx ON ${e} (servable_until);
252
252
  loader: f.loader,
253
253
  ErrorBoundary: f.ErrorBoundary,
254
254
  Pending: f.Pending,
255
- renderMode: m,
256
- chain: y
257
- }, C = {
258
- cookies: S.parseCookieHeader(c.cookie),
259
- headers: c,
260
- url: l
261
- }, T = S.i18n?.resolve(c.cookie, c["accept-language"]), E = f.interactive ?? "full", O = v({
255
+ renderMode: p,
256
+ chain: ee
257
+ }, w = {
258
+ cookies: S.parseCookieHeader(s.cookie),
259
+ headers: s,
260
+ url: c
261
+ }, T = S.i18n?.resolve(s.cookie, s["accept-language"]), D = f.interactive ?? "full";
262
+ if (m) {
263
+ let e = A({
264
+ helpers: S,
265
+ renderInput: {
266
+ descriptor: te,
267
+ params: r,
268
+ pathname: i,
269
+ segmentLoaderData: v,
270
+ requestContext: w,
271
+ ...T ? {
272
+ outerWrap: T.outerWrap,
273
+ locale: T.locale
274
+ } : {}
275
+ }
276
+ }), t = [
277
+ S.renderMetaToHtml(e.meta),
278
+ `<meta name="voltro-interactive" content="${D}" />`,
279
+ e.stateScript
280
+ ].filter((e) => e.length > 0).join("\n "), n = T?.locale ?? w.cookies["voltro:lang"] ?? "en";
281
+ return {
282
+ html: o.replace("<div id=\"root\"></div>", `<div id="root">${e.body}</div>`).replace("</head>", ` ${t}\n </head>`).replace(/<html(\s+lang="[^"]*")?/i, `<html lang="${n}"`),
283
+ renderMode: "spa",
284
+ revalidateMs: null
285
+ };
286
+ }
287
+ let O = g({
262
288
  helpers: S,
263
289
  page: n.pattern,
264
- renderMode: m,
265
- interactive: E,
266
- loaderData: _,
267
- segmentLoaderData: g,
290
+ renderMode: p,
291
+ interactive: D,
292
+ loaderData: y,
293
+ segmentLoaderData: v,
268
294
  pageLoaderRan: typeof f.loader == "function"
269
295
  }), k = {
270
296
  descriptor: te,
@@ -272,22 +298,22 @@ CREATE INDEX IF NOT EXISTS ${e}_servable_until_idx ON ${e} (servable_until);
272
298
  pathname: i,
273
299
  loaderData: O.loaderData,
274
300
  segmentLoaderData: O.segmentLoaderData,
275
- requestContext: C,
301
+ requestContext: w,
276
302
  ...T ? {
277
303
  outerWrap: T.outerWrap,
278
304
  locale: T.locale
279
305
  } : {}
280
- }, ne = (e) => [
306
+ }, re = (e) => [
281
307
  S.renderMetaToHtml(e),
282
- `<meta name="voltro-interactive" content="${E}" />`,
308
+ `<meta name="voltro-interactive" content="${D}" />`,
283
309
  ...O.hasDeferred ? [S.renderDeferredRegistryScript()] : [],
284
310
  S.renderRouterStateScript(O.stateInput)
285
311
  ].filter((e) => e.length > 0).join("\n ");
286
- if (m === "ssr" && E === "full" && e.buffered !== !0) {
287
- let e = T?.locale ?? C.cookies["voltro:lang"] ?? "en", t = w({ shell: s });
312
+ if (p === "ssr" && D === "full" && e.buffered !== !0) {
313
+ let e = T?.locale ?? w.cookies["voltro:lang"] ?? "en", t = ne({ shell: o });
288
314
  return {
289
315
  renderMode: "ssr",
290
- stream: (n) => ee({
316
+ stream: (n) => x({
291
317
  res: n,
292
318
  shell: t,
293
319
  htmlLang: e,
@@ -295,27 +321,27 @@ CREATE INDEX IF NOT EXISTS ${e}_servable_until_idx ON ${e} (servable_until);
295
321
  "content-type": "text/html; charset=utf-8",
296
322
  "x-voltro-rendered-by": "ssr"
297
323
  },
298
- headInjection: ne,
324
+ headInjection: re,
299
325
  render: (e) => S.renderPageToStream({
300
326
  ...k,
301
327
  ...e
302
328
  }),
303
329
  onShellError: (e) => {
304
- K.error("ssr shell render failed", { pathname: i }, e), n.writeHead(500, { "content-type": "text/plain; charset=utf-8" }), n.end("server error");
330
+ J.error("ssr shell render failed", { pathname: i }, e), n.writeHead(500, { "content-type": "text/plain; charset=utf-8" }), n.end("server error");
305
331
  }
306
332
  })
307
333
  };
308
334
  }
309
- let { html: re, meta: ie } = S.renderPageToHtml(k), A = ne(ie), ae = T?.locale ?? C.cookies["voltro:lang"] ?? "en", j = s.replace("<div id=\"root\"></div>", `<div id="root">${re}</div>`).replace("</head>", ` ${A}\n </head>`).replace(/<html(\s+lang="[^"]*")?/i, `<html lang="${ae}"`);
310
- E === "none" && (j = Y(j));
311
- let M = m === "isr" ? o(f.revalidate) : null;
335
+ let { html: ie, meta: ae } = S.renderPageToHtml(k), oe = re(ae), j = T?.locale ?? w.cookies["voltro:lang"] ?? "en", M = o.replace("<div id=\"root\"></div>", `<div id="root">${ie}</div>`).replace("</head>", ` ${oe}\n </head>`).replace(/<html(\s+lang="[^"]*")?/i, `<html lang="${j}"`);
336
+ D === "none" && (M = X(M));
337
+ let N = p === "isr" ? l(f.revalidate) : null;
312
338
  return {
313
- html: j,
314
- renderMode: m,
315
- revalidateMs: M
339
+ html: M,
340
+ renderMode: p,
341
+ revalidateMs: N
316
342
  };
317
- }, Z = (e) => e === "" ? "/" : e, ye = async (e) => {
318
- let t = await import(I(e).href);
343
+ }, $ = (e) => e === "" ? "/" : e, be = async (e) => {
344
+ let t = await import(R(e).href);
319
345
  return {
320
346
  kind: "bundle",
321
347
  getPageMeta: () => t.pageMeta,
@@ -325,18 +351,18 @@ CREATE INDEX IF NOT EXISTS ${e}_servable_until_idx ON ${e} (servable_until);
325
351
  return typeof r == "function" ? await r() : r;
326
352
  },
327
353
  async getLayout(e) {
328
- let n = t.layouts[Z(e)];
329
- if (!n) throw Error(`[voltro start] ssr bundle missing layout for dir ${Z(e)}`);
354
+ let n = t.layouts[$(e)];
355
+ if (!n) throw Error(`[voltro start] ssr bundle missing layout for dir ${$(e)}`);
330
356
  return typeof n == "function" ? await n() : n;
331
357
  },
332
358
  async getError(e) {
333
- let n = t.errors[Z(e)];
334
- if (!n) throw Error(`[voltro start] ssr bundle missing error for dir ${Z(e)}`);
359
+ let n = t.errors[$(e)];
360
+ if (!n) throw Error(`[voltro start] ssr bundle missing error for dir ${$(e)}`);
335
361
  return typeof n == "function" ? await n() : n;
336
362
  },
337
363
  async getPending(e) {
338
- let n = t.pendings[Z(e)];
339
- if (!n) throw Error(`[voltro start] ssr bundle missing pending for dir ${Z(e)}`);
364
+ let n = t.pendings[$(e)];
365
+ if (!n) throw Error(`[voltro start] ssr bundle missing pending for dir ${$(e)}`);
340
366
  return typeof n == "function" ? await n() : n;
341
367
  },
342
368
  async getHelpers() {
@@ -344,8 +370,8 @@ CREATE INDEX IF NOT EXISTS ${e}_servable_until_idx ON ${e} (servable_until);
344
370
  },
345
371
  async close() {}
346
372
  };
347
- }, be = async (e, t) => {
348
- let n = await A("vite", () => import("vite")), r = (await import("@vitejs/plugin-react")).default, i = (await import("@tailwindcss/vite")).default, a = await n.createServer({
373
+ }, xe = async (e, t) => {
374
+ let n = await f("vite", () => import("vite")), r = (await import("@vitejs/plugin-react")).default, i = (await import("@tailwindcss/vite")).default, a = await n.createServer({
349
375
  root: t,
350
376
  envPrefix: "__VOLTRO_VITE_ENV_DISABLED__",
351
377
  plugins: [r(), i()],
@@ -357,114 +383,117 @@ CREATE INDEX IF NOT EXISTS ${e}_servable_until_idx ON ${e} (servable_until);
357
383
  },
358
384
  appType: "custom",
359
385
  logLevel: "warn"
360
- }), o = N(e, "src", "pages"), s = (e) => e === "" ? o : N(o, e);
386
+ }), o = F(e, "src", "pages"), s = (e) => e === "" ? o : F(o, e), c = v({ limit: j() }), l = (e) => c.load(e, async () => await a.ssrLoadModule(e));
361
387
  return {
362
388
  kind: "middleware",
363
389
  async getPage(e, t) {
364
- return a.ssrLoadModule(N(o, t));
390
+ return l(F(o, t));
365
391
  },
366
392
  async getLayout(e) {
367
- return a.ssrLoadModule(N(s(e), "layout.tsx"));
393
+ return l(F(s(e), "layout.tsx"));
368
394
  },
369
395
  async getError(e) {
370
- return a.ssrLoadModule(N(s(e), "error.tsx"));
396
+ return l(F(s(e), "error.tsx"));
371
397
  },
372
398
  async getPending(e) {
373
- return a.ssrLoadModule(N(s(e), "loading.tsx"));
399
+ return l(F(s(e), "loading.tsx"));
374
400
  },
375
401
  async getHelpers() {
376
- return await a.ssrLoadModule("@voltro/web/ssr");
402
+ return await l("@voltro/web/ssr");
377
403
  },
378
404
  async close() {
379
405
  await a.close();
380
406
  }
381
407
  };
382
- }, Q = async (o) => {
383
- let p = await C(o);
384
- if (!p) return {
408
+ }, Se = async (l) => {
409
+ let f = await re(l);
410
+ if (!f) return {
385
411
  ran: !1,
386
412
  exitCode: 0
387
413
  };
388
- if (p.type !== "web") return K.error("only web apps are supported by `voltro start`"), {
414
+ if (f.type !== "web") return J.error("only web apps are supported by `voltro start`"), {
389
415
  ran: !0,
390
416
  exitCode: 1
391
417
  };
392
- let { resolved: v } = await re({
393
- rawEnv: p.env,
418
+ let { resolved: g } = await d({
419
+ rawEnv: f.env,
394
420
  appType: "web",
395
- root: o,
396
- log: K,
421
+ root: l,
422
+ log: J,
397
423
  generateTypes: !1
398
- }), b = v.publicValues, ee = Date.now(), w = u();
399
- t(w), K.info("booting voltro start", { app: p.name ?? "(unnamed)" });
400
- let D = (() => {
424
+ }), _ = g.publicValues, v = Date.now(), x = r();
425
+ i(x), J.info("booting voltro start", { app: f.name ?? "(unnamed)" });
426
+ let C = (() => {
401
427
  if (process.env.VOLTRO_IS_DASHBOARD === "1" && process.env.VOLTRO_DASHBOARD_PORT) return Number(process.env.VOLTRO_DASHBOARD_PORT);
402
428
  if (process.env.PORT) {
403
429
  let e = Number(process.env.PORT);
404
430
  if (Number.isFinite(e) && e > 0) return e;
405
431
  }
406
- return p.port ?? 5173;
407
- })(), A = N(o, ".framework"), j = N(A, "dist"), M = N(j, "index.html");
408
- if (!await X(M)) return K.error("no built dist found — run `voltro build` first", { distDir: j }), {
432
+ return f.port ?? 5173;
433
+ })(), ne = F(l, ".framework"), A = F(ne, "dist"), j = F(A, "index.html");
434
+ if (!await Z(j)) return J.error("no built dist found — run `voltro build` first", { distDir: A }), {
409
435
  ran: !0,
410
436
  exitCode: 1
411
437
  };
412
- let P = p.name ?? "unnamed", F = ie("web", P, D), I = c(P);
413
- await n({
414
- id: F,
415
- name: P,
438
+ let N = f.name ?? "unnamed", P = n("web", N, C), I = ae(N);
439
+ await w({
440
+ id: P,
441
+ name: N,
416
442
  kind: "web",
417
- url: `http://localhost:${D}`,
443
+ url: `http://localhost:${C}`,
418
444
  pid: process.pid,
419
445
  status: "booting",
420
446
  logFile: I.path
421
447
  }).catch(() => {});
422
- let L = N(j, "_voltro", "shell.html"), z = await X(L) ? await R.readFile(L, "utf8") : await R.readFile(M, "utf8"), B = await O(o, p), V = te(B[0]), H, U = null;
448
+ let L = F(A, "_voltro", "shell.html"), R = await Z(L) ? await B.readFile(L, "utf8") : await B.readFile(j, "utf8"), z = await y(l, f), V = O(z[0]), H, U = null;
423
449
  process.env.SSR_CACHE === "postgres" && process.env.PG_HOST ? (U = new (await (import("pg"))).default.Client({
424
450
  host: process.env.PG_HOST,
425
451
  port: Number(process.env.PG_PORT ?? 5432),
426
452
  user: process.env.PG_USER ?? "app",
427
453
  password: process.env.PG_PASSWORD ?? "app",
428
454
  database: process.env.PG_DATABASE ?? "app"
429
- }), await U.connect(), H = de({ client: U }), K.info("isr cache backend: postgres", { table: "voltro_isr_cache" })) : (H = x(), K.info("isr cache backend: memory (per-process)", { hint: "set SSR_CACHE=postgres for persistent storage" })), await g(o, p, B, b);
430
- let { pages: W, dirs: G } = await h(N(o, "src", "pages")), q = ge(W), J = N(j, "server", "ssrEntry.js"), pe = await X(J);
431
- if (!pe && process.env.NODE_ENV === "production") throw K.fatal(`production \`voltro start\` requires a precompiled SSR bundle at ${J} 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 ${J}`);
432
- let Y = pe ? await ye(J) : await be(o, A);
433
- K.info(`ssr loader: ${Y.kind}`, {
455
+ }), await U.connect(), H = fe({ client: U }), J.info("isr cache backend: postgres", { table: "voltro_isr_cache" })) : (H = s(), J.info("isr cache backend: memory (per-process)", { hint: "set SSR_CACHE=postgres for persistent storage" })), await D(l, f, z, _);
456
+ let { pages: W, dirs: G } = await ee(F(l, "src", "pages")), K = _e(W), q = F(A, "server", "ssrEntry.js"), me = await Z(q);
457
+ if (!me && process.env.NODE_ENV === "production") throw J.fatal(`production \`voltro start\` requires a precompiled SSR bundle at ${q} 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 ${q}`);
458
+ let Y = me ? await be(q) : await xe(l, ne);
459
+ J.info(`ssr loader: ${Y.kind}`, {
434
460
  kind: Y.kind,
435
461
  ...Y.kind === "middleware" ? { hint: "no pre-built SSR bundle found; run `voltro build` to enable bundle mode" } : {}
436
462
  });
437
- let he = Y.getPageMeta?.(), Z = /* @__PURE__ */ new Map(), Q = 0;
463
+ let he = Y.getPageMeta?.(), X = /* @__PURE__ */ new Map(), Q = 0;
438
464
  for (let e of W) {
439
465
  let t = he?.[e.pattern];
440
466
  if (t) {
441
- Z.set(e.pattern, t);
467
+ X.set(e.pattern, t);
442
468
  continue;
443
469
  }
444
470
  try {
445
471
  let t = await Y.getPage(e.pattern, e.file);
446
- Z.set(e.pattern, le(t)), Q++;
472
+ X.set(e.pattern, ue(t)), Q++;
447
473
  } catch (t) {
448
- K.warn("failed to load page metadata", { pattern: e.pattern }, t);
474
+ J.warn("failed to load page metadata", { pattern: e.pattern }, t);
449
475
  }
450
476
  }
451
- K.info(`registered ${Z.size} route(s)`, {
452
- count: Z.size,
453
- fromManifest: Z.size - Q,
477
+ J.info(`registered ${X.size} route(s)`, {
478
+ count: X.size,
479
+ fromManifest: X.size - Q,
454
480
  fromModules: Q
455
481
  });
456
- let xe = /* @__PURE__ */ new Map();
457
- for (let [e, t] of Z) t.cacheInvalidatesOn.length > 0 && xe.set(e, t.cacheInvalidatesOn);
482
+ let $ = /* @__PURE__ */ new Set();
483
+ for (let e of K) X.get(e.pattern)?.renderMode === "spa" && E(G, e.dirChain).some((e) => e.hasLayout) && $.add(e.pattern);
484
+ $.size > 0 && J.info(`${$.size} spa route(s) render an SSR layout shell`, { patterns: [...$] });
458
485
  let Se = /* @__PURE__ */ new Map();
459
- for (let e of q) Se.set(e.pattern, e.regex);
460
- let Ce = ue({
486
+ for (let [e, t] of X) t.cacheInvalidatesOn.length > 0 && Se.set(e, t.cacheInvalidatesOn);
487
+ let Ce = /* @__PURE__ */ new Map();
488
+ for (let e of K) Ce.set(e.pattern, e.regex);
489
+ let we = de({
461
490
  cache: H,
462
- tableSubscriptionsByPattern: xe,
463
- regexByPattern: Se
491
+ tableSubscriptionsByPattern: Se,
492
+ regexByPattern: Ce
464
493
  });
465
- await Ce.start();
466
- let we = k(), Te = W.map((e) => {
467
- let t = Z.get(e.pattern);
494
+ await we.start();
495
+ let Te = ie(), Ee = W.map((e) => {
496
+ let t = X.get(e.pattern);
468
497
  return {
469
498
  pattern: e.pattern,
470
499
  file: e.file,
@@ -479,20 +508,20 @@ CREATE INDEX IF NOT EXISTS ${e}_servable_until_idx ON ${e} (servable_until);
479
508
  hasMeta: t?.hasMeta ?? !1,
480
509
  hasGetStaticPaths: t?.hasGetStaticPaths ?? !1
481
510
  };
482
- }), Ee = G.map((e) => ({
511
+ }), De = G.map((e) => ({
483
512
  dir: e.dir,
484
513
  hasLayout: e.hasLayout,
485
514
  hasError: e.hasError,
486
515
  hasPending: e.hasPending,
487
516
  hasNotFound: e.hasNotFound
488
- })), De = U ? "postgres" : "memory", Oe = {
517
+ })), Oe = U ? "postgres" : "memory", ke = {
489
518
  kind: "web",
490
519
  meta: {
491
- name: p.name ?? "(unnamed)",
492
- voltroVersion: fe,
493
- port: D,
520
+ name: f.name ?? "(unnamed)",
521
+ voltroVersion: pe,
522
+ port: C,
494
523
  mode: "start",
495
- apis: Object.entries(p.apis ?? {}).map(([e, t]) => {
524
+ apis: Object.entries(f.apis ?? {}).map(([e, t]) => {
496
525
  let n = {
497
526
  name: e,
498
527
  package: t.package
@@ -500,8 +529,8 @@ CREATE INDEX IF NOT EXISTS ${e}_servable_until_idx ON ${e} (servable_until);
500
529
  return t.url !== void 0 && (n.url = t.url), n;
501
530
  })
502
531
  },
503
- routes: Te,
504
- dirs: Ee,
532
+ routes: Ee,
533
+ dirs: De,
505
534
  cache: () => {
506
535
  let e = Date.now(), t = H.snapshot().map(([t, n]) => ({
507
536
  key: t,
@@ -514,16 +543,16 @@ CREATE INDEX IF NOT EXISTS ${e}_servable_until_idx ON ${e} (servable_until);
514
543
  staleWhileRevalidateMs: n.staleWhileRevalidateMs
515
544
  }));
516
545
  return {
517
- backend: De,
546
+ backend: Oe,
518
547
  size: H.size(),
519
548
  entries: t
520
549
  };
521
550
  },
522
- metrics: () => se()
523
- }, ke = async (t, n) => {
524
- let r = t.split("?")[0] ?? "/";
525
- if (p.name === "voltroDashboard" && r === "/api/dashboard/registry") try {
526
- let e = await l();
551
+ metrics: () => ce()
552
+ }, Ae = async (n, r) => {
553
+ let i = n.split("?")[0] ?? "/";
554
+ if (f.name === "voltroDashboard" && i === "/api/dashboard/registry") try {
555
+ let e = await t();
527
556
  return {
528
557
  status: 200,
529
558
  headers: { "content-type": "application/json; charset=utf-8" },
@@ -536,7 +565,7 @@ CREATE INDEX IF NOT EXISTS ${e}_servable_until_idx ON ${e} (servable_until);
536
565
  body: `registry read error: ${e.message}`
537
566
  };
538
567
  }
539
- if (p.name === "voltroDashboard" && r === "/api/dashboard/config") {
568
+ if (f.name === "voltroDashboard" && i === "/api/dashboard/config") {
540
569
  let e = process.env.VOLTRO_DASHBOARD_APPS, t = [];
541
570
  if (e && e.trim().length > 0) {
542
571
  let n;
@@ -565,16 +594,16 @@ CREATE INDEX IF NOT EXISTS ${e}_servable_until_idx ON ${e} (servable_until);
565
594
  body: JSON.stringify({ apps: t })
566
595
  };
567
596
  }
568
- if (r === "/_voltro/inspect/logs") {
569
- let e = a(t, d());
597
+ if (i === "/_voltro/inspect/logs") {
598
+ let e = M(n, p());
570
599
  return {
571
600
  status: e.status,
572
601
  headers: { "content-type": e.contentType },
573
602
  body: e.body
574
603
  };
575
604
  }
576
- if (r !== "/_voltro/inspect/stream") {
577
- let e = ne(t, Oe, n);
605
+ if (i !== "/_voltro/inspect/stream") {
606
+ let e = k(n, ke, r);
578
607
  if (e !== null) return {
579
608
  status: e.status,
580
609
  headers: {
@@ -584,70 +613,70 @@ CREATE INDEX IF NOT EXISTS ${e}_servable_until_idx ON ${e} (servable_until);
584
613
  body: e.body
585
614
  };
586
615
  }
587
- let i = _e(r, q), c = i ? Z.get(i.route.pattern)?.renderMode : void 0, u = c === "ssr" || c === "isr", f = r === "/" ? N(j, "index.html") : N(j, r.replace(/^\//, ""), "index.html");
588
- if (!u && await X(f)) return {
616
+ let a = ve(i, K), s = a ? X.get(a.route.pattern)?.renderMode : void 0, c = s === "ssr" || s === "isr" || (a ? $.has(a.route.pattern) : !1), u = i === "/" ? F(A, "index.html") : F(A, i.replace(/^\//, ""), "index.html");
617
+ if (!c && await Z(u)) return {
589
618
  status: 200,
590
619
  headers: { "content-type": "text/html; charset=utf-8" },
591
- body: await R.readFile(f)
620
+ body: await B.readFile(u)
592
621
  };
593
- if (/\.[a-z0-9]+$/i.test(r)) {
594
- let e = N(j, r.replace(/^\//, ""));
595
- if (await X(e)) {
596
- let t = await R.readFile(e);
622
+ if (/\.[a-z0-9]+$/i.test(i)) {
623
+ let e = F(A, i.replace(/^\//, ""));
624
+ if (await Z(e)) {
625
+ let t = await B.readFile(e);
597
626
  return {
598
627
  status: 200,
599
- headers: { "content-type": me(e) },
628
+ headers: { "content-type": ge(e) },
600
629
  body: t
601
630
  };
602
631
  }
603
632
  }
604
- let m = _e(r, q);
605
- if (!m) return {
633
+ let d = ve(i, K);
634
+ if (!d) return {
606
635
  status: 404,
607
636
  headers: { "content-type": "text/plain" },
608
637
  body: "not found"
609
638
  };
610
- let h = Z.get(m.route.pattern), g = n["x-tenant"] ?? "anonymous", _ = (await Y.getHelpers()).i18n?.resolve(n.cookie, n["accept-language"])?.locale, v = s(r, {
611
- ...h?.tenantAware ? { tenant: g } : {},
612
- ..._ ? { locale: _ } : {}
613
- }), b = H.get(v), x = Date.now();
614
- if (b && S(b, x)) return w.emit("cache", {
639
+ let m = X.get(d.route.pattern), h = r["x-tenant"] ?? "anonymous", g = (await Y.getHelpers()).i18n?.resolve(r.cookie, r["accept-language"])?.locale, _ = e(i, {
640
+ ...m?.tenantAware ? { tenant: h } : {},
641
+ ...g ? { locale: g } : {}
642
+ }), v = H.get(_), y = Date.now();
643
+ if (v && te(v, y)) return x.emit("cache", {
615
644
  kind: "HIT",
616
- key: v,
617
- ageMs: x - b.renderedAt
645
+ key: _,
646
+ ageMs: y - v.renderedAt
618
647
  }), {
619
648
  status: 200,
620
649
  headers: {
621
650
  "content-type": "text/html; charset=utf-8",
622
651
  "x-voltro-rendered-by": "isr",
623
652
  "x-voltro-cache": "HIT",
624
- "x-voltro-cache-key": v,
625
- "x-voltro-cache-age-ms": String(x - b.renderedAt)
653
+ "x-voltro-cache-key": _,
654
+ "x-voltro-cache-age-ms": String(y - v.renderedAt)
626
655
  },
627
- body: b.html
656
+ body: v.html
628
657
  };
629
- if (b && e(b, x)) return w.emit("cache", {
658
+ if (v && o(v, y)) return x.emit("cache", {
630
659
  kind: "STALE",
631
- key: v,
632
- ageMs: x - b.renderedAt
660
+ key: _,
661
+ ageMs: y - v.renderedAt
633
662
  }), (async () => {
634
663
  try {
635
- let e = await ve({
664
+ let e = await ye({
636
665
  provider: Y,
637
- root: o,
638
- route: m.route,
639
- params: m.params,
640
- pathname: r,
666
+ root: l,
667
+ route: d.route,
668
+ params: d.params,
669
+ pathname: i,
641
670
  dirs: G,
642
- shellTemplate: z,
643
- requestHeaders: n,
671
+ shellTemplate: R,
672
+ requestHeaders: r,
644
673
  apiOrigin: V,
645
- requestUrl: t,
674
+ requestUrl: n,
646
675
  buffered: !0
647
676
  });
648
677
  if (e && "html" in e && e.renderMode === "isr" && e.revalidateMs !== null) {
649
- let t = Z.get(m.route.pattern)?.staleWhileRevalidateMs ?? 0, n = Date.now();
650
- H.set(v, {
678
+ let t = X.get(d.route.pattern)?.staleWhileRevalidateMs ?? 0, n = Date.now();
679
+ H.set(_, {
651
680
  html: e.html,
652
681
  renderedAt: n,
653
682
  expiresAt: n + e.revalidateMs,
@@ -657,7 +686,7 @@ CREATE INDEX IF NOT EXISTS ${e}_servable_until_idx ON ${e} (servable_until);
657
686
  });
658
687
  }
659
688
  } catch (e) {
660
- K.warn("background SWR refresh failed", { url: r }, e);
689
+ J.warn("background SWR refresh failed", { url: i }, e);
661
690
  }
662
691
  })(), {
663
692
  status: 200,
@@ -665,23 +694,23 @@ CREATE INDEX IF NOT EXISTS ${e}_servable_until_idx ON ${e} (servable_until);
665
694
  "content-type": "text/html; charset=utf-8",
666
695
  "x-voltro-rendered-by": "isr",
667
696
  "x-voltro-cache": "STALE",
668
- "x-voltro-cache-key": v,
669
- "x-voltro-cache-age-ms": String(x - b.renderedAt)
697
+ "x-voltro-cache-key": _,
698
+ "x-voltro-cache-age-ms": String(y - v.renderedAt)
670
699
  },
671
- body: b.html
700
+ body: v.html
672
701
  };
673
702
  try {
674
- let e = await ve({
703
+ let e = await ye({
675
704
  provider: Y,
676
- root: o,
677
- route: m.route,
678
- params: m.params,
679
- pathname: r,
705
+ root: l,
706
+ route: d.route,
707
+ params: d.params,
708
+ pathname: i,
680
709
  dirs: G,
681
- shellTemplate: z,
682
- requestHeaders: n,
710
+ shellTemplate: R,
711
+ requestHeaders: r,
683
712
  apiOrigin: V,
684
- requestUrl: t
713
+ requestUrl: n
685
714
  });
686
715
  if (!e) return {
687
716
  status: 200,
@@ -689,7 +718,7 @@ CREATE INDEX IF NOT EXISTS ${e}_servable_until_idx ON ${e} (servable_until);
689
718
  "content-type": "text/html; charset=utf-8",
690
719
  "x-voltro-rendered-by": "spa-fallback"
691
720
  },
692
- body: z
721
+ body: R
693
722
  };
694
723
  if ("stream" in e) return {
695
724
  status: 200,
@@ -712,36 +741,36 @@ CREATE INDEX IF NOT EXISTS ${e}_servable_until_idx ON ${e} (servable_until);
712
741
  },
713
742
  body: "not found"
714
743
  };
715
- let i = {
744
+ let t = {
716
745
  "content-type": "text/html; charset=utf-8",
717
746
  "x-voltro-rendered-by": e.renderMode
718
747
  };
719
748
  if (e.renderMode === "isr" && e.revalidateMs !== null) {
720
- let t = Date.now(), n = Z.get(m.route.pattern)?.staleWhileRevalidateMs ?? 0;
721
- H.set(v, {
749
+ let n = Date.now(), r = X.get(d.route.pattern)?.staleWhileRevalidateMs ?? 0;
750
+ H.set(_, {
722
751
  html: e.html,
723
- renderedAt: t,
724
- expiresAt: t + e.revalidateMs,
725
- servableUntil: t + e.revalidateMs + n,
752
+ renderedAt: n,
753
+ expiresAt: n + e.revalidateMs,
754
+ servableUntil: n + e.revalidateMs + r,
726
755
  revalidateMs: e.revalidateMs,
727
- staleWhileRevalidateMs: n
728
- }), 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)), w.emit("cache", {
756
+ staleWhileRevalidateMs: r
757
+ }), t["x-voltro-cache"] = "MISS", t["x-voltro-cache-key"] = _, t["x-voltro-cache-revalidate-ms"] = String(e.revalidateMs), r > 0 && (t["x-voltro-cache-swr-ms"] = String(r)), x.emit("cache", {
729
758
  kind: "MISS",
730
- key: v,
759
+ key: _,
731
760
  revalidateMs: e.revalidateMs,
732
- swrMs: n
761
+ swrMs: r
733
762
  });
734
- } else e.renderMode === "isr" && (i["x-voltro-cache"] = "BYPASS", w.emit("cache", {
763
+ } else e.renderMode === "isr" && (t["x-voltro-cache"] = "BYPASS", x.emit("cache", {
735
764
  kind: "BYPASS",
736
- key: v
765
+ key: _
737
766
  }));
738
767
  return {
739
768
  status: 200,
740
- headers: i,
769
+ headers: t,
741
770
  body: e.html
742
771
  };
743
772
  } catch (e) {
744
- return K.error("render error", { url: r }, e), y(e) ? {
773
+ return J.error("render error", { url: i }, e), b(e) ? {
745
774
  status: 500,
746
775
  headers: {
747
776
  "content-type": "text/plain; charset=utf-8",
@@ -754,9 +783,9 @@ CREATE INDEX IF NOT EXISTS ${e}_servable_until_idx ON ${e} (servable_until);
754
783
  body: "server error"
755
784
  };
756
785
  }
757
- }, Ae = !1, je = ce(async (e, t) => {
758
- let n = e.url ?? "/", r = Date.now(), a = {};
759
- for (let [t, n] of Object.entries(e.headers)) n !== void 0 && (a[t.toLowerCase()] = Array.isArray(n) ? n.join(", ") : n);
786
+ }, je = !1, Me = le(async (e, t) => {
787
+ let n = e.url ?? "/", r = Date.now(), i = {};
788
+ for (let [t, n] of Object.entries(e.headers)) n !== void 0 && (i[t.toLowerCase()] = Array.isArray(n) ? n.join(", ") : n);
760
789
  let o = n.split("?")[0] ?? "/", s = (e.method ?? "GET").toUpperCase();
761
790
  if (o === "/internal/liveness") {
762
791
  t.writeHead(200, {
@@ -766,33 +795,33 @@ CREATE INDEX IF NOT EXISTS ${e}_servable_until_idx ON ${e} (servable_until);
766
795
  return;
767
796
  }
768
797
  if (o === "/internal/readiness") {
769
- let e = Ae ? 200 : 503;
798
+ let e = je ? 200 : 503;
770
799
  t.writeHead(e, {
771
800
  "content-type": "text/plain",
772
801
  "cache-control": "no-store"
773
- }), t.end(Ae ? "ready" : "not-ready");
802
+ }), t.end(je ? "ready" : "not-ready");
774
803
  return;
775
804
  }
776
805
  if (s === "OPTIONS" && o.startsWith("/_voltro/inspect")) {
777
- let e = _(a.origin);
806
+ let e = T(i.origin);
778
807
  t.writeHead(204, e), t.end();
779
808
  return;
780
809
  }
781
- if (p.name === "voltroDashboard" && o === "/api/dashboard/proxy") {
810
+ if (f.name === "voltroDashboard" && o === "/api/dashboard/proxy") {
782
811
  let r = new URL(n, "http://x").searchParams.get("target");
783
812
  if (!r) {
784
813
  t.writeHead(400, { "content-type": "text/plain" }), t.end("missing ?target=");
785
814
  return;
786
815
  }
787
816
  try {
788
- let n = { accept: a.accept ?? "application/json" }, i = a.authorization;
789
- i && (n.authorization = Array.isArray(i) ? i[0] : i);
817
+ let n = { accept: i.accept ?? "application/json" }, a = i.authorization;
818
+ a && (n.authorization = Array.isArray(a) ? a[0] : a);
790
819
  let o;
791
820
  if (s && s !== "GET" && s !== "HEAD") {
792
821
  let t = [];
793
822
  for await (let n of e) t.push(n);
794
823
  o = Buffer.concat(t);
795
- let r = a["content-type"];
824
+ let r = i["content-type"];
796
825
  r && (n["content-type"] = Array.isArray(r) ? r[0] : r);
797
826
  }
798
827
  let c = await fetch(r, {
@@ -809,22 +838,22 @@ CREATE INDEX IF NOT EXISTS ${e}_servable_until_idx ON ${e} (servable_until);
809
838
  }
810
839
  return;
811
840
  }
812
- if (p.name === "voltroDashboard" && o === "/api/dashboard/proxy/stream") {
841
+ if (f.name === "voltroDashboard" && o === "/api/dashboard/proxy/stream") {
813
842
  let r = new URL(n, "http://x").searchParams.get("target");
814
843
  if (!r) {
815
844
  t.writeHead(400, { "content-type": "text/plain" }), t.end("missing ?target=");
816
845
  return;
817
846
  }
818
- let i = new AbortController();
819
- e.on("close", () => i.abort()), t.on("close", () => i.abort());
847
+ let a = new AbortController();
848
+ e.on("close", () => a.abort()), t.on("close", () => a.abort());
820
849
  try {
821
- let e = a.authorization, n = await fetch(r, {
850
+ let e = i.authorization, n = await fetch(r, {
822
851
  method: "GET",
823
852
  headers: {
824
853
  accept: "text/event-stream",
825
854
  ...e ? { authorization: Array.isArray(e) ? e[0] : e } : {}
826
855
  },
827
- signal: i.signal
856
+ signal: a.signal
828
857
  });
829
858
  if (!n.ok || !n.body) {
830
859
  t.writeHead(n.status, { "content-type": "text/plain" }), t.end(`upstream ${n.status}`);
@@ -852,15 +881,15 @@ CREATE INDEX IF NOT EXISTS ${e}_servable_until_idx ON ${e} (servable_until);
852
881
  return;
853
882
  }
854
883
  if (o === "/_voltro/inspect/stream") {
855
- let n = _(a.origin);
856
- if (T()) {
884
+ let n = T(i.origin);
885
+ if (S()) {
857
886
  t.writeHead(503, {
858
887
  "content-type": "application/json",
859
888
  ...n
860
889
  }), t.end(JSON.stringify({ error: "inspect disabled (VOLTRO_INSPECT=off)" }));
861
890
  return;
862
891
  }
863
- let r = E(a);
892
+ let r = h(i);
864
893
  if (!r.ok) {
865
894
  t.writeHead(401, {
866
895
  "content-type": "application/json",
@@ -878,11 +907,11 @@ CREATE INDEX IF NOT EXISTS ${e}_servable_until_idx ON ${e} (servable_until);
878
907
  "x-accel-buffering": "no",
879
908
  ...n
880
909
  }), t.flushHeaders(), t.write("retry: 5000\n\n");
881
- for (let e of w.buffered()) t.write(i(e));
882
- let o = w.subscribe((e) => {
883
- t.write(i(e));
910
+ for (let e of x.buffered()) t.write(m(e));
911
+ let o = x.subscribe((e) => {
912
+ t.write(m(e));
884
913
  }), s = setInterval(() => {
885
- t.write(f());
914
+ t.write(a());
886
915
  }, 15e3), c = () => {
887
916
  clearInterval(s), o();
888
917
  };
@@ -890,18 +919,18 @@ CREATE INDEX IF NOT EXISTS ${e}_servable_until_idx ON ${e} (servable_until);
890
919
  return;
891
920
  }
892
921
  try {
893
- let e = await ke(n, a);
922
+ let e = await Ae(n, i);
894
923
  if (e.stream ? e.stream(t) : (t.writeHead(e.status, e.headers), t.end(e.body)), !o.startsWith("/_voltro/inspect")) {
895
924
  let t = Date.now() - r;
896
- w.emit("request", {
925
+ x.emit("request", {
897
926
  url: o,
898
927
  status: e.status,
899
928
  durationMs: t,
900
929
  renderedBy: e.headers["x-voltro-rendered-by"],
901
930
  cache: e.headers["x-voltro-cache"]
902
931
  });
903
- let n = _e(o, q)?.route.pattern ?? (e.status === 404 ? "<unmatched>" : "<asset>");
904
- we.record({
932
+ let n = ve(o, K)?.route.pattern ?? (e.status === 404 ? "<unmatched>" : "<asset>");
933
+ Te.record({
905
934
  kind: "request",
906
935
  tag: n,
907
936
  durationMs: t,
@@ -912,66 +941,66 @@ CREATE INDEX IF NOT EXISTS ${e}_servable_until_idx ON ${e} (servable_until);
912
941
  t.writeHead(500, { "content-type": "text/plain" }), t.end(`internal error: ${e.message}`);
913
942
  }
914
943
  });
915
- await new Promise((e) => je.listen(D, "::", e)), Ae = !0, K.info(`listening on http://localhost:${D}`, {
916
- port: D,
917
- distDir: j
918
- }), K.debug("dynamic + ssr/isr routes resolve via SSR loader");
944
+ await new Promise((e) => Me.listen(C, "::", e)), je = !0, J.info(`listening on http://localhost:${C}`, {
945
+ port: C,
946
+ distDir: A
947
+ }), J.debug("dynamic + ssr/isr routes resolve via SSR loader");
919
948
  try {
920
- await n({
921
- id: F,
922
- name: P,
949
+ await w({
950
+ id: P,
951
+ name: N,
923
952
  kind: "web",
924
- url: `http://localhost:${D}`,
953
+ url: `http://localhost:${C}`,
925
954
  pid: process.pid,
926
955
  status: "live",
927
956
  logFile: I.path
928
957
  });
929
- let e = m(o);
958
+ let e = u(l);
930
959
  if (e) {
931
- let t = await ae({ dashboardAppPath: e });
932
- t.status === "launched" ? K.info(`dashboard launched at http://localhost:${t.port}`, { port: t.port }) : t.status === "already-running" && K.debug(`dashboard already running on :${t.port}`, { port: t.port });
960
+ let t = await oe({ dashboardAppPath: e });
961
+ 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 });
933
962
  }
934
963
  setInterval(() => {
935
- n({
936
- id: F,
937
- name: P,
964
+ w({
965
+ id: P,
966
+ name: N,
938
967
  kind: "web",
939
- url: `http://localhost:${D}`,
968
+ url: `http://localhost:${C}`,
940
969
  pid: process.pid,
941
970
  status: "live",
942
971
  logFile: I.path
943
972
  }).catch(() => {});
944
973
  }, 1e4).unref();
945
974
  } catch (e) {
946
- K.warn("runtime-registry write failed", {}, e);
975
+ J.warn("runtime-registry write failed", {}, e);
947
976
  }
948
- oe({
949
- app: p.name ?? "unnamed",
977
+ se({
978
+ app: f.name ?? "unnamed",
950
979
  kind: "web",
951
- url: `http://localhost:${D}`,
952
- bootMs: Date.now() - ee
980
+ url: `http://localhost:${C}`,
981
+ bootMs: Date.now() - v
953
982
  });
954
- let Me = !1, $ = (e) => async () => {
955
- if (!Me) {
956
- if (Me = !0, K.info(`received ${e}, shutting down`, { signal: e }), je.close(), await Ce.stop(), U) try {
983
+ let Ne = !1, Pe = (e) => async () => {
984
+ if (!Ne) {
985
+ if (Ne = !0, J.info(`received ${e}, shutting down`, { signal: e }), Me.close(), await we.stop(), U) try {
957
986
  await U.end();
958
987
  } catch {}
959
- await Y.close(), await r(F), await I.dispose(), process.exit(0);
988
+ await Y.close(), await c(P), await I.dispose(), process.exit(0);
960
989
  }
961
990
  };
962
- process.on("SIGINT", $("SIGINT")), process.on("SIGTERM", $("SIGTERM"));
963
- let Ne = process.ppid;
964
- if (Ne > 1) {
991
+ process.on("SIGINT", Pe("SIGINT")), process.on("SIGTERM", Pe("SIGTERM"));
992
+ let Fe = process.ppid;
993
+ if (Fe > 1) {
965
994
  let e = setInterval(() => {
966
- (process.ppid !== Ne || process.ppid === 1) && (clearInterval(e), $("SIGTERM")());
995
+ (process.ppid !== Fe || process.ppid === 1) && (clearInterval(e), Pe("SIGTERM")());
967
996
  }, 2e3);
968
997
  e.unref();
969
998
  }
970
999
  return new Promise(() => {});
971
- }, xe = async (e) => {
1000
+ }, Ce = async (e) => {
972
1001
  process.env.NODE_ENV || (process.env.NODE_ENV = "production");
973
- let t = await Q(P(e.find((e) => !e.startsWith("-")) ?? process.cwd()));
974
- return t.ran ? t.exitCode : (K.error("no web app found at this path"), 1);
1002
+ let t = await Se(I(e.find((e) => !e.startsWith("-")) ?? process.cwd()));
1003
+ return t.ran ? t.exitCode : (J.error("no web app found at this path"), 1);
975
1004
  };
976
1005
  //#endregion
977
- export { le as n, xe as t };
1006
+ export { ue as n, Ce as t };