@voltro/cli 0.10.0 → 0.11.1

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