@voltro/cli 0.30.1 → 0.31.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 (124) hide show
  1. package/CHANGELOG.md +163 -0
  2. package/dist/apiBuild-BOqL1dlg.js +2 -0
  3. package/dist/{apiBuild-DmkzRyv7.js → apiBuild-CLPt-pX6.js} +2 -2
  4. package/dist/appGraph-CvQCte0z.js +2 -0
  5. package/dist/appGraph-gQ_6GkQQ.js +110 -0
  6. package/dist/bin.js +3 -3
  7. package/dist/checkCommand-ClRvH_SN.js +2 -0
  8. package/dist/{checkCommand-C4konUy9.js → checkCommand-D7r6_pk7.js} +439 -530
  9. package/dist/{commands-BkJft9K2.js → commands-CNVVv03h.js} +1941 -1880
  10. package/dist/{dbCommand-qn__kLEt.js → dbCommand-BH8GAYuf.js} +76 -19
  11. package/dist/dbCommand-BwQ_Jl98.js +2 -0
  12. package/dist/{dev-DXhhZ7-f.js → dev-DOZVMVfi.js} +1 -1
  13. package/dist/{dev-C_NPcLDp.js → dev-DdQEn2Ia.js} +1986 -1967
  14. package/dist/{frameworkTableAssembly-Cpgn2e88.js → frameworkTableAssembly-BwIrO5nv.js} +122 -103
  15. package/dist/frameworkTableAssembly-D-EebUQX.js +2 -0
  16. package/dist/index.js +1 -1
  17. package/dist/{inspectMetrics-CkB2J0Zn.js → inspectMetrics-BeEAnjqw.js} +774 -527
  18. package/dist/{sdkgen-wsWLrq4l.js → sdkgen-v9WV8zRi.js} +1 -1
  19. package/dist/{serveCommand-HtI4X5kj.js → serveCommand-KsKXXWn4.js} +294 -293
  20. package/dist/serveEntry.js +2 -2
  21. package/dist/{start-egkbpugc.js → start-CI2QdKy9.js} +351 -346
  22. package/dist/startEntry.js +2 -2
  23. package/package.json +17 -17
  24. package/templates/AGENTS.md +43 -43
  25. package/templates/agent-docs/_index.md +43 -43
  26. package/templates/agent-docs/_manifest.json +84 -42
  27. package/templates/agent-docs/cli.md +4 -2
  28. package/templates/agent-docs/database/migrations.md +14 -1
  29. package/templates/agent-docs/internationalization.md +54 -3
  30. package/templates/agent-docs/plugins/ai-flows.md +148 -0
  31. package/templates/agent-docs/plugins/analytics-postgres.md +90 -0
  32. package/templates/agent-docs/plugins/atlassian.md +378 -0
  33. package/templates/agent-docs/plugins/audit.md +324 -0
  34. package/templates/agent-docs/plugins/auth-auth0.md +92 -0
  35. package/templates/agent-docs/plugins/auth-clerk.md +90 -0
  36. package/templates/agent-docs/plugins/auth-kinde.md +88 -0
  37. package/templates/agent-docs/plugins/auth-oidc.md +95 -0
  38. package/templates/agent-docs/plugins/auth-supabase.md +103 -0
  39. package/templates/agent-docs/plugins/auth-workos.md +105 -0
  40. package/templates/agent-docs/plugins/auth.md +227 -0
  41. package/templates/agent-docs/plugins/billing.md +324 -0
  42. package/templates/agent-docs/plugins/broadcast.md +144 -0
  43. package/templates/agent-docs/plugins/cdc-out.md +116 -0
  44. package/templates/agent-docs/plugins/clickhouse.md +91 -0
  45. package/templates/agent-docs/plugins/datadog.md +105 -0
  46. package/templates/agent-docs/plugins/deactivation.md +114 -0
  47. package/templates/agent-docs/plugins/duckdb.md +82 -0
  48. package/templates/agent-docs/plugins/flags.md +146 -0
  49. package/templates/agent-docs/plugins/governance.md +143 -0
  50. package/templates/agent-docs/plugins/licensing.md +74 -0
  51. package/templates/agent-docs/plugins/logship.md +56 -0
  52. package/templates/agent-docs/plugins/mail.md +334 -0
  53. package/templates/agent-docs/plugins/moderation.md +65 -0
  54. package/templates/agent-docs/plugins/multitenancy.md +99 -0
  55. package/templates/agent-docs/plugins/notifications.md +252 -0
  56. package/templates/agent-docs/plugins/openapi.md +94 -0
  57. package/templates/agent-docs/plugins/postgis.md +140 -0
  58. package/templates/agent-docs/plugins/posthog.md +91 -0
  59. package/templates/agent-docs/plugins/presence.md +115 -0
  60. package/templates/agent-docs/plugins/prometheus.md +124 -0
  61. package/templates/agent-docs/plugins/ratelimit.md +274 -0
  62. package/templates/agent-docs/plugins/rbac.md +270 -0
  63. package/templates/agent-docs/plugins/scim.md +63 -0
  64. package/templates/agent-docs/plugins/search.md +116 -0
  65. package/templates/agent-docs/plugins/sentry.md +192 -0
  66. package/templates/agent-docs/plugins/soft-delete.md +72 -0
  67. package/templates/agent-docs/plugins/sso-saml.md +132 -0
  68. package/templates/agent-docs/plugins/storage.md +709 -0
  69. package/templates/agent-docs/plugins/tinybird.md +92 -0
  70. package/templates/agent-docs/plugins/versioning.md +226 -0
  71. package/templates/agent-docs/plugins/webhooks.md +585 -0
  72. package/templates/agent-docs/security.md +12 -1
  73. package/templates/agent-docs/whats-new.md +81 -37
  74. package/templates/apps/api-ai/package.json +7 -7
  75. package/templates/apps/api-auth/package.json +8 -8
  76. package/templates/apps/api-backend/package.json +7 -7
  77. package/templates/apps/api-backend-deactivation/package.json +7 -7
  78. package/templates/apps/api-backend-mail/package.json +8 -8
  79. package/templates/apps/api-backend-mariadb/package.json +9 -9
  80. package/templates/apps/api-backend-sqlite/package.json +8 -8
  81. package/templates/apps/api-backend-storage/package.json +8 -8
  82. package/templates/apps/api-cms/package.json +10 -10
  83. package/templates/apps/api-collab/package.json +8 -8
  84. package/templates/apps/api-data-advanced/package.json +8 -8
  85. package/templates/apps/api-durable/package.json +8 -8
  86. package/templates/apps/api-feature-flags/package.json +9 -9
  87. package/templates/apps/api-governance/package.json +8 -8
  88. package/templates/apps/api-kv/package.json +8 -8
  89. package/templates/apps/api-moderation/package.json +8 -8
  90. package/templates/apps/api-observability/package.json +8 -8
  91. package/templates/apps/api-ratelimit/package.json +8 -8
  92. package/templates/apps/api-rbac/package.json +8 -8
  93. package/templates/apps/api-rest/package.json +7 -7
  94. package/templates/apps/api-saas/package.json +11 -11
  95. package/templates/apps/api-saas-starter/package.json +10 -10
  96. package/templates/apps/api-search/package.json +8 -8
  97. package/templates/apps/api-status/package.json +8 -8
  98. package/templates/apps/api-versioning/package.json +8 -8
  99. package/templates/apps/api-webhooks/package.json +9 -9
  100. package/templates/apps/changelog/package.json +6 -6
  101. package/templates/apps/edge-functions/package.json +2 -2
  102. package/templates/apps/frontend-admin/package.json +8 -8
  103. package/templates/apps/frontend-app/package.json +8 -8
  104. package/templates/apps/frontend-auth/package.json +8 -8
  105. package/templates/apps/frontend-blank/package.json +7 -7
  106. package/templates/apps/frontend-cms/package.json +9 -9
  107. package/templates/apps/frontend-collab/package.json +9 -9
  108. package/templates/apps/frontend-contact/package.json +7 -7
  109. package/templates/apps/frontend-dashboard/package.json +7 -7
  110. package/templates/apps/frontend-docs/package.json +7 -7
  111. package/templates/apps/frontend-i18n/package.json +6 -6
  112. package/templates/apps/frontend-landing/package.json +7 -7
  113. package/templates/apps/frontend-portal/package.json +8 -8
  114. package/templates/apps/frontend-saas/package.json +8 -8
  115. package/templates/apps/frontend-spa/package.json +7 -7
  116. package/templates/apps/frontend-ssr/package.json +7 -7
  117. package/templates/apps/frontend-ssr-api/package.json +8 -8
  118. package/templates/apps/frontend-static-blog/package.json +6 -6
  119. package/templates/apps/frontend-status/package.json +8 -8
  120. package/templates/apps/mobile-app/package.json +2 -2
  121. package/dist/apiBuild-Ca6Sq5jy.js +0 -2
  122. package/dist/checkCommand-DHD0aBeR.js +0 -2
  123. package/dist/dbCommand-wfGi3FgG.js +0 -2
  124. package/dist/frameworkTableAssembly-Bn_c4Mnl.js +0 -2
