@voltro/cli 0.30.1 → 0.30.2
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 +48 -0
- package/dist/{apiBuild-DmkzRyv7.js → apiBuild-BUS1RfPi.js} +2 -2
- package/dist/apiBuild-DMlxvL8h.js +2 -0
- package/dist/bin.js +3 -3
- package/dist/checkCommand-CARZ36Tr.js +2 -0
- package/dist/{checkCommand-C4konUy9.js → checkCommand-D_wdOFhw.js} +346 -293
- package/dist/{commands-BkJft9K2.js → commands-BgGAUcku.js} +1680 -1680
- package/dist/{dbCommand-qn__kLEt.js → dbCommand-CbPRCD1x.js} +56 -19
- package/dist/dbCommand-Ht47LrV-.js +2 -0
- package/dist/{dev-C_NPcLDp.js → dev-GAOIot9G.js} +2169 -2153
- package/dist/{dev-DXhhZ7-f.js → dev-tPcOmjPJ.js} +1 -1
- package/dist/{frameworkTableAssembly-Cpgn2e88.js → frameworkTableAssembly-BwIrO5nv.js} +122 -103
- package/dist/frameworkTableAssembly-D-EebUQX.js +2 -0
- package/dist/index.js +1 -1
- package/dist/{inspectMetrics-CkB2J0Zn.js → inspectMetrics-BM1vrsga.js} +314 -314
- package/dist/{sdkgen-wsWLrq4l.js → sdkgen-BV4fFucu.js} +1 -1
- package/dist/{serveCommand-HtI4X5kj.js → serveCommand-ClqXCX1y.js} +17 -16
- package/dist/serveEntry.js +2 -2
- package/dist/{start-egkbpugc.js → start-CTnNvKlk.js} +348 -348
- package/dist/startEntry.js +2 -2
- package/package.json +17 -17
- package/templates/AGENTS.md +1 -1
- package/templates/agent-docs/_index.md +1 -1
- package/templates/agent-docs/cli.md +4 -2
- package/templates/agent-docs/internationalization.md +25 -3
- package/templates/agent-docs/whats-new.md +24 -47
- 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-sqlite/package.json +8 -8
- package/templates/apps/api-backend-storage/package.json +8 -8
- package/templates/apps/api-cms/package.json +10 -10
- package/templates/apps/api-collab/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-saas-starter/package.json +10 -10
- package/templates/apps/api-search/package.json +8 -8
- package/templates/apps/api-status/package.json +8 -8
- package/templates/apps/api-versioning/package.json +8 -8
- package/templates/apps/api-webhooks/package.json +9 -9
- 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-auth/package.json +8 -8
- package/templates/apps/frontend-blank/package.json +7 -7
- package/templates/apps/frontend-cms/package.json +9 -9
- package/templates/apps/frontend-collab/package.json +9 -9
- 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-portal/package.json +8 -8
- package/templates/apps/frontend-saas/package.json +8 -8
- 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/templates/apps/frontend-status/package.json +8 -8
- package/templates/apps/mobile-app/package.json +2 -2
- package/dist/apiBuild-Ca6Sq5jy.js +0 -2
- package/dist/checkCommand-DHD0aBeR.js +0 -2
- package/dist/dbCommand-wfGi3FgG.js +0 -2
- package/dist/frameworkTableAssembly-Bn_c4Mnl.js +0 -2
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { A as
|
|
1
|
+
import { $ as e, C as t, D as n, E as r, G as i, J as a, K as o, L as s, P as c, Q as l, S as u, V as d, W as ee, _ as f, _t as p, a as m, at as h, b as g, c as _, f as v, g as y, gt as b, h as x, ht as S, i as C, it as te, k as w, m as T, o as ne, ot as re, p as ie, pt as E, q as D, r as ae, rt as O, s as k, st as oe, t as A, ut as j, v as M, vt as N, x as P, y as F } from "./inspectMetrics-BM1vrsga.js";
|
|
2
|
+
import { A as se, E as I, O as ce, a as le, k as L, m as ue } from "./inspect-BUUjt773.js";
|
|
3
3
|
import { t as de } from "./bootTiming-BdyP9nYw.js";
|
|
4
|
-
import { dirname as
|
|
5
|
-
import { fileURLToPath as
|
|
6
|
-
import { createLogger as
|
|
7
|
-
import { promises as
|
|
4
|
+
import { dirname as fe, extname as pe, join as R, resolve as z } from "node:path";
|
|
5
|
+
import { fileURLToPath as B, pathToFileURL as V } from "node:url";
|
|
6
|
+
import { createLogger as H, printReadyBlock as me } from "@voltro/logger";
|
|
7
|
+
import { promises as U } from "node:fs";
|
|
8
8
|
import { snapshotMetricsSync as he } from "@voltro/runtime";
|
|
9
9
|
import { createServer as ge } from "node:http";
|
|
10
10
|
//#region src/isrCdcInvalidator.ts
|
|
11
|
-
var
|
|
11
|
+
var W = H({ scope: "voltro:start:cdc" }), G = (e) => (t) => {
|
|
12
12
|
let n = 0;
|
|
13
13
|
for (let [r, i] of e.tableSubscriptionsByPattern) {
|
|
14
14
|
if (!i.includes(t)) continue;
|
|
@@ -19,23 +19,23 @@ var U = V({ scope: "voltro:start:cdc" }), W = (e) => (t) => {
|
|
|
19
19
|
}));
|
|
20
20
|
}
|
|
21
21
|
return n;
|
|
22
|
-
},
|
|
22
|
+
}, _e = () => !process.env.PG_HOST && !process.env.PG_DATABASE ? null : {
|
|
23
23
|
host: process.env.PG_HOST ?? "localhost",
|
|
24
24
|
port: Number(process.env.PG_PORT ?? 5432),
|
|
25
25
|
user: process.env.PG_USER ?? "app",
|
|
26
26
|
password: process.env.PG_PASSWORD ?? "app",
|
|
27
27
|
database: process.env.PG_DATABASE ?? "app"
|
|
28
|
-
},
|
|
29
|
-
let t = e.channel ?? "framework_changes", n =
|
|
28
|
+
}, ve = (e) => {
|
|
29
|
+
let t = e.channel ?? "framework_changes", n = G(e), r = null, i = null;
|
|
30
30
|
return {
|
|
31
31
|
start: async () => {
|
|
32
|
-
let a =
|
|
32
|
+
let a = _e();
|
|
33
33
|
if (!a) {
|
|
34
|
-
|
|
34
|
+
W.debug("skipped — no PG_* env vars set");
|
|
35
35
|
return;
|
|
36
36
|
}
|
|
37
37
|
if (e.tableSubscriptionsByPattern.size === 0) {
|
|
38
|
-
|
|
38
|
+
W.debug("skipped — no pages declare cacheInvalidatesOn");
|
|
39
39
|
return;
|
|
40
40
|
}
|
|
41
41
|
r = new (await (import("pg"))).default.Client(a), await r.connect(), i = (e) => {
|
|
@@ -44,16 +44,16 @@ var U = V({ scope: "voltro:start:cdc" }), W = (e) => (t) => {
|
|
|
44
44
|
try {
|
|
45
45
|
r = JSON.parse(e.payload);
|
|
46
46
|
} catch (e) {
|
|
47
|
-
|
|
47
|
+
W.warn("bad CDC payload", {}, e);
|
|
48
48
|
return;
|
|
49
49
|
}
|
|
50
50
|
let i = n(r.table);
|
|
51
|
-
i > 0 &&
|
|
51
|
+
i > 0 && W.info(`${r.op} on '${r.table}' → dropped ${i} cache entries`, {
|
|
52
52
|
op: r.op,
|
|
53
53
|
table: r.table,
|
|
54
54
|
dropped: i
|
|
55
55
|
});
|
|
56
|
-
}, r.on("notification", i), await r.query(`LISTEN ${t}`),
|
|
56
|
+
}, r.on("notification", i), await r.query(`LISTEN ${t}`), W.info(`LISTEN ${t}`, {
|
|
57
57
|
channel: t,
|
|
58
58
|
host: a.host,
|
|
59
59
|
port: a.port,
|
|
@@ -69,7 +69,7 @@ var U = V({ scope: "voltro:start:cdc" }), W = (e) => (t) => {
|
|
|
69
69
|
}
|
|
70
70
|
}
|
|
71
71
|
};
|
|
72
|
-
}, K =
|
|
72
|
+
}, K = H({ scope: "voltro:start:isr-cache" }), ye = "voltro_isr_cache", q = (e) => `
|
|
73
73
|
CREATE TABLE IF NOT EXISTS ${e} (
|
|
74
74
|
cache_key TEXT PRIMARY KEY,
|
|
75
75
|
html TEXT NOT NULL,
|
|
@@ -80,9 +80,9 @@ CREATE TABLE IF NOT EXISTS ${e} (
|
|
|
80
80
|
stale_while_revalidate_ms BIGINT NOT NULL DEFAULT 0
|
|
81
81
|
);
|
|
82
82
|
CREATE INDEX IF NOT EXISTS ${e}_servable_until_idx ON ${e} (servable_until);
|
|
83
|
-
`,
|
|
84
|
-
let t = e.tableName ??
|
|
85
|
-
i || (i = !0, await n.query(
|
|
83
|
+
`, be = (e) => {
|
|
84
|
+
let t = e.tableName ?? ye, { client: n } = e, r = /* @__PURE__ */ new Map(), i = !1, a = (async () => {
|
|
85
|
+
i || (i = !0, await n.query(q(t)));
|
|
86
86
|
})().then(async () => {
|
|
87
87
|
let e = await n.query(`SELECT * FROM ${t}`);
|
|
88
88
|
for (let t of e.rows) r.set(t.cache_key, {
|
|
@@ -142,14 +142,14 @@ CREATE INDEX IF NOT EXISTS ${e}_servable_until_idx ON ${e} (servable_until);
|
|
|
142
142
|
return Array.from(r.entries());
|
|
143
143
|
}
|
|
144
144
|
};
|
|
145
|
-
}, J =
|
|
145
|
+
}, J = H({ scope: "voltro:start" }), xe = await (async () => {
|
|
146
146
|
try {
|
|
147
|
-
let e = R(
|
|
147
|
+
let e = R(fe(B(import.meta.url)), "..", "package.json"), t = await U.readFile(e, "utf8");
|
|
148
148
|
return JSON.parse(t).version ?? "0.0.0";
|
|
149
149
|
} catch {
|
|
150
150
|
return "0.0.0";
|
|
151
151
|
}
|
|
152
|
-
})(), Y = (e) => e instanceof Error && e._voltroControl === "redirect" && typeof e.location == "string", X = (e) => e instanceof Error && e._voltroControl === "not-found",
|
|
152
|
+
})(), Y = (e) => e instanceof Error && e._voltroControl === "redirect" && typeof e.location == "string", X = (e) => e instanceof Error && e._voltroControl === "not-found", Se = {
|
|
153
153
|
".html": "text/html; charset=utf-8",
|
|
154
154
|
".js": "application/javascript",
|
|
155
155
|
".mjs": "application/javascript",
|
|
@@ -167,13 +167,13 @@ CREATE INDEX IF NOT EXISTS ${e}_servable_until_idx ON ${e} (servable_until);
|
|
|
167
167
|
".woff": "font/woff",
|
|
168
168
|
".woff2": "font/woff2",
|
|
169
169
|
".txt": "text/plain; charset=utf-8"
|
|
170
|
-
},
|
|
170
|
+
}, Ce = (e) => Se[pe(e).toLowerCase()] ?? "application/octet-stream", we = (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) => {
|
|
171
171
|
try {
|
|
172
|
-
return await
|
|
172
|
+
return await U.stat(e), !0;
|
|
173
173
|
} catch {
|
|
174
174
|
return !1;
|
|
175
175
|
}
|
|
176
|
-
},
|
|
176
|
+
}, Q = (e) => {
|
|
177
177
|
let t = [], n = 0, r = e.split("/").filter(Boolean), i = [];
|
|
178
178
|
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, "\\$&"));
|
|
179
179
|
let a = i.join("/");
|
|
@@ -182,8 +182,8 @@ CREATE INDEX IF NOT EXISTS ${e}_servable_until_idx ON ${e} (servable_until);
|
|
|
182
182
|
paramNames: t,
|
|
183
183
|
priority: n
|
|
184
184
|
};
|
|
185
|
-
},
|
|
186
|
-
let { regex: t, paramNames: n, priority: r } =
|
|
185
|
+
}, Te = (e) => e.map((e) => {
|
|
186
|
+
let { regex: t, paramNames: n, priority: r } = Q(e.pattern);
|
|
187
187
|
return {
|
|
188
188
|
pattern: e.pattern,
|
|
189
189
|
file: e.file,
|
|
@@ -192,7 +192,7 @@ CREATE INDEX IF NOT EXISTS ${e}_servable_until_idx ON ${e} (servable_until);
|
|
|
192
192
|
paramNames: n,
|
|
193
193
|
priority: r
|
|
194
194
|
};
|
|
195
|
-
}).slice().sort((e, t) => e.priority - t.priority),
|
|
195
|
+
}).slice().sort((e, t) => e.priority - t.priority), Ee = (e, t) => {
|
|
196
196
|
for (let n of t) {
|
|
197
197
|
let t = n.regex.exec(e);
|
|
198
198
|
if (!t) continue;
|
|
@@ -204,31 +204,31 @@ CREATE INDEX IF NOT EXISTS ${e}_servable_until_idx ON ${e} (servable_until);
|
|
|
204
204
|
};
|
|
205
205
|
}
|
|
206
206
|
return null;
|
|
207
|
-
},
|
|
208
|
-
let { provider:
|
|
209
|
-
if (
|
|
210
|
-
let
|
|
207
|
+
}, De = async (e) => {
|
|
208
|
+
let { provider: n, route: r, params: i, pathname: a, dirs: o, shellTemplate: c, requestHeaders: l, requestUrl: d = "", apiOrigin: ee, apiName: p } = e, { search: h } = t(d), _ = C(ee, l.cookie, { apiName: p }), v = await n.getPage(r.pattern, r.file), b = s(v, r.file), S = b === "spa" && ne(o, r.dirChain).some((e) => e.hasLayout);
|
|
209
|
+
if (b !== "ssr" && b !== "isr" && !S) return null;
|
|
210
|
+
let te = ne(o, r.dirChain), w = {}, re = null, ie, E = new AbortController();
|
|
211
211
|
try {
|
|
212
|
-
(await
|
|
213
|
-
entries:
|
|
214
|
-
loadLayout: (e) =>
|
|
215
|
-
loadError: (e) =>
|
|
216
|
-
loadPending: (e) =>
|
|
212
|
+
(await n.getHelpers()).beginStoreSeeds(), {chain: ie, segmentLoaderData: w} = await m({
|
|
213
|
+
entries: te,
|
|
214
|
+
loadLayout: (e) => n.getLayout(e.dir),
|
|
215
|
+
loadError: (e) => n.getError(e.dir),
|
|
216
|
+
loadPending: (e) => n.getPending(e.dir),
|
|
217
217
|
ctx: {
|
|
218
218
|
params: i,
|
|
219
219
|
pathname: a,
|
|
220
|
-
search:
|
|
221
|
-
signal:
|
|
220
|
+
search: h,
|
|
221
|
+
signal: E.signal,
|
|
222
222
|
headers: l,
|
|
223
|
-
query:
|
|
223
|
+
query: _
|
|
224
224
|
}
|
|
225
|
-
}), typeof
|
|
225
|
+
}), typeof v.loader == "function" && !S && (re = await v.loader({
|
|
226
226
|
params: i,
|
|
227
227
|
pathname: a,
|
|
228
|
-
search:
|
|
229
|
-
signal:
|
|
228
|
+
search: h,
|
|
229
|
+
signal: E.signal,
|
|
230
230
|
headers: l,
|
|
231
|
-
query:
|
|
231
|
+
query: _
|
|
232
232
|
}));
|
|
233
233
|
} catch (e) {
|
|
234
234
|
if (Y(e)) return {
|
|
@@ -239,13 +239,13 @@ CREATE INDEX IF NOT EXISTS ${e}_servable_until_idx ON ${e} (servable_until);
|
|
|
239
239
|
if (X(e)) return { control: "not-found" };
|
|
240
240
|
throw e;
|
|
241
241
|
}
|
|
242
|
-
let
|
|
243
|
-
|
|
244
|
-
pageMod:
|
|
242
|
+
let D = await n.getHelpers();
|
|
243
|
+
S || await T({
|
|
244
|
+
pageMod: v,
|
|
245
245
|
params: i,
|
|
246
|
-
query:
|
|
247
|
-
apiName:
|
|
248
|
-
seed:
|
|
246
|
+
query: _,
|
|
247
|
+
apiName: p,
|
|
248
|
+
seed: D.seedPreloadedSubscription,
|
|
249
249
|
onError: ({ tag: e, apiName: t }, n) => J.warn("preload seed failed", {
|
|
250
250
|
tag: e,
|
|
251
251
|
apiName: t,
|
|
@@ -253,57 +253,57 @@ CREATE INDEX IF NOT EXISTS ${e}_servable_until_idx ON ${e} (servable_until);
|
|
|
253
253
|
}, n)
|
|
254
254
|
});
|
|
255
255
|
let ae = {
|
|
256
|
-
pattern:
|
|
257
|
-
Component:
|
|
258
|
-
meta:
|
|
259
|
-
loader:
|
|
260
|
-
ErrorBoundary:
|
|
261
|
-
Pending:
|
|
262
|
-
renderMode:
|
|
263
|
-
chain:
|
|
264
|
-
},
|
|
265
|
-
cookies:
|
|
256
|
+
pattern: r.pattern,
|
|
257
|
+
Component: v.default,
|
|
258
|
+
meta: v.meta,
|
|
259
|
+
loader: v.loader,
|
|
260
|
+
ErrorBoundary: v.ErrorBoundary,
|
|
261
|
+
Pending: v.Pending,
|
|
262
|
+
renderMode: b,
|
|
263
|
+
chain: ie
|
|
264
|
+
}, O = {
|
|
265
|
+
cookies: D.parseCookieHeader(l.cookie),
|
|
266
266
|
headers: l,
|
|
267
|
-
url:
|
|
268
|
-
},
|
|
269
|
-
if (
|
|
270
|
-
let e =
|
|
271
|
-
helpers:
|
|
272
|
-
page:
|
|
273
|
-
interactive:
|
|
267
|
+
url: d
|
|
268
|
+
}, k = D.i18n?.resolve(l.cookie, l["accept-language"]), A = v.interactive ?? "full";
|
|
269
|
+
if (S) {
|
|
270
|
+
let e = g({
|
|
271
|
+
helpers: D,
|
|
272
|
+
page: r.pattern,
|
|
273
|
+
interactive: A,
|
|
274
274
|
delivery: "stream",
|
|
275
275
|
renderInput: {
|
|
276
276
|
descriptor: ae,
|
|
277
277
|
params: i,
|
|
278
278
|
pathname: a,
|
|
279
|
-
search:
|
|
280
|
-
segmentLoaderData:
|
|
281
|
-
requestContext:
|
|
282
|
-
...
|
|
283
|
-
outerWrap:
|
|
284
|
-
locale:
|
|
279
|
+
search: h,
|
|
280
|
+
segmentLoaderData: w,
|
|
281
|
+
requestContext: O,
|
|
282
|
+
...k ? {
|
|
283
|
+
outerWrap: k.outerWrap,
|
|
284
|
+
locale: k.locale
|
|
285
285
|
} : {}
|
|
286
286
|
}
|
|
287
|
-
}), t =
|
|
288
|
-
helpers:
|
|
287
|
+
}), t = k?.locale ?? O.cookies["voltro:locale"] ?? "en", n = (t) => u({
|
|
288
|
+
helpers: D,
|
|
289
289
|
prepared: e,
|
|
290
290
|
meta: t,
|
|
291
|
-
interactive:
|
|
291
|
+
interactive: A
|
|
292
292
|
});
|
|
293
293
|
if (e.hasDeferred) {
|
|
294
|
-
let
|
|
294
|
+
let r = y({ shell: c });
|
|
295
295
|
return {
|
|
296
296
|
renderMode: "spa",
|
|
297
|
-
stream: (i) =>
|
|
297
|
+
stream: (i) => f({
|
|
298
298
|
res: i,
|
|
299
|
-
shell:
|
|
299
|
+
shell: r,
|
|
300
300
|
htmlLang: t,
|
|
301
301
|
headers: {
|
|
302
302
|
"content-type": "text/html; charset=utf-8",
|
|
303
303
|
"x-voltro-rendered-by": "spa"
|
|
304
304
|
},
|
|
305
|
-
headInjection:
|
|
306
|
-
render: (t) =>
|
|
305
|
+
headInjection: n,
|
|
306
|
+
render: (t) => D.renderPageToStream({
|
|
307
307
|
...e.renderInput,
|
|
308
308
|
...t
|
|
309
309
|
}),
|
|
@@ -313,48 +313,48 @@ CREATE INDEX IF NOT EXISTS ${e}_servable_until_idx ON ${e} (servable_until);
|
|
|
313
313
|
})
|
|
314
314
|
};
|
|
315
315
|
}
|
|
316
|
-
let o =
|
|
317
|
-
helpers:
|
|
316
|
+
let o = P({
|
|
317
|
+
helpers: D,
|
|
318
318
|
prepared: e
|
|
319
319
|
});
|
|
320
320
|
return {
|
|
321
|
-
html:
|
|
321
|
+
html: x(c.replace("<div id=\"root\"></div>", `<div id="root">${o.body}</div>`), n(o.meta)).replace(/<html(\s+lang="[^"]*")?/i, `<html lang="${t}"`),
|
|
322
322
|
renderMode: "spa",
|
|
323
323
|
revalidateMs: null
|
|
324
324
|
};
|
|
325
325
|
}
|
|
326
|
-
let
|
|
327
|
-
helpers:
|
|
328
|
-
page:
|
|
326
|
+
let j = F({
|
|
327
|
+
helpers: D,
|
|
328
|
+
page: r.pattern,
|
|
329
329
|
pathname: a,
|
|
330
|
-
renderMode:
|
|
331
|
-
interactive:
|
|
332
|
-
loaderData:
|
|
333
|
-
segmentLoaderData:
|
|
334
|
-
pageLoaderRan: typeof
|
|
335
|
-
}),
|
|
330
|
+
renderMode: b,
|
|
331
|
+
interactive: A,
|
|
332
|
+
loaderData: re,
|
|
333
|
+
segmentLoaderData: w,
|
|
334
|
+
pageLoaderRan: typeof v.loader == "function"
|
|
335
|
+
}), M = {
|
|
336
336
|
descriptor: ae,
|
|
337
337
|
params: i,
|
|
338
338
|
pathname: a,
|
|
339
|
-
search:
|
|
340
|
-
loaderData:
|
|
341
|
-
segmentLoaderData:
|
|
342
|
-
requestContext:
|
|
343
|
-
...
|
|
344
|
-
outerWrap:
|
|
345
|
-
locale:
|
|
339
|
+
search: h,
|
|
340
|
+
loaderData: j.loaderData,
|
|
341
|
+
segmentLoaderData: j.segmentLoaderData,
|
|
342
|
+
requestContext: O,
|
|
343
|
+
...k ? {
|
|
344
|
+
outerWrap: k.outerWrap,
|
|
345
|
+
locale: k.locale
|
|
346
346
|
} : {}
|
|
347
|
-
},
|
|
348
|
-
|
|
349
|
-
`<meta name="voltro-interactive" content="${
|
|
350
|
-
...
|
|
351
|
-
|
|
347
|
+
}, N = (e) => [
|
|
348
|
+
D.renderMetaToHtml(e),
|
|
349
|
+
`<meta name="voltro-interactive" content="${A}" />`,
|
|
350
|
+
...j.hasDeferred ? [D.renderDeferredRegistryScript()] : [],
|
|
351
|
+
D.renderRouterStateScript(j.stateInput)
|
|
352
352
|
].filter((e) => e.length > 0).join("\n ");
|
|
353
|
-
if (
|
|
354
|
-
let e =
|
|
353
|
+
if (b === "ssr" && A === "full" && e.buffered !== !0) {
|
|
354
|
+
let e = k?.locale ?? O.cookies["voltro:locale"] ?? "en", t = y({ shell: c });
|
|
355
355
|
return {
|
|
356
356
|
renderMode: "ssr",
|
|
357
|
-
stream: (n) =>
|
|
357
|
+
stream: (n) => f({
|
|
358
358
|
res: n,
|
|
359
359
|
shell: t,
|
|
360
360
|
htmlLang: e,
|
|
@@ -362,9 +362,9 @@ CREATE INDEX IF NOT EXISTS ${e}_servable_until_idx ON ${e} (servable_until);
|
|
|
362
362
|
"content-type": "text/html; charset=utf-8",
|
|
363
363
|
"x-voltro-rendered-by": "ssr"
|
|
364
364
|
},
|
|
365
|
-
headInjection:
|
|
366
|
-
render: (e) =>
|
|
367
|
-
...
|
|
365
|
+
headInjection: N,
|
|
366
|
+
render: (e) => D.renderPageToStream({
|
|
367
|
+
...M,
|
|
368
368
|
...e
|
|
369
369
|
}),
|
|
370
370
|
onShellError: (e) => {
|
|
@@ -373,16 +373,16 @@ CREATE INDEX IF NOT EXISTS ${e}_servable_until_idx ON ${e} (servable_until);
|
|
|
373
373
|
})
|
|
374
374
|
};
|
|
375
375
|
}
|
|
376
|
-
let { html:
|
|
377
|
-
|
|
378
|
-
let ue =
|
|
376
|
+
let { html: se, meta: I } = D.renderPageToHtml(M), ce = N(I), le = k?.locale ?? O.cookies["voltro:locale"] ?? "en", L = x(c.replace("<div id=\"root\"></div>", `<div id="root">${se}</div>`), ce).replace(/<html(\s+lang="[^"]*")?/i, `<html lang="${le}"`);
|
|
377
|
+
A === "none" && (L = we(L));
|
|
378
|
+
let ue = b === "isr" ? oe(v.revalidate) : null;
|
|
379
379
|
return {
|
|
380
|
-
html:
|
|
381
|
-
renderMode:
|
|
380
|
+
html: L,
|
|
381
|
+
renderMode: b,
|
|
382
382
|
revalidateMs: ue
|
|
383
383
|
};
|
|
384
|
-
}, $ = (e) => e === "" ? "/" : e,
|
|
385
|
-
let t = await import(
|
|
384
|
+
}, $ = (e) => e === "" ? "/" : e, Oe = async (e) => {
|
|
385
|
+
let t = await import(V(e).href);
|
|
386
386
|
return {
|
|
387
387
|
kind: "bundle",
|
|
388
388
|
getPageMeta: () => t.pageMeta,
|
|
@@ -411,11 +411,11 @@ CREATE INDEX IF NOT EXISTS ${e}_servable_until_idx ON ${e} (servable_until);
|
|
|
411
411
|
},
|
|
412
412
|
async close() {}
|
|
413
413
|
};
|
|
414
|
-
},
|
|
415
|
-
let
|
|
416
|
-
root:
|
|
414
|
+
}, ke = async (t, n) => {
|
|
415
|
+
let r = await E("vite", () => import("vite")), i = (await import("@vitejs/plugin-react")).default, a = (await import("@tailwindcss/vite")).default, o = await r.createServer({
|
|
416
|
+
root: n,
|
|
417
417
|
envPrefix: "__VOLTRO_VITE_ENV_DISABLED__",
|
|
418
|
-
plugins: [
|
|
418
|
+
plugins: [i(), a()],
|
|
419
419
|
resolve: { dedupe: ["react", "react-dom"] },
|
|
420
420
|
ssr: { noExternal: ["react-intl"] },
|
|
421
421
|
server: {
|
|
@@ -424,129 +424,129 @@ CREATE INDEX IF NOT EXISTS ${e}_servable_until_idx ON ${e} (servable_until);
|
|
|
424
424
|
},
|
|
425
425
|
appType: "custom",
|
|
426
426
|
logLevel: "warn"
|
|
427
|
-
}),
|
|
428
|
-
limit:
|
|
427
|
+
}), s = R(t, "src", "pages"), c = (e) => e === "" ? s : R(s, e), u = l({
|
|
428
|
+
limit: e(),
|
|
429
429
|
onColdStart: (e) => J.debug("ssr cold-compile start", { id: e }),
|
|
430
430
|
onColdEnd: (e, { durationMs: t, failed: n }) => J.debug(`ssr cold-compile ${n ? "FAILED" : "end"} ${t}ms`, {
|
|
431
431
|
id: e,
|
|
432
432
|
ms: t,
|
|
433
433
|
...n ? { failed: !0 } : {}
|
|
434
434
|
})
|
|
435
|
-
}),
|
|
435
|
+
}), d = (e) => u.load(e, async () => await o.ssrLoadModule(e));
|
|
436
436
|
return {
|
|
437
437
|
kind: "middleware",
|
|
438
438
|
async getPage(e, t) {
|
|
439
|
-
return
|
|
439
|
+
return d(R(s, t));
|
|
440
440
|
},
|
|
441
441
|
async getLayout(e) {
|
|
442
|
-
return
|
|
442
|
+
return d(R(c(e), "layout.tsx"));
|
|
443
443
|
},
|
|
444
444
|
async getError(e) {
|
|
445
|
-
return
|
|
445
|
+
return d(R(c(e), "error.tsx"));
|
|
446
446
|
},
|
|
447
447
|
async getPending(e) {
|
|
448
|
-
return
|
|
448
|
+
return d(R(c(e), "loading.tsx"));
|
|
449
449
|
},
|
|
450
450
|
async getHelpers() {
|
|
451
|
-
return await
|
|
451
|
+
return await d("@voltro/web/ssr");
|
|
452
452
|
},
|
|
453
453
|
async close() {
|
|
454
|
-
await
|
|
454
|
+
await o.close();
|
|
455
455
|
}
|
|
456
456
|
};
|
|
457
|
-
},
|
|
458
|
-
let
|
|
459
|
-
if (!
|
|
457
|
+
}, Ae = async (e) => {
|
|
458
|
+
let t = de(), s = await k(e);
|
|
459
|
+
if (!s) return {
|
|
460
460
|
ran: !1,
|
|
461
461
|
exitCode: 0
|
|
462
462
|
};
|
|
463
|
-
if (
|
|
463
|
+
if (s.type !== "web") return J.error("only web apps are supported by `voltro start`"), {
|
|
464
464
|
ran: !0,
|
|
465
465
|
exitCode: 1
|
|
466
466
|
};
|
|
467
|
-
let { resolved:
|
|
468
|
-
rawEnv:
|
|
467
|
+
let { resolved: l } = await j({
|
|
468
|
+
rawEnv: s.env,
|
|
469
469
|
appType: "web",
|
|
470
|
-
root:
|
|
470
|
+
root: e,
|
|
471
471
|
log: J,
|
|
472
472
|
generateTypes: !1
|
|
473
|
-
}),
|
|
474
|
-
|
|
475
|
-
let
|
|
476
|
-
|
|
477
|
-
let
|
|
473
|
+
}), u = l.publicValues;
|
|
474
|
+
t.mark("config");
|
|
475
|
+
let f = D();
|
|
476
|
+
ee(f), J.info("booting voltro start", { app: s.name ?? "(unnamed)" });
|
|
477
|
+
let m = (() => {
|
|
478
478
|
if (process.env.VOLTRO_IS_DASHBOARD === "1" && process.env.VOLTRO_DASHBOARD_PORT) return Number(process.env.VOLTRO_DASHBOARD_PORT);
|
|
479
479
|
if (process.env.PORT) {
|
|
480
480
|
let e = Number(process.env.PORT);
|
|
481
481
|
if (Number.isFinite(e) && e > 0) return e;
|
|
482
482
|
}
|
|
483
|
-
return
|
|
484
|
-
})(),
|
|
485
|
-
if (!await
|
|
483
|
+
return s.port ?? 5173;
|
|
484
|
+
})(), g = R(e, ".framework"), y = R(g, "dist"), x = R(y, "index.html");
|
|
485
|
+
if (!await Z(x)) return J.error("no built dist found — run `voltro build` first", { distDir: y }), {
|
|
486
486
|
ran: !0,
|
|
487
487
|
exitCode: 1
|
|
488
488
|
};
|
|
489
|
-
let C =
|
|
490
|
-
await
|
|
489
|
+
let C = s.name ?? "unnamed", T = S("web", C, m), E = w(C);
|
|
490
|
+
await N({
|
|
491
491
|
id: T,
|
|
492
492
|
name: C,
|
|
493
493
|
kind: "web",
|
|
494
|
-
url: `http://localhost:${
|
|
494
|
+
url: `http://localhost:${m}`,
|
|
495
495
|
pid: process.pid,
|
|
496
496
|
status: "booting",
|
|
497
|
-
logFile:
|
|
497
|
+
logFile: E.path
|
|
498
498
|
}).catch(() => {});
|
|
499
|
-
let
|
|
499
|
+
let oe = R(y, "_voltro", "shell.html"), P = await Z(oe) ? await U.readFile(oe, "utf8") : await U.readFile(x, "utf8"), F = await _(e, s), fe = ae(F[0]), pe = F[0]?.name, z, B = null;
|
|
500
500
|
process.env.SSR_CACHE === "postgres" && process.env.PG_HOST ? (B = new (await (import("pg"))).default.Client({
|
|
501
501
|
host: process.env.PG_HOST,
|
|
502
502
|
port: Number(process.env.PG_PORT ?? 5432),
|
|
503
503
|
user: process.env.PG_USER ?? "app",
|
|
504
504
|
password: process.env.PG_PASSWORD ?? "app",
|
|
505
505
|
database: process.env.PG_DATABASE ?? "app"
|
|
506
|
-
}), await B.connect(), z =
|
|
507
|
-
let { pages: V, dirs:
|
|
508
|
-
|
|
509
|
-
let G = R(
|
|
510
|
-
if (!
|
|
511
|
-
let
|
|
512
|
-
J.info(`ssr loader: ${
|
|
513
|
-
kind:
|
|
514
|
-
...
|
|
515
|
-
}),
|
|
516
|
-
let
|
|
506
|
+
}), await B.connect(), z = be({ client: B }), J.info("isr cache backend: postgres", { table: "voltro_isr_cache" })) : (z = re(), J.info("isr cache backend: memory (per-process)", { hint: "set SSR_CACHE=postgres for persistent storage" })), await ie(e, s, F, u);
|
|
507
|
+
let { pages: V, dirs: H } = await v(R(e, "src", "pages")), W = Te(V);
|
|
508
|
+
t.mark("scan");
|
|
509
|
+
let G = R(y, "server", "ssrEntry.js"), _e = await Z(G);
|
|
510
|
+
if (!_e && process.env.NODE_ENV === "production") throw J.fatal(`production \`voltro start\` requires a precompiled SSR bundle at ${G} 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 ${G}`);
|
|
511
|
+
let K = _e ? await Oe(G) : await ke(e, g);
|
|
512
|
+
J.info(`ssr loader: ${K.kind}`, {
|
|
513
|
+
kind: K.kind,
|
|
514
|
+
...K.kind === "middleware" ? { hint: "no pre-built SSR bundle found; run `voltro build` to enable bundle mode" } : {}
|
|
515
|
+
}), t.mark("provider");
|
|
516
|
+
let ye = K.getPageMeta?.(), q = /* @__PURE__ */ new Map(), Y = 0;
|
|
517
517
|
for (let e of V) {
|
|
518
|
-
let t =
|
|
518
|
+
let t = ye?.[e.pattern];
|
|
519
519
|
if (t) {
|
|
520
|
-
|
|
520
|
+
q.set(e.pattern, t);
|
|
521
521
|
continue;
|
|
522
522
|
}
|
|
523
523
|
try {
|
|
524
|
-
let t = await
|
|
525
|
-
|
|
524
|
+
let t = await K.getPage(e.pattern, e.file);
|
|
525
|
+
q.set(e.pattern, c(t, e.file)), Y++;
|
|
526
526
|
} catch (t) {
|
|
527
527
|
J.warn("failed to load page metadata", { pattern: e.pattern }, t);
|
|
528
528
|
}
|
|
529
529
|
}
|
|
530
|
-
J.info(`registered ${
|
|
531
|
-
count:
|
|
532
|
-
fromManifest:
|
|
533
|
-
fromModules:
|
|
534
|
-
}),
|
|
535
|
-
let
|
|
536
|
-
for (let e of W)
|
|
537
|
-
|
|
530
|
+
J.info(`registered ${q.size} route(s)`, {
|
|
531
|
+
count: q.size,
|
|
532
|
+
fromManifest: q.size - Y,
|
|
533
|
+
fromModules: Y
|
|
534
|
+
}), t.mark("routes");
|
|
535
|
+
let X = /* @__PURE__ */ new Set();
|
|
536
|
+
for (let e of W) q.get(e.pattern)?.renderMode === "spa" && ne(H, e.dirChain).some((e) => e.hasLayout) && X.add(e.pattern);
|
|
537
|
+
X.size > 0 && J.info(`${X.size} spa route(s) render an SSR layout shell`, { patterns: [...X] });
|
|
538
538
|
let Se = /* @__PURE__ */ new Map();
|
|
539
|
-
for (let [e, t] of
|
|
540
|
-
let
|
|
541
|
-
for (let e of W)
|
|
542
|
-
let
|
|
539
|
+
for (let [e, t] of q) t.cacheInvalidatesOn.length > 0 && Se.set(e, t.cacheInvalidatesOn);
|
|
540
|
+
let we = /* @__PURE__ */ new Map();
|
|
541
|
+
for (let e of W) we.set(e.pattern, e.regex);
|
|
542
|
+
let Q = ve({
|
|
543
543
|
cache: z,
|
|
544
544
|
tableSubscriptionsByPattern: Se,
|
|
545
|
-
regexByPattern:
|
|
545
|
+
regexByPattern: we
|
|
546
546
|
});
|
|
547
|
-
await
|
|
548
|
-
let
|
|
549
|
-
let t =
|
|
547
|
+
await Q.start(), t.mark("cdc");
|
|
548
|
+
let $ = A(), Ae = V.map((e) => {
|
|
549
|
+
let t = q.get(e.pattern);
|
|
550
550
|
return {
|
|
551
551
|
pattern: e.pattern,
|
|
552
552
|
file: e.file,
|
|
@@ -561,7 +561,7 @@ CREATE INDEX IF NOT EXISTS ${e}_servable_until_idx ON ${e} (servable_until);
|
|
|
561
561
|
hasMeta: t?.hasMeta ?? !1,
|
|
562
562
|
hasGetStaticPaths: t?.hasGetStaticPaths ?? !1
|
|
563
563
|
};
|
|
564
|
-
}), je =
|
|
564
|
+
}), je = H.map((e) => ({
|
|
565
565
|
dir: e.dir,
|
|
566
566
|
hasLayout: e.hasLayout,
|
|
567
567
|
hasError: e.hasError,
|
|
@@ -570,11 +570,11 @@ CREATE INDEX IF NOT EXISTS ${e}_servable_until_idx ON ${e} (servable_until);
|
|
|
570
570
|
})), Me = B ? "postgres" : "memory", Ne = {
|
|
571
571
|
kind: "web",
|
|
572
572
|
meta: {
|
|
573
|
-
name:
|
|
574
|
-
voltroVersion:
|
|
575
|
-
port:
|
|
573
|
+
name: s.name ?? "(unnamed)",
|
|
574
|
+
voltroVersion: xe,
|
|
575
|
+
port: m,
|
|
576
576
|
mode: "start",
|
|
577
|
-
apis: Object.entries(
|
|
577
|
+
apis: Object.entries(s.apis ?? {}).map(([e, t]) => {
|
|
578
578
|
let n = {
|
|
579
579
|
name: e,
|
|
580
580
|
package: t.package
|
|
@@ -603,9 +603,9 @@ CREATE INDEX IF NOT EXISTS ${e}_servable_until_idx ON ${e} (servable_until);
|
|
|
603
603
|
},
|
|
604
604
|
metrics: () => he()
|
|
605
605
|
}, Pe = async (t, n) => {
|
|
606
|
-
let
|
|
607
|
-
if (
|
|
608
|
-
let e = await
|
|
606
|
+
let r = t.split("?")[0] ?? "/";
|
|
607
|
+
if (s.name === "voltroDashboard" && r === "/api/dashboard/registry") try {
|
|
608
|
+
let e = await b();
|
|
609
609
|
return {
|
|
610
610
|
status: 200,
|
|
611
611
|
headers: { "content-type": "application/json; charset=utf-8" },
|
|
@@ -618,7 +618,7 @@ CREATE INDEX IF NOT EXISTS ${e}_servable_until_idx ON ${e} (servable_until);
|
|
|
618
618
|
body: `registry read error: ${e.message}`
|
|
619
619
|
};
|
|
620
620
|
}
|
|
621
|
-
if (
|
|
621
|
+
if (s.name === "voltroDashboard" && r === "/api/dashboard/config") {
|
|
622
622
|
let e = process.env.VOLTRO_DASHBOARD_APPS, t = [];
|
|
623
623
|
if (e && e.trim().length > 0) {
|
|
624
624
|
let n;
|
|
@@ -647,18 +647,18 @@ CREATE INDEX IF NOT EXISTS ${e}_servable_until_idx ON ${e} (servable_until);
|
|
|
647
647
|
body: JSON.stringify({ apps: t })
|
|
648
648
|
};
|
|
649
649
|
}
|
|
650
|
-
if (
|
|
651
|
-
let
|
|
650
|
+
if (r === "/_voltro/inspect/logs") {
|
|
651
|
+
let e = d(t, i(), n);
|
|
652
652
|
return {
|
|
653
|
-
status:
|
|
653
|
+
status: e.status,
|
|
654
654
|
headers: {
|
|
655
|
-
"content-type":
|
|
656
|
-
...
|
|
655
|
+
"content-type": e.contentType,
|
|
656
|
+
...I(n.origin)
|
|
657
657
|
},
|
|
658
|
-
body:
|
|
658
|
+
body: e.body
|
|
659
659
|
};
|
|
660
660
|
}
|
|
661
|
-
if (
|
|
661
|
+
if (r !== "/_voltro/inspect/stream") {
|
|
662
662
|
let e = ue(t, Ne, n);
|
|
663
663
|
if (e !== null) return {
|
|
664
664
|
status: e.status,
|
|
@@ -669,36 +669,36 @@ CREATE INDEX IF NOT EXISTS ${e}_servable_until_idx ON ${e} (servable_until);
|
|
|
669
669
|
body: e.body
|
|
670
670
|
};
|
|
671
671
|
}
|
|
672
|
-
let a =
|
|
673
|
-
if (!
|
|
672
|
+
let a = Ee(r, W), o = a ? q.get(a.route.pattern)?.renderMode : void 0, c = o === "ssr" || o === "isr" || (a ? X.has(a.route.pattern) : !1), l = r === "/" ? R(y, "index.html") : R(y, r.replace(/^\//, ""), "index.html");
|
|
673
|
+
if (!c && await Z(l)) return {
|
|
674
674
|
status: 200,
|
|
675
675
|
headers: { "content-type": "text/html; charset=utf-8" },
|
|
676
|
-
body: await
|
|
676
|
+
body: await U.readFile(l)
|
|
677
677
|
};
|
|
678
|
-
if (/\.[a-z0-9]+$/i.test(
|
|
679
|
-
let e = R(
|
|
680
|
-
if (await
|
|
681
|
-
let t = await
|
|
678
|
+
if (/\.[a-z0-9]+$/i.test(r)) {
|
|
679
|
+
let e = R(y, r.replace(/^\//, ""));
|
|
680
|
+
if (await Z(e)) {
|
|
681
|
+
let t = await U.readFile(e);
|
|
682
682
|
return {
|
|
683
683
|
status: 200,
|
|
684
|
-
headers: { "content-type":
|
|
684
|
+
headers: { "content-type": Ce(e) },
|
|
685
685
|
body: t
|
|
686
686
|
};
|
|
687
687
|
}
|
|
688
688
|
}
|
|
689
|
-
let u =
|
|
689
|
+
let u = Ee(r, W);
|
|
690
690
|
if (!u) return {
|
|
691
691
|
status: 404,
|
|
692
692
|
headers: { "content-type": "text/plain" },
|
|
693
693
|
body: "not found"
|
|
694
694
|
};
|
|
695
|
-
let
|
|
696
|
-
...
|
|
695
|
+
let ee = q.get(u.route.pattern), p = n["x-tenant"] ?? "anonymous", m = (await K.getHelpers()).i18n?.resolve(n.cookie, n["accept-language"])?.locale, g = O(r, {
|
|
696
|
+
...ee?.tenantAware ? { tenant: p } : {},
|
|
697
697
|
...m ? { locale: m } : {}
|
|
698
|
-
}), _ = z.get(
|
|
699
|
-
if (_ &&
|
|
698
|
+
}), _ = z.get(g), v = Date.now();
|
|
699
|
+
if (_ && te(_, v)) return f.emit("cache", {
|
|
700
700
|
kind: "HIT",
|
|
701
|
-
key:
|
|
701
|
+
key: g,
|
|
702
702
|
ageMs: v - _.renderedAt
|
|
703
703
|
}), {
|
|
704
704
|
status: 200,
|
|
@@ -706,44 +706,44 @@ CREATE INDEX IF NOT EXISTS ${e}_servable_until_idx ON ${e} (servable_until);
|
|
|
706
706
|
"content-type": "text/html; charset=utf-8",
|
|
707
707
|
"x-voltro-rendered-by": "isr",
|
|
708
708
|
"x-voltro-cache": "HIT",
|
|
709
|
-
"x-voltro-cache-key":
|
|
709
|
+
"x-voltro-cache-key": g,
|
|
710
710
|
"x-voltro-cache-age-ms": String(v - _.renderedAt)
|
|
711
711
|
},
|
|
712
712
|
body: _.html
|
|
713
713
|
};
|
|
714
|
-
if (_ &&
|
|
714
|
+
if (_ && h(_, v)) return f.emit("cache", {
|
|
715
715
|
kind: "STALE",
|
|
716
|
-
key:
|
|
716
|
+
key: g,
|
|
717
717
|
ageMs: v - _.renderedAt
|
|
718
718
|
}), (async () => {
|
|
719
719
|
try {
|
|
720
|
-
let
|
|
721
|
-
provider:
|
|
722
|
-
root:
|
|
720
|
+
let i = await De({
|
|
721
|
+
provider: K,
|
|
722
|
+
root: e,
|
|
723
723
|
route: u.route,
|
|
724
724
|
params: u.params,
|
|
725
|
-
pathname:
|
|
726
|
-
dirs:
|
|
727
|
-
shellTemplate:
|
|
725
|
+
pathname: r,
|
|
726
|
+
dirs: H,
|
|
727
|
+
shellTemplate: P,
|
|
728
728
|
requestHeaders: n,
|
|
729
729
|
apiOrigin: fe,
|
|
730
730
|
apiName: pe,
|
|
731
731
|
requestUrl: t,
|
|
732
732
|
buffered: !0
|
|
733
733
|
});
|
|
734
|
-
if (
|
|
735
|
-
let
|
|
736
|
-
z.set(
|
|
737
|
-
html:
|
|
738
|
-
renderedAt:
|
|
739
|
-
expiresAt:
|
|
740
|
-
servableUntil:
|
|
741
|
-
revalidateMs:
|
|
742
|
-
staleWhileRevalidateMs:
|
|
734
|
+
if (i && "html" in i && i.renderMode === "isr" && i.revalidateMs !== null) {
|
|
735
|
+
let e = q.get(u.route.pattern)?.staleWhileRevalidateMs ?? 0, t = Date.now();
|
|
736
|
+
z.set(g, {
|
|
737
|
+
html: i.html,
|
|
738
|
+
renderedAt: t,
|
|
739
|
+
expiresAt: t + i.revalidateMs,
|
|
740
|
+
servableUntil: t + i.revalidateMs + e,
|
|
741
|
+
revalidateMs: i.revalidateMs,
|
|
742
|
+
staleWhileRevalidateMs: e
|
|
743
743
|
});
|
|
744
744
|
}
|
|
745
745
|
} catch (e) {
|
|
746
|
-
J.warn("background SWR refresh failed", { url:
|
|
746
|
+
J.warn("background SWR refresh failed", { url: r }, e);
|
|
747
747
|
}
|
|
748
748
|
})(), {
|
|
749
749
|
status: 200,
|
|
@@ -751,43 +751,43 @@ CREATE INDEX IF NOT EXISTS ${e}_servable_until_idx ON ${e} (servable_until);
|
|
|
751
751
|
"content-type": "text/html; charset=utf-8",
|
|
752
752
|
"x-voltro-rendered-by": "isr",
|
|
753
753
|
"x-voltro-cache": "STALE",
|
|
754
|
-
"x-voltro-cache-key":
|
|
754
|
+
"x-voltro-cache-key": g,
|
|
755
755
|
"x-voltro-cache-age-ms": String(v - _.renderedAt)
|
|
756
756
|
},
|
|
757
757
|
body: _.html
|
|
758
758
|
};
|
|
759
759
|
try {
|
|
760
|
-
let
|
|
761
|
-
provider:
|
|
762
|
-
root:
|
|
760
|
+
let i = await De({
|
|
761
|
+
provider: K,
|
|
762
|
+
root: e,
|
|
763
763
|
route: u.route,
|
|
764
764
|
params: u.params,
|
|
765
|
-
pathname:
|
|
766
|
-
dirs:
|
|
767
|
-
shellTemplate:
|
|
765
|
+
pathname: r,
|
|
766
|
+
dirs: H,
|
|
767
|
+
shellTemplate: P,
|
|
768
768
|
requestHeaders: n,
|
|
769
769
|
apiOrigin: fe,
|
|
770
770
|
apiName: pe,
|
|
771
771
|
requestUrl: t
|
|
772
772
|
});
|
|
773
|
-
if (!
|
|
773
|
+
if (!i) return {
|
|
774
774
|
status: 200,
|
|
775
775
|
headers: {
|
|
776
776
|
"content-type": "text/html; charset=utf-8",
|
|
777
777
|
"x-voltro-rendered-by": "spa-fallback"
|
|
778
778
|
},
|
|
779
|
-
body:
|
|
779
|
+
body: P
|
|
780
780
|
};
|
|
781
|
-
if ("stream" in
|
|
781
|
+
if ("stream" in i) return {
|
|
782
782
|
status: 200,
|
|
783
|
-
headers: { "x-voltro-rendered-by":
|
|
783
|
+
headers: { "x-voltro-rendered-by": i.renderMode },
|
|
784
784
|
body: "",
|
|
785
|
-
stream:
|
|
785
|
+
stream: i.stream
|
|
786
786
|
};
|
|
787
|
-
if ("control" in
|
|
788
|
-
status:
|
|
787
|
+
if ("control" in i) return i.control === "redirect" ? {
|
|
788
|
+
status: i.status,
|
|
789
789
|
headers: {
|
|
790
|
-
location:
|
|
790
|
+
location: i.location,
|
|
791
791
|
"x-voltro-rendered-by": "loader-redirect"
|
|
792
792
|
},
|
|
793
793
|
body: ""
|
|
@@ -801,34 +801,34 @@ CREATE INDEX IF NOT EXISTS ${e}_servable_until_idx ON ${e} (servable_until);
|
|
|
801
801
|
};
|
|
802
802
|
let a = {
|
|
803
803
|
"content-type": "text/html; charset=utf-8",
|
|
804
|
-
"x-voltro-rendered-by":
|
|
804
|
+
"x-voltro-rendered-by": i.renderMode
|
|
805
805
|
};
|
|
806
|
-
if (
|
|
807
|
-
let
|
|
808
|
-
z.set(
|
|
809
|
-
html:
|
|
810
|
-
renderedAt:
|
|
811
|
-
expiresAt:
|
|
812
|
-
servableUntil:
|
|
813
|
-
revalidateMs:
|
|
814
|
-
staleWhileRevalidateMs:
|
|
815
|
-
}), a["x-voltro-cache"] = "MISS", a["x-voltro-cache-key"] =
|
|
806
|
+
if (i.renderMode === "isr" && i.revalidateMs !== null) {
|
|
807
|
+
let e = Date.now(), t = q.get(u.route.pattern)?.staleWhileRevalidateMs ?? 0;
|
|
808
|
+
z.set(g, {
|
|
809
|
+
html: i.html,
|
|
810
|
+
renderedAt: e,
|
|
811
|
+
expiresAt: e + i.revalidateMs,
|
|
812
|
+
servableUntil: e + i.revalidateMs + t,
|
|
813
|
+
revalidateMs: i.revalidateMs,
|
|
814
|
+
staleWhileRevalidateMs: t
|
|
815
|
+
}), a["x-voltro-cache"] = "MISS", a["x-voltro-cache-key"] = g, a["x-voltro-cache-revalidate-ms"] = String(i.revalidateMs), t > 0 && (a["x-voltro-cache-swr-ms"] = String(t)), f.emit("cache", {
|
|
816
816
|
kind: "MISS",
|
|
817
|
-
key:
|
|
818
|
-
revalidateMs:
|
|
819
|
-
swrMs:
|
|
817
|
+
key: g,
|
|
818
|
+
revalidateMs: i.revalidateMs,
|
|
819
|
+
swrMs: t
|
|
820
820
|
});
|
|
821
|
-
} else
|
|
821
|
+
} else i.renderMode === "isr" && (a["x-voltro-cache"] = "BYPASS", f.emit("cache", {
|
|
822
822
|
kind: "BYPASS",
|
|
823
|
-
key:
|
|
823
|
+
key: g
|
|
824
824
|
}));
|
|
825
825
|
return {
|
|
826
826
|
status: 200,
|
|
827
827
|
headers: a,
|
|
828
|
-
body:
|
|
828
|
+
body: i.html
|
|
829
829
|
};
|
|
830
830
|
} catch (e) {
|
|
831
|
-
return J.error("render error", { url:
|
|
831
|
+
return J.error("render error", { url: r }, e), M(e) ? {
|
|
832
832
|
status: 500,
|
|
833
833
|
headers: {
|
|
834
834
|
"content-type": "text/plain; charset=utf-8",
|
|
@@ -842,17 +842,17 @@ CREATE INDEX IF NOT EXISTS ${e}_servable_until_idx ON ${e} (servable_until);
|
|
|
842
842
|
};
|
|
843
843
|
}
|
|
844
844
|
}, Fe = !1, Ie = ge(async (e, t) => {
|
|
845
|
-
let
|
|
846
|
-
for (let [t, n] of Object.entries(e.headers)) n !== void 0 && (
|
|
847
|
-
let
|
|
848
|
-
if (
|
|
845
|
+
let n = e.url ?? "/", r = Date.now(), i = {};
|
|
846
|
+
for (let [t, n] of Object.entries(e.headers)) n !== void 0 && (i[t.toLowerCase()] = Array.isArray(n) ? n.join(", ") : n);
|
|
847
|
+
let c = n.split("?")[0] ?? "/", l = (e.method ?? "GET").toUpperCase();
|
|
848
|
+
if (c === "/internal/liveness") {
|
|
849
849
|
t.writeHead(200, {
|
|
850
850
|
"content-type": "text/plain",
|
|
851
851
|
"cache-control": "no-store"
|
|
852
852
|
}), t.end("ok");
|
|
853
853
|
return;
|
|
854
854
|
}
|
|
855
|
-
if (
|
|
855
|
+
if (c === "/internal/readiness") {
|
|
856
856
|
let e = Fe ? 200 : 503;
|
|
857
857
|
t.writeHead(e, {
|
|
858
858
|
"content-type": "text/plain",
|
|
@@ -860,71 +860,71 @@ CREATE INDEX IF NOT EXISTS ${e}_servable_until_idx ON ${e} (servable_until);
|
|
|
860
860
|
}), t.end(Fe ? "ready" : "not-ready");
|
|
861
861
|
return;
|
|
862
862
|
}
|
|
863
|
-
if (
|
|
864
|
-
let e =
|
|
863
|
+
if (l === "OPTIONS" && c.startsWith("/_voltro/inspect")) {
|
|
864
|
+
let e = I(i.origin);
|
|
865
865
|
t.writeHead(204, e), t.end();
|
|
866
866
|
return;
|
|
867
867
|
}
|
|
868
|
-
if (
|
|
869
|
-
let
|
|
870
|
-
if (!
|
|
868
|
+
if (s.name === "voltroDashboard" && c === "/api/dashboard/proxy") {
|
|
869
|
+
let r = new URL(n, "http://x").searchParams.get("target");
|
|
870
|
+
if (!r) {
|
|
871
871
|
t.writeHead(400, { "content-type": "text/plain" }), t.end("missing ?target=");
|
|
872
872
|
return;
|
|
873
873
|
}
|
|
874
|
-
if (!
|
|
874
|
+
if (!ce(r)) {
|
|
875
875
|
t.writeHead(400, { "content-type": "text/plain" }), t.end("target not allowed: must be loopback or an origin configured in VOLTRO_DASHBOARD_APPS");
|
|
876
876
|
return;
|
|
877
877
|
}
|
|
878
878
|
try {
|
|
879
|
-
let
|
|
880
|
-
|
|
879
|
+
let n = { accept: i.accept ?? "application/json" }, a = i.authorization;
|
|
880
|
+
a ? n.authorization = Array.isArray(a) ? a[0] : a : se(r) && process.env.VOLTRO_INSPECT_TOKEN && (n.authorization = `Bearer ${process.env.VOLTRO_INSPECT_TOKEN}`);
|
|
881
881
|
let o;
|
|
882
|
-
if (
|
|
882
|
+
if (l && l !== "GET" && l !== "HEAD") {
|
|
883
883
|
let t = [];
|
|
884
884
|
for await (let n of e) t.push(n);
|
|
885
885
|
o = Buffer.concat(t);
|
|
886
|
-
let
|
|
887
|
-
|
|
886
|
+
let r = i["content-type"];
|
|
887
|
+
r && (n["content-type"] = Array.isArray(r) ? r[0] : r);
|
|
888
888
|
}
|
|
889
|
-
let
|
|
889
|
+
let s = await fetch(r, {
|
|
890
890
|
redirect: "manual",
|
|
891
|
-
method:
|
|
892
|
-
headers:
|
|
891
|
+
method: l,
|
|
892
|
+
headers: n,
|
|
893
893
|
...o ? { body: new Uint8Array(o.buffer, o.byteOffset, o.byteLength) } : {}
|
|
894
|
-
}),
|
|
895
|
-
t.writeHead(
|
|
896
|
-
"content-type":
|
|
897
|
-
"content-length": String(
|
|
898
|
-
}), t.end(
|
|
894
|
+
}), c = Buffer.from(await s.arrayBuffer());
|
|
895
|
+
t.writeHead(s.status, {
|
|
896
|
+
"content-type": s.headers.get("content-type") ?? "application/octet-stream",
|
|
897
|
+
"content-length": String(c.length)
|
|
898
|
+
}), t.end(c);
|
|
899
899
|
} catch (e) {
|
|
900
900
|
t.writeHead(502, { "content-type": "text/plain" }), t.end(`proxy error: ${e.message}`);
|
|
901
901
|
}
|
|
902
902
|
return;
|
|
903
903
|
}
|
|
904
|
-
if (
|
|
905
|
-
let
|
|
906
|
-
if (!
|
|
904
|
+
if (s.name === "voltroDashboard" && c === "/api/dashboard/proxy/stream") {
|
|
905
|
+
let r = new URL(n, "http://x").searchParams.get("target");
|
|
906
|
+
if (!r) {
|
|
907
907
|
t.writeHead(400, { "content-type": "text/plain" }), t.end("missing ?target=");
|
|
908
908
|
return;
|
|
909
909
|
}
|
|
910
|
-
if (!
|
|
910
|
+
if (!ce(r)) {
|
|
911
911
|
t.writeHead(400, { "content-type": "text/plain" }), t.end("target not allowed: must be loopback or an origin configured in VOLTRO_DASHBOARD_APPS");
|
|
912
912
|
return;
|
|
913
913
|
}
|
|
914
|
-
let
|
|
915
|
-
e.on("close", () =>
|
|
914
|
+
let a = new AbortController();
|
|
915
|
+
e.on("close", () => a.abort()), t.on("close", () => a.abort());
|
|
916
916
|
try {
|
|
917
|
-
let e =
|
|
917
|
+
let e = i.authorization ?? (se(r) && process.env.VOLTRO_INSPECT_TOKEN ? `Bearer ${process.env.VOLTRO_INSPECT_TOKEN}` : void 0), n = await fetch(r, {
|
|
918
918
|
redirect: "manual",
|
|
919
919
|
method: "GET",
|
|
920
920
|
headers: {
|
|
921
921
|
accept: "text/event-stream",
|
|
922
922
|
...e ? { authorization: Array.isArray(e) ? e[0] : e } : {}
|
|
923
923
|
},
|
|
924
|
-
signal:
|
|
924
|
+
signal: a.signal
|
|
925
925
|
});
|
|
926
|
-
if (!
|
|
927
|
-
t.writeHead(
|
|
926
|
+
if (!n.ok || !n.body) {
|
|
927
|
+
t.writeHead(n.status, { "content-type": "text/plain" }), t.end(`upstream ${n.status}`);
|
|
928
928
|
return;
|
|
929
929
|
}
|
|
930
930
|
t.writeHead(200, {
|
|
@@ -933,7 +933,7 @@ CREATE INDEX IF NOT EXISTS ${e}_servable_until_idx ON ${e} (servable_until);
|
|
|
933
933
|
connection: "keep-alive",
|
|
934
934
|
"x-accel-buffering": "no"
|
|
935
935
|
}), t.flushHeaders();
|
|
936
|
-
let o =
|
|
936
|
+
let o = n.body.getReader();
|
|
937
937
|
try {
|
|
938
938
|
for (;;) {
|
|
939
939
|
let { done: e, value: n } = await o.read();
|
|
@@ -948,23 +948,23 @@ CREATE INDEX IF NOT EXISTS ${e}_servable_until_idx ON ${e} (servable_until);
|
|
|
948
948
|
}
|
|
949
949
|
return;
|
|
950
950
|
}
|
|
951
|
-
if (
|
|
952
|
-
let
|
|
953
|
-
if (
|
|
951
|
+
if (c === "/_voltro/inspect/stream") {
|
|
952
|
+
let n = I(i.origin);
|
|
953
|
+
if (L()) {
|
|
954
954
|
t.writeHead(503, {
|
|
955
955
|
"content-type": "application/json",
|
|
956
|
-
...
|
|
956
|
+
...n
|
|
957
957
|
}), t.end(JSON.stringify({ error: "inspect disabled (VOLTRO_INSPECT=off)" }));
|
|
958
958
|
return;
|
|
959
959
|
}
|
|
960
|
-
let
|
|
961
|
-
if (!
|
|
960
|
+
let r = le(i, "GET");
|
|
961
|
+
if (!r.ok) {
|
|
962
962
|
t.writeHead(401, {
|
|
963
963
|
"content-type": "application/json",
|
|
964
|
-
...
|
|
964
|
+
...n
|
|
965
965
|
}), t.end(JSON.stringify({
|
|
966
966
|
error: "unauthorized",
|
|
967
|
-
reason:
|
|
967
|
+
reason: r.reason
|
|
968
968
|
}));
|
|
969
969
|
return;
|
|
970
970
|
}
|
|
@@ -973,32 +973,32 @@ CREATE INDEX IF NOT EXISTS ${e}_servable_until_idx ON ${e} (servable_until);
|
|
|
973
973
|
"cache-control": "no-cache, no-transform",
|
|
974
974
|
connection: "keep-alive",
|
|
975
975
|
"x-accel-buffering": "no",
|
|
976
|
-
...
|
|
976
|
+
...n
|
|
977
977
|
}), t.flushHeaders(), t.write("retry: 5000\n\n");
|
|
978
|
-
for (let e of
|
|
979
|
-
let
|
|
980
|
-
t.write(
|
|
981
|
-
}),
|
|
982
|
-
t.write(
|
|
983
|
-
}, 15e3),
|
|
984
|
-
clearInterval(
|
|
978
|
+
for (let e of f.buffered()) t.write(o(e));
|
|
979
|
+
let s = f.subscribe((e) => {
|
|
980
|
+
t.write(o(e));
|
|
981
|
+
}), c = setInterval(() => {
|
|
982
|
+
t.write(a());
|
|
983
|
+
}, 15e3), l = () => {
|
|
984
|
+
clearInterval(c), s();
|
|
985
985
|
};
|
|
986
|
-
e.on("close",
|
|
986
|
+
e.on("close", l), t.on("close", l);
|
|
987
987
|
return;
|
|
988
988
|
}
|
|
989
989
|
try {
|
|
990
|
-
let e = await Pe(
|
|
991
|
-
if (e.stream ? e.stream(t) : (t.writeHead(e.status, e.headers), t.end(e.body)), !
|
|
992
|
-
let t = Date.now() -
|
|
993
|
-
|
|
994
|
-
url:
|
|
990
|
+
let e = await Pe(n, i);
|
|
991
|
+
if (e.stream ? e.stream(t) : (t.writeHead(e.status, e.headers), t.end(e.body)), !c.startsWith("/_voltro/inspect")) {
|
|
992
|
+
let t = Date.now() - r;
|
|
993
|
+
f.emit("request", {
|
|
994
|
+
url: c,
|
|
995
995
|
status: e.status,
|
|
996
996
|
durationMs: t,
|
|
997
997
|
renderedBy: e.headers["x-voltro-rendered-by"],
|
|
998
998
|
cache: e.headers["x-voltro-cache"]
|
|
999
999
|
});
|
|
1000
|
-
let n =
|
|
1001
|
-
|
|
1000
|
+
let n = Ee(c, W)?.route.pattern ?? (e.status === 404 ? "<unmatched>" : "<asset>");
|
|
1001
|
+
$.record({
|
|
1002
1002
|
kind: "request",
|
|
1003
1003
|
tag: n,
|
|
1004
1004
|
durationMs: t,
|
|
@@ -1009,56 +1009,56 @@ CREATE INDEX IF NOT EXISTS ${e}_servable_until_idx ON ${e} (servable_until);
|
|
|
1009
1009
|
t.writeHead(500, { "content-type": "text/plain" }), t.end(`internal error: ${e.message}`);
|
|
1010
1010
|
}
|
|
1011
1011
|
});
|
|
1012
|
-
await new Promise((e) => Ie.listen(
|
|
1013
|
-
port:
|
|
1014
|
-
distDir:
|
|
1012
|
+
await new Promise((e) => Ie.listen(m, "::", e)), Fe = !0, t.mark("ready"), J.info(`listening on http://localhost:${m}`, {
|
|
1013
|
+
port: m,
|
|
1014
|
+
distDir: y
|
|
1015
1015
|
}), J.debug("dynamic + ssr/isr routes resolve via SSR loader");
|
|
1016
1016
|
try {
|
|
1017
|
-
await
|
|
1017
|
+
await N({
|
|
1018
1018
|
id: T,
|
|
1019
1019
|
name: C,
|
|
1020
1020
|
kind: "web",
|
|
1021
|
-
url: `http://localhost:${
|
|
1021
|
+
url: `http://localhost:${m}`,
|
|
1022
1022
|
pid: process.pid,
|
|
1023
1023
|
status: "live",
|
|
1024
|
-
logFile:
|
|
1024
|
+
logFile: E.path
|
|
1025
1025
|
});
|
|
1026
|
-
let
|
|
1027
|
-
if (
|
|
1028
|
-
let
|
|
1029
|
-
|
|
1026
|
+
let t = n(e);
|
|
1027
|
+
if (t) {
|
|
1028
|
+
let e = await r({ dashboardAppPath: t });
|
|
1029
|
+
e.status === "launched" ? J.info(`dashboard launched at http://localhost:${e.port}`, { port: e.port }) : e.status === "already-running" && J.debug(`dashboard already running on :${e.port}`, { port: e.port });
|
|
1030
1030
|
}
|
|
1031
1031
|
setInterval(() => {
|
|
1032
|
-
|
|
1032
|
+
N({
|
|
1033
1033
|
id: T,
|
|
1034
1034
|
name: C,
|
|
1035
1035
|
kind: "web",
|
|
1036
|
-
url: `http://localhost:${
|
|
1036
|
+
url: `http://localhost:${m}`,
|
|
1037
1037
|
pid: process.pid,
|
|
1038
1038
|
status: "live",
|
|
1039
|
-
logFile:
|
|
1039
|
+
logFile: E.path
|
|
1040
1040
|
}).catch(() => {});
|
|
1041
1041
|
}, 1e4).unref();
|
|
1042
1042
|
} catch (e) {
|
|
1043
1043
|
J.warn("runtime-registry write failed", {}, e);
|
|
1044
1044
|
}
|
|
1045
1045
|
me({
|
|
1046
|
-
app:
|
|
1046
|
+
app: s.name ?? "unnamed",
|
|
1047
1047
|
kind: "web",
|
|
1048
|
-
url: `http://localhost:${
|
|
1049
|
-
bootMs:
|
|
1048
|
+
url: `http://localhost:${m}`,
|
|
1049
|
+
bootMs: t.total()
|
|
1050
1050
|
});
|
|
1051
|
-
let Le =
|
|
1052
|
-
J.info(`start: ready in ${
|
|
1053
|
-
bootMs:
|
|
1051
|
+
let Le = t.phaseBreakdown();
|
|
1052
|
+
J.info(`start: ready in ${t.total()}ms`, {
|
|
1053
|
+
bootMs: t.total(),
|
|
1054
1054
|
...Le ? { phases: Le } : {}
|
|
1055
1055
|
});
|
|
1056
1056
|
let Re = !1, ze = (e) => async () => {
|
|
1057
1057
|
if (!Re) {
|
|
1058
|
-
if (Re = !0, J.info(`received ${e}, shutting down`, { signal: e }), Ie.close(), await
|
|
1058
|
+
if (Re = !0, J.info(`received ${e}, shutting down`, { signal: e }), Ie.close(), await Q.stop(), B) try {
|
|
1059
1059
|
await B.end();
|
|
1060
1060
|
} catch {}
|
|
1061
|
-
await
|
|
1061
|
+
await K.close(), await p(T), await E.dispose(), process.exit(0);
|
|
1062
1062
|
}
|
|
1063
1063
|
};
|
|
1064
1064
|
process.on("SIGINT", ze("SIGINT")), process.on("SIGTERM", ze("SIGTERM"));
|
|
@@ -1070,10 +1070,10 @@ CREATE INDEX IF NOT EXISTS ${e}_servable_until_idx ON ${e} (servable_until);
|
|
|
1070
1070
|
e.unref();
|
|
1071
1071
|
}
|
|
1072
1072
|
return new Promise(() => {});
|
|
1073
|
-
},
|
|
1073
|
+
}, je = async (e) => {
|
|
1074
1074
|
process.env.NODE_ENV || (process.env.NODE_ENV = "production");
|
|
1075
|
-
let t = await
|
|
1075
|
+
let t = await Ae(z(e.find((e) => !e.startsWith("-")) ?? process.cwd()));
|
|
1076
1076
|
return t.ran ? t.exitCode : (J.error("no web app found at this path"), 1);
|
|
1077
1077
|
};
|
|
1078
1078
|
//#endregion
|
|
1079
|
-
export {
|
|
1079
|
+
export { je as t };
|