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