@@ -1,14 +1,14 @@
1
- import { B as e, E as t, G as n, I as r, K as i, N as a, O as o, Q as s, S as c, T as l, U as u, W as ee, Z as d, _ as f, _t as p, a as m, at as h, b as g, c as _, f as v, ft as y, g as b, gt as x, h as S, ht as te, i as ne, it as re, lt as ie, m as C, mt as w, nt as ae, o as oe, ot as T, p as E, q as D, r as O, rt as k, s as A, t as j, v as M, x as se, y as N } from "./inspectMetrics-CkB2J0Zn.js";
2
- import { A as ce, E as P, O as F, a as le, k as I, m as ue } from "./inspect-BUUjt773.js";
1
+ import { $ as e, C as t, Ct as n, D as r, E as i, G as a, J as o, K as s, L as c, P as l, Q as u, S as d, St as ee, Tt as f, V as p, W as m, _ as h, _t as g, a as _, b as v, bt as y, c as b, dt as te, f as x, ft as S, g as C, h as w, i as T, k as E, m as D, mt as O, o as ne, p as re, pt as k, q as ie, r as A, s as j, t as M, ut as N, v as ae, wt as oe, x as P, y as F } from "./inspectMetrics-BeEAnjqw.js";
2
+ import { A as se, E as I, O as ce, a as le, k as L, m as ue } from "./inspect-BUUjt773.js";
3
3
  import { t as de } from "./bootTiming-BdyP9nYw.js";
4
- import { dirname as L, extname as fe, join as R, resolve as pe } from "node:path";
5
- import { fileURLToPath as z, pathToFileURL as B } from "node:url";
6
- import { createLogger as V, printReadyBlock as me } from "@voltro/logger";
7
- import { promises as H } from "node:fs";
4
+ import { dirname as fe, extname as pe, join as R, resolve as z } from "node:path";
5
+ import { fileURLToPath as B, pathToFileURL as V } from "node:url";
6
+ import { createLogger as H, printReadyBlock as me } from "@voltro/logger";
7
+ import { promises as U } from "node:fs";
8
8
  import { snapshotMetricsSync as he } from "@voltro/runtime";
9
9
  import { createServer as ge } from "node:http";
10
10
  //#region src/isrCdcInvalidator.ts
11
- var U = V({ scope: "voltro:start:cdc" }), W = (e) => (t) => {
11
+ var W = H({ scope: "voltro:start:cdc" }), G = (e) => (t) => {
12
12
  let n = 0;
13
13
  for (let [r, i] of e.tableSubscriptionsByPattern) {
14
14
  if (!i.includes(t)) continue;
@@ -19,23 +19,23 @@ var U = V({ scope: "voltro:start:cdc" }), W = (e) => (t) => {
19
19
  }));
20
20
  }
21
21
  return n;
