@voltro/cli 0.52.0 → 0.53.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 (195) hide show
  1. package/CHANGELOG.md +229 -0
  2. package/THIRD-PARTY-NOTICES.md +8311 -3318
  3. package/dist/{apiBuild-CSFI8QGq.js → apiBuild-CaPfoWku.js} +11 -5
  4. package/dist/apiBuild-DHtLXYx9.js +2 -0
  5. package/dist/bin.js +1 -1
  6. package/dist/build-D-OnvNMf.js +843 -0
  7. package/dist/{checkCommand-COmqc2cB.js → checkCommand-C5elt0tW.js} +6 -6
  8. package/dist/{checkCommand-2SbqzukH.js → checkCommand-D2ZduVlh.js} +1 -1
  9. package/dist/codegen-BWpt3VgF.js +2 -0
  10. package/dist/{codegen-VF479Cnb.js → codegen-FEk8AZHb.js} +2 -2
  11. package/dist/{codegenCommand-DCdG2JN-.js → codegenCommand-BOiWQ5hz.js} +4 -4
  12. package/dist/{codemodRunner-r7J9lIa7.js → codemodRunner-BjtB2lq6.js} +109 -11
  13. package/dist/{commands-Cc_nV8WI.js → commands-DyxAmhP0.js} +30 -30
  14. package/dist/{dashboardCommand-C-gKvwqh.js → dashboardCommand-BdKTyT13.js} +5 -5
  15. package/dist/{dataCommand-BgpBHnlB.js → dataCommand-Bab9X7s8.js} +2 -2
  16. package/dist/{dbCommand-sHedr-NJ.js → dbCommand-06O2finM.js} +277 -236
  17. package/dist/dbCommand-B1EXBC6f.js +2 -0
  18. package/dist/{dev-CRHoCEiy.js → dev-C6LGF4iY.js} +3006 -2426
  19. package/dist/{dev--A3nsxA3.js → dev-GjJWAYo2.js} +1 -1
  20. package/dist/doctorCommand-B0hX0tdz.js +2 -0
  21. package/dist/{doctorCommand-DtfJ3FA6.js → doctorCommand-etMkflRc.js} +101 -69
  22. package/dist/{dormancyCommand-Drn7o0No.js → dormancyCommand-UwZ1AZzB.js} +1 -1
  23. package/dist/{embeddingsCommand-Z-jO1fWN.js → embeddingsCommand-C70zWHwo.js} +1 -1
  24. package/dist/{envCommand-D4gCrrTZ.js → envCommand-dSyKvRkM.js} +18 -18
  25. package/dist/{evolveCommand-CMROeKeA.js → evolveCommand-CG0_ebO5.js} +2 -2
  26. package/dist/fileConventions-DASGEmj-.js +35 -0
  27. package/dist/{fileTaxonomy-DvDUV9wq.js → fileTaxonomy-B7uxipWS.js} +55 -55
  28. package/dist/fontPipeline-LxIHa1vo.js +2 -0
  29. package/dist/fontPipeline-Tsh8kZfA.js +152 -0
  30. package/dist/frameworkTableAssembly-C_7Z-rMs.js +2 -0
  31. package/dist/{frameworkTableAssembly-w-XnLa3q.js → frameworkTableAssembly-DKx3ba3S.js} +5 -5
  32. package/dist/imagePipeline-B_GVJgm6.js +2 -0
  33. package/dist/imagePipeline-CBZmjT4i.js +127 -0
  34. package/dist/index.js +1 -1
  35. package/dist/{infoCommand-DXM868o_.js → infoCommand-_53iOc_j.js} +1 -1
  36. package/dist/{inspect-CtL_xTbu.js → inspect-Bd8-9wsi.js} +1 -1
  37. package/dist/inspect-CuoDInfZ.js +2 -0
  38. package/dist/{inspectGateHint-BjnFubmH.js → inspectGateHint-4LxkNtrz.js} +1 -1
  39. package/dist/manifestBuild-C4-J1-m_.js +2 -0
  40. package/dist/{manifestBuild-CuU1VrSm.js → manifestBuild-Cqgsx2bM.js} +1 -1
  41. package/dist/{metaCommands-C6RFmF1r.js → metaCommands-Cn2oboG4.js} +8 -2
  42. package/dist/{migrate-D0F-eTlK.js → migrate-Cko9rswM.js} +2 -2
  43. package/dist/{pageConvention-CzUiSbtU.js → pageConvention-C938S8oC.js} +1 -1
  44. package/dist/{privacyCommand-DGdopOI6.js → privacyCommand-DWTQMC6R.js} +2 -2
  45. package/dist/{probeCommand-C9gazU0H.js → probeCommand-DkGGLknv.js} +83 -24
  46. package/dist/{renderModeScan-CcH2X1_D.js → renderModeScan-CUbOeOAg.js} +3 -1
  47. package/dist/{renderProfile-Ck32Fzxr.js → renderProfile-CskIgAfn.js} +2 -2
  48. package/dist/{runtimeTrace-BPQyCmC5.js → runtimeTrace-c0APJz7E.js} +1 -1
  49. package/dist/{sdkgen-Se88ifTd.js → sdkgen-BiQCgIEr.js} +1 -1
  50. package/dist/{serveCommand-DkP3OT0W.js → serveCommand-CueKQgzl.js} +869 -805
  51. package/dist/serveCommand-DsnrVN3U.js +2 -0
  52. package/dist/serveEntry.js +1 -1
  53. package/dist/start-BJzZLbt8.js +3 -0
  54. package/dist/start-ekPan8BT.js +1510 -0
  55. package/dist/startEntry.js +1 -1
  56. package/dist/{staticCommand-BwNEDlSU.js → staticCommand-xlSL-IWk.js} +1 -1
  57. package/dist/{test-f3amja6a.js → test-BWPQcRoB.js} +1 -1
  58. package/dist/updateCommand-Bqql_rsQ.js +2 -0
  59. package/dist/{updateCommand-BMk2e4ky.js → updateCommand-C_8I8Rzo.js} +139 -115
  60. package/dist/webDev-C7jWJ5dX.js +2 -0
  61. package/dist/{webDev-BgWL9gKV.js → webDev-oczpugbx.js} +1455 -922
  62. package/dist/{webhooksCommand-CoIO3jbj.js → webhooksCommand-4SVPDjKg.js} +1 -1
  63. package/package.json +60 -19
  64. package/templates/AGENTS.md +5 -3
  65. package/templates/agent-docs/_index.md +5 -3
  66. package/templates/agent-docs/_manifest.json +20 -4
  67. package/templates/agent-docs/ai.md +2 -2
  68. package/templates/agent-docs/authentication.md +1 -1
  69. package/templates/agent-docs/cli.md +2 -2
  70. package/templates/agent-docs/configuration.md +17 -0
  71. package/templates/agent-docs/data.md +470 -26
  72. package/templates/agent-docs/database/advancedqueries.md +7 -7
  73. package/templates/agent-docs/database/columntypes.md +2 -2
  74. package/templates/agent-docs/database/querying.md +1 -1
  75. package/templates/agent-docs/database/schema.md +1 -1
  76. package/templates/agent-docs/database/seedsdialects.md +1 -1
  77. package/templates/agent-docs/database/transactions.md +3 -3
  78. package/templates/agent-docs/deployment.md +8 -0
  79. package/templates/agent-docs/internationalization.md +2 -2
  80. package/templates/agent-docs/introduction.md +7 -1
  81. package/templates/agent-docs/local-first-mobile.md +102 -4
  82. package/templates/agent-docs/observability.md +2 -0
  83. package/templates/agent-docs/plugins/auth.md +1 -1
  84. package/templates/agent-docs/plugins/comments.md +142 -0
  85. package/templates/agent-docs/plugins/notifications.md +47 -4
  86. package/templates/agent-docs/plugins/presence.md +16 -3
  87. package/templates/agent-docs/plugins/prometheus.md +1 -1
  88. package/templates/agent-docs/plugins/queue.md +129 -0
  89. package/templates/agent-docs/plugins.md +11 -7
  90. package/templates/agent-docs/reference.md +16 -4
  91. package/templates/agent-docs/routing.md +527 -3
  92. package/templates/agent-docs/schema-driven-ui.md +214 -3
  93. package/templates/agent-docs/security.md +3 -3
  94. package/templates/agent-docs/whats-new.md +160 -66
  95. package/templates/apps/api-ai/package.json +6 -6
  96. package/templates/apps/api-auth/package.json +8 -8
  97. package/templates/apps/api-backend/package.json +7 -7
  98. package/templates/apps/api-backend-deactivation/package.json +7 -7
  99. package/templates/apps/api-backend-mail/package.json +8 -8
  100. package/templates/apps/api-backend-mariadb/package.json +9 -9
  101. package/templates/apps/api-backend-sqlite/package.json +8 -8
  102. package/templates/apps/api-backend-storage/package.json +8 -8
  103. package/templates/apps/api-cms/package.json +9 -9
  104. package/templates/apps/api-collab/package.json +8 -8
  105. package/templates/apps/api-data-advanced/package.json +8 -8
  106. package/templates/apps/api-durable/package.json +8 -8
  107. package/templates/apps/api-feature-flags/package.json +9 -9
  108. package/templates/apps/api-governance/package.json +8 -8
  109. package/templates/apps/api-kv/package.json +8 -8
  110. package/templates/apps/api-moderation/package.json +8 -8
  111. package/templates/apps/api-observability/package.json +8 -8
  112. package/templates/apps/api-ratelimit/package.json +8 -8
  113. package/templates/apps/api-rbac/package.json +8 -8
  114. package/templates/apps/api-rest/package.json +7 -7
  115. package/templates/apps/api-row-history/package.json +8 -8
  116. package/templates/apps/api-saas/package.json +10 -10
  117. package/templates/apps/api-saas-starter/package.json +10 -10
  118. package/templates/apps/api-search/package.json +8 -8
  119. package/templates/apps/api-status/package.json +8 -8
  120. package/templates/apps/api-webhooks/package.json +9 -9
  121. package/templates/apps/changelog/app.config.ts +26 -2
  122. package/templates/apps/changelog/content/releases/{0.1.0.mdx → v0-1-0.mdx} +0 -1
  123. package/templates/apps/changelog/content/releases/{0.2.0.mdx → v0-2-0.mdx} +0 -1
  124. package/templates/apps/changelog/package.json +8 -8
  125. package/templates/apps/changelog/src/collections/releases.collection.ts +48 -0
  126. package/templates/apps/changelog/src/globals.d.ts +1 -1
  127. package/templates/apps/changelog/src/locales/de.ts +1 -1
  128. package/templates/apps/changelog/src/locales/en.ts +1 -1
  129. package/templates/apps/changelog/src/pages/[locale]/[slug]/page.tsx +7 -4
  130. package/templates/apps/changelog/src/pages/[locale]/mirrors.test.tsx +13 -41
  131. package/templates/apps/changelog/src/pages/[slug]/page.test.tsx +26 -51
  132. package/templates/apps/changelog/src/pages/[slug]/page.tsx +21 -19
  133. package/templates/apps/changelog/src/pages/page.test.tsx +14 -37
  134. package/templates/apps/changelog/src/pages/page.tsx +18 -12
  135. package/templates/apps/edge-functions/package.json +2 -2
  136. package/templates/apps/frontend-admin/package.json +8 -8
  137. package/templates/apps/frontend-app/package.json +9 -9
  138. package/templates/apps/frontend-auth/package.json +8 -8
  139. package/templates/apps/frontend-blank/package.json +7 -7
  140. package/templates/apps/frontend-cms/package.json +9 -9
  141. package/templates/apps/frontend-collab/package.json +10 -10
  142. package/templates/apps/frontend-contact/package.json +7 -7
  143. package/templates/apps/frontend-dashboard/package.json +7 -7
  144. package/templates/apps/frontend-docs/content/docs/de/guides/first-page.md +4 -0
  145. package/templates/apps/frontend-docs/content/docs/de/intro/getting-started.md +4 -0
  146. package/templates/apps/frontend-docs/content/docs/en/guides/first-page.md +4 -0
  147. package/templates/apps/frontend-docs/content/docs/en/intro/getting-started.md +4 -0
  148. package/templates/apps/frontend-docs/package.json +8 -6
  149. package/templates/apps/frontend-docs/src/collections/docs.collection.ts +21 -0
  150. package/templates/apps/frontend-docs/src/locales/de.ts +0 -5
  151. package/templates/apps/frontend-docs/src/locales/en.ts +0 -5
  152. package/templates/apps/frontend-docs/src/pages/[locale]/docs/[...slug]/page.tsx +17 -9
  153. package/templates/apps/frontend-docs/src/pages/[locale]/mirrors.test.tsx +10 -5
  154. package/templates/apps/frontend-docs/src/pages/[locale]/page.tsx +8 -0
  155. package/templates/apps/frontend-docs/src/pages/docs/[...slug]/page.test.tsx +53 -15
  156. package/templates/apps/frontend-docs/src/pages/docs/[...slug]/page.tsx +27 -33
  157. package/templates/apps/frontend-docs/src/pages/page.test.tsx +17 -3
  158. package/templates/apps/frontend-docs/src/pages/page.tsx +16 -12
  159. package/templates/apps/frontend-i18n/package.json +6 -6
  160. package/templates/apps/frontend-landing/package.json +6 -6
  161. package/templates/apps/frontend-portal/package.json +8 -8
  162. package/templates/apps/frontend-saas/package.json +8 -8
  163. package/templates/apps/frontend-spa/package.json +7 -7
  164. package/templates/apps/frontend-ssr/package.json +7 -7
  165. package/templates/apps/frontend-ssr-api/package.json +8 -8
  166. package/templates/apps/frontend-static-blog/content/posts/cms-to-ssg.md +12 -0
  167. package/templates/apps/frontend-static-blog/content/posts/hello-static.md +12 -0
  168. package/templates/apps/frontend-static-blog/content/posts/islands-not-hydration.md +14 -0
  169. package/templates/apps/frontend-static-blog/package.json +8 -6
  170. package/templates/apps/frontend-static-blog/src/collections/posts.collection.ts +27 -0
  171. package/templates/apps/frontend-static-blog/src/pages/[locale]/blog/[slug]/page.tsx +7 -4
  172. package/templates/apps/frontend-static-blog/src/pages/[locale]/mirrors.test.tsx +7 -1
  173. package/templates/apps/frontend-static-blog/src/pages/blog/[slug]/page.test.tsx +19 -9
  174. package/templates/apps/frontend-static-blog/src/pages/blog/[slug]/page.tsx +19 -21
  175. package/templates/apps/frontend-static-blog/src/pages/page.test.tsx +18 -5
  176. package/templates/apps/frontend-static-blog/src/pages/page.tsx +21 -14
  177. package/templates/apps/frontend-status/package.json +8 -8
  178. package/templates/apps/mobile-app/package.json +4 -4
  179. package/dist/apiBuild-BYBpL7Pz.js +0 -2
  180. package/dist/build-CPgcMQug.js +0 -793
  181. package/dist/codegen-CctkDO-1.js +0 -2
  182. package/dist/dbCommand-DNb6yeOG.js +0 -2
  183. package/dist/doctorCommand-CqoWA2p5.js +0 -2
  184. package/dist/fileConventions-DOqD3lPS.js +0 -34
  185. package/dist/frameworkTableAssembly-C6ETawPR.js +0 -2
  186. package/dist/inspect-CuGDYES0.js +0 -2
  187. package/dist/manifestBuild-CPjhvM62.js +0 -2
  188. package/dist/serveCommand-DLc-BznW.js +0 -2
  189. package/dist/start-DfL3fOiN.js +0 -3
  190. package/dist/start-jw89Xbqy.js +0 -1339
  191. package/dist/updateCommand-5gFVfK5q.js +0 -2
  192. package/dist/webDev-CZbTsDcH.js +0 -2
  193. package/templates/apps/changelog/scripts/generate-rss.mjs +0 -38
  194. package/templates/apps/changelog/src/lib/releases.ts +0 -21
  195. package/templates/apps/frontend-static-blog/src/content/posts.ts +0 -64
