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