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