@@ -0,0 +1,1510 @@
1
+ import { i as e, t } from "./nodeEnvironment-cGFAj1J8.js";
2
+ import { r as n } from "./appPort-B_HpJ_ck.js";
3
+ import { $ as r, A as i, At as a, B as o, C as s, D as c, E as l, F as u, H as d, I as ee, K as f, L as te, M as p, N as m, O as h, Ot as g, Q as ne, R as _, S as v, T as y, Tt as b, U as x, V as S, W as C, Wt as w, Y as T, bt as re, ct as E, dt as ie, et as D, ft as O, ht as ae, i as oe, j as se, jt as k, k as ce, kt as le, l as ue, lt as A, m as de, mt as j, n as fe, nt as pe, o as me, ot as M, p as N, q as P, qt as F, s as he, st as I, tt as ge, ut as L, w as _e, x as ve, z as ye } from "./webDev-oczpugbx.js";
4
+ import { o as be, t as xe } from "./connectionConfig-Bk9IC7D0.js";
5
+ import { A as Se, D as R, a as Ce, h as we, j as Te, k as Ee } from "./inspect-Bd8-9wsi.js";
6
+ import { n as De, r as Oe, t as ke } from "./inspectMetrics-CGF94puw.js";
7
+ import { a as Ae, c as z, d as je, f as Me, l as Ne, p as B, u as Pe } from "./renderModeScan-CUbOeOAg.js";
8
+ import { i as Fe, n as Ie, r as Le, t as Re } from "./runtimeRegistry-DMeKfTHP.js";
9
+ import { n as ze } from "./logFileSink-B4uP8pvf.js";
10
+ import { t as Be } from "./bootTiming-BdyP9nYw.js";
11
+ import { dirname as V, extname as H, join as U, resolve as Ve } from "node:path";
12
+ import { promises as W } from "node:fs";
13
+ import { fileURLToPath as He, pathToFileURL as G } from "node:url";
14
+ import { createLogger as K, printReadyBlock as Ue } from "@voltro/logger";
15
+ import { Effect as We } from "effect";
16
+ import { maybeCompress as q, snapshotMetricsSync as Ge } from "@voltro/runtime";
17
+ import { createHash as J } from "node:crypto";
18
+ import { resolveBroadcastProvider as Ke } from "@voltro/plugin-broadcast";
19
+ import { createServer as qe } from "node:http";
20
+ //#region src/httpResponseWrite.ts
21
+ var Je = (e) => `W/"${J("md5").update(e).digest("hex")}"`, Ye = (e) => {
22
+ let { response: t, status: n, headers: r, body: i, requestHeaders: a } = e, o = r["cache-control"], s = (typeof o == "string" ? o : "").toLowerCase();
23
+ if (i === void 0 || n !== 200 || s.includes("no-store")) return !1;
24
+ let c = r["content-type"], l = typeof c == "string" ? c : void 0, u = Je(i), d = a["if-none-match"];
25
+ if (d !== void 0 && d.split(",").some((e) => e.trim() === u)) return t.writeHead(304, {
26
+ ...r,
27
+ etag: u
28
+ }), t.end(), !0;
29
+ let ee = q({
30
+ body: typeof i == "string" ? new TextEncoder().encode(i) : new Uint8Array(i),
31
+ contentType: l,
32
+ acceptEncoding: a["accept-encoding"],
33
+ options: e.compression
34
+ }), f = {
35
+ ...r,
36
+ ...ee.headers,
37
+ etag: u
38
+ };
39
+ return ee.compressed && delete f["content-length"], t.writeHead(n, f), t.end(Buffer.from(ee.bytes)), !0;
40
+ }, Y = K({ scope: "voltro:start:cdc" }), Xe = (e) => (t) => {
41
+ let n = 0;
42
+ for (let [r, i] of e.tableSubscriptionsByPattern) {
43
+ if (!i.includes(t)) continue;
44
+ let a = e.regexByPattern.get(r);
45
+ a && (n += e.cache.invalidateBy((e) => {
46
+ let t = e.split("|")[0] ?? e;
47
+ return a.test(t);
48
+ }));
49
+ }
50
+ return n;
51
+ }, Ze = () => xe() ? be() : null, Qe = (e) => {
52
+ let t = e.channel ?? "framework_changes", n = e.revalidateChannel ?? "voltro_revalidate", r = Xe(e), i = null, a = null;
53
+ return {
54
+ start: async () => {
55
+ let o = e.tableSubscriptionsByPattern.size > 0, s = e.onRevalidate !== void 0;
56
+ if (!o && !s) return Y.debug("skipped — no pages declare cacheInvalidatesOn and no revalidation handler is wired"), !1;
57
+ let c = Ze();
58
+ if (!c && !o) return Y.debug("no database configured — the revalidation LISTEN line is unavailable"), !1;
59
+ if (!c) return Y.warn(`${e.tableSubscriptionsByPattern.size} route(s) declare \`cacheInvalidatesOn\` and will NOT be invalidated live — no database is configured for this web process. Set DB_URL (or DB_HOST / PG_HOST) so the CDC listener can connect; until then those routes go stale until their \`revalidate\` window expires.`, { routes: [...e.tableSubscriptionsByPattern.keys()] }), !1;
60
+ i = new (await (import("pg"))).default.Client(c), await i.connect(), a = (i) => {
61
+ if (i.channel === n && i.payload && e.onRevalidate) {
62
+ e.onRevalidate(i.payload);
63
+ return;
64
+ }
65
+ if (i.channel !== t || !i.payload) return;
66
+ let a;
67
+ try {
68
+ a = JSON.parse(i.payload);
69
+ } catch (e) {
70
+ Y.warn("bad CDC payload", {}, e);
71
+ return;
72
+ }
73
+ let o = r(a.table);
74
+ o > 0 && Y.info(`${a.op} on '${a.table}' → dropped ${o} cache entries`, {
75
+ op: a.op,
76
+ table: a.table,
77
+ dropped: o
78
+ });
79
+ }, i.on("notification", a), o && await i.query(`LISTEN ${t}`), s && await i.query(`LISTEN ${n}`);
80
+ let l = [...o ? [t] : [], ...s ? [n] : []];
81
+ return Y.info(`LISTEN ${l.join(", ")}`, {
82
+ channels: l,
83
+ ..."connectionString" in c ? { target: c.connectionString.replace(/\/\/[^@/]*@/, "//") } : {
84
+ host: c.host,
85
+ port: c.port,
86
+ database: c.database
87
+ }
88
+ }), !0;
89
+ },
90
+ stop: async () => {
91
+ if (i) {
92
+ try {
93
+ a && i.off("notification", a), await i.end();
94
+ } catch {}
95
+ i = null, a = null;
96
+ }
97
+ }
98
+ };
99
+ }, X = K({ scope: "voltro:start:isr-cache" }), $e = "voltro_isr_cache", et = (e) => `
100
+ CREATE TABLE IF NOT EXISTS ${e} (
101
+ cache_key TEXT PRIMARY KEY,
102
+ html TEXT NOT NULL,
103
+ rendered_at BIGINT NOT NULL,
104
+ expires_at BIGINT NOT NULL,
105
+ servable_until BIGINT NOT NULL,
106
+ revalidate_ms BIGINT NOT NULL,
107
+ stale_while_revalidate_ms BIGINT NOT NULL DEFAULT 0
108
+ );
109
+ CREATE INDEX IF NOT EXISTS ${e}_servable_until_idx ON ${e} (servable_until);
110
+ `, tt = (e) => {
111
+ let t = e.tableName ?? $e, { client: n } = e, r = /* @__PURE__ */ new Map(), i = !1, a = (async () => {
112
+ i || (i = !0, await n.query(et(t)));
113
+ })().then(async () => {
114
+ let e = await n.query(`SELECT * FROM ${t}`);
115
+ for (let t of e.rows) r.set(t.cache_key, {
116
+ html: t.html,
117
+ renderedAt: Number(t.rendered_at),
118
+ expiresAt: Number(t.expires_at),
119
+ servableUntil: Number(t.servable_until),
120
+ revalidateMs: Number(t.revalidate_ms),
121
+ staleWhileRevalidateMs: Number(t.stale_while_revalidate_ms)
122
+ });
123
+ }).catch((e) => {
124
+ X.warn("postgres bootstrap failed", {}, e);
125
+ }), o = (e, t) => {
126
+ a.then(() => n.query(e, t)).catch((e) => {
127
+ X.warn("postgres write failed", {}, e);
128
+ });
129
+ }, s = /* @__PURE__ */ new Map(), c = (e) => {
130
+ s.set(e, (s.get(e) ?? 0) + 1);
131
+ };
132
+ return {
133
+ get(e) {
134
+ return r.get(e);
135
+ },
136
+ set(e, n, i) {
137
+ return i?.ifGeneration !== void 0 && (s.get(e) ?? 0) !== i.ifGeneration ? !1 : (r.set(e, n), o(`INSERT INTO ${t}
138
+ (cache_key, html, rendered_at, expires_at, servable_until, revalidate_ms, stale_while_revalidate_ms)
139
+ VALUES ($1, $2, $3, $4, $5, $6, $7)
140
+ ON CONFLICT (cache_key) DO UPDATE SET
141
+ html = EXCLUDED.html,
142
+ rendered_at = EXCLUDED.rendered_at,
143
+ expires_at = EXCLUDED.expires_at,
144
+ servable_until = EXCLUDED.servable_until,
145
+ revalidate_ms = EXCLUDED.revalidate_ms,
146
+ stale_while_revalidate_ms = EXCLUDED.stale_while_revalidate_ms`, [
147
+ e,
148
+ n.html,
149
+ n.renderedAt,
150
+ n.expiresAt,
151
+ n.servableUntil,
152
+ n.revalidateMs,
153
+ n.staleWhileRevalidateMs
154
+ ]), !0);
155
+ },
156
+ generation(e) {
157
+ return s.get(e) ?? 0;
158
+ },
159
+ invalidate(e) {
160
+ r.delete(e), c(e), o(`DELETE FROM ${t} WHERE cache_key = $1`, [e]);
161
+ },
162
+ invalidateBy(e) {
163
+ let n = 0, i = [];
164
+ for (let t of r.keys()) e(t) && (r.delete(t), c(t), i.push(t), n++);
165
+ return i.length > 0 && o(`DELETE FROM ${t} WHERE cache_key = ANY($1)`, [i]), n;
166
+ },
167
+ clear() {
168
+ for (let e of r.keys()) c(e);
169
+ r.clear(), o(`DELETE FROM ${t}`, []);
170
+ },
171
+ size() {
172
+ return r.size;
173
+ },
174
+ snapshot() {
175
+ return Array.from(r.entries());
176
+ }
177
+ };
178
+ }, Z = K({ scope: "voltro:start:revalidate" }), nt = (e) => {
179
+ try {
180
+ let t = JSON.parse(e);
181
+ return (t.kind === "path" || t.kind === "table" || t.kind === "tag") && typeof t.value == "string" && t.value.length > 0 && (t.tenant === void 0 || typeof t.tenant == "string") ? {
182
+ kind: t.kind,
183
+ value: t.value,
184
+ ...t.tenant === void 0 ? {} : { tenant: t.tenant }
185
+ } : (Z.warn("bad revalidation payload (shape)", { payload: e }), null);
186
+ } catch {
187
+ return Z.warn("bad revalidation payload (not JSON)", { payload: e }), null;
188
+ }
189
+ }, rt = (e, t) => {
190
+ if (t.kind === "table" || t.kind === "tag") {
191
+ let n = e.tableSink(t.value);
192
+ return Z.info(`revalidate ${t.kind} '${t.value}' → dropped ${n} cache entries`, {
193
+ kind: t.kind,
194
+ value: t.value,
195
+ dropped: n
196
+ }), n;
197
+ }
198
+ let n = t.value, r = (e) => t.tenant === void 0 || e.split("|").includes(`tenant=${t.tenant}`), i = e.regexByPattern.get(n);
199
+ if (i !== void 0) {
200
+ let a = e.renderModeByPattern.get(n);
201
+ if (a !== "isr") return Z.error(`revalidatePath('${n}') targets a '${a ?? "unknown"}' route — only \`renderMode: 'isr'\` routes have cache entries to drop. Static HTML is a build artifact this process never re-renders; rebuild to change it.`, {
202
+ path: n,
203
+ renderMode: a ?? "unknown"
204
+ }), 0;
205
+ let o = e.cache.invalidateBy((e) => {
206
+ let t = e.split("|")[0] ?? e;
207
+ return i.test(t) && r(e);
208
+ });
209
+ return Z.info(`revalidate path pattern '${n}' → dropped ${o} cache entries`, {
210
+ path: n,
211
+ dropped: o,
212
+ ...t.tenant === void 0 ? {} : { tenant: t.tenant }
213
+ }), o;
214
+ }
215
+ let a = [...e.regexByPattern.entries()].find(([, e]) => e.test(n));
216
+ if (a === void 0) return Z.error(`revalidatePath('${n}') matches no declared route — nothing was dropped. Pass a declared route pattern (e.g. /blog/[slug]) or a concrete path of one.`, { path: n }), 0;
217
+ let o = e.renderModeByPattern.get(a[0]);
218
+ if (o !== "isr") return Z.error(`revalidatePath('${n}') targets a '${o ?? "unknown"}' route (${a[0]}) — only \`renderMode: 'isr'\` routes have cache entries to drop.`, {
219
+ path: n,
220
+ route: a[0],
221
+ renderMode: o ?? "unknown"
222
+ }), 0;
223
+ let s = e.cache.invalidateBy((e) => (e.split("|")[0] ?? e) === n && r(e));
224
+ return Z.info(`revalidate path '${n}' → dropped ${s} cache entries`, {
225
+ path: n,
226
+ dropped: s,
227
+ ...t.tenant === void 0 ? {} : { tenant: t.tenant }
228
+ }), s;
229
+ }, Q = K({ scope: "voltro:start" }), it = await (async () => {
230
+ try {
231
+ let e = U(V(He(import.meta.url)), "..", "package.json"), t = await W.readFile(e, "utf8");
232
+ return JSON.parse(t).version ?? "0.0.0";
233
+ } catch {
234
+ return "0.0.0";
235
+ }
236
+ })(), at = (e) => e instanceof Error && e._voltroControl === "redirect" && typeof e.location == "string", ot = (e) => e instanceof Error && e._voltroControl === "not-found", st = {
237
+ ".html": "text/html; charset=utf-8",
238
+ ".js": "application/javascript",
239
+ ".mjs": "application/javascript",
240
+ ".css": "text/css",
241
+ ".json": "application/json",
242
+ ".xml": "application/xml; charset=utf-8",
243
+ ".rss": "application/rss+xml; charset=utf-8",
244
+ ".atom": "application/atom+xml; charset=utf-8",
245
+ ".svg": "image/svg+xml",
246
+ ".png": "image/png",
247
+ ".jpg": "image/jpeg",
248
+ ".jpeg": "image/jpeg",
249
+ ".webp": "image/webp",
250
+ ".ico": "image/x-icon",
251
+ ".woff": "font/woff",
252
+ ".woff2": "font/woff2",
253
+ ".txt": "text/plain; charset=utf-8"
254
+ }, ct = (e) => st[H(e).toLowerCase()] ?? "application/octet-stream", lt = (e) => e.replace(/<script\b(?=[^>]*\btype="module")(?:(?!<\/script>).)*<\/script>/gi, "").replace(/<script\b(?=[^>]*\bsrc=)(?:(?!<\/script>).)*<\/script>/gi, "").replace(/<link\b[^>]*\brel="modulepreload"[^>]*>/gi, ""), ut = async (e) => {
255
+ try {
256
+ return await W.stat(e), !0;
257
+ } catch {
258
+ return !1;
259
+ }
260
+ }, dt = (e) => {
261
+ let t = [], n = 0, r = e.split("/").filter(Boolean), i = [];
262
+ 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, "\\$&"));
263
+ let a = i.join("/");
264
+ return {
265
+ regex: a.length === 0 ? /^\/?$/ : RegExp(`^/${a}/?$`),
266
+ paramNames: t,
267
+ priority: n
268
+ };
269
+ }, ft = (e) => e.map((e) => {
270
+ let { regex: t, paramNames: n, priority: r } = dt(e.pattern);
271
+ return {
272
+ pattern: e.pattern,
273
+ file: e.file,
274
+ dirChain: e.dirChain,
275
+ regex: t,
276
+ paramNames: n,
277
+ priority: r
278
+ };
279
+ }).slice().sort((e, t) => e.priority - t.priority), pt = (e, t) => {
280
+ for (let n of t) {
281
+ let t = n.regex.exec(e);
282
+ if (!t) continue;
283
+ let r = {};
284
+ for (let e = 0; e < n.paramNames.length; e++) r[n.paramNames[e]] = t[e + 1] ?? "";
285
+ return {
286
+ route: n,
287
+ params: r
288
+ };
289
+ }
290
+ return null;
291
+ }, mt = null, ht = async (e) => {
292
+ let { provider: t, route: n, params: r, pathname: a, dirs: s, shellTemplate: l, requestHeaders: f, requestUrl: m = "", apiOrigin: g, apiName: ne } = e, { search: _ } = ie(m), v = await ee(te(e.middlewares ?? [], {
293
+ route: n.pattern,
294
+ pathname: a
295
+ }), {
296
+ pathname: a,
297
+ search: _,
298
+ headers: f,
299
+ cookies: u(f.cookie),
300
+ route: n.pattern
301
+ }, e.onCookieWarning), b = await t.getPage(n.pattern, n.file), C = e.forceSsrRender === !0 ? "ssr" : z(b, n.file), w = C === "isr" && b.ppr === !0, T = C === "isr" && e.holesOnly !== !0 ? i(v.headers) : v.headers, re = me(g, T.cookie, {
302
+ apiName: ne,
303
+ headers: T
304
+ });
305
+ if (e.holesOnly === !0) {
306
+ if (typeof b.loader != "function") return null;
307
+ let e = new AbortController();
308
+ return {
309
+ holes: {
310
+ loader: b.loader,
311
+ ctx: {
312
+ params: r,
313
+ pathname: a,
314
+ search: _,
315
+ signal: e.signal,
316
+ headers: T,
317
+ query: re,
318
+ isServer: !0
319
+ },
320
+ helpers: await t.getHelpers(),
321
+ page: n.pattern
322
+ },
323
+ setCookies: v.setCookies
324
+ };
325
+ }
326
+ let D = C === "spa" && ue(s, n.dirChain).some((e) => e.hasLayout);
327
+ if (C !== "ssr" && C !== "isr" && !D) return null;
328
+ let ae = ue(s, n.dirChain), oe = {}, se = null, k, le = new AbortController(), de = w ? h(T, n.pattern) : T;
329
+ try {
330
+ (await t.getHelpers()).beginStoreSeeds(), {chain: k, segmentLoaderData: oe} = await he({
331
+ entries: ae,
332
+ loadLayout: (e) => t.getLayout(e.dir),
333
+ loadError: (e) => t.getError(e.dir),
334
+ loadPending: (e) => t.getPending(e.dir),
335
+ ctx: {
336
+ params: r,
337
+ pathname: a,
338
+ search: _,
339
+ signal: le.signal,
340
+ headers: de,
341
+ query: re,
342
+ isServer: !0
343
+ }
344
+ }), typeof b.loader == "function" && !D && (se = await b.loader({
345
+ params: r,
346
+ pathname: a,
347
+ search: _,
348
+ signal: le.signal,
349
+ headers: de,
350
+ query: re,
351
+ isServer: !0
352
+ }));
353
+ } catch (e) {
354
+ if (at(e)) return {
355
+ control: "redirect",
356
+ status: e.status,
357
+ location: e.location,
358
+ setCookies: v.setCookies,
359
+ responseHeaders: v.responseHeaders
360
+ };
361
+ if (ot(e)) return {
362
+ control: "not-found",
363
+ setCookies: v.setCookies,
364
+ responseHeaders: v.responseHeaders
365
+ };
366
+ throw e;
367
+ }
368
+ let j = await t.getHelpers();
369
+ D || await ye({
370
+ pageMod: b,
371
+ params: r,
372
+ query: re,
373
+ apiName: ne,
374
+ seed: j.seedPreloadedSubscription,
375
+ seedFailure: j.seedPreloadedSubscriptionFailure,
376
+ onError: ({ tag: e, apiName: t }, n) => Q.warn("preload seed failed", {
377
+ tag: e,
378
+ apiName: t,
379
+ pathname: a
380
+ }, n)
381
+ });
382
+ let fe = {
383
+ pattern: n.pattern,
384
+ Component: b.default,
385
+ meta: b.meta,
386
+ loader: b.loader,
387
+ ErrorBoundary: b.ErrorBoundary,
388
+ Pending: b.Pending,
389
+ renderMode: C,
390
+ chain: k
391
+ };
392
+ if (C === "isr" && v.cspNonce !== void 0) throw Error(`page '${n.pattern}' is renderMode 'isr' while middleware.ts mints a cspNonce — an isr render is CACHED and a cached nonce is a lie the browser enforces. Use renderMode 'ssr' for nonce'd pages, or a hash-based CSP for isr.`);
393
+ let pe = {
394
+ cookies: w ? c(ce(v.cookies), n.pattern) : C === "isr" ? ce(v.cookies) : v.cookies,
395
+ headers: de,
396
+ url: m,
397
+ ...e.formFlash === void 0 ? {} : { formFlash: e.formFlash }
398
+ }, M = j.i18n?.resolve(T.cookie, T["accept-language"]), N = {
399
+ lang: M?.locale ?? pe.cookies["voltro:locale"] ?? "en",
400
+ ...M?.timeZone === void 0 ? {} : { timeZone: M.timeZone },
401
+ renderedAt: Date.now()
402
+ }, P = b.interactive ?? "full";
403
+ if (D) {
404
+ let e = E({
405
+ helpers: j,
406
+ page: n.pattern,
407
+ interactive: P,
408
+ delivery: "stream",
409
+ renderInput: {
410
+ descriptor: fe,
411
+ params: r,
412
+ pathname: a,
413
+ search: _,
414
+ segmentLoaderData: oe,
415
+ requestContext: pe,
416
+ ...M ? {
417
+ outerWrap: M.outerWrap,
418
+ locale: M.locale
419
+ } : {}
420
+ }
421
+ }), t = (t) => L({
422
+ helpers: j,
423
+ prepared: e,
424
+ meta: t,
425
+ interactive: P
426
+ });
427
+ if (e.hasDeferred) {
428
+ let n = d({ shell: l });
429
+ return {
430
+ renderMode: "spa",
431
+ setCookies: v.setCookies,
432
+ responseHeaders: v.responseHeaders,
433
+ stream: (r) => x({
434
+ res: r,
435
+ shell: n,
436
+ documentAttrs: N,
437
+ headers: {
438
+ ...v.responseHeaders,
439
+ "content-type": "text/html; charset=utf-8",
440
+ "x-voltro-rendered-by": "spa",
441
+ ...p(v.setCookies)
442
+ },
443
+ headInjection: t,
444
+ render: (t) => j.renderPageToStream({
445
+ ...e.renderInput,
446
+ ...t
447
+ }),
448
+ onShellError: (e) => {
449
+ Q.error("spa layout shell render failed", { pathname: a }, e), r.writeHead(500, { "content-type": "text/plain; charset=utf-8" }), r.end("server error");
450
+ }
451
+ })
452
+ };
453
+ }
454
+ let i = A({
455
+ helpers: j,
456
+ prepared: e
457
+ });
458
+ return {
459
+ html: o(S(l.replace("<div id=\"root\"></div>", `<div id="root">${i.body}</div>`), t(i.meta)), N),
460
+ renderMode: "spa",
461
+ revalidateMs: null,
462
+ setCookies: v.setCookies,
463
+ responseHeaders: v.responseHeaders
464
+ };
465
+ }
466
+ let F = I({
467
+ helpers: j,
468
+ page: n.pattern,
469
+ pathname: a,
470
+ renderMode: C,
471
+ interactive: P,
472
+ loaderData: se,
473
+ segmentLoaderData: oe,
474
+ pageLoaderRan: typeof b.loader == "function",
475
+ ...w ? { ppr: !0 } : {}
476
+ });
477
+ w && y(F.stateInput, n.pattern);
478
+ let ge = {
479
+ descriptor: fe,
480
+ params: r,
481
+ pathname: a,
482
+ search: _,
483
+ loaderData: F.loaderData,
484
+ segmentLoaderData: F.segmentLoaderData,
485
+ requestContext: pe,
486
+ ...M ? {
487
+ outerWrap: M.outerWrap,
488
+ locale: M.locale
489
+ } : {}
490
+ }, _e = (t) => {
491
+ if (mt === null || C !== "ssr" && C !== "isr" || typeof b.ogImage != "function" || t.includes("og:image")) return "";
492
+ let r = T["x-tenant"], i = mt.signOgUrl({
493
+ pattern: n.pattern,
494
+ params: e.params,
495
+ ...r === void 0 ? {} : { tenant: r }
496
+ });
497
+ return `<meta property="og:image" content="${i}" /><meta name="twitter:image" content="${i}" /><meta name="twitter:card" content="summary_large_image" />`;
498
+ }, ve = (e) => [
499
+ j.renderMetaToHtml(e) + _e(j.renderMetaToHtml(e)),
500
+ `<meta name="voltro-interactive" content="${P}" />`,
501
+ ...F.hasDeferred ? [j.renderDeferredRegistryScript()] : [],
502
+ j.renderRouterStateScript(F.stateInput)
503
+ ].filter((e) => e.length > 0).join("\n ");
504
+ if (C === "ssr" && P === "full" && e.buffered !== !0) {
505
+ let e = d({ shell: l });
506
+ return {
507
+ renderMode: "ssr",
508
+ setCookies: v.setCookies,
509
+ stream: (t) => x({
510
+ res: t,
511
+ shell: e,
512
+ documentAttrs: N,
513
+ headers: {
514
+ ...v.responseHeaders,
515
+ "content-type": "text/html; charset=utf-8",
516
+ "x-voltro-rendered-by": "ssr",
517
+ ...p(v.setCookies)
518
+ },
519
+ headInjection: ve,
520
+ render: (e) => j.renderPageToStream({
521
+ ...ge,
522
+ ...e,
523
+ ...v.cspNonce === void 0 ? {} : { nonce: v.cspNonce }
524
+ }),
525
+ onShellError: (e) => {
526
+ Q.error("ssr shell render failed", { pathname: a }, e), t.writeHead(500, { "content-type": "text/plain; charset=utf-8" }), t.end("server error");
527
+ }
528
+ })
529
+ };
530
+ }
531
+ let { html: be, meta: xe } = j.renderPageToHtml(ge), Se = ve(xe), R = o(S(l.replace("<div id=\"root\"></div>", `<div id="root">${be}</div>`), Se), N);
532
+ P === "none" && (R = lt(R));
533
+ let Ce = C === "isr" ? B(b.revalidate) : null;
534
+ return {
535
+ html: v.cspNonce === void 0 ? R : O(R, v.cspNonce),
536
+ renderMode: C,
537
+ revalidateMs: Ce,
538
+ setCookies: v.setCookies,
539
+ responseHeaders: v.responseHeaders
540
+ };
541
+ }, $ = (e) => e === "" ? "/" : e, gt = async (e) => {
542
+ let t = await import(G(e).href);
543
+ return {
544
+ kind: "bundle",
545
+ getPageMeta: () => t.pageMeta,
546
+ async getPage(e, n) {
547
+ let r = t.pages[e];
548
+ if (!r) throw Error(`[voltro start] ssr bundle missing page for pattern ${e}`);
549
+ return typeof r == "function" ? await r() : r;
550
+ },
551
+ async getLayout(e) {
552
+ let n = t.layouts[$(e)];
553
+ if (!n) throw Error(`[voltro start] ssr bundle missing layout for dir ${$(e)}`);
554
+ return typeof n == "function" ? await n() : n;
555
+ },
556
+ async getError(e) {
557
+ let n = t.errors[$(e)];
558
+ if (!n) throw Error(`[voltro start] ssr bundle missing error for dir ${$(e)}`);
559
+ return typeof n == "function" ? await n() : n;
560
+ },
561
+ async getPending(e) {
562
+ let n = t.pendings[$(e)];
563
+ if (!n) throw Error(`[voltro start] ssr bundle missing pending for dir ${$(e)}`);
564
+ return typeof n == "function" ? await n() : n;
565
+ },
566
+ async getHelpers() {
567
+ return t.helpers;
568
+ },
569
+ async close() {}
570
+ };
571
+ }, _t = async (e, t) => {
572
+ let n = await F("vite", () => import("vite")), r = (await import("@vitejs/plugin-react")).default, i = (await import("@tailwindcss/vite")).default, o = await n.createServer({
573
+ root: t,
574
+ envPrefix: "__VOLTRO_VITE_ENV_DISABLED__",
575
+ plugins: [r(), i()],
576
+ resolve: { dedupe: [
577
+ "react",
578
+ "react-dom",
579
+ "react-intl",
580
+ "@voltro/i18n"
581
+ ] },
582
+ ssr: { noExternal: ["react-intl", "@voltro/i18n"] },
583
+ server: {
584
+ middlewareMode: !0,
585
+ hmr: !1
586
+ },
587
+ appType: "custom",
588
+ logLevel: "warn"
589
+ }), s = U(e, "src", "pages"), c = (e) => e === "" ? s : U(s, e), l = a({
590
+ limit: k(),
591
+ onColdStart: (e) => Q.debug("ssr cold-compile start", { id: e }),
592
+ onColdEnd: (e, { durationMs: t, failed: n }) => Q.debug(`ssr cold-compile ${n ? "FAILED" : "end"} ${t}ms`, {
593
+ id: e,
594
+ ms: t,
595
+ ...n ? { failed: !0 } : {}
596
+ })
597
+ }), u = (e) => l.load(e, async () => await o.ssrLoadModule(e));
598
+ return {
599
+ kind: "middleware",
600
+ async getPage(e, t) {
601
+ return u(U(s, t));
602
+ },
603
+ async getLayout(e) {
604
+ return u(U(c(e), "layout.tsx"));
605
+ },
606
+ async getError(e) {
607
+ return u(U(c(e), "error.tsx"));
608
+ },
609
+ async getPending(e) {
610
+ return u(U(c(e), "loading.tsx"));
611
+ },
612
+ async getHelpers() {
613
+ return await u("@voltro/web/ssr");
614
+ },
615
+ async close() {
616
+ await o.close();
617
+ }
618
+ };
619
+ }, vt = async (t) => {
620
+ let i = Be(), a = await N(t);
621
+ if (!a) return {
622
+ ran: !1,
623
+ exitCode: 0
624
+ };
625
+ if (a.type !== "web") return Q.error("only web apps are supported by `voltro start`"), {
626
+ ran: !0,
627
+ exitCode: 1
628
+ };
629
+ {
630
+ let e = v(a);
631
+ if (e !== void 0) return Q.error(`voltro start: refusing to boot — ${e}`), {
632
+ ran: !0,
633
+ exitCode: 1
634
+ };
635
+ }
636
+ let { resolved: o } = await w({
637
+ rawEnv: a.env,
638
+ appType: "web",
639
+ root: t,
640
+ log: Q,
641
+ generateTypes: !1
642
+ }), c = o.publicValues;
643
+ i.mark("config");
644
+ let d = ge();
645
+ ne(d), Q.info("booting voltro start", { app: a.name ?? "(unnamed)" });
646
+ let p = n({
647
+ kind: "web",
648
+ configPort: a.port,
649
+ env: process.env,
650
+ dashboardPin: process.env[C] === "1"
651
+ });
652
+ for (let e of p.warnings) Q.warn(e);
653
+ let h = p.port, y = U(t, ".framework"), x = U(y, "dist"), S = U(x, "index.html");
654
+ if (!await ut(S)) return Q.error("no built dist found — run `voltro build` first", { distDir: x }), {
655
+ ran: !0,
656
+ exitCode: 1
657
+ };
658
+ let E = a.name ?? "unnamed", O = Re("web", E, h), k = ze(E);
659
+ await Fe({
660
+ id: O,
661
+ name: E,
662
+ kind: "web",
663
+ url: `http://localhost:${h}`,
664
+ pid: process.pid,
665
+ status: "booting",
666
+ logFile: k.path
667
+ }).catch(() => {});
668
+ let ce = U(x, "_voltro", "shell.html"), A = await ut(ce) ? await W.readFile(ce, "utf8") : await W.readFile(S, "utf8"), F = await de(t, a), he = De(a), I = fe(F[0]), L = F[0]?.name, ye = /* @__PURE__ */ new Set(), z = (e) => {
669
+ ye.has(e.name) || (ye.add(e.name), Q.warn(`middleware.ts wrote the cookie "${e.name}" with the HttpOnly default — a browser SDK cannot read it`, {
670
+ cookie: e.name,
671
+ hint: "If your IdP client reads this from `document.cookie` (Supabase's `createBrowserClient` does), pass `httpOnly: false`. Otherwise the SSR render succeeds and the user is signed out at the first client-side call. Set `httpOnly: true` explicitly to silence this."
672
+ }));
673
+ }, B = await m(t);
674
+ B.length > 0 && Q.info(`middleware.ts loaded — ${B.length} middleware(s): ` + B.map((e) => e.exportName).join(", "));
675
+ let V, H = null, Ve = process.env.SSR_CACHE === "postgres";
676
+ if (Ve && xe()) H = new (await (import("pg"))).default.Client(be()), await H.connect(), V = tt({ client: H }), Q.info("isr cache backend: postgres", { table: "voltro_isr_cache" });
677
+ else if (Ve) {
678
+ let t = "SSR_CACHE=postgres, but nothing in the environment names a database (looked for DB_URL, DB_PRIMARY_URL, DB_DIRECT_URL, DB_MIGRATE_URL, DB_HOST, PG_HOST).";
679
+ if (e()) throw Q.fatal(`${t} Refusing to fall back to the per-process memory cache: it is not shared between instances and does not survive a restart, so the pages this process serves would differ from its replicas' with nothing to indicate it.`), Error("[voltro start] SSR_CACHE=postgres with no database configured");
680
+ V = Me(), Q.warn(`${t} Falling back to the per-process memory cache — this would be a hard failure in production.`);
681
+ } else V = Me(), Q.info("isr cache backend: memory (per-process)", { hint: "set SSR_CACHE=postgres for persistent storage" });
682
+ await s(t, a, F, c);
683
+ let He = U(t, "src", "pages"), { pages: G, dirs: K } = await ve(He), q = ft(G);
684
+ se(B, q.map((e) => e.pattern)), i.mark("scan");
685
+ let J = U(x, "server", "ssrEntry.js"), Je = await ut(J);
686
+ if (!Je && process.env.NODE_ENV === "production") throw Q.fatal(`production \`voltro start\` requires a precompiled SSR bundle at ${J} but it is missing. Run \`voltro build\` before serving — production renders from the bundle and never compiles on demand.`), Error(`[voltro start] missing SSR bundle at ${J}`);
687
+ let Y = Je ? await gt(J) : await _t(t, y);
688
+ Q.info(`ssr loader: ${Y.kind}`, {
689
+ kind: Y.kind,
690
+ ...Y.kind === "middleware" ? { hint: "no pre-built SSR bundle found; run `voltro build` to enable bundle mode" } : {}
691
+ }), i.mark("provider");
692
+ let Ze = Y.getPageMeta?.();
693
+ re(t);
694
+ let X = /* @__PURE__ */ new Map(), $e = 0;
695
+ for (let e of G) {
696
+ let t = Ze?.[e.pattern];
697
+ if (t) {
698
+ X.set(e.pattern, t);
699
+ continue;
700
+ }
701
+ try {
702
+ let t = await Y.getPage(e.pattern, e.file);
703
+ X.set(e.pattern, Ae(t, e.file)), $e++;
704
+ } catch (t) {
705
+ Q.warn("failed to load page metadata", { pattern: e.pattern }, t);
706
+ }
707
+ }
708
+ let et = /* @__PURE__ */ new Map();
709
+ for (let [e, t] of X) {
710
+ if (t.interactive !== "islands") continue;
711
+ let n = U(x, "island-shells", `${b(e)}.html`);
712
+ try {
713
+ et.set(e, await W.readFile(n, "utf8"));
714
+ } catch {
715
+ Q.warn("islands page has no built per-page shell — serving the full app shell", {
716
+ pattern: e,
717
+ expected: n
718
+ });
719
+ }
720
+ }
721
+ Q.info(`registered ${X.size} route(s)`, {
722
+ count: X.size,
723
+ fromManifest: X.size - $e,
724
+ fromModules: $e
725
+ }), i.mark("routes");
726
+ let Z = /* @__PURE__ */ new Set();
727
+ for (let e of q) X.get(e.pattern)?.renderMode === "spa" && ue(K, e.dirChain).some((e) => e.hasLayout) && Z.add(e.pattern);
728
+ Z.size > 0 && Q.info(`${Z.size} spa route(s) render an SSR layout shell`, { patterns: [...Z] });
729
+ let at = /* @__PURE__ */ new Map();
730
+ for (let [e, t] of X) t.cacheInvalidatesOn.length > 0 && at.set(e, t.cacheInvalidatesOn);
731
+ let ot = /* @__PURE__ */ new Map();
732
+ for (let e of q) ot.set(e.pattern, e.regex);
733
+ {
734
+ let n = new Set([...X].filter(([, e]) => (e.renderMode === "ssr" || e.renderMode === "isr") && e.hasOgImage).map(([e]) => e));
735
+ if (n.size > 0) {
736
+ let { secret: r, fromEnv: i } = ae();
737
+ if (!i && e()) throw Q.fatal(`${n.size} ssr route(s) export ogImage, but VOLTRO_OG_SECRET is unset. Behind a load balancer the signing replica and the fetching replica differ, so a per-boot secret would 403 every cross-replica image fetch. Set VOLTRO_OG_SECRET (any long random value, same on every replica).`), Error("[voltro start] ssr ogImage routes need VOLTRO_OG_SECRET in a deploy environment");
738
+ let o = new Map(G.map((e) => [e.pattern, e.file]));
739
+ mt = j({
740
+ root: t,
741
+ fonts: a.fonts,
742
+ cache: V,
743
+ secret: r,
744
+ isOgSsrRoute: (e) => n.has(e),
745
+ getPageModule: async (e) => {
746
+ let t = o.get(e);
747
+ return t === void 0 ? null : await Y.getPage(e, t);
748
+ }
749
+ }), Q.info(`og route active for ${n.size} ssr route(s)`, { secret: i ? "env" : "per-boot" });
750
+ }
751
+ }
752
+ let st = /* @__PURE__ */ new Map();
753
+ for (let [e, t] of X) st.set(e, t.renderMode);
754
+ let lt = [...X.values()].some((e) => e.renderMode === "isr"), dt = {
755
+ cache: V,
756
+ tableSink: Xe({
757
+ cache: V,
758
+ tableSubscriptionsByPattern: at,
759
+ regexByPattern: ot
760
+ }),
761
+ regexByPattern: ot,
762
+ renderModeByPattern: st
763
+ }, $ = (e) => {
764
+ let t = nt(e);
765
+ t && rt(dt, t);
766
+ }, vt = Qe({
767
+ cache: V,
768
+ tableSubscriptionsByPattern: at,
769
+ regexByPattern: ot,
770
+ ...lt ? { onRevalidate: $ } : {}
771
+ }), yt = await vt.start(), bt = null, xt = null;
772
+ if (lt) {
773
+ let e = Ke({}, process.env);
774
+ if (e.crossReplica) try {
775
+ xt = e.provider;
776
+ let t = Oe(process.env);
777
+ bt = await We.runPromise(e.provider.subscribe(t, $)), Q.info(`revalidation subscriber: broker (${e.provider.name})`, { channel: t });
778
+ } catch (e) {
779
+ Q.warn("revalidation broker subscribe failed — broker leg disabled", {}, e), xt = null;
780
+ }
781
+ yt && bt === null && Q.info("revalidation subscriber: postgres LISTEN (voltro_revalidate)"), !yt && bt === null && Q.warn("isr routes exist, but this web process has NO revalidation transport: no database is configured for the LISTEN line and no broker is configured. `revalidatePath` / `revalidateTable` / `revalidateTag` from the api will not reach this process — cached pages stay until their own `revalidate` window expires. Set DB_URL (postgres) or BROADCAST_URL (redis:// or nats://) on BOTH the api and this web deployment.");
782
+ }
783
+ i.mark("cdc");
784
+ let St = ke(), Ct = G.map((e) => {
785
+ let t = X.get(e.pattern);
786
+ return {
787
+ pattern: e.pattern,
788
+ file: e.file,
789
+ dirChain: e.dirChain,
790
+ renderMode: t?.renderMode ?? "static",
791
+ interactive: t?.interactive ?? "full",
792
+ tenantAware: t?.tenantAware ?? !1,
793
+ revalidateMs: t?.revalidateMs ?? null,
794
+ staleWhileRevalidateMs: t?.staleWhileRevalidateMs ?? 0,
795
+ cacheInvalidatesOn: t?.cacheInvalidatesOn ?? [],
796
+ hasLoader: t?.hasLoader ?? !1,
797
+ hasMeta: t?.hasMeta ?? !1,
798
+ hasGetStaticPaths: t?.hasGetStaticPaths ?? !1
799
+ };
800
+ }), wt = K.map((e) => ({
801
+ dir: e.dir,
802
+ hasLayout: e.hasLayout,
803
+ hasError: e.hasError,
804
+ hasPending: e.hasPending,
805
+ hasNotFound: e.hasNotFound
806
+ })), Tt = H ? "postgres" : "memory", Et = {
807
+ kind: "web",
808
+ meta: {
809
+ name: a.name ?? "(unnamed)",
810
+ voltroVersion: it,
811
+ port: h,
812
+ mode: "start",
813
+ apis: Object.entries(a.apis ?? {}).map(([e, t]) => {
814
+ let n = {
815
+ name: e,
816
+ package: t.package
817
+ };
818
+ return t.url !== void 0 && (n.url = t.url), n;
819
+ })
820
+ },
821
+ routes: Ct,
822
+ dirs: wt,
823
+ cache: () => {
824
+ let e = Date.now(), t = V.snapshot().map(([t, n]) => ({
825
+ key: t,
826
+ renderedAt: n.renderedAt,
827
+ expiresAt: n.expiresAt,
828
+ servableUntil: n.servableUntil,
829
+ ageMs: e - n.renderedAt,
830
+ htmlBytes: Buffer.byteLength(n.html, "utf8"),
831
+ revalidateMs: n.revalidateMs,
832
+ staleWhileRevalidateMs: n.staleWhileRevalidateMs
833
+ }));
834
+ return {
835
+ backend: Tt,
836
+ size: V.size(),
837
+ entries: t
838
+ };
839
+ },
840
+ metrics: () => Ge()
841
+ }, Dt = async (e, n) => {
842
+ let i = e.split("?")[0] ?? "/";
843
+ if (a.name === "voltroDashboard" && i === "/api/dashboard/registry") try {
844
+ let e = await Ie();
845
+ return {
846
+ status: 200,
847
+ headers: { "content-type": "application/json; charset=utf-8" },
848
+ body: JSON.stringify(e)
849
+ };
850
+ } catch (e) {
851
+ return {
852
+ status: 500,
853
+ headers: { "content-type": "text/plain" },
854
+ body: `registry read error: ${e.message}`
855
+ };
856
+ }
857
+ if (a.name === "voltroDashboard" && i === "/api/dashboard/config") {
858
+ let e = process.env.VOLTRO_DASHBOARD_APPS, t = [];
859
+ if (e && e.trim().length > 0) {
860
+ let n;
861
+ try {
862
+ n = JSON.parse(e);
863
+ } catch (e) {
864
+ return {
865
+ status: 500,
866
+ headers: { "content-type": "text/plain" },
867
+ body: `VOLTRO_DASHBOARD_APPS is not valid JSON: ${e.message}`
868
+ };
869
+ }
870
+ for (let e of Array.isArray(n) ? n : []) {
871
+ if (typeof e != "object" || !e) continue;
872
+ let n = e;
873
+ typeof n.url == "string" && n.url.length !== 0 && t.push({
874
+ url: n.url,
875
+ ...typeof n.name == "string" ? { name: n.name } : {},
876
+ ...typeof n.token == "string" ? { token: n.token } : {}
877
+ });
878
+ }
879
+ }
880
+ return {
881
+ status: 200,
882
+ headers: { "content-type": "application/json; charset=utf-8" },
883
+ body: JSON.stringify({ apps: t })
884
+ };
885
+ }
886
+ if (mt !== null && i === "/_voltro/og") {
887
+ let t = await mt.handle(new URL(e, "http://localhost"));
888
+ if (t !== null) return {
889
+ status: t.status,
890
+ headers: { ...t.headers },
891
+ body: Buffer.from(t.body)
892
+ };
893
+ }
894
+ if (i === "/_voltro/inspect/logs") {
895
+ let t = T(e, r(), n);
896
+ return {
897
+ status: t.status,
898
+ headers: {
899
+ "content-type": t.contentType,
900
+ ...R(n.origin)
901
+ },
902
+ body: t.body
903
+ };
904
+ }
905
+ if (i !== "/_voltro/inspect/stream") {
906
+ let t = we(e, Et, n);
907
+ if (t !== null) return {
908
+ status: t.status,
909
+ headers: {
910
+ "content-type": t.contentType,
911
+ ...t.headers ?? {}
912
+ },
913
+ body: t.body
914
+ };
915
+ }
916
+ let o = pt(i, q), s = o ? X.get(o.route.pattern)?.renderMode : void 0, c = s === "ssr" || s === "isr" || (o ? Z.has(o.route.pattern) : !1), f = [];
917
+ if (!c && B.length > 0) {
918
+ let t = te(B, {
919
+ route: void 0,
920
+ pathname: i
921
+ });
922
+ if (t !== void 0) {
923
+ let r = await ee(t, {
924
+ pathname: i,
925
+ search: e.slice(i.length),
926
+ headers: n,
927
+ cookies: u(n.cookie),
928
+ route: void 0
929
+ });
930
+ f.push(...r.setCookies);
931
+ }
932
+ }
933
+ let p = (e) => f.length === 0 ? e : {
934
+ ...e,
935
+ "set-cookie": f.map(_)
936
+ }, m = i === "/" ? U(x, "index.html") : U(x, i.replace(/^\//, ""), "index.html");
937
+ if (!c && await ut(m)) {
938
+ let e = await W.readFile(m);
939
+ return {
940
+ status: 200,
941
+ headers: p({ "content-type": "text/html; charset=utf-8" }),
942
+ body: e
943
+ };
944
+ }
945
+ if (/\.[a-z0-9]+$/i.test(i)) {
946
+ let e = U(x, i.replace(/^\//, ""));
947
+ if (await ut(e)) {
948
+ let t = await W.readFile(e);
949
+ return {
950
+ status: 200,
951
+ headers: p({ "content-type": ct(e) }),
952
+ body: t
953
+ };
954
+ }
955
+ }
956
+ let h = pt(i, q);
957
+ if (!h) {
958
+ let r = oe(K, i);
959
+ if (r !== void 0) try {
960
+ let a = await ht({
961
+ provider: Y,
962
+ root: t,
963
+ route: {
964
+ pattern: "<not-found>",
965
+ file: r.dir === "" ? "not-found.tsx" : `${r.dir}/not-found.tsx`,
966
+ dirChain: r.chain,
967
+ regex: /^$/,
968
+ paramNames: [],
969
+ priority: 2 ** 53 - 1
970
+ },
971
+ params: {},
972
+ pathname: i,
973
+ dirs: K,
974
+ shellTemplate: A,
975
+ requestHeaders: n,
976
+ apiOrigin: I,
977
+ apiName: L,
978
+ middlewares: B,
979
+ onCookieWarning: z,
980
+ requestUrl: e,
981
+ buffered: !0,
982
+ forceSsrRender: !0
983
+ });
984
+ if (a && "html" in a && typeof a.html == "string") return {
985
+ status: 404,
986
+ headers: p({
987
+ "content-type": "text/html; charset=utf-8",
988
+ "x-voltro-rendered-by": "ssr-not-found"
989
+ }),
990
+ body: a.html
991
+ };
992
+ } catch (e) {
993
+ Q.warn("not-found.tsx failed to render — serving the plain 404", { pathname: i }, e instanceof Error ? e : Error(String(e)));
994
+ }
995
+ return {
996
+ status: 404,
997
+ headers: p({
998
+ "content-type": "text/plain",
999
+ "x-voltro-rendered-by": "plain-not-found"
1000
+ }),
1001
+ body: "not found"
1002
+ };
1003
+ }
1004
+ let g = X.get(h.route.pattern), ne = n["x-tenant"] ?? "anonymous", v = (await Y.getHelpers()).i18n?.resolve(n.cookie, n["accept-language"])?.locale, y = Ne(i, {
1005
+ ...g?.tenantAware ? { tenant: ne } : {},
1006
+ ...v ? { locale: v } : {}
1007
+ }), b = g?.ppr === !0 && g.renderMode === "isr", S = (r, a) => ({
1008
+ status: 200,
1009
+ headers: {},
1010
+ body: "",
1011
+ stream: (o) => {
1012
+ l().shellServes += 1, o.writeHead(200, {
1013
+ "content-type": "text/html; charset=utf-8",
1014
+ "x-voltro-rendered-by": "isr",
1015
+ "x-voltro-ppr": "shell+holes",
1016
+ ...a
1017
+ }), o.write(r), (async () => {
1018
+ try {
1019
+ let r = await ht({
1020
+ provider: Y,
1021
+ root: t,
1022
+ route: h.route,
1023
+ params: h.params,
1024
+ pathname: i,
1025
+ dirs: K,
1026
+ shellTemplate: et.get(h.route.pattern) ?? A,
1027
+ requestHeaders: n,
1028
+ apiOrigin: I,
1029
+ apiName: L,
1030
+ middlewares: B,
1031
+ onCookieWarning: z,
1032
+ requestUrl: e,
1033
+ holesOnly: !0
1034
+ });
1035
+ r !== null && "holes" in r ? await _e({
1036
+ loader: r.holes.loader,
1037
+ ctx: r.holes.ctx,
1038
+ res: o,
1039
+ helpers: r.holes.helpers,
1040
+ page: r.holes.page,
1041
+ log: Q
1042
+ }) : o.writableEnded || o.end();
1043
+ } catch (e) {
1044
+ Q.warn("ppr hole pass failed", { url: i }, e), o.writableEnded || o.end();
1045
+ }
1046
+ })();
1047
+ }
1048
+ }), C = V.get(y), w = Date.now();
1049
+ if (C && Pe(C, w)) return d.emit("cache", {
1050
+ kind: "HIT",
1051
+ key: y,
1052
+ ageMs: w - C.renderedAt
1053
+ }), b ? S(C.html, {
1054
+ "x-voltro-cache": "HIT",
1055
+ "x-voltro-cache-key": y,
1056
+ "x-voltro-cache-age-ms": String(w - C.renderedAt)
1057
+ }) : {
1058
+ status: 200,
1059
+ headers: {
1060
+ "content-type": "text/html; charset=utf-8",
1061
+ "x-voltro-rendered-by": "isr",
1062
+ "x-voltro-cache": "HIT",
1063
+ "x-voltro-cache-key": y,
1064
+ "x-voltro-cache-age-ms": String(w - C.renderedAt)
1065
+ },
1066
+ body: C.html
1067
+ };
1068
+ if (C && je(C, w)) {
1069
+ d.emit("cache", {
1070
+ kind: "STALE",
1071
+ key: y,
1072
+ ageMs: w - C.renderedAt
1073
+ });
1074
+ let r = V.generation(y);
1075
+ return (async () => {
1076
+ try {
1077
+ let a = await ht({
1078
+ provider: Y,
1079
+ root: t,
1080
+ route: h.route,
1081
+ params: h.params,
1082
+ pathname: i,
1083
+ dirs: K,
1084
+ shellTemplate: et.get(h.route.pattern) ?? A,
1085
+ requestHeaders: n,
1086
+ apiOrigin: I,
1087
+ apiName: L,
1088
+ middlewares: B,
1089
+ onCookieWarning: z,
1090
+ requestUrl: e,
1091
+ buffered: !0
1092
+ });
1093
+ if (a && "html" in a && a.renderMode === "isr" && a.revalidateMs !== null) {
1094
+ let e = X.get(h.route.pattern)?.staleWhileRevalidateMs ?? 0, t = Date.now();
1095
+ V.set(y, {
1096
+ html: a.html,
1097
+ renderedAt: t,
1098
+ expiresAt: t + a.revalidateMs,
1099
+ servableUntil: t + a.revalidateMs + e,
1100
+ revalidateMs: a.revalidateMs,
1101
+ staleWhileRevalidateMs: e
1102
+ }, { ifGeneration: r }) || Q.info("SWR refresh discarded — the entry was purged while it rendered", { key: y });
1103
+ }
1104
+ } catch (e) {
1105
+ Q.warn("background SWR refresh failed", { url: i }, e);
1106
+ }
1107
+ })(), b ? S(C.html, {
1108
+ "x-voltro-cache": "STALE",
1109
+ "x-voltro-cache-key": y,
1110
+ "x-voltro-cache-age-ms": String(w - C.renderedAt)
1111
+ }) : {
1112
+ status: 200,
1113
+ headers: {
1114
+ "content-type": "text/html; charset=utf-8",
1115
+ "x-voltro-rendered-by": "isr",
1116
+ "x-voltro-cache": "STALE",
1117
+ "x-voltro-cache-key": y,
1118
+ "x-voltro-cache-age-ms": String(w - C.renderedAt)
1119
+ },
1120
+ body: C.html
1121
+ };
1122
+ }
1123
+ try {
1124
+ let r = V.generation(y), a = await ht({
1125
+ provider: Y,
1126
+ root: t,
1127
+ route: h.route,
1128
+ params: h.params,
1129
+ pathname: i,
1130
+ dirs: K,
1131
+ shellTemplate: et.get(h.route.pattern) ?? A,
1132
+ requestHeaders: n,
1133
+ apiOrigin: I,
1134
+ apiName: L,
1135
+ middlewares: B,
1136
+ onCookieWarning: z,
1137
+ requestUrl: e
1138
+ });
1139
+ if (!a) return {
1140
+ status: 200,
1141
+ headers: {
1142
+ "content-type": "text/html; charset=utf-8",
1143
+ "x-voltro-rendered-by": "spa-fallback"
1144
+ },
1145
+ body: A
1146
+ };
1147
+ let o = a.setCookies ?? [], s = a.responseHeaders ?? {}, c = (e) => ({
1148
+ ...s,
1149
+ ...e,
1150
+ ...o.length === 0 ? {} : { "set-cookie": o.map(_) }
1151
+ });
1152
+ if ("stream" in a) return {
1153
+ status: 200,
1154
+ headers: { "x-voltro-rendered-by": a.renderMode },
1155
+ body: "",
1156
+ stream: a.stream
1157
+ };
1158
+ if ("control" in a) return a.control === "redirect" ? {
1159
+ status: a.status,
1160
+ headers: c({
1161
+ location: a.location,
1162
+ "x-voltro-rendered-by": "loader-redirect"
1163
+ }),
1164
+ body: ""
1165
+ } : {
1166
+ status: 404,
1167
+ headers: c({
1168
+ "content-type": "text/plain; charset=utf-8",
1169
+ "x-voltro-rendered-by": "loader-not-found"
1170
+ }),
1171
+ body: "not found"
1172
+ };
1173
+ if ("holes" in a) throw Error("renderPageForRequest returned a holes arm without holesOnly");
1174
+ let l = c({
1175
+ "content-type": "text/html; charset=utf-8",
1176
+ "x-voltro-rendered-by": a.renderMode
1177
+ });
1178
+ if (a.renderMode === "isr" && a.revalidateMs !== null) {
1179
+ let e = Date.now(), t = X.get(h.route.pattern)?.staleWhileRevalidateMs ?? 0;
1180
+ V.set(y, {
1181
+ html: a.html,
1182
+ renderedAt: e,
1183
+ expiresAt: e + a.revalidateMs,
1184
+ servableUntil: e + a.revalidateMs + t,
1185
+ revalidateMs: a.revalidateMs,
1186
+ staleWhileRevalidateMs: t
1187
+ }, { ifGeneration: r }) || Q.info("miss fill discarded — the entry was purged while it rendered", { key: y }), l["x-voltro-cache"] = "MISS", l["x-voltro-cache-key"] = y, l["x-voltro-cache-revalidate-ms"] = String(a.revalidateMs), t > 0 && (l["x-voltro-cache-swr-ms"] = String(t)), d.emit("cache", {
1188
+ kind: "MISS",
1189
+ key: y,
1190
+ revalidateMs: a.revalidateMs,
1191
+ swrMs: t
1192
+ });
1193
+ } else a.renderMode === "isr" && (l["x-voltro-cache"] = "BYPASS", d.emit("cache", {
1194
+ kind: "BYPASS",
1195
+ key: y
1196
+ }));
1197
+ return b && a.renderMode === "isr" ? S(a.html, {
1198
+ "x-voltro-cache": l["x-voltro-cache"] ?? "MISS",
1199
+ "x-voltro-cache-key": y
1200
+ }) : {
1201
+ status: 200,
1202
+ headers: l,
1203
+ body: a.html
1204
+ };
1205
+ } catch (e) {
1206
+ return Q.error("render error", { url: i }, e), M(e) ? {
1207
+ status: 500,
1208
+ headers: {
1209
+ "content-type": "text/plain; charset=utf-8",
1210
+ "x-voltro-rendered-by": "defer-unsupported"
1211
+ },
1212
+ body: e.message
1213
+ } : e instanceof Error && e.name === "PprShellCredentialAccessError" ? {
1214
+ status: 500,
1215
+ headers: {
1216
+ "content-type": "text/plain; charset=utf-8",
1217
+ "x-voltro-rendered-by": "ppr-shell-credential"
1218
+ },
1219
+ body: e.message
1220
+ } : {
1221
+ status: 500,
1222
+ headers: { "content-type": "text/plain" },
1223
+ body: "server error"
1224
+ };
1225
+ }
1226
+ }, Ot = !1, kt = le({
1227
+ apiName: L,
1228
+ apiOrigin: I,
1229
+ loadDescriptors: async () => {
1230
+ if (L === void 0) return;
1231
+ let e = (await Y.getHelpers()).apiDescriptors?.[L];
1232
+ return e === void 0 ? void 0 : await e();
1233
+ },
1234
+ rpcQuery: (e, t) => me(I, e, {
1235
+ apiName: L,
1236
+ headers: t
1237
+ }),
1238
+ renderErrorPage: async ({ path: e, headers: n, flash: r }) => {
1239
+ let { pathname: i } = ie(e), a = pt(i, q);
1240
+ if (!a) return;
1241
+ let o = await ht({
1242
+ provider: Y,
1243
+ root: t,
1244
+ route: a.route,
1245
+ params: a.params,
1246
+ pathname: i,
1247
+ dirs: K,
1248
+ shellTemplate: A,
1249
+ requestHeaders: n,
1250
+ apiOrigin: I,
1251
+ apiName: L,
1252
+ middlewares: B,
1253
+ onCookieWarning: z,
1254
+ requestUrl: e,
1255
+ formFlash: r,
1256
+ buffered: !0
1257
+ });
1258
+ return o !== null && "html" in o ? o.html : void 0;
1259
+ }
1260
+ }), At = qe(async (e, t) => {
1261
+ let n = e.url ?? "/", r = Date.now(), i = {};
1262
+ for (let [t, n] of Object.entries(e.headers)) n !== void 0 && (i[t.toLowerCase()] = Array.isArray(n) ? n.join(", ") : n);
1263
+ let o = n.split("?")[0] ?? "/", s = (e.method ?? "GET").toUpperCase();
1264
+ if (o === "/internal/liveness") {
1265
+ t.writeHead(200, {
1266
+ "content-type": "text/plain",
1267
+ "cache-control": "no-store"
1268
+ }), t.end("ok");
1269
+ return;
1270
+ }
1271
+ if (o === "/internal/readiness") {
1272
+ let e = Ot ? 200 : 503;
1273
+ t.writeHead(e, {
1274
+ "content-type": "text/plain",
1275
+ "cache-control": "no-store"
1276
+ }), t.end(Ot ? "ready" : "not-ready");
1277
+ return;
1278
+ }
1279
+ if (!(o.startsWith(g) && await kt(e, t))) {
1280
+ if (s === "OPTIONS" && o.startsWith("/_voltro/inspect")) {
1281
+ let e = R(i.origin);
1282
+ t.writeHead(204, e), t.end();
1283
+ return;
1284
+ }
1285
+ if (a.name === "voltroDashboard" && o === "/api/dashboard/proxy") {
1286
+ let r = new URL(n, "http://x").searchParams.get("target");
1287
+ if (!r) {
1288
+ t.writeHead(400, { "content-type": "text/plain" }), t.end("missing ?target=");
1289
+ return;
1290
+ }
1291
+ if (!Ee(r)) {
1292
+ t.writeHead(400, { "content-type": "text/plain" }), t.end("target not allowed: must be loopback or an origin configured in VOLTRO_DASHBOARD_APPS");
1293
+ return;
1294
+ }
1295
+ try {
1296
+ let n = { accept: i.accept ?? "application/json" }, a = i.authorization;
1297
+ a ? n.authorization = Array.isArray(a) ? a[0] : a : Te(r) && process.env.VOLTRO_INSPECT_TOKEN && (n.authorization = `Bearer ${process.env.VOLTRO_INSPECT_TOKEN}`);
1298
+ let o;
1299
+ if (s && s !== "GET" && s !== "HEAD") {
1300
+ let t = [];
1301
+ for await (let n of e) t.push(n);
1302
+ o = Buffer.concat(t);
1303
+ let r = i["content-type"];
1304
+ r && (n["content-type"] = Array.isArray(r) ? r[0] : r);
1305
+ }
1306
+ let c = await fetch(r, {
1307
+ redirect: "manual",
1308
+ method: s,
1309
+ headers: n,
1310
+ ...o ? { body: new Uint8Array(o.buffer, o.byteOffset, o.byteLength) } : {}
1311
+ }), l = Buffer.from(await c.arrayBuffer());
1312
+ t.writeHead(c.status, {
1313
+ "content-type": c.headers.get("content-type") ?? "application/octet-stream",
1314
+ "content-length": String(l.length)
1315
+ }), t.end(l);
1316
+ } catch (e) {
1317
+ t.writeHead(502, { "content-type": "text/plain" }), t.end(`proxy error: ${e.message}`);
1318
+ }
1319
+ return;
1320
+ }
1321
+ if (a.name === "voltroDashboard" && o === "/api/dashboard/proxy/stream") {
1322
+ let r = new URL(n, "http://x").searchParams.get("target");
1323
+ if (!r) {
1324
+ t.writeHead(400, { "content-type": "text/plain" }), t.end("missing ?target=");
1325
+ return;
1326
+ }
1327
+ if (!Ee(r)) {
1328
+ t.writeHead(400, { "content-type": "text/plain" }), t.end("target not allowed: must be loopback or an origin configured in VOLTRO_DASHBOARD_APPS");
1329
+ return;
1330
+ }
1331
+ let a = new AbortController();
1332
+ e.on("close", () => a.abort()), t.on("close", () => a.abort());
1333
+ try {
1334
+ let e = i.authorization ?? (Te(r) && process.env.VOLTRO_INSPECT_TOKEN ? `Bearer ${process.env.VOLTRO_INSPECT_TOKEN}` : void 0), n = await fetch(r, {
1335
+ redirect: "manual",
1336
+ method: "GET",
1337
+ headers: {
1338
+ accept: "text/event-stream",
1339
+ ...e ? { authorization: Array.isArray(e) ? e[0] : e } : {}
1340
+ },
1341
+ signal: a.signal
1342
+ });
1343
+ if (!n.ok || !n.body) {
1344
+ t.writeHead(n.status, { "content-type": "text/plain" }), t.end(`upstream ${n.status}`);
1345
+ return;
1346
+ }
1347
+ t.writeHead(200, {
1348
+ "content-type": "text/event-stream; charset=utf-8",
1349
+ "cache-control": "no-cache, no-transform",
1350
+ connection: "keep-alive",
1351
+ "x-accel-buffering": "no"
1352
+ }), t.flushHeaders();
1353
+ let o = n.body.getReader();
1354
+ try {
1355
+ for (;;) {
1356
+ let { done: e, value: n } = await o.read();
1357
+ if (e) break;
1358
+ n && t.write(Buffer.from(n));
1359
+ }
1360
+ } finally {
1361
+ o.releaseLock(), t.end();
1362
+ }
1363
+ } catch (e) {
1364
+ e.name !== "AbortError" && (t.writeHead(502, { "content-type": "text/plain" }), t.end(`proxy stream error: ${e.message}`));
1365
+ }
1366
+ return;
1367
+ }
1368
+ if (o === "/_voltro/inspect/stream") {
1369
+ let n = R(i.origin);
1370
+ if (Se()) {
1371
+ t.writeHead(503, {
1372
+ "content-type": "application/json",
1373
+ ...n
1374
+ }), t.end(JSON.stringify({ error: "inspect disabled (VOLTRO_INSPECT=off)" }));
1375
+ return;
1376
+ }
1377
+ let r = Ce(i, "GET");
1378
+ if (!r.ok) {
1379
+ t.writeHead(401, {
1380
+ "content-type": "application/json",
1381
+ ...n
1382
+ }), t.end(JSON.stringify({
1383
+ error: "unauthorized",
1384
+ reason: r.reason
1385
+ }));
1386
+ return;
1387
+ }
1388
+ t.writeHead(200, {
1389
+ "content-type": "text/event-stream; charset=utf-8",
1390
+ "cache-control": "no-cache, no-transform",
1391
+ connection: "keep-alive",
1392
+ "x-accel-buffering": "no",
1393
+ ...n
1394
+ }), t.flushHeaders(), t.write("retry: 5000\n\n");
1395
+ for (let e of d.buffered()) t.write(D(e));
1396
+ let a = d.subscribe((e) => {
1397
+ t.write(D(e));
1398
+ }), o = setInterval(() => {
1399
+ t.write(pe());
1400
+ }, 15e3), s = () => {
1401
+ clearInterval(o), a();
1402
+ };
1403
+ e.on("close", s), t.on("close", s);
1404
+ return;
1405
+ }
1406
+ try {
1407
+ let e = await Dt(n, i);
1408
+ if (e.stream ? e.stream(t) : Ye({
1409
+ response: t,
1410
+ status: e.status,
1411
+ headers: e.headers,
1412
+ body: e.body,
1413
+ requestHeaders: i,
1414
+ compression: he.compression
1415
+ }) || (t.writeHead(e.status, e.headers), t.end(e.body)), !o.startsWith("/_voltro/inspect")) {
1416
+ let t = Date.now() - r;
1417
+ d.emit("request", {
1418
+ url: o,
1419
+ status: e.status,
1420
+ durationMs: t,
1421
+ renderedBy: e.headers["x-voltro-rendered-by"],
1422
+ cache: e.headers["x-voltro-cache"]
1423
+ });
1424
+ let n = pt(o, q)?.route.pattern ?? (e.status === 404 ? "<unmatched>" : "<asset>");
1425
+ St.record({
1426
+ kind: "request",
1427
+ tag: n,
1428
+ durationMs: t,
1429
+ status: e.status >= 500 ? "error" : "ok"
1430
+ });
1431
+ }
1432
+ } catch (e) {
1433
+ t.writeHead(500, { "content-type": "text/plain" }), t.end(`internal error: ${e.message}`);
1434
+ }
1435
+ }
1436
+ });
1437
+ await new Promise((e) => At.listen(h, "::", e)), Ot = !0, i.mark("ready"), Q.info(`listening on http://localhost:${h}`, {
1438
+ port: h,
1439
+ distDir: x
1440
+ }), Q.debug("dynamic + ssr/isr routes resolve via SSR loader");
1441
+ try {
1442
+ await Fe({
1443
+ id: O,
1444
+ name: E,
1445
+ kind: "web",
1446
+ url: `http://localhost:${h}`,
1447
+ pid: process.pid,
1448
+ status: "live",
1449
+ logFile: k.path
1450
+ });
1451
+ let e = P(t);
1452
+ if (e) {
1453
+ let t = await f({ dashboardAppPath: e });
1454
+ t.status === "launched" ? Q.info(`dashboard launched at http://localhost:${t.port}`, { port: t.port }) : t.status === "already-running" && Q.debug(`dashboard already running on :${t.port}`, { port: t.port });
1455
+ }
1456
+ setInterval(() => {
1457
+ Fe({
1458
+ id: O,
1459
+ name: E,
1460
+ kind: "web",
1461
+ url: `http://localhost:${h}`,
1462
+ pid: process.pid,
1463
+ status: "live",
1464
+ logFile: k.path
1465
+ }).catch(() => {});
1466
+ }, 1e4).unref();
1467
+ } catch (e) {
1468
+ Q.warn("runtime-registry write failed", {}, e);
1469
+ }
1470
+ Ue({
1471
+ app: a.name ?? "unnamed",
1472
+ kind: "web",
1473
+ url: `http://localhost:${h}`,
1474
+ bootMs: i.total()
1475
+ });
1476
+ let jt = i.phaseBreakdown();
1477
+ Q.info(`start: ready in ${i.total()}ms`, {
1478
+ bootMs: i.total(),
1479
+ ...jt ? { phases: jt } : {}
1480
+ });
1481
+ let Mt = !1, Nt = (e) => async () => {
1482
+ if (!Mt) {
1483
+ if (Mt = !0, Q.info(`received ${e}, shutting down`, { signal: e }), At.close(), await vt.stop(), bt) try {
1484
+ bt();
1485
+ } catch {}
1486
+ if (xt) try {
1487
+ await We.runPromise(xt.close());
1488
+ } catch {}
1489
+ if (H) try {
1490
+ await H.end();
1491
+ } catch {}
1492
+ await Y.close(), await Le(O), await k.dispose(), process.exit(0);
1493
+ }
1494
+ };
1495
+ process.on("SIGINT", Nt("SIGINT")), process.on("SIGTERM", Nt("SIGTERM"));
1496
+ let Pt = process.ppid;
1497
+ if (Pt > 1) {
1498
+ let e = setInterval(() => {
1499
+ (process.ppid !== Pt || process.ppid === 1) && (clearInterval(e), Nt("SIGTERM")());
1500
+ }, 2e3);
1501
+ e.unref();
1502
+ }
1503
+ return new Promise(() => {});
1504
+ }, yt = async (e) => {
1505
+ t("start");
1506
+ let n = e.find((e) => !e.startsWith("-")) ?? process.cwd(), r = await vt(Ve(n));
1507
+ return r.ran ? r.exitCode : (Q.error("no web app found at this path"), 1);
1508
+ };
1509
+ //#endregion
1510
+ export { vt as n, yt as t };