22
- }, G = () => !process.env.PG_HOST && !process.env.PG_DATABASE ? null : {
22
+ }, _e = () => !process.env.PG_HOST && !process.env.PG_DATABASE ? null : {
23
23
  host: process.env.PG_HOST ?? "localhost",
24
24
  port: Number(process.env.PG_PORT ?? 5432),
25
25
  user: process.env.PG_USER ?? "app",
26
26
  password: process.env.PG_PASSWORD ?? "app",
27
27
  database: process.env.PG_DATABASE ?? "app"
28
- }, _e = (e) => {
29
- let t = e.channel ?? "framework_changes", n = W(e), r = null, i = null;
28
+ }, ve = (e) => {
29
+ let t = e.channel ?? "framework_changes", n = G(e), r = null, i = null;
30
30
  return {
31
31
  start: async () => {
32
- let a = G();
32
+ let a = _e();
33
33
  if (!a) {
34
- U.debug("skipped — no PG_* env vars set");
34
+ W.debug("skipped — no PG_* env vars set");
35
35
  return;
36
36
  }
37
37
  if (e.tableSubscriptionsByPattern.size === 0) {
38
- U.debug("skipped — no pages declare cacheInvalidatesOn");
38
+ W.debug("skipped — no pages declare cacheInvalidatesOn");
39
39
  return;
40
40
  }
41
41
  r = new (await (import("pg"))).default.Client(a), await r.connect(), i = (e) => {
@@ -44,16 +44,16 @@ var U = V({ scope: "voltro:start:cdc" }), W = (e) => (t) => {
44
44
  try {
45
45
  r = JSON.parse(e.payload);
46
46
  } catch (e) {
47
- U.warn("bad CDC payload", {}, e);
47
+ W.warn("bad CDC payload", {}, e);
48
48
  return;
49
49
  }
50
50
  let i = n(r.table);
51
- i > 0 && U.info(`${r.op} on '${r.table}' → dropped ${i} cache entries`, {
51
+ i > 0 && W.info(`${r.op} on '${r.table}' → dropped ${i} cache entries`, {
52
52
  op: r.op,
53
53
  table: r.table,
54
54
  dropped: i
55
55
  });
56
- }, r.on("notification", i), await r.query(`LISTEN ${t}`), U.info(`LISTEN ${t}`, {
56
+ }, r.on("notification", i), await r.query(`LISTEN ${t}`), W.info(`LISTEN ${t}`, {
57
57
  channel: t,
58
58
  host: a.host,
59
59
  port: a.port,
@@ -69,7 +69,7 @@ var U = V({ scope: "voltro:start:cdc" }), W = (e) => (t) => {
69
69
  }
70
70
  }
71
71
  };
72
- }, K = V({ scope: "voltro:start:isr-cache" }), q = "voltro_isr_cache", ve = (e) => `
72
+ }, K = H({ scope: "voltro:start:isr-cache" }), ye = "voltro_isr_cache", q = (e) => `
73
73
  CREATE TABLE IF NOT EXISTS ${e} (
74
74
  cache_key TEXT PRIMARY KEY,
75
75
  html TEXT NOT NULL,
@@ -80,9 +80,9 @@ CREATE TABLE IF NOT EXISTS ${e} (
80
80
  stale_while_revalidate_ms BIGINT NOT NULL DEFAULT 0
81
81
  );
82
82
  CREATE INDEX IF NOT EXISTS ${e}_servable_until_idx ON ${e} (servable_until);
83
- `, ye = (e) => {
84
- let t = e.tableName ?? q, { client: n } = e, r = /* @__PURE__ */ new Map(), i = !1, a = (async () => {
85
- i || (i = !0, await n.query(ve(t)));
83
+ `, be = (e) => {
84
+ let t = e.tableName ?? ye, { client: n } = e, r = /* @__PURE__ */ new Map(), i = !1, a = (async () => {
85
+ i || (i = !0, await n.query(q(t)));
86
86
  })().then(async () => {
87
87
  let e = await n.query(`SELECT * FROM ${t}`);
88
88
  for (let t of e.rows) r.set(t.cache_key, {
@@ -142,14 +142,14 @@ CREATE INDEX IF NOT EXISTS ${e}_servable_until_idx ON ${e} (servable_until);
142
142
  return Array.from(r.entries());
143
143
  }
144
144
  };
145
- }, J = V({ scope: "voltro:start" }), be = await (async () => {
145
+ }, J = H({ scope: "voltro:start" }), xe = await (async () => {
146
146
  try {
147
- let e = R(L(z(import.meta.url)), "..", "package.json"), t = await H.readFile(e, "utf8");
147
+ let e = R(fe(B(import.meta.url)), "..", "package.json"), t = await U.readFile(e, "utf8");
148
148
  return JSON.parse(t).version ?? "0.0.0";
149
149
  } catch {
150
150
  return "0.0.0";
151
151
  }
152
- })(), Y = (e) => e instanceof Error && e._voltroControl === "redirect" && typeof e.location == "string", X = (e) => e instanceof Error && e._voltroControl === "not-found", Z = {
152
+ })(), Y = (e) => e instanceof Error && e._voltroControl === "redirect" && typeof e.location == "string", X = (e) => e instanceof Error && e._voltroControl === "not-found", Se = {
153
153
  ".html": "text/html; charset=utf-8",
154
154
  ".js": "application/javascript",
155
155
  ".mjs": "application/javascript",
@@ -167,13 +167,13 @@ CREATE INDEX IF NOT EXISTS ${e}_servable_until_idx ON ${e} (servable_until);
167
167
  ".woff": "font/woff",
168
168
  ".woff2": "font/woff2",
169
169
  ".txt": "text/plain; charset=utf-8"
170
- }, xe = (e) => Z[fe(e).toLowerCase()] ?? "application/octet-stream", Se = (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) => {
170
+ }, Ce = (e) => Se[pe(e).toLowerCase()] ?? "application/octet-stream", we = (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) => {
171
171
  try {
172
- return await H.stat(e), !0;
172
+ return await U.stat(e), !0;
173
173
  } catch {
174
174
  return !1;
175
175
  }
176
- }, Ce = (e) => {
176
+ }, Q = (e) => {
177
177
  let t = [], n = 0, r = e.split("/").filter(Boolean), i = [];
178
178
  for (let e of r) e.startsWith("[[...") && e.endsWith("]]") ? (i.push("(.*)"), t.push(e.slice(5, -2)), n += 2) : e.startsWith("[...") && e.endsWith("]") ? (i.push("(.+)"), t.push(e.slice(4, -1)), n += 3) : e.startsWith("[") && e.endsWith("]") ? (i.push("([^/]+)"), t.push(e.slice(1, -1)), n += 1) : i.push(e.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"));
179
179
  let a = i.join("/");
@@ -182,8 +182,8 @@ CREATE INDEX IF NOT EXISTS ${e}_servable_until_idx ON ${e} (servable_until);
182
182
  paramNames: t,
183
183
  priority: n
184
184
  };
185
- }, we = (e) => e.map((e) => {
186
- let { regex: t, paramNames: n, priority: r } = Ce(e.pattern);
185
+ }, Te = (e) => e.map((e) => {
186
+ let { regex: t, paramNames: n, priority: r } = Q(e.pattern);
187
187
  return {
188
188
  pattern: e.pattern,
189
189
  file: e.file,
@@ -192,7 +192,7 @@ CREATE INDEX IF NOT EXISTS ${e}_servable_until_idx ON ${e} (servable_until);
192
192
  paramNames: n,
193
193
  priority: r
194
194
  };
195
- }).slice().sort((e, t) => e.priority - t.priority), Te = (e, t) => {
195
+ }).slice().sort((e, t) => e.priority - t.priority), Ee = (e, t) => {
196
196
  for (let n of t) {
197
197
  let t = n.regex.exec(e);
198
198
  if (!t) continue;
@@ -204,31 +204,31 @@ CREATE INDEX IF NOT EXISTS ${e}_servable_until_idx ON ${e} (servable_until);
204
204
  };
205
205
  }
206
206
  return null;
207
- }, Ee = async (e) => {
208
- let { provider: t, route: n, params: i, pathname: a, dirs: o, shellTemplate: s, requestHeaders: l, requestUrl: u = "", apiOrigin: ee, apiName: d } = e, { search: f } = c(u), p = ne(ee, l.cookie, { apiName: d }), h = await t.getPage(n.pattern, n.file), _ = r(h, n.file), v = _ === "spa" && oe(o, n.dirChain).some((e) => e.hasLayout);
209
- if (_ !== "ssr" && _ !== "isr" && !v) return null;
210
- let y = oe(o, n.dirChain), x = {}, te = null, re, ie = new AbortController();
207
+ }, De = async (e) => {
208
+ let { provider: n, route: r, params: i, pathname: a, dirs: o, shellTemplate: s, requestHeaders: l, requestUrl: u = "", apiOrigin: ee, apiName: f } = e, { search: p } = t(u), m = T(ee, l.cookie, { apiName: f }), g = await n.getPage(r.pattern, r.file), y = c(g, r.file), b = y === "spa" && ne(o, r.dirChain).some((e) => e.hasLayout);
209
+ if (y !== "ssr" && y !== "isr" && !b) return null;
210
+ let te = ne(o, r.dirChain), x = {}, S = null, E, re = new AbortController();
211
211
  try {
212
- (await t.getHelpers()).beginStoreSeeds(), {chain: re, segmentLoaderData: x} = await m({
213
- entries: y,
214
- loadLayout: (e) => t.getLayout(e.dir),
215
- loadError: (e) => t.getError(e.dir),
216
- loadPending: (e) => t.getPending(e.dir),
212
+ (await n.getHelpers()).beginStoreSeeds(), {chain: E, segmentLoaderData: x} = await _({
213
+ entries: te,
214
+ loadLayout: (e) => n.getLayout(e.dir),
215
+ loadError: (e) => n.getError(e.dir),
216
+ loadPending: (e) => n.getPending(e.dir),
217
217
  ctx: {
218
218
  params: i,
219
219
  pathname: a,
220
- search: f,
221
- signal: ie.signal,
220
+ search: p,
221
+ signal: re.signal,
222
222
  headers: l,
223
- query: p
223
+ query: m
224
224
  }
225
- }), typeof h.loader == "function" && !v && (te = await h.loader({
225
+ }), typeof g.loader == "function" && !b && (S = await g.loader({
226
226
  params: i,
227
227
  pathname: a,
228
- search: f,
229
- signal: ie.signal,
228
+ search: p,
229
+ signal: re.signal,
230
230
  headers: l,
231
- query: p
231
+ query: m
232
232
  }));
233
233
  } catch (e) {
234
234
  if (Y(e)) return {
@@ -239,71 +239,71 @@ CREATE INDEX IF NOT EXISTS ${e}_servable_until_idx ON ${e} (servable_until);
239
239
  if (X(e)) return { control: "not-found" };
240
240
  throw e;
241
241
  }
242
- let w = await t.getHelpers();
243
- v || await C({
244
- pageMod: h,
242
+ let k = await n.getHelpers();
243
+ b || await D({
244
+ pageMod: g,
245
245
  params: i,
246
- query: p,
247
- apiName: d,
248
- seed: w.seedPreloadedSubscription,
246
+ query: m,
247
+ apiName: f,
248
+ seed: k.seedPreloadedSubscription,
249
249
  onError: ({ tag: e, apiName: t }, n) => J.warn("preload seed failed", {
250
250
  tag: e,
251
251
  apiName: t,
252
252
  pathname: a
253
253
  }, n)
254
254
  });
255
- let ae = {
256
- pattern: n.pattern,
257
- Component: h.default,
258
- meta: h.meta,
259
- loader: h.loader,
260
- ErrorBoundary: h.ErrorBoundary,
261
- Pending: h.Pending,
262
- renderMode: _,
263
- chain: re
264
- }, E = {
265
- cookies: w.parseCookieHeader(l.cookie),
255
+ let ie = {
256
+ pattern: r.pattern,
257
+ Component: g.default,
258
+ meta: g.meta,
259
+ loader: g.loader,
260
+ ErrorBoundary: g.ErrorBoundary,
261
+ Pending: g.Pending,
262
+ renderMode: y,
263
+ chain: E
264
+ }, A = {
265
+ cookies: k.parseCookieHeader(l.cookie),
266
266
  headers: l,
267
267
  url: u
268
- }, D = w.i18n?.resolve(l.cookie, l["accept-language"]), O = h.interactive ?? "full";
269
- if (v) {
270
- let e = N({
271
- helpers: w,
272
- page: n.pattern,
273
- interactive: O,
268
+ }, j = k.i18n?.resolve(l.cookie, l["accept-language"]), M = g.interactive ?? "full";
269
+ if (b) {
270
+ let e = v({
271
+ helpers: k,
272
+ page: r.pattern,
273
+ interactive: M,
274
274
  delivery: "stream",
275
275
  renderInput: {
276
- descriptor: ae,
276
+ descriptor: ie,
277
277
  params: i,
278
278
  pathname: a,
279
- search: f,
279
+ search: p,
280
280
  segmentLoaderData: x,
281
- requestContext: E,
282
- ...D ? {
283
- outerWrap: D.outerWrap,
284
- locale: D.locale
281
+ requestContext: A,
282
+ ...j ? {
283
+ outerWrap: j.outerWrap,
284
+ locale: j.locale
285
285
  } : {}
286
286
  }
287
- }), t = D?.locale ?? E.cookies["voltro:locale"] ?? "en", r = (t) => se({
288
- helpers: w,
287
+ }), t = j?.locale ?? A.cookies["voltro:locale"] ?? "en", n = (t) => d({
288
+ helpers: k,
289
289
  prepared: e,
290
290
  meta: t,
291
- interactive: O
291
+ interactive: M
292
292
  });
293
293
  if (e.hasDeferred) {
294
- let n = S({ shell: s });
294
+ let r = C({ shell: s });
295
295
  return {
296
296
  renderMode: "spa",
297
- stream: (i) => b({
297
+ stream: (i) => h({
298
298
  res: i,
299
- shell: n,
299
+ shell: r,
300
300
  htmlLang: t,
301
301
  headers: {
302
302
  "content-type": "text/html; charset=utf-8",
303
303
  "x-voltro-rendered-by": "spa"
304
304
  },
305
- headInjection: r,
306
- render: (t) => w.renderPageToStream({
305
+ headInjection: n,
306
+ render: (t) => k.renderPageToStream({
307
307
  ...e.renderInput,
308
308
  ...t
309
309
  }),
@@ -313,48 +313,48 @@ CREATE INDEX IF NOT EXISTS ${e}_servable_until_idx ON ${e} (servable_until);
313
313
  })
314
314
  };
315
315
  }
316
- let o = g({
317
- helpers: w,
316
+ let o = P({
317
+ helpers: k,
318
318
  prepared: e
319
319
  });
320
320
  return {
321
- html: s.replace("<div id=\"root\"></div>", `<div id="root">${o.body}</div>`).replace("</head>", ` ${r(o.meta)}\n </head>`).replace(/<html(\s+lang="[^"]*")?/i, `<html lang="${t}"`),
321
+ html: w(s.replace("<div id=\"root\"></div>", `<div id="root">${o.body}</div>`), n(o.meta)).replace(/<html(\s+lang="[^"]*")?/i, `<html lang="${t}"`),
322
322
  renderMode: "spa",
323
323
  revalidateMs: null
324
324
  };
325
325
  }
326
- let k = M({
327
- helpers: w,
328
- page: n.pattern,
326
+ let N = F({
327
+ helpers: k,
328
+ page: r.pattern,
329
329
  pathname: a,
330
- renderMode: _,
331
- interactive: O,
332
- loaderData: te,
330
+ renderMode: y,
331
+ interactive: M,
332
+ loaderData: S,
333
333
  segmentLoaderData: x,
334
- pageLoaderRan: typeof h.loader == "function"
335
- }), A = {
336
- descriptor: ae,
334
+ pageLoaderRan: typeof g.loader == "function"
335
+ }), ae = {
336
+ descriptor: ie,
337
337
  params: i,
338
338
  pathname: a,
339
- search: f,
340
- loaderData: k.loaderData,
341
- segmentLoaderData: k.segmentLoaderData,
342
- requestContext: E,
343
- ...D ? {
344
- outerWrap: D.outerWrap,
345
- locale: D.locale
339
+ search: p,
340
+ loaderData: N.loaderData,
341
+ segmentLoaderData: N.segmentLoaderData,
342
+ requestContext: A,
343
+ ...j ? {
344
+ outerWrap: j.outerWrap,
345
+ locale: j.locale
346
346
  } : {}
347
- }, j = (e) => [
348
- w.renderMetaToHtml(e),
349
- `<meta name="voltro-interactive" content="${O}" />`,
350
- ...k.hasDeferred ? [w.renderDeferredRegistryScript()] : [],
351
- w.renderRouterStateScript(k.stateInput)
347
+ }, oe = (e) => [
348
+ k.renderMetaToHtml(e),
349
+ `<meta name="voltro-interactive" content="${M}" />`,
350
+ ...N.hasDeferred ? [k.renderDeferredRegistryScript()] : [],
351
+ k.renderRouterStateScript(N.stateInput)
352
352
  ].filter((e) => e.length > 0).join("\n ");
353
- if (_ === "ssr" && O === "full" && e.buffered !== !0) {
354
- let e = D?.locale ?? E.cookies["voltro:locale"] ?? "en", t = S({ shell: s });
353
+ if (y === "ssr" && M === "full" && e.buffered !== !0) {
354
+ let e = j?.locale ?? A.cookies["voltro:locale"] ?? "en", t = C({ shell: s });
355
355
  return {
356
356
  renderMode: "ssr",
357
- stream: (n) => b({
357
+ stream: (n) => h({
358
358
  res: n,
359
359
  shell: t,
360
360
  htmlLang: e,
@@ -362,9 +362,9 @@ CREATE INDEX IF NOT EXISTS ${e}_servable_until_idx ON ${e} (servable_until);
362
362
  "content-type": "text/html; charset=utf-8",
363
363
  "x-voltro-rendered-by": "ssr"
364
364
  },
365
- headInjection: j,
366
- render: (e) => w.renderPageToStream({
367
- ...A,
365
+ headInjection: oe,
366
+ render: (e) => k.renderPageToStream({
367
+ ...ae,
368
368
  ...e
369
369
  }),
370
370
  onShellError: (e) => {
@@ -373,16 +373,16 @@ CREATE INDEX IF NOT EXISTS ${e}_servable_until_idx ON ${e} (servable_until);
373
373
  })
374
374
  };
375
375
  }
376
- let { html: ce, meta: P } = w.renderPageToHtml(A), F = j(P), le = D?.locale ?? E.cookies["voltro:locale"] ?? "en", I = s.replace("<div id=\"root\"></div>", `<div id="root">${ce}</div>`).replace("</head>", ` ${F}\n </head>`).replace(/<html(\s+lang="[^"]*")?/i, `<html lang="${le}"`);
377
- O === "none" && (I = Se(I));
378
- let ue = _ === "isr" ? T(h.revalidate) : null;
376
+ let { html: se, meta: I } = k.renderPageToHtml(ae), ce = oe(I), le = j?.locale ?? A.cookies["voltro:locale"] ?? "en", L = w(s.replace("<div id=\"root\"></div>", `<div id="root">${se}</div>`), ce).replace(/<html(\s+lang="[^"]*")?/i, `<html lang="${le}"`);
377
+ M === "none" && (L = we(L));
378
+ let ue = y === "isr" ? O(g.revalidate) : null;
379
379
  return {
380
- html: I,
381
- renderMode: _,
380
+ html: L,
381
+ renderMode: y,
382
382
  revalidateMs: ue
383
383
  };
384
- }, $ = (e) => e === "" ? "/" : e, De = async (e) => {
385
- let t = await import(B(e).href);
384
+ }, $ = (e) => e === "" ? "/" : e, Oe = async (e) => {
385
+ let t = await import(V(e).href);
386
386
  return {
387
387
  kind: "bundle",
388
388
  getPageMeta: () => t.pageMeta,
@@ -411,51 +411,56 @@ CREATE INDEX IF NOT EXISTS ${e}_servable_until_idx ON ${e} (servable_until);
411
411
  },
412
412
  async close() {}
413
413
  };
414
- }, Oe = async (e, t) => {
415
- let n = await y("vite", () => import("vite")), r = (await import("@vitejs/plugin-react")).default, i = (await import("@tailwindcss/vite")).default, a = await n.createServer({
416
- root: t,
414
+ }, ke = async (t, n) => {
415
+ let r = await y("vite", () => import("vite")), i = (await import("@vitejs/plugin-react")).default, a = (await import("@tailwindcss/vite")).default, o = await r.createServer({
416
+ root: n,
417
417
  envPrefix: "__VOLTRO_VITE_ENV_DISABLED__",
418
- plugins: [r(), i()],
419
- resolve: { dedupe: ["react", "react-dom"] },
420
- ssr: { noExternal: ["react-intl"] },
418
+ plugins: [i(), a()],
419
+ resolve: { dedupe: [
420
+ "react",
421
+ "react-dom",
422
+ "react-intl",
423
+ "@voltro/i18n"
424
+ ] },
425
+ ssr: { noExternal: ["react-intl", "@voltro/i18n"] },
421
426
  server: {
422
427
  middlewareMode: !0,
423
428
  hmr: !1
424
429
  },
425
430
  appType: "custom",
426
431
  logLevel: "warn"
427
- }), o = R(e, "src", "pages"), c = (e) => e === "" ? o : R(o, e), l = d({
428
- limit: s(),
432
+ }), s = R(t, "src", "pages"), c = (e) => e === "" ? s : R(s, e), l = u({
433
+ limit: e(),
429
434
  onColdStart: (e) => J.debug("ssr cold-compile start", { id: e }),
430
435
  onColdEnd: (e, { durationMs: t, failed: n }) => J.debug(`ssr cold-compile ${n ? "FAILED" : "end"} ${t}ms`, {
431
436
  id: e,
432
437
  ms: t,
433
438
  ...n ? { failed: !0 } : {}
434
439
  })
435
- }), u = (e) => l.load(e, async () => await a.ssrLoadModule(e));
440
+ }), d = (e) => l.load(e, async () => await o.ssrLoadModule(e));
436
441
  return {
437
442
  kind: "middleware",
438
443
  async getPage(e, t) {
439
- return u(R(o, t));
444
+ return d(R(s, t));
440
445
  },
441
446
  async getLayout(e) {
442
- return u(R(c(e), "layout.tsx"));
447
+ return d(R(c(e), "layout.tsx"));
443
448
  },
444
449
  async getError(e) {
445
- return u(R(c(e), "error.tsx"));
450
+ return d(R(c(e), "error.tsx"));
446
451
  },
447
452
  async getPending(e) {
448
- return u(R(c(e), "loading.tsx"));
453
+ return d(R(c(e), "loading.tsx"));
449
454
  },
450
455
  async getHelpers() {
451
- return await u("@voltro/web/ssr");
456
+ return await d("@voltro/web/ssr");
452
457
  },
453
458
  async close() {
454
- await a.close();
459
+ await o.close();
455
460
  }
456
461
  };
457
- }, ke = async (r) => {
458
- let s = de(), c = await A(r);
462
+ }, Ae = async (e) => {
463
+ let t = de(), c = await j(e);
459
464
  if (!c) return {
460
465
  ran: !1,
461
466
  exitCode: 0
@@ -464,89 +469,89 @@ CREATE INDEX IF NOT EXISTS ${e}_servable_until_idx ON ${e} (servable_until);
464
469
  ran: !0,
465
470
  exitCode: 1
466
471
  };
467
- let { resolved: d } = await ie({
472
+ let { resolved: u } = await g({
468
473
  rawEnv: c.env,
469
474
  appType: "web",
470
- root: r,
475
+ root: e,
471
476
  log: J,
472
477
  generateTypes: !1
473
- }), m = d.publicValues;
474
- s.mark("config");
475
- let g = i();
476
- u(g), J.info("booting voltro start", { app: c.name ?? "(unnamed)" });
477
- let y = (() => {
478
+ }), d = u.publicValues;
479
+ t.mark("config");
480
+ let h = ie();
481
+ m(h), J.info("booting voltro start", { app: c.name ?? "(unnamed)" });
482
+ let _ = (() => {
478
483
  if (process.env.VOLTRO_IS_DASHBOARD === "1" && process.env.VOLTRO_DASHBOARD_PORT) return Number(process.env.VOLTRO_DASHBOARD_PORT);
479
484
  if (process.env.PORT) {
480
485
  let e = Number(process.env.PORT);
481
486
  if (Number.isFinite(e) && e > 0) return e;
482
487
  }
483
488
  return c.port ?? 5173;
484
- })(), b = R(r, ".framework"), S = R(b, "dist"), ne = R(S, "index.html");
485
- if (!await Q(ne)) return J.error("no built dist found — run `voltro build` first", { distDir: S }), {
489
+ })(), v = R(e, ".framework"), y = R(v, "dist"), C = R(y, "index.html");
490
+ if (!await Z(C)) return J.error("no built dist found — run `voltro build` first", { distDir: y }), {
486
491
  ran: !0,
487
492
  exitCode: 1
488
493
  };
489
- let C = c.name ?? "unnamed", T = w("web", C, y), M = o(C);
490
- await p({
494
+ let w = c.name ?? "unnamed", T = ee("web", w, _), D = E(w);
495
+ await f({
491
496
  id: T,
492
- name: C,
497
+ name: w,
493
498
  kind: "web",
494
- url: `http://localhost:${y}`,
499
+ url: `http://localhost:${_}`,
495
500
  pid: process.pid,
496
501
  status: "booting",
497
- logFile: M.path
502
+ logFile: D.path
498
503
  }).catch(() => {});
499
- let se = R(S, "_voltro", "shell.html"), N = await Q(se) ? await H.readFile(se, "utf8") : await H.readFile(ne, "utf8"), L = await _(r, c), fe = O(L[0]), pe = L[0]?.name, z, B = null;
504
+ let O = R(y, "_voltro", "shell.html"), P = await Z(O) ? await U.readFile(O, "utf8") : await U.readFile(C, "utf8"), F = await b(e, c), fe = A(F[0]), pe = F[0]?.name, z, B = null;
500
505
  process.env.SSR_CACHE === "postgres" && process.env.PG_HOST ? (B = new (await (import("pg"))).default.Client({
501
506
  host: process.env.PG_HOST,
502
507
  port: Number(process.env.PG_PORT ?? 5432),
503
508
  user: process.env.PG_USER ?? "app",
504
509
  password: process.env.PG_PASSWORD ?? "app",
505
510
  database: process.env.PG_DATABASE ?? "app"
506
- }), await B.connect(), z = ye({ client: B }), J.info("isr cache backend: postgres", { table: "voltro_isr_cache" })) : (z = h(), J.info("isr cache backend: memory (per-process)", { hint: "set SSR_CACHE=postgres for persistent storage" })), await E(r, c, L, m);
507
- let { pages: V, dirs: U } = await v(R(r, "src", "pages")), W = we(V);
508
- s.mark("scan");
509
- let G = R(S, "server", "ssrEntry.js"), K = await Q(G);
510
- if (!K && process.env.NODE_ENV === "production") throw J.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}`);
511
- let q = K ? await De(G) : await Oe(r, b);
512
- J.info(`ssr loader: ${q.kind}`, {
513
- kind: q.kind,
514
- ...q.kind === "middleware" ? { hint: "no pre-built SSR bundle found; run `voltro build` to enable bundle mode" } : {}
515
- }), s.mark("provider");
516
- let ve = q.getPageMeta?.(), Y = /* @__PURE__ */ new Map(), X = 0;
511
+ }), await B.connect(), z = be({ client: B }), J.info("isr cache backend: postgres", { table: "voltro_isr_cache" })) : (z = k(), J.info("isr cache backend: memory (per-process)", { hint: "set SSR_CACHE=postgres for persistent storage" })), await re(e, c, F, d);
512
+ let { pages: V, dirs: H } = await x(R(e, "src", "pages")), W = Te(V);
513
+ t.mark("scan");
514
+ let G = R(y, "server", "ssrEntry.js"), _e = await Z(G);
515
+ if (!_e && process.env.NODE_ENV === "production") throw J.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}`);
516
+ let K = _e ? await Oe(G) : await ke(e, v);
517
+ J.info(`ssr loader: ${K.kind}`, {
518
+ kind: K.kind,
519
+ ...K.kind === "middleware" ? { hint: "no pre-built SSR bundle found; run `voltro build` to enable bundle mode" } : {}
520
+ }), t.mark("provider");
521
+ let ye = K.getPageMeta?.(), q = /* @__PURE__ */ new Map(), Y = 0;
517
522
  for (let e of V) {
518
- let t = ve?.[e.pattern];
523
+ let t = ye?.[e.pattern];
519
524
  if (t) {
520
- Y.set(e.pattern, t);
525
+ q.set(e.pattern, t);
521
526
  continue;
522
527
  }
523
528
  try {
524
- let t = await q.getPage(e.pattern, e.file);
525
- Y.set(e.pattern, a(t, e.file)), X++;
529
+ let t = await K.getPage(e.pattern, e.file);
530
+ q.set(e.pattern, l(t, e.file)), Y++;
526
531
  } catch (t) {
527
532
  J.warn("failed to load page metadata", { pattern: e.pattern }, t);
528
533
  }
529
534
  }
530
- J.info(`registered ${Y.size} route(s)`, {
531
- count: Y.size,
532
- fromManifest: Y.size - X,
533
- fromModules: X
534
- }), s.mark("routes");
535
- let Z = /* @__PURE__ */ new Set();
536
- for (let e of W) Y.get(e.pattern)?.renderMode === "spa" && oe(U, e.dirChain).some((e) => e.hasLayout) && Z.add(e.pattern);
537
- Z.size > 0 && J.info(`${Z.size} spa route(s) render an SSR layout shell`, { patterns: [...Z] });
535
+ J.info(`registered ${q.size} route(s)`, {
536
+ count: q.size,
537
+ fromManifest: q.size - Y,
538
+ fromModules: Y
539
+ }), t.mark("routes");
540
+ let X = /* @__PURE__ */ new Set();
541
+ for (let e of W) q.get(e.pattern)?.renderMode === "spa" && ne(H, e.dirChain).some((e) => e.hasLayout) && X.add(e.pattern);
542
+ X.size > 0 && J.info(`${X.size} spa route(s) render an SSR layout shell`, { patterns: [...X] });
538
543
  let Se = /* @__PURE__ */ new Map();
539
- for (let [e, t] of Y) t.cacheInvalidatesOn.length > 0 && Se.set(e, t.cacheInvalidatesOn);
540
- let Ce = /* @__PURE__ */ new Map();
541
- for (let e of W) Ce.set(e.pattern, e.regex);
542
- let $ = _e({
544
+ for (let [e, t] of q) t.cacheInvalidatesOn.length > 0 && Se.set(e, t.cacheInvalidatesOn);
545
+ let we = /* @__PURE__ */ new Map();
546
+ for (let e of W) we.set(e.pattern, e.regex);
547
+ let Q = ve({
543
548
  cache: z,
544
549
  tableSubscriptionsByPattern: Se,
545
- regexByPattern: Ce
550
+ regexByPattern: we
546
551
  });
547
- await $.start(), s.mark("cdc");
548
- let ke = j(), Ae = V.map((e) => {
549
- let t = Y.get(e.pattern);
552
+ await Q.start(), t.mark("cdc");
553
+ let $ = M(), Ae = V.map((e) => {
554
+ let t = q.get(e.pattern);
550
555
  return {
551
556
  pattern: e.pattern,
552
557
  file: e.file,
@@ -561,7 +566,7 @@ CREATE INDEX IF NOT EXISTS ${e}_servable_until_idx ON ${e} (servable_until);
561
566
  hasMeta: t?.hasMeta ?? !1,
562
567
  hasGetStaticPaths: t?.hasGetStaticPaths ?? !1
563
568
  };
564
- }), je = U.map((e) => ({
569
+ }), je = H.map((e) => ({
565
570
  dir: e.dir,
566
571
  hasLayout: e.hasLayout,
567
572
  hasError: e.hasError,
@@ -571,8 +576,8 @@ CREATE INDEX IF NOT EXISTS ${e}_servable_until_idx ON ${e} (servable_until);
571
576
  kind: "web",
572
577
  meta: {
573
578
  name: c.name ?? "(unnamed)",
574
- voltroVersion: be,
575
- port: y,
579
+ voltroVersion: xe,
580
+ port: _,
576
581
  mode: "start",
577
582
  apis: Object.entries(c.apis ?? {}).map(([e, t]) => {
578
583
  let n = {
@@ -602,10 +607,10 @@ CREATE INDEX IF NOT EXISTS ${e}_servable_until_idx ON ${e} (servable_until);
602
607
  };
603
608
  },
604
609
  metrics: () => he()
605
- }, Pe = async (t, n) => {
610
+ }, Pe = async (t, r) => {
606
611
  let i = t.split("?")[0] ?? "/";
607
612
  if (c.name === "voltroDashboard" && i === "/api/dashboard/registry") try {
608
- let e = await te();
613
+ let e = await n();
609
614
  return {
610
615
  status: 200,
611
616
  headers: { "content-type": "application/json; charset=utf-8" },
@@ -648,18 +653,18 @@ CREATE INDEX IF NOT EXISTS ${e}_servable_until_idx ON ${e} (servable_until);
648
653
  };
649
654
  }
650
655
  if (i === "/_voltro/inspect/logs") {
651
- let r = e(t, ee(), n);
656
+ let e = p(t, a(), r);
652
657
  return {
653
- status: r.status,
658
+ status: e.status,
654
659
  headers: {
655
- "content-type": r.contentType,
656
- ...P(n.origin)
660
+ "content-type": e.contentType,
661
+ ...I(r.origin)
657
662
  },
658
- body: r.body
663
+ body: e.body
659
664
  };
660
665
  }
661
666
  if (i !== "/_voltro/inspect/stream") {
662
- let e = ue(t, Ne, n);
667
+ let e = ue(t, Ne, r);
663
668
  if (e !== null) return {
664
669
  status: e.status,
665
670
  headers: {
@@ -669,36 +674,36 @@ CREATE INDEX IF NOT EXISTS ${e}_servable_until_idx ON ${e} (servable_until);
669
674
  body: e.body
670
675
  };
671
676
  }
672
- let a = Te(i, W), o = a ? Y.get(a.route.pattern)?.renderMode : void 0, s = o === "ssr" || o === "isr" || (a ? Z.has(a.route.pattern) : !1), l = i === "/" ? R(S, "index.html") : R(S, i.replace(/^\//, ""), "index.html");
673
- if (!s && await Q(l)) return {
677
+ let o = Ee(i, W), s = o ? q.get(o.route.pattern)?.renderMode : void 0, l = s === "ssr" || s === "isr" || (o ? X.has(o.route.pattern) : !1), u = i === "/" ? R(y, "index.html") : R(y, i.replace(/^\//, ""), "index.html");
678
+ if (!l && await Z(u)) return {
674
679
  status: 200,
675
680
  headers: { "content-type": "text/html; charset=utf-8" },
676
- body: await H.readFile(l)
681
+ body: await U.readFile(u)
677
682
  };
678
683
  if (/\.[a-z0-9]+$/i.test(i)) {
679
- let e = R(S, i.replace(/^\//, ""));
680
- if (await Q(e)) {
681
- let t = await H.readFile(e);
684
+ let e = R(y, i.replace(/^\//, ""));
685
+ if (await Z(e)) {
686
+ let t = await U.readFile(e);
682
687
  return {
683
688
  status: 200,
684
- headers: { "content-type": xe(e) },
689
+ headers: { "content-type": Ce(e) },
685
690
  body: t
686
691
  };
687
692
  }
688
693
  }
689
- let u = Te(i, W);
690
- if (!u) return {
694
+ let d = Ee(i, W);
695
+ if (!d) return {
691
696
  status: 404,
692
697
  headers: { "content-type": "text/plain" },
693
698
  body: "not found"
694
699
  };
695
- let d = Y.get(u.route.pattern), p = n["x-tenant"] ?? "anonymous", m = (await q.getHelpers()).i18n?.resolve(n.cookie, n["accept-language"])?.locale, h = ae(i, {
696
- ...d?.tenantAware ? { tenant: p } : {},
700
+ let ee = q.get(d.route.pattern), f = r["x-tenant"] ?? "anonymous", m = (await K.getHelpers()).i18n?.resolve(r.cookie, r["accept-language"])?.locale, g = N(i, {
701
+ ...ee?.tenantAware ? { tenant: f } : {},
697
702
  ...m ? { locale: m } : {}
698
- }), _ = z.get(h), v = Date.now();
699
- if (_ && k(_, v)) return g.emit("cache", {
703
+ }), _ = z.get(g), v = Date.now();
704
+ if (_ && te(_, v)) return h.emit("cache", {
700
705
  kind: "HIT",
701
- key: h,
706
+ key: g,
702
707
  ageMs: v - _.renderedAt
703
708
  }), {
704
709
  status: 200,
@@ -706,40 +711,40 @@ CREATE INDEX IF NOT EXISTS ${e}_servable_until_idx ON ${e} (servable_until);
706
711
  "content-type": "text/html; charset=utf-8",
707
712
  "x-voltro-rendered-by": "isr",
708
713
  "x-voltro-cache": "HIT",
709
- "x-voltro-cache-key": h,
714
+ "x-voltro-cache-key": g,
710
715
  "x-voltro-cache-age-ms": String(v - _.renderedAt)
711
716
  },
712
717
  body: _.html
713
718
  };
714
- if (_ && re(_, v)) return g.emit("cache", {
719
+ if (_ && S(_, v)) return h.emit("cache", {
715
720
  kind: "STALE",
716
- key: h,
721
+ key: g,
717
722
  ageMs: v - _.renderedAt
718
723
  }), (async () => {
719
724
  try {
720
- let e = await Ee({
721
- provider: q,
722
- root: r,
723
- route: u.route,
724
- params: u.params,
725
+ let n = await De({
726
+ provider: K,
727
+ root: e,
728
+ route: d.route,
729
+ params: d.params,
725
730
  pathname: i,
726
- dirs: U,
727
- shellTemplate: N,
728
- requestHeaders: n,
731
+ dirs: H,
732
+ shellTemplate: P,
733
+ requestHeaders: r,
729
734
  apiOrigin: fe,
730
735
  apiName: pe,
731
736
  requestUrl: t,
732
737
  buffered: !0
733
738
  });
734
- if (e && "html" in e && e.renderMode === "isr" && e.revalidateMs !== null) {
735
- let t = Y.get(u.route.pattern)?.staleWhileRevalidateMs ?? 0, n = Date.now();
736
- z.set(h, {
737
- html: e.html,
738
- renderedAt: n,
739
- expiresAt: n + e.revalidateMs,
740
- servableUntil: n + e.revalidateMs + t,
741
- revalidateMs: e.revalidateMs,
742
- staleWhileRevalidateMs: t
739
+ if (n && "html" in n && n.renderMode === "isr" && n.revalidateMs !== null) {
740
+ let e = q.get(d.route.pattern)?.staleWhileRevalidateMs ?? 0, t = Date.now();
741
+ z.set(g, {
742
+ html: n.html,
743
+ renderedAt: t,
744
+ expiresAt: t + n.revalidateMs,
745
+ servableUntil: t + n.revalidateMs + e,
746
+ revalidateMs: n.revalidateMs,
747
+ staleWhileRevalidateMs: e
743
748
  });
744
749
  }
745
750
  } catch (e) {
@@ -751,43 +756,43 @@ CREATE INDEX IF NOT EXISTS ${e}_servable_until_idx ON ${e} (servable_until);
751
756
  "content-type": "text/html; charset=utf-8",
752
757
  "x-voltro-rendered-by": "isr",
753
758
  "x-voltro-cache": "STALE",
754
- "x-voltro-cache-key": h,
759
+ "x-voltro-cache-key": g,
755
760
  "x-voltro-cache-age-ms": String(v - _.renderedAt)
756
761
  },
757
762
  body: _.html
758
763
  };
759
764
  try {
760
- let e = await Ee({
761
- provider: q,
762
- root: r,
763
- route: u.route,
764
- params: u.params,
765
+ let n = await De({
766
+ provider: K,
767
+ root: e,
768
+ route: d.route,
769
+ params: d.params,
765
770
  pathname: i,
766
- dirs: U,
767
- shellTemplate: N,
768
- requestHeaders: n,
771
+ dirs: H,
772
+ shellTemplate: P,
773
+ requestHeaders: r,
769
774
  apiOrigin: fe,
770
775
  apiName: pe,
771
776
  requestUrl: t
772
777
  });
773
- if (!e) return {
778
+ if (!n) return {
774
779
  status: 200,
775
780
  headers: {
776
781
  "content-type": "text/html; charset=utf-8",
777
782
  "x-voltro-rendered-by": "spa-fallback"
778
783
  },
779
- body: N
784
+ body: P
780
785
  };
781
- if ("stream" in e) return {
786
+ if ("stream" in n) return {
782
787
  status: 200,
783
- headers: { "x-voltro-rendered-by": e.renderMode },
788
+ headers: { "x-voltro-rendered-by": n.renderMode },
784
789
  body: "",
785
- stream: e.stream
790
+ stream: n.stream
786
791
  };
787
- if ("control" in e) return e.control === "redirect" ? {
788
- status: e.status,
792
+ if ("control" in n) return n.control === "redirect" ? {
793
+ status: n.status,
789
794
  headers: {
790
- location: e.location,
795
+ location: n.location,
791
796
  "x-voltro-rendered-by": "loader-redirect"
792
797
  },
793
798
  body: ""
@@ -801,34 +806,34 @@ CREATE INDEX IF NOT EXISTS ${e}_servable_until_idx ON ${e} (servable_until);
801
806
  };
802
807
  let a = {
803
808
  "content-type": "text/html; charset=utf-8",
804
- "x-voltro-rendered-by": e.renderMode
809
+ "x-voltro-rendered-by": n.renderMode
805
810
  };
806
- if (e.renderMode === "isr" && e.revalidateMs !== null) {
807
- let t = Date.now(), n = Y.get(u.route.pattern)?.staleWhileRevalidateMs ?? 0;
808
- z.set(h, {
809
- html: e.html,
810
- renderedAt: t,
811
- expiresAt: t + e.revalidateMs,
812
- servableUntil: t + e.revalidateMs + n,
813
- revalidateMs: e.revalidateMs,
814
- staleWhileRevalidateMs: n
815
- }), a["x-voltro-cache"] = "MISS", a["x-voltro-cache-key"] = h, a["x-voltro-cache-revalidate-ms"] = String(e.revalidateMs), n > 0 && (a["x-voltro-cache-swr-ms"] = String(n)), g.emit("cache", {
811
+ if (n.renderMode === "isr" && n.revalidateMs !== null) {
812
+ let e = Date.now(), t = q.get(d.route.pattern)?.staleWhileRevalidateMs ?? 0;
813
+ z.set(g, {
814
+ html: n.html,
815
+ renderedAt: e,
816
+ expiresAt: e + n.revalidateMs,
817
+ servableUntil: e + n.revalidateMs + t,
818
+ revalidateMs: n.revalidateMs,
819
+ staleWhileRevalidateMs: t
820
+ }), 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)), h.emit("cache", {
816
821
  kind: "MISS",
817
- key: h,
818
- revalidateMs: e.revalidateMs,
819
- swrMs: n
822
+ key: g,
823
+ revalidateMs: n.revalidateMs,
824
+ swrMs: t
820
825
  });
821
- } else e.renderMode === "isr" && (a["x-voltro-cache"] = "BYPASS", g.emit("cache", {
826
+ } else n.renderMode === "isr" && (a["x-voltro-cache"] = "BYPASS", h.emit("cache", {
822
827
  kind: "BYPASS",
823
- key: h
828
+ key: g
824
829
  }));
825
830
  return {
826
831
  status: 200,
827
832
  headers: a,
828
- body: e.html
833
+ body: n.html
829
834
  };
830
835
  } catch (e) {
831
- return J.error("render error", { url: i }, e), f(e) ? {
836
+ return J.error("render error", { url: i }, e), ae(e) ? {
832
837
  status: 500,
833
838
  headers: {
834
839
  "content-type": "text/plain; charset=utf-8",
@@ -842,17 +847,17 @@ CREATE INDEX IF NOT EXISTS ${e}_servable_until_idx ON ${e} (servable_until);
842
847
  };
843
848
  }
844
849
  }, Fe = !1, Ie = ge(async (e, t) => {
845
- let r = e.url ?? "/", i = Date.now(), a = {};
846
- for (let [t, n] of Object.entries(e.headers)) n !== void 0 && (a[t.toLowerCase()] = Array.isArray(n) ? n.join(", ") : n);
847
- let o = r.split("?")[0] ?? "/", s = (e.method ?? "GET").toUpperCase();
848
- if (o === "/internal/liveness") {
850
+ let n = e.url ?? "/", r = Date.now(), i = {};
851
+ for (let [t, n] of Object.entries(e.headers)) n !== void 0 && (i[t.toLowerCase()] = Array.isArray(n) ? n.join(", ") : n);
852
+ let a = n.split("?")[0] ?? "/", l = (e.method ?? "GET").toUpperCase();
853
+ if (a === "/internal/liveness") {
849
854
  t.writeHead(200, {
850
855
  "content-type": "text/plain",
851
856
  "cache-control": "no-store"
852
857
  }), t.end("ok");
853
858
  return;
854
859
  }
855
- if (o === "/internal/readiness") {
860
+ if (a === "/internal/readiness") {
856
861
  let e = Fe ? 200 : 503;
857
862
  t.writeHead(e, {
858
863
  "content-type": "text/plain",
@@ -860,71 +865,71 @@ CREATE INDEX IF NOT EXISTS ${e}_servable_until_idx ON ${e} (servable_until);
860
865
  }), t.end(Fe ? "ready" : "not-ready");
861
866
  return;
862
867
  }
863
- if (s === "OPTIONS" && o.startsWith("/_voltro/inspect")) {
864
- let e = P(a.origin);
868
+ if (l === "OPTIONS" && a.startsWith("/_voltro/inspect")) {
869
+ let e = I(i.origin);
865
870
  t.writeHead(204, e), t.end();
866
871
  return;
867
872
  }
868
- if (c.name === "voltroDashboard" && o === "/api/dashboard/proxy") {
869
- let n = new URL(r, "http://x").searchParams.get("target");
870
- if (!n) {
873
+ if (c.name === "voltroDashboard" && a === "/api/dashboard/proxy") {
874
+ let r = new URL(n, "http://x").searchParams.get("target");
875
+ if (!r) {
871
876
  t.writeHead(400, { "content-type": "text/plain" }), t.end("missing ?target=");
872
877
  return;
873
878
  }
874
- if (!F(n)) {
879
+ if (!ce(r)) {
875
880
  t.writeHead(400, { "content-type": "text/plain" }), t.end("target not allowed: must be loopback or an origin configured in VOLTRO_DASHBOARD_APPS");
876
881
  return;
877
882
  }
878
883
  try {
879
- let r = { accept: a.accept ?? "application/json" }, i = a.authorization;
880
- i ? r.authorization = Array.isArray(i) ? i[0] : i : ce(n) && process.env.VOLTRO_INSPECT_TOKEN && (r.authorization = `Bearer ${process.env.VOLTRO_INSPECT_TOKEN}`);
884
+ let n = { accept: i.accept ?? "application/json" }, a = i.authorization;
885
+ a ? n.authorization = Array.isArray(a) ? a[0] : a : se(r) && process.env.VOLTRO_INSPECT_TOKEN && (n.authorization = `Bearer ${process.env.VOLTRO_INSPECT_TOKEN}`);
881
886
  let o;
882
- if (s && s !== "GET" && s !== "HEAD") {
887
+ if (l && l !== "GET" && l !== "HEAD") {
883
888
  let t = [];
884
889
  for await (let n of e) t.push(n);
885
890
  o = Buffer.concat(t);
886
- let n = a["content-type"];
887
- n && (r["content-type"] = Array.isArray(n) ? n[0] : n);
891
+ let r = i["content-type"];
892
+ r && (n["content-type"] = Array.isArray(r) ? r[0] : r);
888
893
  }
889
- let c = await fetch(n, {
894
+ let s = await fetch(r, {
890
895
  redirect: "manual",
891
- method: s,
892
- headers: r,
896
+ method: l,
897
+ headers: n,
893
898
  ...o ? { body: new Uint8Array(o.buffer, o.byteOffset, o.byteLength) } : {}
894
- }), l = Buffer.from(await c.arrayBuffer());
895
- t.writeHead(c.status, {
896
- "content-type": c.headers.get("content-type") ?? "application/octet-stream",
897
- "content-length": String(l.length)
898
- }), t.end(l);
899
+ }), c = Buffer.from(await s.arrayBuffer());
900
+ t.writeHead(s.status, {
901
+ "content-type": s.headers.get("content-type") ?? "application/octet-stream",
902
+ "content-length": String(c.length)
903
+ }), t.end(c);
899
904
  } catch (e) {
900
905
  t.writeHead(502, { "content-type": "text/plain" }), t.end(`proxy error: ${e.message}`);
901
906
  }
902
907
  return;
903
908
  }
904
- if (c.name === "voltroDashboard" && o === "/api/dashboard/proxy/stream") {
905
- let n = new URL(r, "http://x").searchParams.get("target");
906
- if (!n) {
909
+ if (c.name === "voltroDashboard" && a === "/api/dashboard/proxy/stream") {
910
+ let r = new URL(n, "http://x").searchParams.get("target");
911
+ if (!r) {
907
912
  t.writeHead(400, { "content-type": "text/plain" }), t.end("missing ?target=");
908
913
  return;
909
914
  }
910
- if (!F(n)) {
915
+ if (!ce(r)) {
911
916
  t.writeHead(400, { "content-type": "text/plain" }), t.end("target not allowed: must be loopback or an origin configured in VOLTRO_DASHBOARD_APPS");
912
917
  return;
913
918
  }
914
- let i = new AbortController();
915
- e.on("close", () => i.abort()), t.on("close", () => i.abort());
919
+ let a = new AbortController();
920
+ e.on("close", () => a.abort()), t.on("close", () => a.abort());
916
921
  try {
917
- let e = a.authorization ?? (ce(n) && process.env.VOLTRO_INSPECT_TOKEN ? `Bearer ${process.env.VOLTRO_INSPECT_TOKEN}` : void 0), r = await fetch(n, {
922
+ let e = i.authorization ?? (se(r) && process.env.VOLTRO_INSPECT_TOKEN ? `Bearer ${process.env.VOLTRO_INSPECT_TOKEN}` : void 0), n = await fetch(r, {
918
923
  redirect: "manual",
919
924
  method: "GET",
920
925
  headers: {
921
926
  accept: "text/event-stream",
922
927
  ...e ? { authorization: Array.isArray(e) ? e[0] : e } : {}
923
928
  },
924
- signal: i.signal
929
+ signal: a.signal
925
930
  });
926
- if (!r.ok || !r.body) {
927
- t.writeHead(r.status, { "content-type": "text/plain" }), t.end(`upstream ${r.status}`);
931
+ if (!n.ok || !n.body) {
932
+ t.writeHead(n.status, { "content-type": "text/plain" }), t.end(`upstream ${n.status}`);
928
933
  return;
929
934
  }
930
935
  t.writeHead(200, {
@@ -933,7 +938,7 @@ CREATE INDEX IF NOT EXISTS ${e}_servable_until_idx ON ${e} (servable_until);
933
938
  connection: "keep-alive",
934
939
  "x-accel-buffering": "no"
935
940
  }), t.flushHeaders();
936
- let o = r.body.getReader();
941
+ let o = n.body.getReader();
937
942
  try {
938
943
  for (;;) {
939
944
  let { done: e, value: n } = await o.read();
@@ -948,23 +953,23 @@ CREATE INDEX IF NOT EXISTS ${e}_servable_until_idx ON ${e} (servable_until);
948
953
  }
949
954
  return;
950
955
  }
951
- if (o === "/_voltro/inspect/stream") {
952
- let r = P(a.origin);
953
- if (I()) {
956
+ if (a === "/_voltro/inspect/stream") {
957
+ let n = I(i.origin);
958
+ if (L()) {
954
959
  t.writeHead(503, {
955
960
  "content-type": "application/json",
956
- ...r
961
+ ...n
957
962
  }), t.end(JSON.stringify({ error: "inspect disabled (VOLTRO_INSPECT=off)" }));
958
963
  return;
959
964
  }
960
- let i = le(a, "GET");
961
- if (!i.ok) {
965
+ let r = le(i, "GET");
966
+ if (!r.ok) {
962
967
  t.writeHead(401, {
963
968
  "content-type": "application/json",
964
- ...r
969
+ ...n
965
970
  }), t.end(JSON.stringify({
966
971
  error: "unauthorized",
967
- reason: i.reason
972
+ reason: r.reason
968
973
  }));
969
974
  return;
970
975
  }
@@ -973,32 +978,32 @@ CREATE INDEX IF NOT EXISTS ${e}_servable_until_idx ON ${e} (servable_until);
973
978
  "cache-control": "no-cache, no-transform",
974
979
  connection: "keep-alive",
975
980
  "x-accel-buffering": "no",
976
- ...r
981
+ ...n
977
982
  }), t.flushHeaders(), t.write("retry: 5000\n\n");
978
- for (let e of g.buffered()) t.write(n(e));
979
- let o = g.subscribe((e) => {
980
- t.write(n(e));
981
- }), s = setInterval(() => {
982
- t.write(D());
983
- }, 15e3), c = () => {
984
- clearInterval(s), o();
983
+ for (let e of h.buffered()) t.write(s(e));
984
+ let a = h.subscribe((e) => {
985
+ t.write(s(e));
986
+ }), c = setInterval(() => {
987
+ t.write(o());
988
+ }, 15e3), l = () => {
989
+ clearInterval(c), a();
985
990
  };
986
- e.on("close", c), t.on("close", c);
991
+ e.on("close", l), t.on("close", l);
987
992
  return;
988
993
  }
989
994
  try {
990
- let e = await Pe(r, a);
991
- if (e.stream ? e.stream(t) : (t.writeHead(e.status, e.headers), t.end(e.body)), !o.startsWith("/_voltro/inspect")) {
992
- let t = Date.now() - i;
993
- g.emit("request", {
994
- url: o,
995
+ let e = await Pe(n, i);
996
+ if (e.stream ? e.stream(t) : (t.writeHead(e.status, e.headers), t.end(e.body)), !a.startsWith("/_voltro/inspect")) {
997
+ let t = Date.now() - r;
998
+ h.emit("request", {
999
+ url: a,
995
1000
  status: e.status,
996
1001
  durationMs: t,
997
1002
  renderedBy: e.headers["x-voltro-rendered-by"],
998
1003
  cache: e.headers["x-voltro-cache"]
999
1004
  });
1000
- let n = Te(o, W)?.route.pattern ?? (e.status === 404 ? "<unmatched>" : "<asset>");
1001
- ke.record({
1005
+ let n = Ee(a, W)?.route.pattern ?? (e.status === 404 ? "<unmatched>" : "<asset>");
1006
+ $.record({
1002
1007
  kind: "request",
1003
1008
  tag: n,
1004
1009
  durationMs: t,
@@ -1009,34 +1014,34 @@ CREATE INDEX IF NOT EXISTS ${e}_servable_until_idx ON ${e} (servable_until);
1009
1014
  t.writeHead(500, { "content-type": "text/plain" }), t.end(`internal error: ${e.message}`);
1010
1015
  }
1011
1016
  });
1012
- await new Promise((e) => Ie.listen(y, "::", e)), Fe = !0, s.mark("ready"), J.info(`listening on http://localhost:${y}`, {
1013
- port: y,
1014
- distDir: S
1017
+ await new Promise((e) => Ie.listen(_, "::", e)), Fe = !0, t.mark("ready"), J.info(`listening on http://localhost:${_}`, {
1018
+ port: _,
1019
+ distDir: y
1015
1020
  }), J.debug("dynamic + ssr/isr routes resolve via SSR loader");
1016
1021
  try {
1017
- await p({
1022
+ await f({
1018
1023
  id: T,
1019
- name: C,
1024
+ name: w,
1020
1025
  kind: "web",
1021
- url: `http://localhost:${y}`,
1026
+ url: `http://localhost:${_}`,
1022
1027
  pid: process.pid,
1023
1028
  status: "live",
1024
- logFile: M.path
1029
+ logFile: D.path
1025
1030
  });
1026
- let e = t(r);
1027
- if (e) {
1028
- let t = await l({ dashboardAppPath: e });
1029
- 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 });
1031
+ let t = r(e);
1032
+ if (t) {
1033
+ let e = await i({ dashboardAppPath: t });
1034
+ e.status === "launched" ? J.info(`dashboard launched at http://localhost:${e.port}`, { port: e.port }) : e.status === "already-running" && J.debug(`dashboard already running on :${e.port}`, { port: e.port });
1030
1035
  }
1031
1036
  setInterval(() => {
1032
- p({
1037
+ f({
1033
1038
  id: T,
1034
- name: C,
1039
+ name: w,
1035
1040
  kind: "web",
1036
- url: `http://localhost:${y}`,
1041
+ url: `http://localhost:${_}`,
1037
1042
  pid: process.pid,
1038
1043
  status: "live",
1039
- logFile: M.path
1044
+ logFile: D.path
1040
1045
  }).catch(() => {});
1041
1046
  }, 1e4).unref();
1042
1047
  } catch (e) {
@@ -1045,20 +1050,20 @@ CREATE INDEX IF NOT EXISTS ${e}_servable_until_idx ON ${e} (servable_until);
1045
1050
  me({
1046
1051
  app: c.name ?? "unnamed",
1047
1052
  kind: "web",
1048
- url: `http://localhost:${y}`,
1049
- bootMs: s.total()
1053
+ url: `http://localhost:${_}`,
1054
+ bootMs: t.total()
1050
1055
  });
1051
- let Le = s.phaseBreakdown();
1052
- J.info(`start: ready in ${s.total()}ms`, {
1053
- bootMs: s.total(),
1056
+ let Le = t.phaseBreakdown();
1057
+ J.info(`start: ready in ${t.total()}ms`, {
1058
+ bootMs: t.total(),
1054
1059
  ...Le ? { phases: Le } : {}
1055
1060
  });
1056
1061
  let Re = !1, ze = (e) => async () => {
1057
1062
  if (!Re) {
1058
- if (Re = !0, J.info(`received ${e}, shutting down`, { signal: e }), Ie.close(), await $.stop(), B) try {
1063
+ if (Re = !0, J.info(`received ${e}, shutting down`, { signal: e }), Ie.close(), await Q.stop(), B) try {
1059
1064
  await B.end();
1060
1065
  } catch {}
1061
- await q.close(), await x(T), await M.dispose(), process.exit(0);
1066
+ await K.close(), await oe(T), await D.dispose(), process.exit(0);
1062
1067
  }
1063
1068
  };
1064
1069
  process.on("SIGINT", ze("SIGINT")), process.on("SIGTERM", ze("SIGTERM"));
@@ -1070,10 +1075,10 @@ CREATE INDEX IF NOT EXISTS ${e}_servable_until_idx ON ${e} (servable_until);
1070
1075
  e.unref();
1071
1076
  }
1072
1077
  return new Promise(() => {});
1073
- }, Ae = async (e) => {
1078
+ }, je = async (e) => {
1074
1079
  process.env.NODE_ENV || (process.env.NODE_ENV = "production");
1075
- let t = await ke(pe(e.find((e) => !e.startsWith("-")) ?? process.cwd()));
1080
+ let t = await Ae(z(e.find((e) => !e.startsWith("-")) ?? process.cwd()));
1076
1081
  return t.ran ? t.exitCode : (J.error("no web app found at this path"), 1);
1077
1082
  };
1078
1083
  //#endregion
1079
- export { Ae as t };
1084
+ export { je as t };