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