@voltro/cli 0.51.0 → 0.52.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 (164) hide show
  1. package/CHANGELOG.md +127 -0
  2. package/dist/{agentsMd-D6yD7IQv.js → agentsMd-0l980yhL.js} +4 -1
  3. package/dist/agentsMd-SDDSkyl4.js +2 -0
  4. package/dist/apiBuild-BYBpL7Pz.js +2 -0
  5. package/dist/{apiBuild-CPDHXF72.js → apiBuild-CSFI8QGq.js} +3 -3
  6. package/dist/bin.js +1 -1
  7. package/dist/build-CPgcMQug.js +793 -0
  8. package/dist/checkCommand-2SbqzukH.js +2 -0
  9. package/dist/{checkCommand-DNuPiWMc.js → checkCommand-COmqc2cB.js} +92 -46
  10. package/dist/{cloudCmd-F4YJeqM3.js → cloudCmd-QUXh-b5w.js} +1 -1
  11. package/dist/codegen-CctkDO-1.js +2 -0
  12. package/dist/{codegen-CrMXs4hb.js → codegen-VF479Cnb.js} +1 -1
  13. package/dist/{codegenCommand-BNBHcNNj.js → codegenCommand-DCdG2JN-.js} +12 -12
  14. package/dist/{codemodRunner-BDVixlSw.js → codemodRunner-r7J9lIa7.js} +588 -540
  15. package/dist/{commands-B1OiS9bX.js → commands-Cc_nV8WI.js} +35 -35
  16. package/dist/{dashboardCommand-C-vvPY1B.js → dashboardCommand-C-gKvwqh.js} +5 -5
  17. package/dist/{dataCommand-C1GxXW5q.js → dataCommand-BgpBHnlB.js} +27 -27
  18. package/dist/dbCommand-DNb6yeOG.js +2 -0
  19. package/dist/{dbCommand-If4Y1xQ-.js → dbCommand-sHedr-NJ.js} +2 -2
  20. package/dist/dev--A3nsxA3.js +3 -0
  21. package/dist/{dev-kdAg9Q7l.js → dev-CRHoCEiy.js} +2142 -2103
  22. package/dist/doctorCommand-CqoWA2p5.js +2 -0
  23. package/dist/{doctorCommand-nKmeW78u.js → doctorCommand-DtfJ3FA6.js} +314 -234
  24. package/dist/{dormancyCommand-CY3wa_SW.js → dormancyCommand-Drn7o0No.js} +1 -1
  25. package/dist/{embeddingsCommand-BDLIgje_.js → embeddingsCommand-Z-jO1fWN.js} +1 -1
  26. package/dist/{envCommand-C6V_xVlT.js → envCommand-D4gCrrTZ.js} +8 -8
  27. package/dist/{evolveCommand-D3c4DSfN.js → evolveCommand-CMROeKeA.js} +2 -2
  28. package/dist/fileConventions-DOqD3lPS.js +34 -0
  29. package/dist/{fileTaxonomy-CJfgOllU.js → fileTaxonomy-DvDUV9wq.js} +1 -1
  30. package/dist/frameworkTableAssembly-C6ETawPR.js +2 -0
  31. package/dist/{frameworkTableAssembly-BwJVEKLr.js → frameworkTableAssembly-w-XnLa3q.js} +1 -1
  32. package/dist/index.js +1 -1
  33. package/dist/{infoCommand-BnRFEF1o.js → infoCommand-DXM868o_.js} +1 -1
  34. package/dist/inspectMetrics-CGF94puw.js +143 -0
  35. package/dist/{metaCommands-CfRLra0s.js → metaCommands-C6RFmF1r.js} +2 -2
  36. package/dist/{migrate-DehuBakM.js → migrate-D0F-eTlK.js} +2 -2
  37. package/dist/{pageConvention-cEiRxdab.js → pageConvention-CzUiSbtU.js} +1 -1
  38. package/dist/{privacyCommand-XejDMvmu.js → privacyCommand-DGdopOI6.js} +1 -1
  39. package/dist/{projectScaffold-mIX_DpSe.js → projectScaffold-B4dmTlwT.js} +1 -1
  40. package/dist/{projectScaffold-BIl97_E6.js → projectScaffold-EzlErR4E.js} +1 -1
  41. package/dist/{renderModeScan-D7J1B7Kw.js → renderModeScan-CcH2X1_D.js} +25 -10
  42. package/dist/{renderProfile-1OWWAAtx.js → renderProfile-Ck32Fzxr.js} +2 -2
  43. package/dist/{runtimeTrace-ZsBU7Tkx.js → runtimeTrace-BPQyCmC5.js} +1 -1
  44. package/dist/{sdkgen-O4XqWOjM.js → sdkgen-Se88ifTd.js} +1 -1
  45. package/dist/serveCommand-DLc-BznW.js +2 -0
  46. package/dist/{serveCommand-DdiYNBBu.js → serveCommand-DkP3OT0W.js} +885 -868
  47. package/dist/serveEntry.js +1 -1
  48. package/dist/start-DfL3fOiN.js +3 -0
  49. package/dist/start-jw89Xbqy.js +1339 -0
  50. package/dist/startEntry.js +1 -1
  51. package/dist/{staticCommand-Dr2M6tpU.js → staticCommand-BwNEDlSU.js} +1 -1
  52. package/dist/{test-rXFq4S76.js → test-f3amja6a.js} +1 -1
  53. package/dist/updateCommand-5gFVfK5q.js +2 -0
  54. package/dist/{updateCommand-Bs322Q78.js → updateCommand-BMk2e4ky.js} +1 -1
  55. package/dist/{webDev-B-ubQEMX.js → webDev-BgWL9gKV.js} +1156 -835
  56. package/dist/webDev-CZbTsDcH.js +2 -0
  57. package/dist/{webhooksCommand-FLYY9IXh.js → webhooksCommand-CoIO3jbj.js} +1 -1
  58. package/package.json +30 -17
  59. package/templates/AGENTS.core.md +11 -0
  60. package/templates/AGENTS.md +15 -4
  61. package/templates/agent-docs/_index.md +4 -4
  62. package/templates/agent-docs/_manifest.json +11 -11
  63. package/templates/agent-docs/cli.md +96 -14
  64. package/templates/agent-docs/data.md +210 -7
  65. package/templates/agent-docs/database/schema.md +1 -1
  66. package/templates/agent-docs/database/seedsdialects.md +1 -1
  67. package/templates/agent-docs/deployment.md +22 -3
  68. package/templates/agent-docs/introduction.md +46 -0
  69. package/templates/agent-docs/local-first-mobile.md +34 -7
  70. package/templates/agent-docs/plugins/ai-flows.md +1 -1
  71. package/templates/agent-docs/plugins/audit.md +5 -5
  72. package/templates/agent-docs/plugins/cdc-out.md +2 -2
  73. package/templates/agent-docs/plugins/{versioning.md → row-history.md} +22 -22
  74. package/templates/agent-docs/plugins/storage.md +2 -2
  75. package/templates/agent-docs/plugins.md +29 -7
  76. package/templates/agent-docs/reference.md +39 -2
  77. package/templates/agent-docs/routing.md +341 -47
  78. package/templates/agent-docs/schema-driven-ui.md +78 -2
  79. package/templates/agent-docs/security.md +125 -8
  80. package/templates/agent-docs/templates/apibackends.md +14 -14
  81. package/templates/agent-docs/templates/overview.md +1 -1
  82. package/templates/agent-docs/whats-new.md +76 -53
  83. package/templates/apps/api-ai/package.json +6 -7
  84. package/templates/apps/api-ai/tests/summarize.test.ts +1 -1
  85. package/templates/apps/api-auth/package.json +8 -8
  86. package/templates/apps/api-backend/package.json +7 -7
  87. package/templates/apps/api-backend-deactivation/package.json +7 -7
  88. package/templates/apps/api-backend-mail/package.json +8 -8
  89. package/templates/apps/api-backend-mariadb/package.json +9 -9
  90. package/templates/apps/api-backend-sqlite/package.json +8 -8
  91. package/templates/apps/api-backend-storage/package.json +8 -8
  92. package/templates/apps/api-cms/package.json +9 -10
  93. package/templates/apps/api-collab/package.json +8 -8
  94. package/templates/apps/api-data-advanced/package.json +8 -8
  95. package/templates/apps/api-durable/package.json +8 -8
  96. package/templates/apps/api-feature-flags/package.json +9 -9
  97. package/templates/apps/api-governance/package.json +8 -8
  98. package/templates/apps/api-kv/package.json +8 -8
  99. package/templates/apps/api-moderation/package.json +8 -8
  100. package/templates/apps/api-observability/package.json +8 -8
  101. package/templates/apps/api-ratelimit/package.json +8 -8
  102. package/templates/apps/api-rbac/package.json +8 -8
  103. package/templates/apps/api-rest/package.json +7 -7
  104. package/templates/apps/{api-versioning → api-row-history}/README.md +3 -3
  105. package/templates/apps/{api-versioning → api-row-history}/actions/documents.asOf.action.server.ts +1 -1
  106. package/templates/apps/{api-versioning → api-row-history}/actions/documents.history.action.server.ts +1 -1
  107. package/templates/apps/{api-versioning → api-row-history}/app.config.ts +3 -3
  108. package/templates/apps/{api-versioning → api-row-history}/database/schema.ts +1 -1
  109. package/templates/apps/{api-versioning → api-row-history}/mutations/documents.create.mutation.server.ts +1 -1
  110. package/templates/apps/{api-versioning → api-row-history}/mutations/documents.create.mutation.ts +1 -1
  111. package/templates/apps/{api-versioning → api-row-history}/mutations/documents.update.mutation.ts +1 -1
  112. package/templates/apps/{api-versioning → api-row-history}/package.json +8 -8
  113. package/templates/apps/api-row-history/template.json +6 -0
  114. package/templates/apps/{api-versioning → api-row-history}/tests/documents.create.test.ts +1 -1
  115. package/templates/apps/api-saas/app.config.ts +1 -0
  116. package/templates/apps/api-saas/package.json +10 -11
  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/package.json +6 -6
  122. package/templates/apps/edge-functions/package.json +2 -2
  123. package/templates/apps/frontend-admin/package.json +8 -8
  124. package/templates/apps/frontend-app/package.json +9 -9
  125. package/templates/apps/frontend-auth/package.json +8 -8
  126. package/templates/apps/frontend-blank/package.json +7 -7
  127. package/templates/apps/frontend-cms/package.json +9 -9
  128. package/templates/apps/frontend-collab/package.json +10 -10
  129. package/templates/apps/frontend-collab/src/pages/page.test.tsx +10 -9
  130. package/templates/apps/frontend-collab/src/pages/page.tsx +42 -65
  131. package/templates/apps/frontend-contact/package.json +7 -7
  132. package/templates/apps/frontend-dashboard/package.json +7 -7
  133. package/templates/apps/frontend-docs/package.json +6 -7
  134. package/templates/apps/frontend-i18n/package.json +6 -6
  135. package/templates/apps/frontend-landing/package.json +6 -7
  136. package/templates/apps/frontend-portal/package.json +8 -8
  137. package/templates/apps/frontend-saas/package.json +8 -8
  138. package/templates/apps/frontend-spa/package.json +7 -7
  139. package/templates/apps/frontend-ssr/package.json +7 -7
  140. package/templates/apps/frontend-ssr-api/package.json +8 -8
  141. package/templates/apps/frontend-static-blog/package.json +6 -6
  142. package/templates/apps/frontend-status/package.json +8 -8
  143. package/templates/apps/mobile-app/package.json +4 -4
  144. package/dist/agentsMd-Bu_XQgVf.js +0 -2
  145. package/dist/apiBuild-GDKuGOMV.js +0 -2
  146. package/dist/build-DETLZAFt.js +0 -752
  147. package/dist/checkCommand-CWcnDArJ.js +0 -2
  148. package/dist/codegen-DiMn2KkZ.js +0 -2
  149. package/dist/dbCommand-C27HIsGE.js +0 -2
  150. package/dist/dev-CK522MV5.js +0 -3
  151. package/dist/doctorCommand-BK4l18eG.js +0 -2
  152. package/dist/fileConventions-Cof68_BL.js +0 -33
  153. package/dist/frameworkTableAssembly-CVDB2hCq.js +0 -2
  154. package/dist/inspectMetrics-CfdKLh6t.js +0 -72
  155. package/dist/serveCommand-BRnPCxVd.js +0 -2
  156. package/dist/start-BLNmWkLa.js +0 -1154
  157. package/dist/start-Dzicuyw8.js +0 -3
  158. package/dist/updateCommand-eXB35SEv.js +0 -2
  159. package/dist/webDev-DposiF3j.js +0 -2
  160. package/templates/apps/api-versioning/template.json +0 -6
  161. /package/templates/apps/{api-versioning → api-row-history}/actions/documents.asOf.action.ts +0 -0
  162. /package/templates/apps/{api-versioning → api-row-history}/actions/documents.history.action.ts +0 -0
  163. /package/templates/apps/{api-versioning → api-row-history}/mutations/documents.update.mutation.server.ts +0 -0
  164. /package/templates/apps/{api-versioning → api-row-history}/tsconfig.json +0 -0
