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