@@ -1,1154 +0,0 @@
1
- import { i as e, t } from "./nodeEnvironment-cGFAj1J8.js";
2
- import { r as n } from "./appPort-B_HpJ_ck.js";
3
- import { A as r, B as i, C as a, D as o, E as s, F as c, G as l, H as u, I as d, J as f, L as ee, M as p, N as m, O as te, P as ne, Q as re, R as h, S as g, T as ie, U as _, X as v, Y as y, Z as b, a as x, b as S, d as C, f as w, gt as ae, i as oe, j as T, k as E, n as D, nt as O, rt as k, s as se, x as ce, y as A, yt as j, z as le } from "./webDev-B-ubQEMX.js";
4
- import { o as M, t as N } from "./connectionConfig-Bk9IC7D0.js";
5
- import { A as P, D as F, a as I, h as ue, j as de, k as fe } from "./inspect-CtL_xTbu.js";
6
- import { a as pe, c as me, d as he, f as L, l as ge, p as _e, u as ve } from "./renderModeScan-D7J1B7Kw.js";
7
- import { i as ye, n as be, r as xe, t as Se } from "./runtimeRegistry-DMeKfTHP.js";
8
- import { n as Ce } from "./logFileSink-B4uP8pvf.js";
9
- import { t as we } from "./inspectMetrics-CfdKLh6t.js";
10
- import { t as Te } from "./bootTiming-BdyP9nYw.js";
11
- import { dirname as Ee, extname as De, join as R, resolve as z } from "node:path";
12
- import { promises as B } from "node:fs";
13
- import { fileURLToPath as V, pathToFileURL as H } from "node:url";
14
- import { createLogger as U, printReadyBlock as Oe } from "@voltro/logger";
15
- import { snapshotMetricsSync as ke } from "@voltro/runtime";
16
- import { createServer as Ae } from "node:http";
17
- //#region src/isrCdcInvalidator.ts
18
- var W = U({ scope: "voltro:start:cdc" }), je = (e) => (t) => {
19
- let n = 0;
20
- for (let [r, i] of e.tableSubscriptionsByPattern) {
21
- if (!i.includes(t)) continue;
22
- let a = e.regexByPattern.get(r);
23
- a && (n += e.cache.invalidateBy((e) => {
24
- let t = e.split("|")[0] ?? e;
25
- return a.test(t);
26
- }));
27
- }
28
- return n;
29
- }, G = () => N() ? M() : null, Me = (e) => {
30
- let t = e.channel ?? "framework_changes", n = je(e), r = null, i = null;
31
- return {
32
- start: async () => {
33
- if (e.tableSubscriptionsByPattern.size === 0) {
34
- W.debug("skipped — no pages declare cacheInvalidatesOn");
35
- return;
36
- }
37
- let a = G();
38
- if (!a) {
39
- W.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()] });
40
- return;
41
- }
42
- r = new (await (import("pg"))).default.Client(a), await r.connect(), i = (e) => {
43
- if (e.channel !== t || !e.payload) return;
44
- let r;
45
- try {
46
- r = JSON.parse(e.payload);
47
- } catch (e) {
48
- W.warn("bad CDC payload", {}, e);
49
- return;
50
- }
51
- let i = n(r.table);
52
- i > 0 && W.info(`${r.op} on '${r.table}' → dropped ${i} cache entries`, {
53
- op: r.op,
54
- table: r.table,
55
- dropped: i
56
- });
57
- }, r.on("notification", i), await r.query(`LISTEN ${t}`), W.info(`LISTEN ${t}`, {
58
- channel: t,
59
- ..."connectionString" in a ? { target: a.connectionString.replace(/\/\/[^@/]*@/, "//") } : {
60
- host: a.host,
61
- port: a.port,
62
- database: a.database
63
- }
64
- });
65
- },
66
- stop: async () => {
67
- if (r) {
68
- try {
69
- i && r.off("notification", i), await r.end();
70
- } catch {}
71
- r = null, i = null;
72
- }
73
- }
74
- };
75
- }, K = U({ scope: "voltro:start:isr-cache" }), q = "voltro_isr_cache", Ne = (e) => `
76
- CREATE TABLE IF NOT EXISTS ${e} (
77
- cache_key TEXT PRIMARY KEY,
78
- html TEXT NOT NULL,
79
- rendered_at BIGINT NOT NULL,
80
- expires_at BIGINT NOT NULL,
81
- servable_until BIGINT NOT NULL,
82
- revalidate_ms BIGINT NOT NULL,
83
- stale_while_revalidate_ms BIGINT NOT NULL DEFAULT 0
84
- );
85
- CREATE INDEX IF NOT EXISTS ${e}_servable_until_idx ON ${e} (servable_until);
86
- `, Pe = (e) => {
87
- let t = e.tableName ?? q, { client: n } = e, r = /* @__PURE__ */ new Map(), i = !1, a = (async () => {
88
- i || (i = !0, await n.query(Ne(t)));
89
- })().then(async () => {
90
- let e = await n.query(`SELECT * FROM ${t}`);
91
- for (let t of e.rows) r.set(t.cache_key, {
92
- html: t.html,
93
- renderedAt: Number(t.rendered_at),
94
- expiresAt: Number(t.expires_at),
95
- servableUntil: Number(t.servable_until),
96
- revalidateMs: Number(t.revalidate_ms),
97
- staleWhileRevalidateMs: Number(t.stale_while_revalidate_ms)
98
- });
99
- }).catch((e) => {
100
- K.warn("postgres bootstrap failed", {}, e);
101
- }), o = (e, t) => {
102
- a.then(() => n.query(e, t)).catch((e) => {
103
- K.warn("postgres write failed", {}, e);
104
- });
105
- };
106
- return {
107
- get(e) {
108
- return r.get(e);
109
- },
110
- set(e, n) {
111
- r.set(e, n), o(`INSERT INTO ${t}
112
- (cache_key, html, rendered_at, expires_at, servable_until, revalidate_ms, stale_while_revalidate_ms)
113
- VALUES ($1, $2, $3, $4, $5, $6, $7)
114
- ON CONFLICT (cache_key) DO UPDATE SET
115
- html = EXCLUDED.html,
116
- rendered_at = EXCLUDED.rendered_at,
117
- expires_at = EXCLUDED.expires_at,
118
- servable_until = EXCLUDED.servable_until,
119
- revalidate_ms = EXCLUDED.revalidate_ms,
120
- stale_while_revalidate_ms = EXCLUDED.stale_while_revalidate_ms`, [
121
- e,
122
- n.html,
123
- n.renderedAt,
124
- n.expiresAt,
125
- n.servableUntil,
126
- n.revalidateMs,
127
- n.staleWhileRevalidateMs
128
- ]);
129
- },
130
- invalidate(e) {
131
- r.delete(e), o(`DELETE FROM ${t} WHERE cache_key = $1`, [e]);
132
- },
133
- invalidateBy(e) {
134
- let n = 0, i = [];
135
- for (let t of r.keys()) e(t) && (r.delete(t), i.push(t), n++);
136
- return i.length > 0 && o(`DELETE FROM ${t} WHERE cache_key = ANY($1)`, [i]), n;
137
- },
138
- clear() {
139
- r.clear(), o(`DELETE FROM ${t}`, []);
140
- },
141
- size() {
142
- return r.size;
143
- },
144
- snapshot() {
145
- return Array.from(r.entries());
146
- }
147
- };
148
- }, J = U({ scope: "voltro:start" }), Fe = await (async () => {
149
- try {
150
- let e = R(Ee(V(import.meta.url)), "..", "package.json"), t = await B.readFile(e, "utf8");
151
- return JSON.parse(t).version ?? "0.0.0";
152
- } catch {
153
- return "0.0.0";
154
- }
155
- })(), Y = (e) => e instanceof Error && e._voltroControl === "redirect" && typeof e.location == "string", Ie = (e) => e instanceof Error && e._voltroControl === "not-found", X = {
156
- ".html": "text/html; charset=utf-8",
157
- ".js": "application/javascript",
158
- ".mjs": "application/javascript",
159
- ".css": "text/css",
160
- ".json": "application/json",
161
- ".xml": "application/xml; charset=utf-8",
162
- ".rss": "application/rss+xml; charset=utf-8",
163
- ".atom": "application/atom+xml; charset=utf-8",
164
- ".svg": "image/svg+xml",
165
- ".png": "image/png",
166
- ".jpg": "image/jpeg",
167
- ".jpeg": "image/jpeg",
168
- ".webp": "image/webp",
169
- ".ico": "image/x-icon",
170
- ".woff": "font/woff",
171
- ".woff2": "font/woff2",
172
- ".txt": "text/plain; charset=utf-8"
173
- }, Le = (e) => X[De(e).toLowerCase()] ?? "application/octet-stream", Re = (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) => {
174
- try {
175
- return await B.stat(e), !0;
176
- } catch {
177
- return !1;
178
- }
179
- }, Q = (e) => {
180
- let t = [], n = 0, r = e.split("/").filter(Boolean), i = [];
181
- 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, "\\$&"));
182
- let a = i.join("/");
183
- return {
184
- regex: a.length === 0 ? /^\/?$/ : RegExp(`^/${a}/?$`),
185
- paramNames: t,
186
- priority: n
187
- };
188
- }, ze = (e) => e.map((e) => {
189
- let { regex: t, paramNames: n, priority: r } = Q(e.pattern);
190
- return {
191
- pattern: e.pattern,
192
- file: e.file,
193
- dirChain: e.dirChain,
194
- regex: t,
195
- paramNames: n,
196
- priority: r
197
- };
198
- }).slice().sort((e, t) => e.priority - t.priority), Be = (e, t) => {
199
- for (let n of t) {
200
- let t = n.regex.exec(e);
201
- if (!t) continue;
202
- let r = {};
203
- for (let e = 0; e < n.paramNames.length; e++) r[n.paramNames[e]] = t[e + 1] ?? "";
204
- return {
205
- route: n,
206
- params: r
207
- };
208
- }
209
- return null;
210
- }, Ve = async (e) => {
211
- let { provider: t, route: n, params: i, pathname: a, dirs: l, shellTemplate: u, requestHeaders: f, requestUrl: te = "", apiOrigin: ne, apiName: re } = e, { search: _ } = le(te), v = await s(o(e.middlewares ?? [], {
212
- route: n.pattern,
213
- pathname: a
214
- }), {
215
- pathname: a,
216
- search: _,
217
- headers: f,
218
- cookies: ie(f.cookie),
219
- route: n.pattern
220
- }, e.onCookieWarning), y = v.headers, b = oe(ne, y.cookie, {
221
- apiName: re,
222
- headers: y
223
- }), S = await t.getPage(n.pattern, n.file), C = me(S, n.file), w = C === "spa" && se(l, n.dirChain).some((e) => e.hasLayout);
224
- if (C !== "ssr" && C !== "isr" && !w) return null;
225
- let ae = se(l, n.dirChain), D = {}, O = null, k, ce = new AbortController();
226
- try {
227
- (await t.getHelpers()).beginStoreSeeds(), {chain: k, segmentLoaderData: D} = await x({
228
- entries: ae,
229
- loadLayout: (e) => t.getLayout(e.dir),
230
- loadError: (e) => t.getError(e.dir),
231
- loadPending: (e) => t.getPending(e.dir),
232
- ctx: {
233
- params: i,
234
- pathname: a,
235
- search: _,
236
- signal: ce.signal,
237
- headers: y,
238
- query: b,
239
- isServer: !0
240
- }
241
- }), typeof S.loader == "function" && !w && (O = await S.loader({
242
- params: i,
243
- pathname: a,
244
- search: _,
245
- signal: ce.signal,
246
- headers: y,
247
- query: b,
248
- isServer: !0
249
- }));
250
- } catch (e) {
251
- if (Y(e)) return {
252
- control: "redirect",
253
- status: e.status,
254
- location: e.location,
255
- setCookies: v.setCookies
256
- };
257
- if (Ie(e)) return {
258
- control: "not-found",
259
- setCookies: v.setCookies
260
- };
261
- throw e;
262
- }
263
- let A = await t.getHelpers();
264
- w || await E({
265
- pageMod: S,
266
- params: i,
267
- query: b,
268
- apiName: re,
269
- seed: A.seedPreloadedSubscription,
270
- seedFailure: A.seedPreloadedSubscriptionFailure,
271
- onError: ({ tag: e, apiName: t }, n) => J.warn("preload seed failed", {
272
- tag: e,
273
- apiName: t,
274
- pathname: a
275
- }, n)
276
- });
277
- let j = {
278
- pattern: n.pattern,
279
- Component: S.default,
280
- meta: S.meta,
281
- loader: S.loader,
282
- ErrorBoundary: S.ErrorBoundary,
283
- Pending: S.Pending,
284
- renderMode: C,
285
- chain: k
286
- }, M = {
287
- cookies: v.cookies,
288
- headers: y,
289
- url: te
290
- }, N = A.i18n?.resolve(y.cookie, y["accept-language"]), P = {
291
- lang: N?.locale ?? M.cookies["voltro:locale"] ?? "en",
292
- ...N?.timeZone === void 0 ? {} : { timeZone: N.timeZone },
293
- renderedAt: Date.now()
294
- }, F = S.interactive ?? "full";
295
- if (w) {
296
- let e = d({
297
- helpers: A,
298
- page: n.pattern,
299
- interactive: F,
300
- delivery: "stream",
301
- renderInput: {
302
- descriptor: j,
303
- params: i,
304
- pathname: a,
305
- search: _,
306
- segmentLoaderData: D,
307
- requestContext: M,
308
- ...N ? {
309
- outerWrap: N.outerWrap,
310
- locale: N.locale
311
- } : {}
312
- }
313
- }), t = (t) => h({
314
- helpers: A,
315
- prepared: e,
316
- meta: t,
317
- interactive: F
318
- });
319
- if (e.hasDeferred) {
320
- let n = p({ shell: u });
321
- return {
322
- renderMode: "spa",
323
- setCookies: v.setCookies,
324
- stream: (r) => m({
325
- res: r,
326
- shell: n,
327
- documentAttrs: P,
328
- headers: {
329
- "content-type": "text/html; charset=utf-8",
330
- "x-voltro-rendered-by": "spa",
331
- ...g(v.setCookies)
332
- },
333
- headInjection: t,
334
- render: (t) => A.renderPageToStream({
335
- ...e.renderInput,
336
- ...t
337
- }),
338
- onShellError: (e) => {
339
- J.error("spa layout shell render failed", { pathname: a }, e), r.writeHead(500, { "content-type": "text/plain; charset=utf-8" }), r.end("server error");
340
- }
341
- })
342
- };
343
- }
344
- let o = ee({
345
- helpers: A,
346
- prepared: e
347
- });
348
- return {
349
- html: r(T(u.replace("<div id=\"root\"></div>", `<div id="root">${o.body}</div>`), t(o.meta)), P),
350
- renderMode: "spa",
351
- revalidateMs: null,
352
- setCookies: v.setCookies
353
- };
354
- }
355
- let I = c({
356
- helpers: A,
357
- page: n.pattern,
358
- pathname: a,
359
- renderMode: C,
360
- interactive: F,
361
- loaderData: O,
362
- segmentLoaderData: D,
363
- pageLoaderRan: typeof S.loader == "function"
364
- }), ue = {
365
- descriptor: j,
366
- params: i,
367
- pathname: a,
368
- search: _,
369
- loaderData: I.loaderData,
370
- segmentLoaderData: I.segmentLoaderData,
371
- requestContext: M,
372
- ...N ? {
373
- outerWrap: N.outerWrap,
374
- locale: N.locale
375
- } : {}
376
- }, de = (e) => [
377
- A.renderMetaToHtml(e),
378
- `<meta name="voltro-interactive" content="${F}" />`,
379
- ...I.hasDeferred ? [A.renderDeferredRegistryScript()] : [],
380
- A.renderRouterStateScript(I.stateInput)
381
- ].filter((e) => e.length > 0).join("\n ");
382
- if (C === "ssr" && F === "full" && e.buffered !== !0) {
383
- let e = p({ shell: u });
384
- return {
385
- renderMode: "ssr",
386
- setCookies: v.setCookies,
387
- stream: (t) => m({
388
- res: t,
389
- shell: e,
390
- documentAttrs: P,
391
- headers: {
392
- "content-type": "text/html; charset=utf-8",
393
- "x-voltro-rendered-by": "ssr",
394
- ...g(v.setCookies)
395
- },
396
- headInjection: de,
397
- render: (e) => A.renderPageToStream({
398
- ...ue,
399
- ...e
400
- }),
401
- onShellError: (e) => {
402
- J.error("ssr shell render failed", { pathname: a }, e), t.writeHead(500, { "content-type": "text/plain; charset=utf-8" }), t.end("server error");
403
- }
404
- })
405
- };
406
- }
407
- let { html: fe, meta: pe } = A.renderPageToHtml(ue), he = de(pe), L = r(T(u.replace("<div id=\"root\"></div>", `<div id="root">${fe}</div>`), he), P);
408
- F === "none" && (L = Re(L));
409
- let ge = C === "isr" ? _e(S.revalidate) : null;
410
- return {
411
- html: L,
412
- renderMode: C,
413
- revalidateMs: ge,
414
- setCookies: v.setCookies
415
- };
416
- }, $ = (e) => e === "" ? "/" : e, He = async (e) => {
417
- let t = await import(H(e).href);
418
- return {
419
- kind: "bundle",
420
- getPageMeta: () => t.pageMeta,
421
- async getPage(e, n) {
422
- let r = t.pages[e];
423
- if (!r) throw Error(`[voltro start] ssr bundle missing page for pattern ${e}`);
424
- return typeof r == "function" ? await r() : r;
425
- },
426
- async getLayout(e) {
427
- let n = t.layouts[$(e)];
428
- if (!n) throw Error(`[voltro start] ssr bundle missing layout for dir ${$(e)}`);
429
- return typeof n == "function" ? await n() : n;
430
- },
431
- async getError(e) {
432
- let n = t.errors[$(e)];
433
- if (!n) throw Error(`[voltro start] ssr bundle missing error for dir ${$(e)}`);
434
- return typeof n == "function" ? await n() : n;
435
- },
436
- async getPending(e) {
437
- let n = t.pendings[$(e)];
438
- if (!n) throw Error(`[voltro start] ssr bundle missing pending for dir ${$(e)}`);
439
- return typeof n == "function" ? await n() : n;
440
- },
441
- async getHelpers() {
442
- return t.helpers;
443
- },
444
- async close() {}
445
- };
446
- }, Ue = async (e, t) => {
447
- let n = await j("vite", () => import("vite")), r = (await import("@vitejs/plugin-react")).default, i = (await import("@tailwindcss/vite")).default, a = await n.createServer({
448
- root: t,
449
- envPrefix: "__VOLTRO_VITE_ENV_DISABLED__",
450
- plugins: [r(), i()],
451
- resolve: { dedupe: [
452
- "react",
453
- "react-dom",
454
- "react-intl",
455
- "@voltro/i18n"
456
- ] },
457
- ssr: { noExternal: ["react-intl", "@voltro/i18n"] },
458
- server: {
459
- middlewareMode: !0,
460
- hmr: !1
461
- },
462
- appType: "custom",
463
- logLevel: "warn"
464
- }), o = R(e, "src", "pages"), s = (e) => e === "" ? o : R(o, e), c = O({
465
- limit: k(),
466
- onColdStart: (e) => J.debug("ssr cold-compile start", { id: e }),
467
- onColdEnd: (e, { durationMs: t, failed: n }) => J.debug(`ssr cold-compile ${n ? "FAILED" : "end"} ${t}ms`, {
468
- id: e,
469
- ms: t,
470
- ...n ? { failed: !0 } : {}
471
- })
472
- }), l = (e) => c.load(e, async () => await a.ssrLoadModule(e));
473
- return {
474
- kind: "middleware",
475
- async getPage(e, t) {
476
- return l(R(o, t));
477
- },
478
- async getLayout(e) {
479
- return l(R(s(e), "layout.tsx"));
480
- },
481
- async getError(e) {
482
- return l(R(s(e), "error.tsx"));
483
- },
484
- async getPending(e) {
485
- return l(R(s(e), "loading.tsx"));
486
- },
487
- async getHelpers() {
488
- return await l("@voltro/web/ssr");
489
- },
490
- async close() {
491
- await a.close();
492
- }
493
- };
494
- }, We = async (t) => {
495
- let r = Te(), c = await C(t);
496
- if (!c) return {
497
- ran: !1,
498
- exitCode: 0
499
- };
500
- if (c.type !== "web") return J.error("only web apps are supported by `voltro start`"), {
501
- ran: !0,
502
- exitCode: 1
503
- };
504
- let { resolved: d } = await ae({
505
- rawEnv: c.env,
506
- appType: "web",
507
- root: t,
508
- log: J,
509
- generateTypes: !1
510
- }), ee = d.publicValues;
511
- r.mark("config");
512
- let p = b();
513
- f(p), J.info("booting voltro start", { app: c.name ?? "(unnamed)" });
514
- let m = n({
515
- kind: "web",
516
- configPort: c.port,
517
- env: process.env,
518
- dashboardPin: process.env[i] === "1"
519
- });
520
- for (let e of m.warnings) J.warn(e);
521
- let h = m.port, g = R(t, ".framework"), x = R(g, "dist"), oe = R(x, "index.html");
522
- if (!await Z(oe)) return J.error("no built dist found — run `voltro build` first", { distDir: x }), {
523
- ran: !0,
524
- exitCode: 1
525
- };
526
- let T = c.name ?? "unnamed", E = Se("web", T, h), O = Ce(T);
527
- await ye({
528
- id: E,
529
- name: T,
530
- kind: "web",
531
- url: `http://localhost:${h}`,
532
- pid: process.pid,
533
- status: "booting",
534
- logFile: O.path
535
- }).catch(() => {});
536
- let k = R(x, "_voltro", "shell.html"), j = await Z(k) ? await B.readFile(k, "utf8") : await B.readFile(oe, "utf8"), le = await w(t, c), me = D(le[0]), _e = le[0]?.name, Ee = /* @__PURE__ */ new Set(), De = (e) => {
537
- Ee.has(e.name) || (Ee.add(e.name), J.warn(`middleware.ts wrote the cookie "${e.name}" with the HttpOnly default — a browser SDK cannot read it`, {
538
- cookie: e.name,
539
- 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."
540
- }));
541
- }, z = await a(t);
542
- z.length > 0 && J.info(`middleware.ts loaded — ${z.length} middleware(s): ` + z.map((e) => e.exportName).join(", "));
543
- let V, H = null, U = process.env.SSR_CACHE === "postgres";
544
- if (U && N()) H = new (await (import("pg"))).default.Client(M()), await H.connect(), V = Pe({ client: H }), J.info("isr cache backend: postgres", { table: "voltro_isr_cache" });
545
- else if (U) {
546
- 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).";
547
- if (e()) throw J.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");
548
- V = L(), J.warn(`${t} Falling back to the per-process memory cache — this would be a hard failure in production.`);
549
- } else V = L(), J.info("isr cache backend: memory (per-process)", { hint: "set SSR_CACHE=postgres for persistent storage" });
550
- await S(t, c, le, ee);
551
- let W = R(t, "src", "pages"), { pages: je, dirs: G } = await A(W), K = ze(je);
552
- ce(z, K.map((e) => e.pattern)), r.mark("scan");
553
- let q = R(x, "server", "ssrEntry.js"), Ne = await Z(q);
554
- if (!Ne && process.env.NODE_ENV === "production") throw J.fatal(`production \`voltro start\` requires a precompiled SSR bundle at ${q} 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 ${q}`);
555
- let Y = Ne ? await He(q) : await Ue(t, g);
556
- J.info(`ssr loader: ${Y.kind}`, {
557
- kind: Y.kind,
558
- ...Y.kind === "middleware" ? { hint: "no pre-built SSR bundle found; run `voltro build` to enable bundle mode" } : {}
559
- }), r.mark("provider");
560
- let Ie = Y.getPageMeta?.(), X = /* @__PURE__ */ new Map(), Re = 0;
561
- for (let e of je) {
562
- let t = Ie?.[e.pattern];
563
- if (t) {
564
- X.set(e.pattern, t);
565
- continue;
566
- }
567
- try {
568
- let t = await Y.getPage(e.pattern, e.file);
569
- X.set(e.pattern, pe(t, e.file)), Re++;
570
- } catch (t) {
571
- J.warn("failed to load page metadata", { pattern: e.pattern }, t);
572
- }
573
- }
574
- J.info(`registered ${X.size} route(s)`, {
575
- count: X.size,
576
- fromManifest: X.size - Re,
577
- fromModules: Re
578
- }), r.mark("routes");
579
- let Q = /* @__PURE__ */ new Set();
580
- for (let e of K) X.get(e.pattern)?.renderMode === "spa" && se(G, e.dirChain).some((e) => e.hasLayout) && Q.add(e.pattern);
581
- Q.size > 0 && J.info(`${Q.size} spa route(s) render an SSR layout shell`, { patterns: [...Q] });
582
- let $ = /* @__PURE__ */ new Map();
583
- for (let [e, t] of X) t.cacheInvalidatesOn.length > 0 && $.set(e, t.cacheInvalidatesOn);
584
- let We = /* @__PURE__ */ new Map();
585
- for (let e of K) We.set(e.pattern, e.regex);
586
- let Ge = Me({
587
- cache: V,
588
- tableSubscriptionsByPattern: $,
589
- regexByPattern: We
590
- });
591
- await Ge.start(), r.mark("cdc");
592
- let Ke = we(), qe = je.map((e) => {
593
- let t = X.get(e.pattern);
594
- return {
595
- pattern: e.pattern,
596
- file: e.file,
597
- dirChain: e.dirChain,
598
- renderMode: t?.renderMode ?? "static",
599
- interactive: t?.interactive ?? "full",
600
- tenantAware: t?.tenantAware ?? !1,
601
- revalidateMs: t?.revalidateMs ?? null,
602
- staleWhileRevalidateMs: t?.staleWhileRevalidateMs ?? 0,
603
- cacheInvalidatesOn: t?.cacheInvalidatesOn ?? [],
604
- hasLoader: t?.hasLoader ?? !1,
605
- hasMeta: t?.hasMeta ?? !1,
606
- hasGetStaticPaths: t?.hasGetStaticPaths ?? !1
607
- };
608
- }), Je = G.map((e) => ({
609
- dir: e.dir,
610
- hasLayout: e.hasLayout,
611
- hasError: e.hasError,
612
- hasPending: e.hasPending,
613
- hasNotFound: e.hasNotFound
614
- })), Ye = H ? "postgres" : "memory", Xe = {
615
- kind: "web",
616
- meta: {
617
- name: c.name ?? "(unnamed)",
618
- voltroVersion: Fe,
619
- port: h,
620
- mode: "start",
621
- apis: Object.entries(c.apis ?? {}).map(([e, t]) => {
622
- let n = {
623
- name: e,
624
- package: t.package
625
- };
626
- return t.url !== void 0 && (n.url = t.url), n;
627
- })
628
- },
629
- routes: qe,
630
- dirs: Je,
631
- cache: () => {
632
- let e = Date.now(), t = V.snapshot().map(([t, n]) => ({
633
- key: t,
634
- renderedAt: n.renderedAt,
635
- expiresAt: n.expiresAt,
636
- servableUntil: n.servableUntil,
637
- ageMs: e - n.renderedAt,
638
- htmlBytes: Buffer.byteLength(n.html, "utf8"),
639
- revalidateMs: n.revalidateMs,
640
- staleWhileRevalidateMs: n.staleWhileRevalidateMs
641
- }));
642
- return {
643
- backend: Ye,
644
- size: V.size(),
645
- entries: t
646
- };
647
- },
648
- metrics: () => ke()
649
- }, Ze = async (e, n) => {
650
- let r = e.split("?")[0] ?? "/";
651
- if (c.name === "voltroDashboard" && r === "/api/dashboard/registry") try {
652
- let e = await be();
653
- return {
654
- status: 200,
655
- headers: { "content-type": "application/json; charset=utf-8" },
656
- body: JSON.stringify(e)
657
- };
658
- } catch (e) {
659
- return {
660
- status: 500,
661
- headers: { "content-type": "text/plain" },
662
- body: `registry read error: ${e.message}`
663
- };
664
- }
665
- if (c.name === "voltroDashboard" && r === "/api/dashboard/config") {
666
- let e = process.env.VOLTRO_DASHBOARD_APPS, t = [];
667
- if (e && e.trim().length > 0) {
668
- let n;
669
- try {
670
- n = JSON.parse(e);
671
- } catch (e) {
672
- return {
673
- status: 500,
674
- headers: { "content-type": "text/plain" },
675
- body: `VOLTRO_DASHBOARD_APPS is not valid JSON: ${e.message}`
676
- };
677
- }
678
- for (let e of Array.isArray(n) ? n : []) {
679
- if (typeof e != "object" || !e) continue;
680
- let n = e;
681
- typeof n.url == "string" && n.url.length !== 0 && t.push({
682
- url: n.url,
683
- ...typeof n.name == "string" ? { name: n.name } : {},
684
- ...typeof n.token == "string" ? { token: n.token } : {}
685
- });
686
- }
687
- }
688
- return {
689
- status: 200,
690
- headers: { "content-type": "application/json; charset=utf-8" },
691
- body: JSON.stringify({ apps: t })
692
- };
693
- }
694
- if (r === "/_voltro/inspect/logs") {
695
- let t = l(e, y(), n);
696
- return {
697
- status: t.status,
698
- headers: {
699
- "content-type": t.contentType,
700
- ...F(n.origin)
701
- },
702
- body: t.body
703
- };
704
- }
705
- if (r !== "/_voltro/inspect/stream") {
706
- let t = ue(e, Xe, n);
707
- if (t !== null) return {
708
- status: t.status,
709
- headers: {
710
- "content-type": t.contentType,
711
- ...t.headers ?? {}
712
- },
713
- body: t.body
714
- };
715
- }
716
- let i = Be(r, K), a = i ? X.get(i.route.pattern)?.renderMode : void 0, u = a === "ssr" || a === "isr" || (i ? Q.has(i.route.pattern) : !1), d = [];
717
- if (!u && z.length > 0) {
718
- let t = o(z, {
719
- route: void 0,
720
- pathname: r
721
- });
722
- if (t !== void 0) {
723
- let i = await s(t, {
724
- pathname: r,
725
- search: e.slice(r.length),
726
- headers: n,
727
- cookies: ie(n.cookie),
728
- route: void 0
729
- });
730
- d.push(...i.setCookies);
731
- }
732
- }
733
- let f = (e) => d.length === 0 ? e : {
734
- ...e,
735
- "set-cookie": d.map(te)
736
- }, ee = r === "/" ? R(x, "index.html") : R(x, r.replace(/^\//, ""), "index.html");
737
- if (!u && await Z(ee)) {
738
- let e = await B.readFile(ee);
739
- return {
740
- status: 200,
741
- headers: f({ "content-type": "text/html; charset=utf-8" }),
742
- body: e
743
- };
744
- }
745
- if (/\.[a-z0-9]+$/i.test(r)) {
746
- let e = R(x, r.replace(/^\//, ""));
747
- if (await Z(e)) {
748
- let t = await B.readFile(e);
749
- return {
750
- status: 200,
751
- headers: f({ "content-type": Le(e) }),
752
- body: t
753
- };
754
- }
755
- }
756
- let m = Be(r, K);
757
- if (!m) return {
758
- status: 404,
759
- headers: f({ "content-type": "text/plain" }),
760
- body: "not found"
761
- };
762
- let re = X.get(m.route.pattern), h = n["x-tenant"] ?? "anonymous", g = (await Y.getHelpers()).i18n?.resolve(n.cookie, n["accept-language"])?.locale, _ = ge(r, {
763
- ...re?.tenantAware ? { tenant: h } : {},
764
- ...g ? { locale: g } : {}
765
- }), v = V.get(_), b = Date.now();
766
- if (v && ve(v, b)) return p.emit("cache", {
767
- kind: "HIT",
768
- key: _,
769
- ageMs: b - v.renderedAt
770
- }), {
771
- status: 200,
772
- headers: {
773
- "content-type": "text/html; charset=utf-8",
774
- "x-voltro-rendered-by": "isr",
775
- "x-voltro-cache": "HIT",
776
- "x-voltro-cache-key": _,
777
- "x-voltro-cache-age-ms": String(b - v.renderedAt)
778
- },
779
- body: v.html
780
- };
781
- if (v && he(v, b)) return p.emit("cache", {
782
- kind: "STALE",
783
- key: _,
784
- ageMs: b - v.renderedAt
785
- }), (async () => {
786
- try {
787
- let i = await Ve({
788
- provider: Y,
789
- root: t,
790
- route: m.route,
791
- params: m.params,
792
- pathname: r,
793
- dirs: G,
794
- shellTemplate: j,
795
- requestHeaders: n,
796
- apiOrigin: me,
797
- apiName: _e,
798
- middlewares: z,
799
- onCookieWarning: De,
800
- requestUrl: e,
801
- buffered: !0
802
- });
803
- if (i && "html" in i && i.renderMode === "isr" && i.revalidateMs !== null) {
804
- let e = X.get(m.route.pattern)?.staleWhileRevalidateMs ?? 0, t = Date.now();
805
- V.set(_, {
806
- html: i.html,
807
- renderedAt: t,
808
- expiresAt: t + i.revalidateMs,
809
- servableUntil: t + i.revalidateMs + e,
810
- revalidateMs: i.revalidateMs,
811
- staleWhileRevalidateMs: e
812
- });
813
- }
814
- } catch (e) {
815
- J.warn("background SWR refresh failed", { url: r }, e);
816
- }
817
- })(), {
818
- status: 200,
819
- headers: {
820
- "content-type": "text/html; charset=utf-8",
821
- "x-voltro-rendered-by": "isr",
822
- "x-voltro-cache": "STALE",
823
- "x-voltro-cache-key": _,
824
- "x-voltro-cache-age-ms": String(b - v.renderedAt)
825
- },
826
- body: v.html
827
- };
828
- try {
829
- let i = await Ve({
830
- provider: Y,
831
- root: t,
832
- route: m.route,
833
- params: m.params,
834
- pathname: r,
835
- dirs: G,
836
- shellTemplate: j,
837
- requestHeaders: n,
838
- apiOrigin: me,
839
- apiName: _e,
840
- middlewares: z,
841
- onCookieWarning: De,
842
- requestUrl: e
843
- });
844
- if (!i) return {
845
- status: 200,
846
- headers: {
847
- "content-type": "text/html; charset=utf-8",
848
- "x-voltro-rendered-by": "spa-fallback"
849
- },
850
- body: j
851
- };
852
- let a = i.setCookies ?? [], o = (e) => a.length === 0 ? e : {
853
- ...e,
854
- "set-cookie": a.map(te)
855
- };
856
- if ("stream" in i) return {
857
- status: 200,
858
- headers: { "x-voltro-rendered-by": i.renderMode },
859
- body: "",
860
- stream: i.stream
861
- };
862
- if ("control" in i) return i.control === "redirect" ? {
863
- status: i.status,
864
- headers: o({
865
- location: i.location,
866
- "x-voltro-rendered-by": "loader-redirect"
867
- }),
868
- body: ""
869
- } : {
870
- status: 404,
871
- headers: o({
872
- "content-type": "text/plain; charset=utf-8",
873
- "x-voltro-rendered-by": "loader-not-found"
874
- }),
875
- body: "not found"
876
- };
877
- let s = o({
878
- "content-type": "text/html; charset=utf-8",
879
- "x-voltro-rendered-by": i.renderMode
880
- });
881
- if (i.renderMode === "isr" && i.revalidateMs !== null) {
882
- let e = Date.now(), t = X.get(m.route.pattern)?.staleWhileRevalidateMs ?? 0;
883
- V.set(_, {
884
- html: i.html,
885
- renderedAt: e,
886
- expiresAt: e + i.revalidateMs,
887
- servableUntil: e + i.revalidateMs + t,
888
- revalidateMs: i.revalidateMs,
889
- staleWhileRevalidateMs: t
890
- }), s["x-voltro-cache"] = "MISS", s["x-voltro-cache-key"] = _, s["x-voltro-cache-revalidate-ms"] = String(i.revalidateMs), t > 0 && (s["x-voltro-cache-swr-ms"] = String(t)), p.emit("cache", {
891
- kind: "MISS",
892
- key: _,
893
- revalidateMs: i.revalidateMs,
894
- swrMs: t
895
- });
896
- } else i.renderMode === "isr" && (s["x-voltro-cache"] = "BYPASS", p.emit("cache", {
897
- kind: "BYPASS",
898
- key: _
899
- }));
900
- return {
901
- status: 200,
902
- headers: s,
903
- body: i.html
904
- };
905
- } catch (e) {
906
- return J.error("render error", { url: r }, e), ne(e) ? {
907
- status: 500,
908
- headers: {
909
- "content-type": "text/plain; charset=utf-8",
910
- "x-voltro-rendered-by": "defer-unsupported"
911
- },
912
- body: e.message
913
- } : {
914
- status: 500,
915
- headers: { "content-type": "text/plain" },
916
- body: "server error"
917
- };
918
- }
919
- }, Qe = !1, $e = Ae(async (e, t) => {
920
- let n = e.url ?? "/", r = Date.now(), i = {};
921
- for (let [t, n] of Object.entries(e.headers)) n !== void 0 && (i[t.toLowerCase()] = Array.isArray(n) ? n.join(", ") : n);
922
- let a = n.split("?")[0] ?? "/", o = (e.method ?? "GET").toUpperCase();
923
- if (a === "/internal/liveness") {
924
- t.writeHead(200, {
925
- "content-type": "text/plain",
926
- "cache-control": "no-store"
927
- }), t.end("ok");
928
- return;
929
- }
930
- if (a === "/internal/readiness") {
931
- let e = Qe ? 200 : 503;
932
- t.writeHead(e, {
933
- "content-type": "text/plain",
934
- "cache-control": "no-store"
935
- }), t.end(Qe ? "ready" : "not-ready");
936
- return;
937
- }
938
- if (o === "OPTIONS" && a.startsWith("/_voltro/inspect")) {
939
- let e = F(i.origin);
940
- t.writeHead(204, e), t.end();
941
- return;
942
- }
943
- if (c.name === "voltroDashboard" && a === "/api/dashboard/proxy") {
944
- let r = new URL(n, "http://x").searchParams.get("target");
945
- if (!r) {
946
- t.writeHead(400, { "content-type": "text/plain" }), t.end("missing ?target=");
947
- return;
948
- }
949
- if (!fe(r)) {
950
- t.writeHead(400, { "content-type": "text/plain" }), t.end("target not allowed: must be loopback or an origin configured in VOLTRO_DASHBOARD_APPS");
951
- return;
952
- }
953
- try {
954
- let n = { accept: i.accept ?? "application/json" }, a = i.authorization;
955
- a ? n.authorization = Array.isArray(a) ? a[0] : a : de(r) && process.env.VOLTRO_INSPECT_TOKEN && (n.authorization = `Bearer ${process.env.VOLTRO_INSPECT_TOKEN}`);
956
- let s;
957
- if (o && o !== "GET" && o !== "HEAD") {
958
- let t = [];
959
- for await (let n of e) t.push(n);
960
- s = Buffer.concat(t);
961
- let r = i["content-type"];
962
- r && (n["content-type"] = Array.isArray(r) ? r[0] : r);
963
- }
964
- let c = await fetch(r, {
965
- redirect: "manual",
966
- method: o,
967
- headers: n,
968
- ...s ? { body: new Uint8Array(s.buffer, s.byteOffset, s.byteLength) } : {}
969
- }), l = Buffer.from(await c.arrayBuffer());
970
- t.writeHead(c.status, {
971
- "content-type": c.headers.get("content-type") ?? "application/octet-stream",
972
- "content-length": String(l.length)
973
- }), t.end(l);
974
- } catch (e) {
975
- t.writeHead(502, { "content-type": "text/plain" }), t.end(`proxy error: ${e.message}`);
976
- }
977
- return;
978
- }
979
- if (c.name === "voltroDashboard" && a === "/api/dashboard/proxy/stream") {
980
- let r = new URL(n, "http://x").searchParams.get("target");
981
- if (!r) {
982
- t.writeHead(400, { "content-type": "text/plain" }), t.end("missing ?target=");
983
- return;
984
- }
985
- if (!fe(r)) {
986
- t.writeHead(400, { "content-type": "text/plain" }), t.end("target not allowed: must be loopback or an origin configured in VOLTRO_DASHBOARD_APPS");
987
- return;
988
- }
989
- let a = new AbortController();
990
- e.on("close", () => a.abort()), t.on("close", () => a.abort());
991
- try {
992
- let e = i.authorization ?? (de(r) && process.env.VOLTRO_INSPECT_TOKEN ? `Bearer ${process.env.VOLTRO_INSPECT_TOKEN}` : void 0), n = await fetch(r, {
993
- redirect: "manual",
994
- method: "GET",
995
- headers: {
996
- accept: "text/event-stream",
997
- ...e ? { authorization: Array.isArray(e) ? e[0] : e } : {}
998
- },
999
- signal: a.signal
1000
- });
1001
- if (!n.ok || !n.body) {
1002
- t.writeHead(n.status, { "content-type": "text/plain" }), t.end(`upstream ${n.status}`);
1003
- return;
1004
- }
1005
- t.writeHead(200, {
1006
- "content-type": "text/event-stream; charset=utf-8",
1007
- "cache-control": "no-cache, no-transform",
1008
- connection: "keep-alive",
1009
- "x-accel-buffering": "no"
1010
- }), t.flushHeaders();
1011
- let o = n.body.getReader();
1012
- try {
1013
- for (;;) {
1014
- let { done: e, value: n } = await o.read();
1015
- if (e) break;
1016
- n && t.write(Buffer.from(n));
1017
- }
1018
- } finally {
1019
- o.releaseLock(), t.end();
1020
- }
1021
- } catch (e) {
1022
- e.name !== "AbortError" && (t.writeHead(502, { "content-type": "text/plain" }), t.end(`proxy stream error: ${e.message}`));
1023
- }
1024
- return;
1025
- }
1026
- if (a === "/_voltro/inspect/stream") {
1027
- let n = F(i.origin);
1028
- if (P()) {
1029
- t.writeHead(503, {
1030
- "content-type": "application/json",
1031
- ...n
1032
- }), t.end(JSON.stringify({ error: "inspect disabled (VOLTRO_INSPECT=off)" }));
1033
- return;
1034
- }
1035
- let r = I(i, "GET");
1036
- if (!r.ok) {
1037
- t.writeHead(401, {
1038
- "content-type": "application/json",
1039
- ...n
1040
- }), t.end(JSON.stringify({
1041
- error: "unauthorized",
1042
- reason: r.reason
1043
- }));
1044
- return;
1045
- }
1046
- t.writeHead(200, {
1047
- "content-type": "text/event-stream; charset=utf-8",
1048
- "cache-control": "no-cache, no-transform",
1049
- connection: "keep-alive",
1050
- "x-accel-buffering": "no",
1051
- ...n
1052
- }), t.flushHeaders(), t.write("retry: 5000\n\n");
1053
- for (let e of p.buffered()) t.write(v(e));
1054
- let a = p.subscribe((e) => {
1055
- t.write(v(e));
1056
- }), o = setInterval(() => {
1057
- t.write(re());
1058
- }, 15e3), s = () => {
1059
- clearInterval(o), a();
1060
- };
1061
- e.on("close", s), t.on("close", s);
1062
- return;
1063
- }
1064
- try {
1065
- let e = await Ze(n, i);
1066
- if (e.stream ? e.stream(t) : (t.writeHead(e.status, e.headers), t.end(e.body)), !a.startsWith("/_voltro/inspect")) {
1067
- let t = Date.now() - r;
1068
- p.emit("request", {
1069
- url: a,
1070
- status: e.status,
1071
- durationMs: t,
1072
- renderedBy: e.headers["x-voltro-rendered-by"],
1073
- cache: e.headers["x-voltro-cache"]
1074
- });
1075
- let n = Be(a, K)?.route.pattern ?? (e.status === 404 ? "<unmatched>" : "<asset>");
1076
- Ke.record({
1077
- kind: "request",
1078
- tag: n,
1079
- durationMs: t,
1080
- status: e.status >= 500 ? "error" : "ok"
1081
- });
1082
- }
1083
- } catch (e) {
1084
- t.writeHead(500, { "content-type": "text/plain" }), t.end(`internal error: ${e.message}`);
1085
- }
1086
- });
1087
- await new Promise((e) => $e.listen(h, "::", e)), Qe = !0, r.mark("ready"), J.info(`listening on http://localhost:${h}`, {
1088
- port: h,
1089
- distDir: x
1090
- }), J.debug("dynamic + ssr/isr routes resolve via SSR loader");
1091
- try {
1092
- await ye({
1093
- id: E,
1094
- name: T,
1095
- kind: "web",
1096
- url: `http://localhost:${h}`,
1097
- pid: process.pid,
1098
- status: "live",
1099
- logFile: O.path
1100
- });
1101
- let e = _(t);
1102
- if (e) {
1103
- let t = await u({ dashboardAppPath: e });
1104
- 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 });
1105
- }
1106
- setInterval(() => {
1107
- ye({
1108
- id: E,
1109
- name: T,
1110
- kind: "web",
1111
- url: `http://localhost:${h}`,
1112
- pid: process.pid,
1113
- status: "live",
1114
- logFile: O.path
1115
- }).catch(() => {});
1116
- }, 1e4).unref();
1117
- } catch (e) {
1118
- J.warn("runtime-registry write failed", {}, e);
1119
- }
1120
- Oe({
1121
- app: c.name ?? "unnamed",
1122
- kind: "web",
1123
- url: `http://localhost:${h}`,
1124
- bootMs: r.total()
1125
- });
1126
- let et = r.phaseBreakdown();
1127
- J.info(`start: ready in ${r.total()}ms`, {
1128
- bootMs: r.total(),
1129
- ...et ? { phases: et } : {}
1130
- });
1131
- let tt = !1, nt = (e) => async () => {
1132
- if (!tt) {
1133
- if (tt = !0, J.info(`received ${e}, shutting down`, { signal: e }), $e.close(), await Ge.stop(), H) try {
1134
- await H.end();
1135
- } catch {}
1136
- await Y.close(), await xe(E), await O.dispose(), process.exit(0);
1137
- }
1138
- };
1139
- process.on("SIGINT", nt("SIGINT")), process.on("SIGTERM", nt("SIGTERM"));
1140
- let rt = process.ppid;
1141
- if (rt > 1) {
1142
- let e = setInterval(() => {
1143
- (process.ppid !== rt || process.ppid === 1) && (clearInterval(e), nt("SIGTERM")());
1144
- }, 2e3);
1145
- e.unref();
1146
- }
1147
- return new Promise(() => {});
1148
- }, Ge = async (e) => {
1149
- t("start");
1150
- let n = e.find((e) => !e.startsWith("-")) ?? process.cwd(), r = await We(z(n));
1151
- return r.ran ? r.exitCode : (J.error("no web app found at this path"), 1);
1152
- };
1153
- //#endregion
1154
- export { We as n, Ge as t };