@voltro/cli 0.7.0 → 0.8.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 +21 -0
- package/dist/apiBuild-CmtI6Ygh.js +2 -0
- package/dist/{apiBuild-deIjJKJm.js → apiBuild-OrDkXGFX.js} +2 -2
- package/dist/bin.js +2 -2
- package/dist/{commands-BHdc71DG.js → commands-DT4PipBz.js} +666 -526
- package/dist/dev-Ca1jdwnt.js +2 -0
- package/dist/{dev-Bqyq62Ak.js → dev-Ga65K4jc.js} +469 -469
- package/dist/index.js +1 -1
- package/dist/{inspectMetrics-BLUBAWLb.js → inspectMetrics-EK0CcHyu.js} +977 -759
- package/dist/{serveCommand-Dn6--0Bv.js → serveCommand-CR5xnYZt.js} +5 -5
- package/dist/serveEntry.js +3 -3
- package/dist/{start-CWZW_4Et.js → start-DuyBQxW3.js} +332 -296
- package/dist/startEntry.js +2 -2
- package/package.json +17 -17
- package/templates/AGENTS.core.md +15 -4
- package/templates/AGENTS.md +15 -4
- package/templates/agent-docs/authentication.md +7 -4
- package/templates/agent-docs/cli.md +35 -4
- package/templates/agent-docs/data.md +94 -70
- package/templates/agent-docs/database/schema.md +1 -1
- package/templates/agent-docs/reference.md +20 -0
- package/templates/agent-docs/routing.md +158 -24
- package/templates/agent-docs/testing.md +24 -0
- package/templates/apps/api-ai/package.json +7 -7
- package/templates/apps/api-auth/package.json +8 -8
- package/templates/apps/api-backend/package.json +7 -7
- package/templates/apps/api-backend-deactivation/package.json +7 -7
- package/templates/apps/api-backend-mail/package.json +8 -8
- package/templates/apps/api-backend-mariadb/package.json +9 -9
- package/templates/apps/api-backend-storage/package.json +8 -8
- package/templates/apps/api-data-advanced/package.json +8 -8
- package/templates/apps/api-durable/package.json +8 -8
- package/templates/apps/api-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-CSM74oEZ.js +0 -2
- package/dist/dev-BYfrYwrT.js +0 -2
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { n as re, t as ie } from "./start-
|
|
3
|
-
import { $ as ae, B as oe, L as se, R as ce, V as le, ct as ue, i as de, l as fe, n as pe, o as me, ot as he, p as ge, tt as _e, ut as ve, z as ye } from "./dev-
|
|
1
|
+
import { C as e, Ct as t, St as n, T as r, Tt as i, _ as a, _t as o, a as s, b as c, bt as l, d as u, f as d, gt as f, ht as p, l as m, o as h, s as g, u as _, vt as v, wt as y, x as ee, xt as te, yt as ne } from "./inspectMetrics-EK0CcHyu.js";
|
|
2
|
+
import { n as re, t as ie } from "./start-DuyBQxW3.js";
|
|
3
|
+
import { $ as ae, B as oe, L as se, R as ce, V as le, ct as ue, i as de, l as fe, n as pe, o as me, ot as he, p as ge, tt as _e, ut as ve, z as ye } from "./dev-Ga65K4jc.js";
|
|
4
4
|
import { a as b, c as be, i as xe, o as Se, s as Ce } from "./devActivity-1WtIVyHc.js";
|
|
5
|
-
import { a as we, t as Te } from "./apiBuild-
|
|
6
|
-
import { n as Ee, r as De } from "./serveCommand-
|
|
5
|
+
import { a as we, t as Te } from "./apiBuild-OrDkXGFX.js";
|
|
6
|
+
import { n as Ee, r as De } from "./serveCommand-CR5xnYZt.js";
|
|
7
7
|
import { basename as x, dirname as S, isAbsolute as Oe, join as C, relative as w, resolve as T } from "node:path";
|
|
8
8
|
import { fileURLToPath as ke, pathToFileURL as Ae } from "node:url";
|
|
9
9
|
import { FileSystem as je } from "@effect/platform";
|
|
@@ -344,35 +344,35 @@ external scheduler owns the once-only guarantee.
|
|
|
344
344
|
let n = e.replace("<div id=\"root\"></div>", `<div id="root">${t.body}</div>`), r = [
|
|
345
345
|
t.metaHtml,
|
|
346
346
|
`<meta name="voltro-interactive" content="${t.interactive}" />`,
|
|
347
|
-
|
|
347
|
+
t.stateScript
|
|
348
348
|
].filter((e) => e.length > 0).join("\n ");
|
|
349
349
|
return n = n.replace("</head>", ` ${r}\n </head>`), t.interactive === "none" && (n = In(n)), n;
|
|
350
|
-
}, Rn = async (
|
|
351
|
-
let { root:
|
|
352
|
-
await M.mkdir(S(
|
|
353
|
-
let
|
|
350
|
+
}, Rn = async (e) => {
|
|
351
|
+
let { root: t, distDir: r, pages: i, dirs: a, vite: o } = e, c = C(r, "index.html"), l = await M.readFile(c, "utf8"), u = C(r, "_voltro", "shell.html");
|
|
352
|
+
await M.mkdir(S(u), { recursive: !0 }), await M.writeFile(u, l, "utf8");
|
|
353
|
+
let d = C(t, "node_modules", "@voltro", "ui-shadcn"), f = A(C(d, "package.json")) ? d : null, p = [...f ? [
|
|
354
354
|
{
|
|
355
355
|
find: "@voltro/ui-shadcn/tokens.css",
|
|
356
|
-
replacement: C(
|
|
356
|
+
replacement: C(f, "src/tokens.css")
|
|
357
357
|
},
|
|
358
358
|
{
|
|
359
359
|
find: "@voltro/ui-shadcn/cn",
|
|
360
|
-
replacement: C(
|
|
360
|
+
replacement: C(f, "src/cn.ts")
|
|
361
361
|
},
|
|
362
362
|
{
|
|
363
363
|
find: "@voltro/ui-shadcn/brand",
|
|
364
|
-
replacement: C(
|
|
364
|
+
replacement: C(f, "src/brand/voltroLogo.tsx")
|
|
365
365
|
},
|
|
366
366
|
{
|
|
367
367
|
find: "@voltro/ui-shadcn",
|
|
368
|
-
replacement: C(
|
|
368
|
+
replacement: C(f, "src/index.ts")
|
|
369
369
|
}
|
|
370
|
-
] : [], ...
|
|
371
|
-
root: C(
|
|
370
|
+
] : [], ...n(t)], m = await o.createServer({
|
|
371
|
+
root: C(t, ".framework"),
|
|
372
372
|
envPrefix: "__VOLTRO_VITE_ENV_DISABLED__",
|
|
373
373
|
plugins: [(await import("@vitejs/plugin-react")).default(), (await import("@tailwindcss/vite")).default()],
|
|
374
374
|
resolve: {
|
|
375
|
-
alias:
|
|
375
|
+
alias: p,
|
|
376
376
|
dedupe: ["react", "react-dom"]
|
|
377
377
|
},
|
|
378
378
|
ssr: { noExternal: ["react-intl"] },
|
|
@@ -383,122 +383,130 @@ external scheduler owns the once-only guarantee.
|
|
|
383
383
|
},
|
|
384
384
|
appType: "custom",
|
|
385
385
|
logLevel: "warn"
|
|
386
|
-
}), { renderPageToHtml: h, renderMetaToHtml: g,
|
|
387
|
-
if (
|
|
388
|
-
let
|
|
389
|
-
if (typeof
|
|
390
|
-
for (let r of
|
|
391
|
-
let i = await m.ssrLoadModule(C(
|
|
392
|
-
|
|
386
|
+
}), { renderPageToHtml: h, renderMetaToHtml: g, renderRouterStateScript: _, isDeferredLoaderResult: v, assertDeferralSupported: y } = await m.ssrLoadModule("@voltro/web/ssr"), ee = /* @__PURE__ */ new Map();
|
|
387
|
+
if (e.locales && e.locales.length > 0 && e.defaultLocale) try {
|
|
388
|
+
let n = (await m.ssrLoadModule("@voltro/i18n")).makeSsgWrap;
|
|
389
|
+
if (typeof n != "function") throw Error("@voltro/i18n is installed but missing the `makeSsgWrap` export — upgrade @voltro/i18n to a version that ships SSG support.");
|
|
390
|
+
for (let r of e.locales) try {
|
|
391
|
+
let i = await m.ssrLoadModule(C(t, "src", "locales", `${r}.ts`)), a = i.default ?? i;
|
|
392
|
+
ee.set(r, n(r, a, e.defaultLocale));
|
|
393
393
|
} catch (e) {
|
|
394
394
|
z.warn(`i18n catalog missing for locale '${r}' — pages rendered at /${r}/* will crash. Add src/locales/${r}.ts.`, {}, e);
|
|
395
395
|
}
|
|
396
396
|
} catch (e) {
|
|
397
397
|
z.warn("i18n wrapper unavailable for SSG — pages that call useT() will fail. Check that @voltro/i18n is installed.", {}, e);
|
|
398
398
|
}
|
|
399
|
-
let
|
|
400
|
-
for (let
|
|
401
|
-
let i = `${C(
|
|
402
|
-
|
|
403
|
-
let
|
|
404
|
-
if (
|
|
399
|
+
let te = [], ne = {};
|
|
400
|
+
for (let n of i) {
|
|
401
|
+
let i = `${C(t, "src", "pages", n.file)}`, o = await m.ssrLoadModule(i);
|
|
402
|
+
ne[n.pattern] = re(o);
|
|
403
|
+
let c = o.renderMode ?? "static";
|
|
404
|
+
if (c !== "static") {
|
|
405
405
|
z.debug("skip page", {
|
|
406
|
-
pattern:
|
|
407
|
-
reason: `renderMode=${
|
|
406
|
+
pattern: n.pattern,
|
|
407
|
+
reason: `renderMode=${c}`
|
|
408
408
|
});
|
|
409
409
|
continue;
|
|
410
410
|
}
|
|
411
|
-
let
|
|
412
|
-
if (Nn(
|
|
411
|
+
let u;
|
|
412
|
+
if (Nn(n.pattern)) {
|
|
413
413
|
if (typeof o.getStaticPaths != "function") {
|
|
414
414
|
z.debug("skip page", {
|
|
415
|
-
pattern:
|
|
415
|
+
pattern: n.pattern,
|
|
416
416
|
reason: "no getStaticPaths export"
|
|
417
417
|
});
|
|
418
418
|
continue;
|
|
419
419
|
}
|
|
420
420
|
try {
|
|
421
|
-
let
|
|
422
|
-
if (!Array.isArray(
|
|
423
|
-
z.warn("skip page — getStaticPaths did not return an array", { pattern:
|
|
421
|
+
let e = await o.getStaticPaths();
|
|
422
|
+
if (!Array.isArray(e)) {
|
|
423
|
+
z.warn("skip page — getStaticPaths did not return an array", { pattern: n.pattern });
|
|
424
424
|
continue;
|
|
425
425
|
}
|
|
426
|
-
|
|
427
|
-
params:
|
|
428
|
-
pathname: Pn(
|
|
426
|
+
u = e.map((e) => ({
|
|
427
|
+
params: e.params,
|
|
428
|
+
pathname: Pn(n.pattern, e.params)
|
|
429
429
|
}));
|
|
430
|
-
} catch (
|
|
431
|
-
z.warn("skip page — getStaticPaths threw", { pattern:
|
|
430
|
+
} catch (e) {
|
|
431
|
+
z.warn("skip page — getStaticPaths threw", { pattern: n.pattern }, e);
|
|
432
432
|
continue;
|
|
433
433
|
}
|
|
434
|
-
if (
|
|
434
|
+
if (u.length === 0) {
|
|
435
435
|
z.debug("skip page", {
|
|
436
|
-
pattern:
|
|
436
|
+
pattern: n.pattern,
|
|
437
437
|
reason: "getStaticPaths returned []"
|
|
438
438
|
});
|
|
439
439
|
continue;
|
|
440
440
|
}
|
|
441
|
-
} else
|
|
441
|
+
} else u = [{
|
|
442
442
|
params: {},
|
|
443
|
-
pathname:
|
|
443
|
+
pathname: n.pattern
|
|
444
444
|
}];
|
|
445
|
-
let
|
|
446
|
-
let
|
|
447
|
-
return e.hasLayout && (r.Layout = (await m.ssrLoadModule(C(
|
|
445
|
+
let d = s(a, n.dirChain), f = await Promise.all(d.map(async (e) => {
|
|
446
|
+
let n = e.dir === "" ? C(t, "src", "pages") : C(t, "src", "pages", e.dir), r = {};
|
|
447
|
+
return e.hasLayout && (r.Layout = (await m.ssrLoadModule(C(n, "layout.tsx"))).default), e.hasError && (r.Error = (await m.ssrLoadModule(C(n, "error.tsx"))).default), e.hasPending && (r.Pending = (await m.ssrLoadModule(C(n, "loading.tsx"))).default), {
|
|
448
448
|
id: e.dir || "/",
|
|
449
449
|
...r
|
|
450
450
|
};
|
|
451
|
-
})),
|
|
452
|
-
pattern:
|
|
451
|
+
})), p = {
|
|
452
|
+
pattern: n.pattern,
|
|
453
453
|
Component: o.default,
|
|
454
454
|
meta: o.meta,
|
|
455
455
|
loader: o.loader,
|
|
456
456
|
ErrorBoundary: o.ErrorBoundary,
|
|
457
457
|
Pending: o.Pending,
|
|
458
|
-
renderMode:
|
|
459
|
-
chain:
|
|
460
|
-
},
|
|
461
|
-
for (let
|
|
458
|
+
renderMode: c,
|
|
459
|
+
chain: f
|
|
460
|
+
}, ie = o.interactive ?? "full";
|
|
461
|
+
for (let t of u) {
|
|
462
462
|
let n = null;
|
|
463
463
|
if (typeof o.loader == "function") {
|
|
464
|
-
let
|
|
464
|
+
let e = new AbortController();
|
|
465
465
|
try {
|
|
466
466
|
n = await o.loader({
|
|
467
|
-
params:
|
|
468
|
-
pathname:
|
|
469
|
-
signal:
|
|
467
|
+
params: t.params,
|
|
468
|
+
pathname: t.pathname,
|
|
469
|
+
signal: e.signal
|
|
470
470
|
});
|
|
471
|
-
} catch (
|
|
472
|
-
if (
|
|
473
|
-
if (
|
|
474
|
-
z.warn("loader threw NotFoundError at build time — skipping artifact", { pathname:
|
|
471
|
+
} catch (e) {
|
|
472
|
+
if (e instanceof Error && e._voltroControl === "redirect") throw Error(`Static page "${t.pathname}" threw RedirectError at build time. Static pages can't redirect per-request — switch it to renderMode 'ssr'.`);
|
|
473
|
+
if (e instanceof Error && e._voltroControl === "not-found") {
|
|
474
|
+
z.warn("loader threw NotFoundError at build time — skipping artifact", { pathname: t.pathname });
|
|
475
475
|
continue;
|
|
476
476
|
}
|
|
477
|
-
z.warn("loader threw, falling back to null", { pathname:
|
|
477
|
+
z.warn("loader threw, falling back to null", { pathname: t.pathname }, e);
|
|
478
478
|
}
|
|
479
479
|
}
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
480
|
+
v(n) && y({
|
|
481
|
+
page: t.pathname,
|
|
482
|
+
renderMode: c,
|
|
483
|
+
interactive: ie
|
|
484
|
+
});
|
|
485
|
+
let i = t.params.locale ?? e.defaultLocale ?? "en", a = ee.get(i) ?? ee.get(e.defaultLocale ?? ""), { html: s, meta: u } = h({
|
|
486
|
+
descriptor: p,
|
|
487
|
+
params: t.params,
|
|
488
|
+
pathname: t.pathname,
|
|
484
489
|
loaderData: n,
|
|
485
490
|
...a ? { outerWrap: a } : {},
|
|
486
491
|
locale: i
|
|
487
|
-
}),
|
|
492
|
+
}), d = Ln(l, {
|
|
488
493
|
body: s,
|
|
489
|
-
metaHtml: g(
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
494
|
+
metaHtml: g(u),
|
|
495
|
+
stateScript: _({
|
|
496
|
+
loaderData: n,
|
|
497
|
+
pageLoaderRan: typeof o.loader == "function"
|
|
498
|
+
}),
|
|
499
|
+
interactive: ie
|
|
500
|
+
}), f = Fn(r, t.pathname);
|
|
501
|
+
await M.mkdir(S(f), { recursive: !0 }), await M.writeFile(f, d, "utf8"), te.push({
|
|
502
|
+
pattern: t.pathname,
|
|
503
|
+
outPath: f
|
|
496
504
|
});
|
|
497
505
|
}
|
|
498
506
|
}
|
|
499
507
|
return await m.close(), {
|
|
500
|
-
rendered:
|
|
501
|
-
pageMeta:
|
|
508
|
+
rendered: te,
|
|
509
|
+
pageMeta: ne
|
|
502
510
|
};
|
|
503
511
|
}, zn = async (e, t, n, r, i, a) => {
|
|
504
512
|
let o = C(e, ".framework"), s = [];
|
|
@@ -530,12 +538,12 @@ external scheduler owns the once-only guarantee.
|
|
|
530
538
|
" const locale = resolveLocale({ cookieHeader: cookieHeader ?? null, acceptLanguageHeader: acceptLanguageHeader ?? null, supported: __I18N_SUPPORTED, defaultLocale: __I18N_DEFAULT })",
|
|
531
539
|
" return { locale, outerWrap: __i18nWraps[locale] ?? __i18nWraps[__I18N_DEFAULT] }",
|
|
532
540
|
"}"
|
|
533
|
-
] : [], g = p ?
|
|
541
|
+
] : [], g = "renderPageToHtml, renderPageToStream, renderMetaToHtml, renderRouterStateScript, renderDeferredRegistryScript, prepareDeferredLoaderData, assertDeferralSupported, parseCookieHeader", _ = p ? `export const helpers = { ${g}, i18n: { resolve: __resolveI18n } }` : `export const helpers = { ${g} }`, v = [
|
|
534
542
|
"// GENERATED BY `voltro build` — do not edit; will be overwritten on next build.",
|
|
535
543
|
"// Entry for the pre-built SSR bundle. Imported by `voltro start`'s",
|
|
536
544
|
"// production runtime; bypasses Vite middleware-mode SSR loading.",
|
|
537
545
|
"",
|
|
538
|
-
"import { renderPageToHtml, renderMetaToHtml,
|
|
546
|
+
"import { renderPageToHtml, renderPageToStream, renderMetaToHtml, renderRouterStateScript, renderDeferredRegistryScript, prepareDeferredLoaderData, assertDeferralSupported, parseCookieHeader } from '@voltro/web/ssr'",
|
|
539
547
|
...m,
|
|
540
548
|
"",
|
|
541
549
|
"// Lazy page loaders — a page's module (and content) loads only when its",
|
|
@@ -557,20 +565,20 @@ external scheduler owns the once-only guarantee.
|
|
|
557
565
|
"}",
|
|
558
566
|
...h,
|
|
559
567
|
"",
|
|
560
|
-
|
|
568
|
+
_,
|
|
561
569
|
""
|
|
562
|
-
].join("\n"),
|
|
563
|
-
return await M.writeFile(
|
|
564
|
-
}, Bn = async (
|
|
565
|
-
let
|
|
566
|
-
if (!
|
|
567
|
-
let { loadApiConfig:
|
|
568
|
-
if (
|
|
569
|
-
z.info("building api app", { app:
|
|
570
|
-
let { runApiBuild:
|
|
571
|
-
await e
|
|
570
|
+
].join("\n"), y = C(o, "ssrEntry.ts");
|
|
571
|
+
return await M.writeFile(y, v, "utf8"), y;
|
|
572
|
+
}, Bn = async (e) => {
|
|
573
|
+
let t = await h(e);
|
|
574
|
+
if (!t) {
|
|
575
|
+
let { loadApiConfig: t } = await import("./dev-Ca1jdwnt.js"), n = await t(e);
|
|
576
|
+
if (n) {
|
|
577
|
+
z.info("building api app", { app: n.name ?? "(unnamed)" });
|
|
578
|
+
let { runApiBuild: t, runServeBundleBuild: r } = await import("./apiBuild-CmtI6Ygh.js");
|
|
579
|
+
await t(e);
|
|
572
580
|
try {
|
|
573
|
-
await r(
|
|
581
|
+
await r(e);
|
|
574
582
|
} catch (e) {
|
|
575
583
|
return z.fatal("serve bundle build FAILED — refusing to ship a bundle-less image. Fix the error above (production serves from the bundle, never tsx).", {}, e), {
|
|
576
584
|
ran: !0,
|
|
@@ -587,82 +595,82 @@ external scheduler owns the once-only guarantee.
|
|
|
587
595
|
exitCode: 0
|
|
588
596
|
};
|
|
589
597
|
}
|
|
590
|
-
z.info("building web app", { app:
|
|
591
|
-
let { resolved:
|
|
592
|
-
rawEnv:
|
|
598
|
+
z.info("building web app", { app: t.name ?? "(unnamed)" });
|
|
599
|
+
let { resolved: r } = await v({
|
|
600
|
+
rawEnv: t.env,
|
|
593
601
|
appType: "web",
|
|
594
|
-
root:
|
|
602
|
+
root: e,
|
|
595
603
|
log: z,
|
|
596
604
|
generateTypes: !0
|
|
597
605
|
});
|
|
598
|
-
await
|
|
599
|
-
let { pages:
|
|
600
|
-
await
|
|
601
|
-
appRoot:
|
|
602
|
-
pages:
|
|
606
|
+
await d(e, t, await g(e, t), r.publicValues);
|
|
607
|
+
let { pages: i } = await u(C(e, "src", "pages"));
|
|
608
|
+
await o({
|
|
609
|
+
appRoot: e,
|
|
610
|
+
pages: i,
|
|
603
611
|
mode: "prod"
|
|
604
612
|
});
|
|
605
|
-
let
|
|
613
|
+
let a = C(e, ".framework"), s = C(a, "dist"), c = C(e, "node_modules", "@voltro", "ui-shadcn"), l = A(C(c, "package.json")) ? c : null, f = [...l ? [
|
|
606
614
|
{
|
|
607
615
|
find: "@voltro/ui-shadcn/tokens.css",
|
|
608
|
-
replacement: C(
|
|
616
|
+
replacement: C(l, "src/tokens.css")
|
|
609
617
|
},
|
|
610
618
|
{
|
|
611
619
|
find: "@voltro/ui-shadcn/cn",
|
|
612
|
-
replacement: C(
|
|
620
|
+
replacement: C(l, "src/cn.ts")
|
|
613
621
|
},
|
|
614
622
|
{
|
|
615
623
|
find: "@voltro/ui-shadcn/brand",
|
|
616
|
-
replacement: C(
|
|
624
|
+
replacement: C(l, "src/brand/voltroLogo.tsx")
|
|
617
625
|
},
|
|
618
626
|
{
|
|
619
627
|
find: "@voltro/ui-shadcn",
|
|
620
|
-
replacement: C(
|
|
628
|
+
replacement: C(l, "src/index.ts")
|
|
621
629
|
}
|
|
622
|
-
] : [], ...e
|
|
630
|
+
] : [], ...n(e)];
|
|
623
631
|
z.info("running vite build");
|
|
624
|
-
let
|
|
625
|
-
await
|
|
626
|
-
root:
|
|
632
|
+
let p = await te("vite", () => import("vite")), m = (await import("@vitejs/plugin-react")).default, y = (await import("@tailwindcss/vite")).default;
|
|
633
|
+
await p.build({
|
|
634
|
+
root: a,
|
|
627
635
|
envPrefix: "__VOLTRO_VITE_ENV_DISABLED__",
|
|
628
|
-
plugins: [
|
|
636
|
+
plugins: [m(), y()],
|
|
629
637
|
resolve: {
|
|
630
|
-
alias:
|
|
638
|
+
alias: f,
|
|
631
639
|
dedupe: ["react", "react-dom"]
|
|
632
640
|
},
|
|
633
|
-
publicDir: C(
|
|
641
|
+
publicDir: C(e, "public"),
|
|
634
642
|
build: {
|
|
635
643
|
outDir: "dist",
|
|
636
644
|
emptyOutDir: !0,
|
|
637
|
-
rollupOptions: { output: { manualChunks:
|
|
645
|
+
rollupOptions: { output: { manualChunks: _ } }
|
|
638
646
|
},
|
|
639
647
|
logLevel: "warn"
|
|
640
648
|
});
|
|
641
|
-
let
|
|
649
|
+
let ee = C(e, "src", "pages"), { pages: ne, dirs: re } = await u(ee);
|
|
642
650
|
if (ne.length === 0) return z.info("no pages found — client-only bundle written", {
|
|
643
|
-
pagesDir:
|
|
644
|
-
distDir:
|
|
651
|
+
pagesDir: ee,
|
|
652
|
+
distDir: s
|
|
645
653
|
}), {
|
|
646
654
|
ran: !0,
|
|
647
655
|
exitCode: 0
|
|
648
656
|
};
|
|
649
657
|
let { rendered: ie, pageMeta: ae } = await Rn({
|
|
650
|
-
root:
|
|
651
|
-
distDir:
|
|
658
|
+
root: e,
|
|
659
|
+
distDir: s,
|
|
652
660
|
pages: ne,
|
|
653
661
|
dirs: re,
|
|
654
|
-
vite:
|
|
655
|
-
...
|
|
656
|
-
...
|
|
662
|
+
vite: p,
|
|
663
|
+
...t.locales ? { locales: t.locales } : {},
|
|
664
|
+
...t.defaultLocale ? { defaultLocale: t.defaultLocale } : {}
|
|
657
665
|
});
|
|
658
|
-
z.info("generating .framework/ssrEntry.ts"), await zn(
|
|
666
|
+
z.info("generating .framework/ssrEntry.ts"), await zn(e, ne, re, t.locales, t.defaultLocale, ae), z.info("vite build --ssr → dist/server/");
|
|
659
667
|
try {
|
|
660
|
-
await
|
|
661
|
-
root:
|
|
668
|
+
await p.build({
|
|
669
|
+
root: a,
|
|
662
670
|
envPrefix: "__VOLTRO_VITE_ENV_DISABLED__",
|
|
663
|
-
plugins: [
|
|
671
|
+
plugins: [m(), y()],
|
|
664
672
|
resolve: {
|
|
665
|
-
alias:
|
|
673
|
+
alias: f,
|
|
666
674
|
dedupe: ["react", "react-dom"]
|
|
667
675
|
},
|
|
668
676
|
ssr: { noExternal: ["react-intl"] },
|
|
@@ -680,20 +688,20 @@ external scheduler owns the once-only guarantee.
|
|
|
680
688
|
exitCode: 1
|
|
681
689
|
};
|
|
682
690
|
}
|
|
683
|
-
let oe = C(
|
|
691
|
+
let oe = C(e, "app.config.ts");
|
|
684
692
|
if (A(oe)) {
|
|
685
693
|
z.info("precompiling app.config.ts → dist/server/appConfig.js");
|
|
686
694
|
try {
|
|
687
|
-
await (await
|
|
695
|
+
await (await te("esbuild", () => import("esbuild"))).build({
|
|
688
696
|
entryPoints: [oe],
|
|
689
|
-
outfile: C(
|
|
697
|
+
outfile: C(s, "server", "appConfig.js"),
|
|
690
698
|
bundle: !0,
|
|
691
699
|
format: "esm",
|
|
692
700
|
platform: "node",
|
|
693
701
|
packages: "external",
|
|
694
|
-
absWorkingDir:
|
|
702
|
+
absWorkingDir: e,
|
|
695
703
|
logLevel: "silent",
|
|
696
|
-
...A(C(
|
|
704
|
+
...A(C(e, "tsconfig.json")) ? { tsconfig: C(e, "tsconfig.json") } : {}
|
|
697
705
|
});
|
|
698
706
|
} catch (e) {
|
|
699
707
|
return z.fatal("app.config precompile FAILED — production `voltro start` would need the tsx loader to read it.", {}, e), {
|
|
@@ -707,19 +715,19 @@ external scheduler owns the once-only guarantee.
|
|
|
707
715
|
routes: ie.map((e) => e.pattern)
|
|
708
716
|
});
|
|
709
717
|
try {
|
|
710
|
-
let
|
|
711
|
-
await M.writeFile(C(
|
|
718
|
+
let t = await jn(e);
|
|
719
|
+
await M.writeFile(C(s, ".voltro-build.json"), JSON.stringify({
|
|
712
720
|
version: 1,
|
|
713
|
-
profile:
|
|
721
|
+
profile: t
|
|
714
722
|
}, null, 2), "utf8"), z.info("wrote deploy profile manifest", {
|
|
715
|
-
staticSafe:
|
|
716
|
-
ssr:
|
|
717
|
-
isr:
|
|
723
|
+
staticSafe: t.staticSafe,
|
|
724
|
+
ssr: t.counts.ssr,
|
|
725
|
+
isr: t.counts.isr
|
|
718
726
|
});
|
|
719
727
|
} catch (e) {
|
|
720
728
|
z.warn("could not write .voltro-build.json deploy manifest", {}, e);
|
|
721
729
|
}
|
|
722
|
-
return z.info("build complete", { distDir:
|
|
730
|
+
return z.info("build complete", { distDir: s }), {
|
|
723
731
|
ran: !0,
|
|
724
732
|
exitCode: 0
|
|
725
733
|
};
|
|
@@ -729,7 +737,7 @@ external scheduler owns the once-only guarantee.
|
|
|
729
737
|
catch: (e) => e
|
|
730
738
|
}).pipe(E.orDie);
|
|
731
739
|
return t.ran ? t.exitCode : (yield* E.logError("no web app found at this path", { hint: "looked for app.config.ts with `type: 'web'`" }), 1);
|
|
732
|
-
}), Hn = async (e) =>
|
|
740
|
+
}), Hn = async (e) => i(Vn(e.find((e) => !e.startsWith("-")) ?? process.cwd()), { scope: "voltro:build" }), Un = (e) => e.source === void 0 ? [] : typeof e.source == "string" ? [e.source] : e.source, Wn = (e) => ({
|
|
733
741
|
tables: new Set(e.tables),
|
|
734
742
|
procedures: new Map(e.procedures.map((e) => [e.tag, e])),
|
|
735
743
|
scopes: new Set(e.scopes ?? []),
|
|
@@ -998,7 +1006,7 @@ external scheduler owns the once-only guarantee.
|
|
|
998
1006
|
error: t.message || String(t)
|
|
999
1007
|
};
|
|
1000
1008
|
}
|
|
1001
|
-
}, lr = async (e) => (await
|
|
1009
|
+
}, lr = async (e) => (await r()).apps.filter((t) => t.kind === "api" && t.status === "live" && t.url.length > 0 && (e === void 0 || t.name === e)), ur = (e) => {
|
|
1002
1010
|
let t = "pretty", n = [];
|
|
1003
1011
|
for (let r = 0; r < e.length; r++) {
|
|
1004
1012
|
let i = e[r];
|
|
@@ -1070,10 +1078,10 @@ external scheduler owns the once-only guarantee.
|
|
|
1070
1078
|
let n = e.indexOf(t);
|
|
1071
1079
|
return n >= 0 ? e[n + 1] : void 0;
|
|
1072
1080
|
}, _r = async (e) => {
|
|
1073
|
-
process.env[
|
|
1081
|
+
process.env[a] = "1";
|
|
1074
1082
|
let t = gr(e, "--port") ?? process.env.VOLTRO_DASHBOARD_PORT ?? "5179";
|
|
1075
1083
|
process.env.VOLTRO_DASHBOARD_PORT = t;
|
|
1076
|
-
let n =
|
|
1084
|
+
let n = c(process.cwd());
|
|
1077
1085
|
if (!n) return hr.error("dashboard app not found. Install it with `pnpm add @voltro/dashboard`, or set VOLTRO_DASHBOARD_PATH to a dashboard app directory."), 1;
|
|
1078
1086
|
let r = A(C(n, ".framework", "dist", "index.html"));
|
|
1079
1087
|
return hr.info(`serving the Voltro dashboard on :${t}`, {
|
|
@@ -1329,7 +1337,7 @@ external scheduler owns the once-only guarantee.
|
|
|
1329
1337
|
id: "hand-serialized-date",
|
|
1330
1338
|
scope: "server",
|
|
1331
1339
|
smell: "Date converted by hand on the way out of a handler",
|
|
1332
|
-
use: "
|
|
1340
|
+
use: "timestampMs / timestampMsOrNull from @voltro/database/wire in the descriptor's output struct — `output` IS the serializer (it is the rpc success schema), so a Date field declared as timestampMs crosses as epoch ms on its own; declaring Schema.Number describes the WIRE type and leaves nothing to convert",
|
|
1333
1341
|
match: (e) => /\.(getTime|toISOString)\s*\(\s*\)/.test(e) && /\.map\s*\(|=>\s*\(\{/.test(e) && /\bexport\s+default\b/.test(e)
|
|
1334
1342
|
}
|
|
1335
1343
|
], jr = [
|
|
@@ -1607,7 +1615,7 @@ external scheduler owns the once-only guarantee.
|
|
|
1607
1615
|
}, Yr = (e) => E.tryPromise({
|
|
1608
1616
|
try: () => Jr(e),
|
|
1609
1617
|
catch: (e) => e
|
|
1610
|
-
}).pipe(E.orDie), Xr = async (e) =>
|
|
1618
|
+
}).pipe(E.orDie), Xr = async (e) => i(Yr(T(e.find((e) => !e.startsWith("-")) ?? process.cwd())), { scope: "voltro:e2e" }), Zr = (e) => {
|
|
1611
1619
|
let t = {
|
|
1612
1620
|
tail: 100,
|
|
1613
1621
|
since: void 0,
|
|
@@ -1700,9 +1708,9 @@ external scheduler owns the once-only guarantee.
|
|
|
1700
1708
|
}, ei = async (e) => {
|
|
1701
1709
|
let t = Zr(e);
|
|
1702
1710
|
if ("error" in t) return t.error !== "help" && console.error(`voltro logs: ${t.error}`), $r(), t.error === "help" ? 0 : 2;
|
|
1703
|
-
let
|
|
1711
|
+
let n = await r(), i = t.process === void 0 ? n.apps : n.apps.filter((e) => e.name === t.process);
|
|
1704
1712
|
if (i.length === 0 && t.process !== void 0) {
|
|
1705
|
-
let e =
|
|
1713
|
+
let e = ee(t.process);
|
|
1706
1714
|
e !== void 0 && (i = [{
|
|
1707
1715
|
id: `orphan:${t.process}`,
|
|
1708
1716
|
name: t.process,
|
|
@@ -1718,7 +1726,7 @@ external scheduler owns the once-only guarantee.
|
|
|
1718
1726
|
if (i.length === 0) {
|
|
1719
1727
|
if (t.process !== void 0) {
|
|
1720
1728
|
console.error(`voltro logs: no running process named '${t.process}' and no orphan log file found`), console.error(" active processes:");
|
|
1721
|
-
for (let e of
|
|
1729
|
+
for (let e of n.apps) console.error(` - ${e.name} (${e.kind} @ ${e.url})`);
|
|
1722
1730
|
return 1;
|
|
1723
1731
|
}
|
|
1724
1732
|
return console.error("voltro logs: no running voltro process found"), console.error(" start one with 'voltro dev' (or 'voltro start') and try again."), 1;
|
|
@@ -1769,24 +1777,24 @@ external scheduler owns the once-only guarantee.
|
|
|
1769
1777
|
} catch (n) {
|
|
1770
1778
|
return ni(e, t, n.message || String(n));
|
|
1771
1779
|
}
|
|
1772
|
-
}, ni = async (
|
|
1773
|
-
if (!
|
|
1780
|
+
}, ni = async (t, n, r) => {
|
|
1781
|
+
if (!t.logFile) return {
|
|
1774
1782
|
kind: "err",
|
|
1775
|
-
name:
|
|
1776
|
-
error: `${
|
|
1783
|
+
name: t.name,
|
|
1784
|
+
error: `${r} (no logFile on entry)`
|
|
1777
1785
|
};
|
|
1778
1786
|
try {
|
|
1779
|
-
let
|
|
1780
|
-
|
|
1781
|
-
let
|
|
1787
|
+
let r = n.since, i = { max: n.tail };
|
|
1788
|
+
r !== void 0 && (i.since = r);
|
|
1789
|
+
let a = await e(t.logFile, i), o = [], s = {
|
|
1782
1790
|
trace: 0,
|
|
1783
1791
|
debug: 1,
|
|
1784
1792
|
info: 2,
|
|
1785
1793
|
warn: 3,
|
|
1786
1794
|
error: 4,
|
|
1787
1795
|
fatal: 5
|
|
1788
|
-
},
|
|
1789
|
-
for (let e of
|
|
1796
|
+
}, c = n.level === void 0 ? 0 : s[n.level], l = n.scope?.toLowerCase(), u = n.source, d = n.filter?.toLowerCase(), f = n.traceId;
|
|
1797
|
+
for (let e of a) s[e.level] < c || u !== void 0 && e.source !== u || l !== void 0 && (e.scope === void 0 || !e.scope.toLowerCase().includes(l)) || d !== void 0 && !e.message.toLowerCase().includes(d) || f !== void 0 && e.fields.traceId !== f || o.push({
|
|
1790
1798
|
ts: e.ts,
|
|
1791
1799
|
level: e.level,
|
|
1792
1800
|
source: e.source,
|
|
@@ -1794,20 +1802,20 @@ external scheduler owns the once-only guarantee.
|
|
|
1794
1802
|
fields: e.fields,
|
|
1795
1803
|
...e.scope === void 0 ? {} : { scope: e.scope }
|
|
1796
1804
|
});
|
|
1797
|
-
let
|
|
1805
|
+
let p = o.length > n.tail ? o.slice(o.length - n.tail) : o;
|
|
1798
1806
|
return {
|
|
1799
1807
|
kind: "ok",
|
|
1800
|
-
name:
|
|
1801
|
-
records:
|
|
1802
|
-
...
|
|
1803
|
-
process:
|
|
1808
|
+
name: t.name,
|
|
1809
|
+
records: p.map((e) => ({
|
|
1810
|
+
...e,
|
|
1811
|
+
process: t.name
|
|
1804
1812
|
}))
|
|
1805
1813
|
};
|
|
1806
|
-
} catch (
|
|
1814
|
+
} catch (e) {
|
|
1807
1815
|
return {
|
|
1808
1816
|
kind: "err",
|
|
1809
|
-
name:
|
|
1810
|
-
error: `${
|
|
1817
|
+
name: t.name,
|
|
1818
|
+
error: `${r}; file read failed: ${e.message || String(e)}`
|
|
1811
1819
|
};
|
|
1812
1820
|
}
|
|
1813
1821
|
}, ri = {
|
|
@@ -1903,7 +1911,7 @@ external scheduler owns the once-only guarantee.
|
|
|
1903
1911
|
}, vi = async (e) => {
|
|
1904
1912
|
let t = await hi(e);
|
|
1905
1913
|
if (!t) return H.error("no app.config.ts found in the current directory"), 1;
|
|
1906
|
-
let n =
|
|
1914
|
+
let n = p(t.name, t.input), r = `${gi("KEY", 32)} ${gi("OWNER", 16)} ${gi("ACCESS", 8)} ${gi("REQ", 4)} SET`;
|
|
1907
1915
|
H.info(`env manifest — ${n.app} (${n.summary.total} vars, ${n.summary.set} set)`), _i(r);
|
|
1908
1916
|
for (let e of n.entries) {
|
|
1909
1917
|
let t = e.isSet ? "✓" : e.satisfied ? "·" : "✗";
|
|
@@ -1913,7 +1921,7 @@ external scheduler owns the once-only guarantee.
|
|
|
1913
1921
|
}, yi = async (e, t) => {
|
|
1914
1922
|
let n = await hi(e);
|
|
1915
1923
|
if (!n) return H.error("no app.config.ts found in the current directory"), 1;
|
|
1916
|
-
let r =
|
|
1924
|
+
let r = f(n.input, ["Environment for this app — generated from app.config.ts `env` + plugin declarations.", "Regenerate with `voltro env sync`. Copy to `.env` and fill in the blanks."]), i = C(e, ".env.example"), a = await M.readFile(i, "utf8").catch(() => null);
|
|
1917
1925
|
if (a !== null && !a.startsWith(mi) && !t) {
|
|
1918
1926
|
let t = C(e, ".env.example.generated");
|
|
1919
1927
|
return await M.writeFile(t, r, "utf8"), H.warn(".env.example exists and is not framework-generated — wrote .env.example.generated instead", { hint: "merge it by hand, or pass --force to overwrite .env.example" }), 0;
|
|
@@ -1923,7 +1931,7 @@ external scheduler owns the once-only guarantee.
|
|
|
1923
1931
|
let t = await me(e).catch(() => null);
|
|
1924
1932
|
if (!t) return H.error("no app.config.ts found in the current directory"), 1;
|
|
1925
1933
|
let n = Ze(t.env) ? t.env : void 0;
|
|
1926
|
-
return n ? (t.type === "web" ? (await
|
|
1934
|
+
return n ? (t.type === "web" ? (await ne(e, n), H.info("wrote src/voltro-env.d.ts (publicEnv augmentation)", { app: t.name ?? "app" })) : (await l(e, n), H.info("wrote env.generated.d.ts (serverEnv augmentation)", { app: t.name ?? "app" })), 0) : (H.warn("no `defineEnv` declared in app.config.ts — nothing to generate", { hint: "add `env: defineEnv({ ... })` to app.config.ts (see @voltro/env)" }), 0);
|
|
1927
1935
|
}, xi = () => {
|
|
1928
1936
|
let e = Xe();
|
|
1929
1937
|
return H.info(`${e.length} framework env vars for turbo.json globalPassThroughEnv:`), _i(JSON.stringify([...e].sort(), null, 2)), H.info("merge these into the workspace turbo.json `globalPassThroughEnv` array (+ your own app vars)."), 0;
|
|
@@ -2205,12 +2213,12 @@ DB_DIALECT=mssql
|
|
|
2205
2213
|
}, Zi = async (e) => {
|
|
2206
2214
|
let t = Yi(e);
|
|
2207
2215
|
if ("error" in t) return t.error !== "help" && console.error(`voltro traces: ${t.error}`), Xi(), t.error === "help" ? 0 : 2;
|
|
2208
|
-
let
|
|
2209
|
-
if (
|
|
2216
|
+
let n = (await r()).apps.filter((e) => e.kind === "api" && e.status === "live" && e.url.length > 0 && (t.process === void 0 || e.name === t.process));
|
|
2217
|
+
if (n.length === 0) return console.error(t.process === void 0 ? "voltro traces: no running api processes found" : `voltro traces: no running api named '${t.process}'`), t.process === void 0 && console.error(" start one with 'voltro dev' and try again."), 1;
|
|
2210
2218
|
if (t.id !== void 0) {
|
|
2211
|
-
let e =
|
|
2219
|
+
let e = n.map((e) => $i(e, t.id)), r = await Promise.all(e), i = r.find((e) => e.kind === "ok" && e.spans.length > 0);
|
|
2212
2220
|
if (!i || i.kind !== "ok") {
|
|
2213
|
-
let e =
|
|
2221
|
+
let e = r.filter((e) => e.kind === "err");
|
|
2214
2222
|
if (t.format === "json") console.log(JSON.stringify({
|
|
2215
2223
|
traceId: t.id,
|
|
2216
2224
|
spans: [],
|
|
@@ -2223,7 +2231,7 @@ DB_DIALECT=mssql
|
|
|
2223
2231
|
console.error(`voltro traces: no spans for trace ${t.id}`);
|
|
2224
2232
|
for (let t of e) console.error(` # ${t.name}: ${t.error}`);
|
|
2225
2233
|
}
|
|
2226
|
-
return +(e.length ===
|
|
2234
|
+
return +(e.length === n.length);
|
|
2227
2235
|
}
|
|
2228
2236
|
return t.format === "json" ? (console.log(JSON.stringify({
|
|
2229
2237
|
traceId: t.id,
|
|
@@ -2231,7 +2239,7 @@ DB_DIALECT=mssql
|
|
|
2231
2239
|
spans: i.spans
|
|
2232
2240
|
})), 0) : (ia(t.id, i.name, ea(i.spans, t), t.color), 0);
|
|
2233
2241
|
}
|
|
2234
|
-
let i =
|
|
2242
|
+
let i = n.map((e) => Qi(e, t)), a = await Promise.all(i), o = [], s = [];
|
|
2235
2243
|
for (let e of a) e.kind === "ok" ? o.push(...e.traces.map((t) => ({
|
|
2236
2244
|
...t,
|
|
2237
2245
|
process: e.name
|
|
@@ -2246,14 +2254,14 @@ DB_DIALECT=mssql
|
|
|
2246
2254
|
traces: c,
|
|
2247
2255
|
fetchErrors: s
|
|
2248
2256
|
} : { traces: c };
|
|
2249
|
-
return console.log(JSON.stringify(e)), +(s.length ===
|
|
2257
|
+
return console.log(JSON.stringify(e)), +(s.length === n.length);
|
|
2250
2258
|
}
|
|
2251
2259
|
ra(c, t.color), c.length === 0 && console.error("voltro traces: no traces matched the given filters.");
|
|
2252
2260
|
for (let e of s) {
|
|
2253
2261
|
let n = `# fetch failed: ${e.name}: ${e.error}`;
|
|
2254
2262
|
console.error(t.color ? O.dim(n) : n);
|
|
2255
2263
|
}
|
|
2256
|
-
return +(s.length ===
|
|
2264
|
+
return +(s.length === n.length);
|
|
2257
2265
|
}, Qi = async (e, t) => {
|
|
2258
2266
|
let n = new URLSearchParams();
|
|
2259
2267
|
n.set("max", String(t.tail)), t.since !== void 0 && n.set("since", String(t.since)), t.errors && n.set("onlyErrors", "1");
|
|
@@ -3496,48 +3504,48 @@ DB_DIALECT=mssql
|
|
|
3496
3504
|
projectName: i
|
|
3497
3505
|
};
|
|
3498
3506
|
}, Zo = async (e) => {
|
|
3499
|
-
let { positional:
|
|
3500
|
-
if (!
|
|
3501
|
-
if (!Po(
|
|
3502
|
-
let
|
|
3503
|
-
if (typeof
|
|
3504
|
-
let
|
|
3505
|
-
if (!
|
|
3506
|
-
templateId:
|
|
3507
|
+
let { positional: n, flags: r } = Fo(e), i = n[0];
|
|
3508
|
+
if (!i) return W.error("add-app: <appName> required", { usage: "voltro add-app <appName> --template <templateId> [--to <projectName>]" }), 2;
|
|
3509
|
+
if (!Po(i)) return W.error("add-app: invalid appName — use camelCase or kebab-case", { appName: i }), 2;
|
|
3510
|
+
let a = r.template;
|
|
3511
|
+
if (typeof a != "string") return W.error("add-app: --template <id> required", { hint: "run `voltro list-templates` to see available ids" }), 2;
|
|
3512
|
+
let o = await qa(a);
|
|
3513
|
+
if (!o) return W.error("add-app: unknown template", {
|
|
3514
|
+
templateId: a,
|
|
3507
3515
|
hint: "run `voltro list-templates` to see available ids"
|
|
3508
3516
|
}), 2;
|
|
3509
|
-
let
|
|
3510
|
-
if (!A(
|
|
3511
|
-
let
|
|
3512
|
-
if (!
|
|
3513
|
-
let
|
|
3514
|
-
A(
|
|
3515
|
-
let
|
|
3516
|
-
if (A(
|
|
3517
|
-
let
|
|
3518
|
-
if (
|
|
3519
|
-
let e = (await Bo(
|
|
3517
|
+
let s = No(process.cwd()), c = C(s, "apps");
|
|
3518
|
+
if (!A(c)) return W.error("add-app: apps/ root not found — not in a voltro workspace?", { projectsRoot: c }), 2;
|
|
3519
|
+
let l = Go(await Ko(c), typeof r.to == "string" ? r.to : void 0);
|
|
3520
|
+
if (!l.ok) return W.error(`add-app: ${l.error}`, l.hint === void 0 ? {} : { hint: l.hint }), 2;
|
|
3521
|
+
let u = l.project, d = C(c, u);
|
|
3522
|
+
A(d) || (j(d, { recursive: !0 }), await Ho(d, u, Ro));
|
|
3523
|
+
let f = Wa(i), p = C(d, f);
|
|
3524
|
+
if (A(p)) return W.error("add-app: target directory already exists", { targetDir: p }), 1;
|
|
3525
|
+
let m = null;
|
|
3526
|
+
if (o.kind === "web" && (m = await Uo(d), m === null)) {
|
|
3527
|
+
let e = (await Bo(d))?.portRange ?? Ro;
|
|
3520
3528
|
return W.error("add-app: project portRange is exhausted", {
|
|
3521
|
-
project:
|
|
3529
|
+
project: u,
|
|
3522
3530
|
range: `${e.start}-${e.end}`,
|
|
3523
3531
|
hint: "edit apps/<project>/project.json and widen portRange, or remove unused app entries"
|
|
3524
3532
|
}), 1;
|
|
3525
3533
|
}
|
|
3526
|
-
let
|
|
3527
|
-
console.log(`→ scaffolding ${
|
|
3528
|
-
let { written:
|
|
3529
|
-
template:
|
|
3530
|
-
targetDir:
|
|
3531
|
-
vars:
|
|
3534
|
+
let h = Qa(f, u, m ?? 0);
|
|
3535
|
+
console.log(`→ scaffolding ${o.id} into ${p}${m === null ? "" : ` (port ${m})`}`);
|
|
3536
|
+
let { written: g } = await Za({
|
|
3537
|
+
template: o,
|
|
3538
|
+
targetDir: p,
|
|
3539
|
+
vars: h
|
|
3532
3540
|
});
|
|
3533
|
-
for (let e of
|
|
3534
|
-
return await Wo(
|
|
3541
|
+
for (let e of g) console.log(` · ${e}`);
|
|
3542
|
+
return await Wo(d, f, o.kind, m === null ? void 0 : m), await t(s, {
|
|
3535
3543
|
appTemplates: [{
|
|
3536
|
-
dir:
|
|
3537
|
-
template:
|
|
3544
|
+
dir: p,
|
|
3545
|
+
template: o.id
|
|
3538
3546
|
}],
|
|
3539
3547
|
preferPointer: !0
|
|
3540
|
-
}).catch(() => void 0), console.log(), console.log(`✓ app '${
|
|
3548
|
+
}).catch(() => void 0), console.log(), console.log(`✓ app '${f}' added to project '${u}' from template '${o.id}'.`), r["no-register"] !== !0 && await Yo(d, u), console.log(), console.log("Next steps:"), console.log(" pnpm install"), o.kind === "serverless" ? (console.log(` voltro serverless list apps/${u}/${f} # what would deploy`), console.log(` voltro serverless dev apps/${u}/${f}/... # run one locally`), console.log(" voltro serverless deploy --target node|cloudflare|scaleway")) : console.log(` pnpm --filter @${u}/${f} dev`), 0;
|
|
3541
3549
|
}, Qo = (e) => {
|
|
3542
3550
|
if (typeof e != "string") return null;
|
|
3543
3551
|
let t = /^(\d+)\s*(?:-|:|\.\.)\s*(\d+)$/.exec(e.trim());
|
|
@@ -3594,23 +3602,23 @@ DB_DIALECT=mssql
|
|
|
3594
3602
|
t.close();
|
|
3595
3603
|
}
|
|
3596
3604
|
}, ns = async (e) => {
|
|
3597
|
-
let { positional:
|
|
3598
|
-
if (
|
|
3599
|
-
existing:
|
|
3605
|
+
let { positional: n, flags: r } = Fo(e), i = No(process.cwd()), a = C(i, "apps"), o = await Ko(a);
|
|
3606
|
+
if (o.length > 0) return W.error("create-project: this monorepo already hosts a project — a monorepo has exactly one", {
|
|
3607
|
+
existing: o,
|
|
3600
3608
|
hint: "use `voltro add-app <name> --template <id>` to add apps to the existing project"
|
|
3601
3609
|
}), 1;
|
|
3602
|
-
A(
|
|
3603
|
-
let
|
|
3604
|
-
if (
|
|
3605
|
-
if (!
|
|
3606
|
-
if (
|
|
3607
|
-
|
|
3608
|
-
}
|
|
3609
|
-
|
|
3610
|
-
let
|
|
3611
|
-
if (A(
|
|
3612
|
-
let
|
|
3613
|
-
if (!
|
|
3610
|
+
A(a) || j(a, { recursive: !0 });
|
|
3611
|
+
let s = $o(r), c = n[0] ?? "";
|
|
3612
|
+
if (c && !Po(c)) return W.error("create-project: invalid name", { name: c }), 2;
|
|
3613
|
+
if (!c) {
|
|
3614
|
+
if (s.noInput) return W.error("create-project: name required (use positional arg or run interactively)"), 2;
|
|
3615
|
+
c = await Io("Project name", "my-project");
|
|
3616
|
+
}
|
|
3617
|
+
c = Wa(c);
|
|
3618
|
+
let l = C(a, c);
|
|
3619
|
+
if (A(l)) return W.error("create-project: target directory already exists", { projectDir: l }), 1;
|
|
3620
|
+
let u = s.api ?? null, d = s.web ?? null;
|
|
3621
|
+
if (!u && !d) if (s.noInput) u = "api-backend", d = "frontend-blank";
|
|
3614
3622
|
else {
|
|
3615
3623
|
let e = Zt({
|
|
3616
3624
|
input: Qt,
|
|
@@ -3618,32 +3626,32 @@ DB_DIALECT=mssql
|
|
|
3618
3626
|
});
|
|
3619
3627
|
try {
|
|
3620
3628
|
let t = (await e.question("Scaffold apps/api (api-backend) and apps/web (frontend-blank)? [Y/n]: ")).trim().toLowerCase();
|
|
3621
|
-
(t === "" || t === "y" || t === "yes") && (
|
|
3629
|
+
(t === "" || t === "y" || t === "yes") && (u = "api-backend", d = "frontend-blank");
|
|
3622
3630
|
} finally {
|
|
3623
3631
|
e.close();
|
|
3624
3632
|
}
|
|
3625
3633
|
}
|
|
3626
|
-
let
|
|
3627
|
-
if (
|
|
3628
|
-
if (
|
|
3629
|
-
if (
|
|
3630
|
-
id: d.id,
|
|
3631
|
-
kind: d.kind,
|
|
3632
|
-
expected: "api"
|
|
3633
|
-
}), 2;
|
|
3634
|
-
if (f && f.kind !== "web") return W.error("create-project: template kind mismatch", {
|
|
3634
|
+
let f = u ? await qa(u) : null, p = d ? await qa(d) : null;
|
|
3635
|
+
if (u && !f) return W.error("create-project: unknown api template", { template: u }), 2;
|
|
3636
|
+
if (d && !p) return W.error("create-project: unknown web template", { template: d }), 2;
|
|
3637
|
+
if (f && f.kind !== "api") return W.error("create-project: template kind mismatch", {
|
|
3635
3638
|
id: f.id,
|
|
3636
3639
|
kind: f.kind,
|
|
3640
|
+
expected: "api"
|
|
3641
|
+
}), 2;
|
|
3642
|
+
if (p && p.kind !== "web") return W.error("create-project: template kind mismatch", {
|
|
3643
|
+
id: p.id,
|
|
3644
|
+
kind: p.kind,
|
|
3637
3645
|
expected: "web"
|
|
3638
3646
|
}), 2;
|
|
3639
|
-
if (!
|
|
3640
|
-
let
|
|
3641
|
-
if (
|
|
3642
|
-
console.log(`\n→ creating ${
|
|
3643
|
-
let
|
|
3644
|
-
let n = C(
|
|
3645
|
-
if (t.kind === "web" && (r = await Uo(
|
|
3646
|
-
let i = Qa(e,
|
|
3647
|
+
if (!f && !p) return W.error("create-project: need at least one of --api or --web"), 2;
|
|
3648
|
+
let m = Ro;
|
|
3649
|
+
if (s.portRange ? m = s.portRange : s.noInput || (m = await ts(Ro)), !zo(m)) return W.error("create-project: invalid port range", { range: `${m.start}-${m.end}` }), 2;
|
|
3650
|
+
console.log(`\n→ creating ${l}`), j(l, { recursive: !0 }), await Ho(l, c, m);
|
|
3651
|
+
let h = async (e, t) => {
|
|
3652
|
+
let n = C(l, e), r = null;
|
|
3653
|
+
if (t.kind === "web" && (r = await Uo(l), r === null)) throw Error(`port range ${m.start}-${m.end} exhausted before app '${e}' could be allocated`);
|
|
3654
|
+
let i = Qa(e, c, r ?? 0);
|
|
3647
3655
|
console.log(`→ ${t.id} → ${e}/${r === null ? "" : ` (port ${r})`}`);
|
|
3648
3656
|
let { written: a } = await Za({
|
|
3649
3657
|
template: t,
|
|
@@ -3651,54 +3659,54 @@ DB_DIALECT=mssql
|
|
|
3651
3659
|
vars: i
|
|
3652
3660
|
});
|
|
3653
3661
|
for (let t of a) console.log(` · ${e}/${t}`);
|
|
3654
|
-
await Wo(
|
|
3662
|
+
await Wo(l, e, t.kind, r === null ? void 0 : r);
|
|
3655
3663
|
};
|
|
3656
|
-
|
|
3657
|
-
appTemplates: [...
|
|
3658
|
-
dir: C(
|
|
3659
|
-
template: d.id
|
|
3660
|
-
}] : [], ...f ? [{
|
|
3661
|
-
dir: C(c, "web"),
|
|
3664
|
+
f && await h("api", f), p && await h("web", p), await t(i, {
|
|
3665
|
+
appTemplates: [...f ? [{
|
|
3666
|
+
dir: C(l, "api"),
|
|
3662
3667
|
template: f.id
|
|
3668
|
+
}] : [], ...p ? [{
|
|
3669
|
+
dir: C(l, "web"),
|
|
3670
|
+
template: p.id
|
|
3663
3671
|
}] : []],
|
|
3664
3672
|
preferPointer: !0
|
|
3665
3673
|
}).catch(() => void 0);
|
|
3666
|
-
let
|
|
3667
|
-
if (
|
|
3668
|
-
let e = await ro(
|
|
3669
|
-
e ?
|
|
3670
|
-
requested:
|
|
3674
|
+
let g = null;
|
|
3675
|
+
if (s.baseline) {
|
|
3676
|
+
let e = await ro(s.baseline);
|
|
3677
|
+
e ? g = e.id : W.warn("unknown baseline — skipping baseline step", {
|
|
3678
|
+
requested: s.baseline,
|
|
3671
3679
|
available: (await no()).map((e) => e.id)
|
|
3672
3680
|
});
|
|
3673
|
-
} else
|
|
3674
|
-
if (
|
|
3675
|
-
console.log(), console.log(`→ applying baseline '${
|
|
3681
|
+
} else s.noInput || (g = await es());
|
|
3682
|
+
if (g) {
|
|
3683
|
+
console.log(), console.log(`→ applying baseline '${g}' at workspace root ${i}`);
|
|
3676
3684
|
try {
|
|
3677
3685
|
let e = await xo({
|
|
3678
|
-
root:
|
|
3679
|
-
baselineId:
|
|
3680
|
-
projectName:
|
|
3686
|
+
root: i,
|
|
3687
|
+
baselineId: g,
|
|
3688
|
+
projectName: c,
|
|
3681
3689
|
quiet: !0
|
|
3682
3690
|
});
|
|
3683
|
-
console.log(` · ${e.written.length} files written, ${e.removed.length} removed`), e.backupDir && console.log(` · backup: ${e.backupDir.replace(
|
|
3691
|
+
console.log(` · ${e.written.length} files written, ${e.removed.length} removed`), e.backupDir && console.log(` · backup: ${e.backupDir.replace(i + "/", "")}`), e.previousBaselineId && e.previousBaselineId !== g && console.log(` · switched from previous baseline '${e.previousBaselineId}'`);
|
|
3684
3692
|
} catch (e) {
|
|
3685
3693
|
W.error("baseline apply failed", {
|
|
3686
|
-
baselineId:
|
|
3694
|
+
baselineId: g,
|
|
3687
3695
|
error: e instanceof Error ? e.message : String(e)
|
|
3688
3696
|
});
|
|
3689
3697
|
}
|
|
3690
3698
|
}
|
|
3691
|
-
if (
|
|
3699
|
+
if (s.cache === "redis") {
|
|
3692
3700
|
console.log(), console.log("→ enabling Redis cache backend");
|
|
3693
3701
|
try {
|
|
3694
|
-
let e = await Pi(
|
|
3702
|
+
let e = await Pi(i);
|
|
3695
3703
|
for (let t of e) console.log(` ✓ ${t}`);
|
|
3696
3704
|
} catch (e) {
|
|
3697
3705
|
W.error("cache enable failed", { error: e instanceof Error ? e.message : String(e) });
|
|
3698
3706
|
}
|
|
3699
3707
|
}
|
|
3700
|
-
return console.log(), console.log(`✓ project '${
|
|
3701
|
-
}, rs = (e, t) => (n) =>
|
|
3708
|
+
return console.log(), console.log(`✓ project '${c}' scaffolded under apps/${c}/.`), g && console.log(` baseline '${g}' applied at workspace root.`), r["no-register"] !== !0 && await Yo(l, c), console.log(), console.log("Next steps:"), console.log(" pnpm install"), f && console.log(` pnpm --filter @${c}/api dev`), p && console.log(` pnpm --filter @${c}/web dev`), g === "compose" ? (console.log(" pnpm db:up # postgres only (native dev)"), console.log(" pnpm dev:docker # OR full-stack docker dev")) : g === "helm" && (console.log(" pnpm helm:lint # verify the chart"), console.log(" pnpm helm:install:dev # deploy to a dev cluster")), 0;
|
|
3709
|
+
}, rs = (e, t) => (n) => i(E.tryPromise({
|
|
3702
3710
|
try: () => e(n),
|
|
3703
3711
|
catch: (e) => e
|
|
3704
3712
|
}).pipe(E.orDie), { scope: t }), is = rs(Lo, "voltro:list-templates"), as = rs(Zo, "voltro:add-app"), os = rs(ns, "voltro:create-project"), ss = Xt(tt), cs = (e) => new Promise((t) => setTimeout(t, e)), ls = () => {
|
|
@@ -4118,7 +4126,7 @@ replicas = 1
|
|
|
4118
4126
|
let e = (process.env.DB_DIALECT ?? "postgres").toLowerCase();
|
|
4119
4127
|
if (e === "memory") throw Error("Cannot migrate against an in-memory store. Set DB_DIALECT to one of: postgres, sqlite, mysql, mariadb, mssql, turso.");
|
|
4120
4128
|
return ue(e);
|
|
4121
|
-
}, Js = async (e) =>
|
|
4129
|
+
}, Js = async (e) => i(Gs(T(e.find((e) => !e.startsWith("-")) ?? process.cwd())), { scope: "voltro:migrate" }), Ys = /\.migration\.ts$/, Xs = async (e, t) => {
|
|
4122
4130
|
let n = [];
|
|
4123
4131
|
for (let r of e) {
|
|
4124
4132
|
let e;
|
|
@@ -5646,7 +5654,7 @@ replicas = 1
|
|
|
5646
5654
|
return yield* E.sync(() => {
|
|
5647
5655
|
for (let e of Xl(t)) console.log(e);
|
|
5648
5656
|
}), 0;
|
|
5649
|
-
}), Ql = (e) =>
|
|
5657
|
+
}), Ql = (e) => i(Zl(process.cwd()), { scope: "voltro:deploy" }), $l = (e) => os(e), eu = {
|
|
5650
5658
|
"data-transfer": {
|
|
5651
5659
|
env: "VOLTRO_DATA_TRANSFER_SECRET",
|
|
5652
5660
|
encoding: "base64url",
|
|
@@ -6308,7 +6316,140 @@ replicas = 1
|
|
|
6308
6316
|
"Alternatively, switch the annotation to `PartialUiStrings` if the object",
|
|
6309
6317
|
"was only ever an override bag."
|
|
6310
6318
|
].join("\n")
|
|
6311
|
-
}), Iu = /\bsetRowFilter\s*\(/, Lu = /\bresolveRowFilterScope\b/, Ru =
|
|
6319
|
+
}), Iu = /\bsetRowFilter\s*\(/, Lu = /\bresolveRowFilterScope\b/, Ru = Z({
|
|
6320
|
+
version: "0.7.0",
|
|
6321
|
+
id: "0.7.0/01_row-filter-load-failure",
|
|
6322
|
+
title: "A row filter that fails to load now errors instead of returning zero rows",
|
|
6323
|
+
kind: "manual",
|
|
6324
|
+
appliesTo: ({ project: e }) => e.getSourceFiles().some((e) => {
|
|
6325
|
+
let t = e.getFullText();
|
|
6326
|
+
return Iu.test(t) || Lu.test(t);
|
|
6327
|
+
}),
|
|
6328
|
+
note: [
|
|
6329
|
+
"Row-level security: a `load` failure is now an ERROR, and is retried first.",
|
|
6330
|
+
"",
|
|
6331
|
+
"What changed and why:",
|
|
6332
|
+
"",
|
|
6333
|
+
" `setRowFilter({ load, predicate })` runs `load` once per request to resolve",
|
|
6334
|
+
" what the subject may see. Previously, ANY `load` failure was answered with a",
|
|
6335
|
+
" predicate matching zero rows — so a single transient DB blip denied every",
|
|
6336
|
+
" constrained table for that request, and the user saw an empty UI with a 200",
|
|
6337
|
+
" status and no error anywhere.",
|
|
6338
|
+
"",
|
|
6339
|
+
" That was wrong in two separate ways, and both are fixed:",
|
|
6340
|
+
"",
|
|
6341
|
+
" 1. No retry. `load` reads your store — for team/shared visibility it MUST —",
|
|
6342
|
+
" which makes it exactly the call that blips. A reaped connection was being",
|
|
6343
|
+
" answered as if it were an authorization fact. `load` now runs under a",
|
|
6344
|
+
" bounded retry (3 attempts, exponential from 20ms) before any decision.",
|
|
6345
|
+
"",
|
|
6346
|
+
" 2. Refusal was expressed as an empty result, which is a lie. \"We could not",
|
|
6347
|
+
" determine your visibility\" and \"you may see nothing\" are different facts,",
|
|
6348
|
+
" and an empty list is byte-identical to legitimate emptiness — the user",
|
|
6349
|
+
" reads \"you have no tickets\", the operator reads a healthy 200, and the",
|
|
6350
|
+
" outage is invisible to both. Refusal is now a typed",
|
|
6351
|
+
" `RowFilterUnavailable` error.",
|
|
6352
|
+
"",
|
|
6353
|
+
"What to do:",
|
|
6354
|
+
"",
|
|
6355
|
+
" 1. DECIDE, per app, what an unresolvable filter should look like to a user.",
|
|
6356
|
+
" This is the one thing this codemod cannot do for you.",
|
|
6357
|
+
"",
|
|
6358
|
+
" • Leave the default (`onLoadError: 'fail'`) if an empty screen would be",
|
|
6359
|
+
" mistaken for real data. This is the right answer for most apps.",
|
|
6360
|
+
" Handle `RowFilterUnavailable` in your UI as an error state (\"could not",
|
|
6361
|
+
" load — retry\"), the same as any other failed request.",
|
|
6362
|
+
"",
|
|
6363
|
+
" • Set `onLoadError: 'deny'` ONLY if you have looked at the screen and",
|
|
6364
|
+
" are content for it to render as empty during an outage:",
|
|
6365
|
+
" setRowFilter({ load, predicate, onLoadError: 'deny' })",
|
|
6366
|
+
" Your `onError` reporter still fires, so the failure stays findable in",
|
|
6367
|
+
" logs even though the response is a 200.",
|
|
6368
|
+
"",
|
|
6369
|
+
" There is deliberately no fail-OPEN option, and there will not be one.",
|
|
6370
|
+
" Serving unfiltered rows when the authorization filter is unavailable leaks",
|
|
6371
|
+
" data precisely when the system is under stress and nobody is watching, and",
|
|
6372
|
+
" it is only safe if every handler still carries the check the row filter",
|
|
6373
|
+
" existed to replace.",
|
|
6374
|
+
"",
|
|
6375
|
+
" 2. Tune the retry if your `load` is unusually slow or unusually cheap:",
|
|
6376
|
+
" setRowFilter({ load, predicate, retry: Schedule.recurs(5) }) // your own",
|
|
6377
|
+
" setRowFilter({ load, predicate, retry: false }) // one attempt",
|
|
6378
|
+
" The default is `DEFAULT_ROW_FILTER_RETRY` (exported from @voltro/runtime).",
|
|
6379
|
+
"",
|
|
6380
|
+
" 3. If you call `resolveRowFilterScope` directly — a custom entrypoint or a test",
|
|
6381
|
+
" harness — it now returns `Effect<RowFilterScope, RowFilterUnavailable>`",
|
|
6382
|
+
" instead of an infallible Effect. Your call sites must handle the error",
|
|
6383
|
+
" channel; `Effect.catchTag('RowFilterUnavailable', …)` or letting it",
|
|
6384
|
+
" propagate are both fine. TypeScript will point at every one.",
|
|
6385
|
+
"",
|
|
6386
|
+
" 4. Check any test that asserted \"a broken load yields an empty result\". Under",
|
|
6387
|
+
" the new default that test now fails with `RowFilterUnavailable` — which is",
|
|
6388
|
+
" the fix working, not a regression.",
|
|
6389
|
+
"",
|
|
6390
|
+
" 5. SUBSCRIPTIONS behave differently now, and this needs no code change but does",
|
|
6391
|
+
" need a client-side look: a re-resolve that fails mid-stream REVOKES the",
|
|
6392
|
+
" subscription and emits an error frame, rather than delivering an empty",
|
|
6393
|
+
" snapshot. An empty snapshot on a live subscription reads to a client as",
|
|
6394
|
+
" \"every row you could see was just deleted\". Make sure your subscription",
|
|
6395
|
+
" error handling surfaces this rather than swallowing it."
|
|
6396
|
+
].join("\n")
|
|
6397
|
+
}), zu = Z({
|
|
6398
|
+
version: "0.7.0",
|
|
6399
|
+
id: "0.7.0/02_testing-invoke-effect-handlers",
|
|
6400
|
+
title: "@voltro/testing: invoke() runs Effect handlers; executor types widened",
|
|
6401
|
+
kind: "manual",
|
|
6402
|
+
appliesTo: ({ project: e }) => e.getSourceFiles().some((e) => {
|
|
6403
|
+
let t = e.getFullText();
|
|
6404
|
+
return t.includes("@voltro/testing") ? /\binvoke\s*\(/.test(t) || /\bProcedureExecutor\b/.test(t) : !1;
|
|
6405
|
+
}),
|
|
6406
|
+
note: [
|
|
6407
|
+
"`invoke(descriptor, executor, input, ctx)` now DETECTS an Effect-returning",
|
|
6408
|
+
"handler and runs it, the way the dispatcher does. Two consequences.",
|
|
6409
|
+
"",
|
|
6410
|
+
"1. Remove your run-the-Effect workaround.",
|
|
6411
|
+
"",
|
|
6412
|
+
" // before — the shim apps wrote because invoke handed back the Effect",
|
|
6413
|
+
" const out = await invoke(d, handler, input, ctx)",
|
|
6414
|
+
" const value = Effect.isEffect(out) ? await Effect.runPromise(out) : out",
|
|
6415
|
+
"",
|
|
6416
|
+
" // after",
|
|
6417
|
+
" const value = await invoke(d, handler, input, ctx)",
|
|
6418
|
+
"",
|
|
6419
|
+
" Leaving the shim in place is not merely redundant: `out` is now the",
|
|
6420
|
+
" resolved VALUE, so `Effect.isEffect(out)` is false and the branch is",
|
|
6421
|
+
" dead — but if the value happens to be an Effect (a handler that returns",
|
|
6422
|
+
" a description of work on purpose) the shim will now run it a second",
|
|
6423
|
+
" time. Delete it.",
|
|
6424
|
+
"",
|
|
6425
|
+
" Deleting it also RESTORES your typed errors. `Effect.runPromise` rejects",
|
|
6426
|
+
" with an opaque FiberFailure; `invoke` unwraps the failure and rejects",
|
|
6427
|
+
" with the tagged error itself, so `rejects.toMatchObject({ _tag: … })`",
|
|
6428
|
+
" works for an Effect handler exactly as for an async one.",
|
|
6429
|
+
"",
|
|
6430
|
+
"2. Two type signatures changed. Both accept strictly MORE than before, so",
|
|
6431
|
+
" handlers keep compiling — what can break is code that reads the type of",
|
|
6432
|
+
" a CALL:",
|
|
6433
|
+
"",
|
|
6434
|
+
" • `ProcedureExecutor<Input, Output>` gained an `Effect<Output, E>` arm",
|
|
6435
|
+
" (and an optional third parameter `E`, defaulting to `never`). If you",
|
|
6436
|
+
" call a value typed `ProcedureExecutor<…>` yourself and assign the",
|
|
6437
|
+
" result to `Output`, it no longer narrows — call it through `invoke`,",
|
|
6438
|
+
" or handle the Effect arm.",
|
|
6439
|
+
"",
|
|
6440
|
+
" • `invoke` now infers from the executor's whole return type instead of",
|
|
6441
|
+
" taking `Output` as its second type parameter. An EXPLICIT type",
|
|
6442
|
+
" argument list — `invoke<typeof d, Note>(…)` — now pins the executor's",
|
|
6443
|
+
" RETURN type (so an async handler no longer matches). Drop the explicit",
|
|
6444
|
+
" type arguments; inference gives the same result, and better:",
|
|
6445
|
+
"",
|
|
6446
|
+
" await invoke(d, handler, input, ctx) // resolves to Note",
|
|
6447
|
+
"",
|
|
6448
|
+
"Nothing else about `invoke` changed — guards, the input decode, the",
|
|
6449
|
+
"transaction, the deadlock replay, `afterCommit` and the plugin interceptor",
|
|
6450
|
+
"chain wrap an Effect handler exactly as they wrap an async one."
|
|
6451
|
+
].join("\n")
|
|
6452
|
+
}), Bu = /\bpasswordHash\b/, Vu = /\b(UserStore|UserRecord|memoryUserStore|postgresUserStore)\b/, Hu = [
|
|
6312
6453
|
_u,
|
|
6313
6454
|
vu,
|
|
6314
6455
|
xu,
|
|
@@ -6320,156 +6461,155 @@ replicas = 1
|
|
|
6320
6461
|
Au,
|
|
6321
6462
|
Pu,
|
|
6322
6463
|
Fu,
|
|
6464
|
+
Ru,
|
|
6465
|
+
zu,
|
|
6323
6466
|
Z({
|
|
6324
|
-
version: "0.
|
|
6325
|
-
id: "0.
|
|
6326
|
-
title: "
|
|
6467
|
+
version: "0.8.0",
|
|
6468
|
+
id: "0.8.0/01_optional-password-hash",
|
|
6469
|
+
title: "`UserRecord.passwordHash` is optional — password-less identities are now first-class",
|
|
6327
6470
|
kind: "manual",
|
|
6328
6471
|
appliesTo: ({ project: e }) => e.getSourceFiles().some((e) => {
|
|
6329
6472
|
let t = e.getFullText();
|
|
6330
|
-
return
|
|
6473
|
+
return Bu.test(t) || Vu.test(t);
|
|
6331
6474
|
}),
|
|
6332
6475
|
note: [
|
|
6333
|
-
"
|
|
6476
|
+
"`UserRecord.passwordHash` is now `string | null | undefined`, not `string`.",
|
|
6334
6477
|
"",
|
|
6335
6478
|
"What changed and why:",
|
|
6336
6479
|
"",
|
|
6337
|
-
" `
|
|
6338
|
-
"
|
|
6339
|
-
"
|
|
6340
|
-
"
|
|
6341
|
-
"
|
|
6480
|
+
" `passwordHash` was required, which quietly asserted that every identity has",
|
|
6481
|
+
" a password. SSO-only, magic-link-only, passkey-only and provider-PAT apps",
|
|
6482
|
+
" have none — and the only way they could use `subjectFromUser(...)` was to",
|
|
6483
|
+
" invent a fake hash. That is strictly worse than storing nothing: a fake hash",
|
|
6484
|
+
" is a real value sitting in the column a verifier compares against. Several",
|
|
6485
|
+
" apps chose instead to hand-build the `Subject`, losing the helper entirely.",
|
|
6486
|
+
"",
|
|
6487
|
+
" The `users` table column is now nullable to match. That side needs NO action",
|
|
6488
|
+
" from you — it rides the declarative differ on `voltro db apply` / next boot.",
|
|
6489
|
+
"",
|
|
6490
|
+
"Why this can break your build even though nothing was removed:",
|
|
6491
|
+
"",
|
|
6492
|
+
" Widening a type is additive for code that WRITES a `UserRecord` and breaking",
|
|
6493
|
+
" for code that READS one. These compiled before and do not now:",
|
|
6494
|
+
"",
|
|
6495
|
+
" const h: string = user.passwordHash // TS2322",
|
|
6496
|
+
" user.passwordHash.length // TS18048/TS2531",
|
|
6497
|
+
" verifyPassword(pw, user.passwordHash) // TS2345",
|
|
6342
6498
|
"",
|
|
6343
|
-
"
|
|
6499
|
+
"What to do — TypeScript will point at every site; decide per site:",
|
|
6344
6500
|
"",
|
|
6345
|
-
"
|
|
6346
|
-
"
|
|
6347
|
-
"
|
|
6348
|
-
"
|
|
6501
|
+
" 1. A site that VERIFIES a password. Treat an absent hash as a REFUSAL, and",
|
|
6502
|
+
" make it indistinguishable from a wrong password — same status, same body,",
|
|
6503
|
+
" and still burn the same work so the latency does not reveal which accounts",
|
|
6504
|
+
" are password-less:",
|
|
6349
6505
|
"",
|
|
6350
|
-
"
|
|
6351
|
-
"
|
|
6352
|
-
"
|
|
6353
|
-
"
|
|
6354
|
-
"
|
|
6355
|
-
"
|
|
6506
|
+
" const stored = user?.passwordHash",
|
|
6507
|
+
" const hasPassword = typeof stored === 'string' && stored.length > 0",
|
|
6508
|
+
" const verdict = hasPassword",
|
|
6509
|
+
" ? yield* verifyPasswordWithRehash(input.password, stored)",
|
|
6510
|
+
" : yield* /* decoy hash + verify */ Effect.succeed({ valid: false as const })",
|
|
6511
|
+
" if (!user || !verdict.valid) return json(401, { error: 'invalid credentials' })",
|
|
6356
6512
|
"",
|
|
6357
|
-
"
|
|
6513
|
+
" Note `''` is treated as absent too. The framework's own `handleSignIn`",
|
|
6514
|
+
" already does exactly this; if you use it, you need no change here.",
|
|
6358
6515
|
"",
|
|
6359
|
-
"
|
|
6360
|
-
"
|
|
6516
|
+
" 2. A site that WRITES a hash (sign-up, password reset, set-password). Nothing",
|
|
6517
|
+
" to do — assigning a hash to a previously password-less user works",
|
|
6518
|
+
" unchanged and promotes them to a password user.",
|
|
6361
6519
|
"",
|
|
6362
|
-
"
|
|
6363
|
-
"
|
|
6364
|
-
" Handle `RowFilterUnavailable` in your UI as an error state (\"could not",
|
|
6365
|
-
" load — retry\"), the same as any other failed request.",
|
|
6520
|
+
" 3. A site that only ever runs for password users. Narrow explicitly and let",
|
|
6521
|
+
" the impossible case be loud, rather than silencing it:",
|
|
6366
6522
|
"",
|
|
6367
|
-
"
|
|
6368
|
-
" are content for it to render as empty during an outage:",
|
|
6369
|
-
" setRowFilter({ load, predicate, onLoadError: 'deny' })",
|
|
6370
|
-
" Your `onError` reporter still fires, so the failure stays findable in",
|
|
6371
|
-
" logs even though the response is a 200.",
|
|
6523
|
+
" if (!user.passwordHash) throw new Error('expected a password user')",
|
|
6372
6524
|
"",
|
|
6373
|
-
"
|
|
6374
|
-
" Serving unfiltered rows when the authorization filter is unavailable leaks",
|
|
6375
|
-
" data precisely when the system is under stress and nobody is watching, and",
|
|
6376
|
-
" it is only safe if every handler still carries the check the row filter",
|
|
6377
|
-
" existed to replace.",
|
|
6525
|
+
"What NOT to do, and this is the whole point of a manual note:",
|
|
6378
6526
|
"",
|
|
6379
|
-
"
|
|
6380
|
-
"
|
|
6381
|
-
" setRowFilter({ load, predicate, retry: false }) // one attempt",
|
|
6382
|
-
" The default is `DEFAULT_ROW_FILTER_RETRY` (exported from @voltro/runtime).",
|
|
6527
|
+
" • Do NOT write `user.passwordHash!`. It re-asserts the invariant that just",
|
|
6528
|
+
" stopped holding, and the failure surfaces at runtime instead of here.",
|
|
6383
6529
|
"",
|
|
6384
|
-
"
|
|
6385
|
-
"
|
|
6386
|
-
"
|
|
6387
|
-
"
|
|
6388
|
-
"
|
|
6530
|
+
" • Do NOT write `user.passwordHash ?? ''` (or any placeholder). You are then",
|
|
6531
|
+
" comparing a submitted password against a value you invented. Whether that",
|
|
6532
|
+
" refuses depends on the verifier, and a verifier that returns true for a",
|
|
6533
|
+
" degenerate hash means ANY password signs in as a password-less user. If you",
|
|
6534
|
+
" take one thing from this note: an absent hash must be a refusal decision,",
|
|
6535
|
+
" never a default value.",
|
|
6389
6536
|
"",
|
|
6390
|
-
"
|
|
6391
|
-
"
|
|
6392
|
-
" the fix working, not a regression.",
|
|
6537
|
+
" • Do NOT add a `NOT NULL` back to your own users table to dodge the change —",
|
|
6538
|
+
" it forces the fake hash back in at insert time.",
|
|
6393
6539
|
"",
|
|
6394
|
-
"
|
|
6395
|
-
"
|
|
6396
|
-
"
|
|
6397
|
-
" snapshot. An empty snapshot on a live subscription reads to a client as",
|
|
6398
|
-
" \"every row you could see was just deleted\". Make sure your subscription",
|
|
6399
|
-
" error handling surfaces this rather than swallowing it."
|
|
6540
|
+
" 4. If you implement your OWN `UserStore`, widen the field on your record type",
|
|
6541
|
+
" to match and make sure your read path maps a NULL column to `null`/",
|
|
6542
|
+
" `undefined` rather than to `''`-by-coercion."
|
|
6400
6543
|
].join("\n")
|
|
6401
6544
|
}),
|
|
6402
6545
|
Z({
|
|
6403
|
-
version: "0.
|
|
6404
|
-
id: "0.
|
|
6405
|
-
title: "
|
|
6546
|
+
version: "0.8.0",
|
|
6547
|
+
id: "0.8.0/02_ssr-streams-and-loaderdata",
|
|
6548
|
+
title: "`ssr` pages stream; `useLoaderData<T>()` returns `LoaderData<T>`",
|
|
6406
6549
|
kind: "manual",
|
|
6407
|
-
appliesTo: ({ project: e }) => e.getSourceFiles().some((e) => {
|
|
6408
|
-
let t = e.getFullText();
|
|
6409
|
-
return t.includes("@voltro/testing") ? /\binvoke\s*\(/.test(t) || /\bProcedureExecutor\b/.test(t) : !1;
|
|
6410
|
-
}),
|
|
6411
6550
|
note: [
|
|
6412
|
-
"
|
|
6413
|
-
"handler and runs it, the way the dispatcher does. Two consequences.",
|
|
6551
|
+
"Two things changed for server-rendered pages.",
|
|
6414
6552
|
"",
|
|
6415
|
-
"1.
|
|
6553
|
+
"1. `renderMode: 'ssr'` responses are now STREAMED.",
|
|
6416
6554
|
"",
|
|
6417
|
-
"
|
|
6418
|
-
"
|
|
6419
|
-
" const value = Effect.isEffect(out) ? await Effect.runPromise(out) : out",
|
|
6555
|
+
" `voltro dev` and `voltro start` send the <head> + page shell first and",
|
|
6556
|
+
" flush each <Suspense> boundary as its data settles. Consequences:",
|
|
6420
6557
|
"",
|
|
6421
|
-
"
|
|
6422
|
-
"
|
|
6558
|
+
" • Re-run `voltro build` before `voltro start`. The prebuilt SSR bundle",
|
|
6559
|
+
" (.framework/dist/server/ssrEntry.js) now has to export the streaming",
|
|
6560
|
+
" helpers; a bundle built by an older CLI will fail at request time.",
|
|
6561
|
+
" If your deploy already runs `voltro build` before `voltro start`,",
|
|
6562
|
+
" nothing to do.",
|
|
6563
|
+
" • `ssr` responses are chunked and carry no `content-length`. If a",
|
|
6564
|
+
" reverse proxy in front of the app buffers responses (nginx",
|
|
6565
|
+
" `proxy_buffering on`, some CDNs), turn buffering off for these",
|
|
6566
|
+
" routes or the streaming win is absorbed by the proxy.",
|
|
6567
|
+
" • Pages with `interactive: 'none'` or `'islands'`, and `isr` /",
|
|
6568
|
+
" `static` pages, are unchanged — still rendered as one buffered",
|
|
6569
|
+
" document.",
|
|
6423
6570
|
"",
|
|
6424
|
-
"
|
|
6425
|
-
" resolved VALUE, so `Effect.isEffect(out)` is false and the branch is",
|
|
6426
|
-
" dead — but if the value happens to be an Effect (a handler that returns",
|
|
6427
|
-
" a description of work on purpose) the shim will now run it a second",
|
|
6428
|
-
" time. Delete it.",
|
|
6571
|
+
"2. `useLoaderData<T>()` now returns `LoaderData<T>`.",
|
|
6429
6572
|
"",
|
|
6430
|
-
"
|
|
6431
|
-
"
|
|
6432
|
-
"
|
|
6433
|
-
"
|
|
6573
|
+
" For every concrete `T`, `LoaderData<T>` IS `T` — the overwhelming",
|
|
6574
|
+
" majority of call sites need no change. It differs only for a loader that",
|
|
6575
|
+
" returns the new `defer()`, where it flattens to eager fields as values",
|
|
6576
|
+
" plus deferred fields as promises.",
|
|
6434
6577
|
"",
|
|
6435
|
-
"
|
|
6436
|
-
"
|
|
6437
|
-
" a CALL:",
|
|
6578
|
+
" The one shape that can stop compiling is a call that passes an",
|
|
6579
|
+
" UNRESOLVED generic through, e.g.",
|
|
6438
6580
|
"",
|
|
6439
|
-
"
|
|
6440
|
-
" (and an optional third parameter `E`, defaulting to `never`). If you",
|
|
6441
|
-
" call a value typed `ProcedureExecutor<…>` yourself and assign the",
|
|
6442
|
-
" result to `Output`, it no longer narrows — call it through `invoke`,",
|
|
6443
|
-
" or handle the Effect arm.",
|
|
6581
|
+
" const usePageData = <D,>(): D => useLoaderData<D>()",
|
|
6444
6582
|
"",
|
|
6445
|
-
"
|
|
6446
|
-
"
|
|
6447
|
-
" argument list — `invoke<typeof d, Note>(…)` — now pins the executor's",
|
|
6448
|
-
" RETURN type (so an async handler no longer matches). Drop the explicit",
|
|
6449
|
-
" type arguments; inference gives the same result, and better:",
|
|
6583
|
+
" `LoaderData<D>` cannot be assigned to `D` while `D` is still a type",
|
|
6584
|
+
" parameter. Fix by propagating the mapped type instead of `D`:",
|
|
6450
6585
|
"",
|
|
6451
|
-
"
|
|
6586
|
+
" const usePageData = <D,>(): LoaderData<D> => useLoaderData<D>()",
|
|
6452
6587
|
"",
|
|
6453
|
-
"
|
|
6454
|
-
"
|
|
6455
|
-
"
|
|
6588
|
+
" Run your app's `typecheck` after upgrading — that is the only reliable",
|
|
6589
|
+
" way to find these, which is why this step is written out rather than",
|
|
6590
|
+
" applied automatically.",
|
|
6591
|
+
"",
|
|
6592
|
+
"New in the same release: `defer()` + `<Await>` for streaming one slow field",
|
|
6593
|
+
"of a loader instead of blocking the whole response. See the Loaders & meta",
|
|
6594
|
+
"docs. `defer()` requires `renderMode: 'ssr'` and `interactive: 'full'`;",
|
|
6595
|
+
"every other combination is a hard error naming the page."
|
|
6456
6596
|
].join("\n")
|
|
6457
6597
|
})
|
|
6458
|
-
],
|
|
6598
|
+
], Uu = (e) => [
|
|
6459
6599
|
`${e}/**/*.ts`,
|
|
6460
6600
|
`${e}/**/*.tsx`,
|
|
6461
6601
|
`!${e}/**/node_modules/**`,
|
|
6462
6602
|
`!${e}/**/dist/**`,
|
|
6463
6603
|
`!${e}/**/.framework/**`,
|
|
6464
6604
|
`!${e}/**/*.d.ts`
|
|
6465
|
-
],
|
|
6605
|
+
], Wu = (e, t) => {
|
|
6466
6606
|
let n = e.split(".").map(Number), r = t.split(".").map(Number);
|
|
6467
6607
|
for (let e = 0; e < 3; e++) {
|
|
6468
6608
|
let t = (n[e] ?? 0) - (r[e] ?? 0);
|
|
6469
6609
|
if (t !== 0) return t;
|
|
6470
6610
|
}
|
|
6471
6611
|
return 0;
|
|
6472
|
-
},
|
|
6612
|
+
}, Gu = (e, t, n = Hu) => n.filter((n) => Wu(e, n.version) < 0 && Wu(n.version, t) <= 0).slice().sort(gu), Ku = (e, t, n = () => {}) => {
|
|
6473
6613
|
let r = [], i = [], a = [];
|
|
6474
6614
|
for (let o of t) {
|
|
6475
6615
|
if (!(!o.appliesTo || o.appliesTo({ project: e }))) {
|
|
@@ -6506,8 +6646,8 @@ replicas = 1
|
|
|
6506
6646
|
manual: i,
|
|
6507
6647
|
skipped: a
|
|
6508
6648
|
};
|
|
6509
|
-
},
|
|
6510
|
-
let t = e.log ?? (() => {}), n =
|
|
6649
|
+
}, qu = async (e) => {
|
|
6650
|
+
let t = e.log ?? (() => {}), n = Gu(e.from, e.to, e.codemods ?? Hu);
|
|
6511
6651
|
if (n.length === 0) return {
|
|
6512
6652
|
applied: [],
|
|
6513
6653
|
manual: [],
|
|
@@ -6518,24 +6658,24 @@ replicas = 1
|
|
|
6518
6658
|
manipulationSettings: { quoteKind: tn.Single }
|
|
6519
6659
|
}), i = /* @__PURE__ */ new Set();
|
|
6520
6660
|
for (let t of n) {
|
|
6521
|
-
let n = t.scope ? t.scope.flatMap((t) => t.startsWith("!") ? [`!${e.root}/${t.slice(1)}`] : [`${e.root}/${t}`]) :
|
|
6661
|
+
let n = t.scope ? t.scope.flatMap((t) => t.startsWith("!") ? [`!${e.root}/${t.slice(1)}`] : [`${e.root}/${t}`]) : Uu(e.root);
|
|
6522
6662
|
for (let e of n) i.add(e);
|
|
6523
6663
|
}
|
|
6524
6664
|
r.addSourceFilesAtPaths([...i]);
|
|
6525
|
-
let a =
|
|
6665
|
+
let a = Ku(r, n, t);
|
|
6526
6666
|
return e.dryRun || await r.save(), a;
|
|
6527
|
-
},
|
|
6667
|
+
}, Ju = /^(workspace:|catalog:|link:|file:|npm:|portal:)/, Yu = /* @__PURE__ */ new Set([
|
|
6528
6668
|
"pnpm",
|
|
6529
6669
|
"npm",
|
|
6530
6670
|
"yarn",
|
|
6531
6671
|
"bun"
|
|
6532
|
-
]),
|
|
6672
|
+
]), Xu = [
|
|
6533
6673
|
["pnpm-lock.yaml", "pnpm"],
|
|
6534
6674
|
["yarn.lock", "yarn"],
|
|
6535
6675
|
["bun.lock", "bun"],
|
|
6536
6676
|
["bun.lockb", "bun"],
|
|
6537
6677
|
["package-lock.json", "npm"]
|
|
6538
|
-
],
|
|
6678
|
+
], Zu = (e) => {
|
|
6539
6679
|
let t = [], n = T(e);
|
|
6540
6680
|
for (; t.push(n), !A(C(n, ".git"));) {
|
|
6541
6681
|
let e = S(n);
|
|
@@ -6543,20 +6683,20 @@ replicas = 1
|
|
|
6543
6683
|
n = e;
|
|
6544
6684
|
}
|
|
6545
6685
|
return t;
|
|
6546
|
-
},
|
|
6547
|
-
for (let t of
|
|
6686
|
+
}, Qu = (e) => {
|
|
6687
|
+
for (let t of Zu(e)) {
|
|
6548
6688
|
let e = C(t, "package.json");
|
|
6549
6689
|
if (A(e)) try {
|
|
6550
6690
|
let t = JSON.parse(N(e, "utf8")).packageManager;
|
|
6551
6691
|
if (typeof t == "string") {
|
|
6552
6692
|
let e = t.split("@")[0]?.trim();
|
|
6553
|
-
if (e &&
|
|
6693
|
+
if (e && Yu.has(e)) return e;
|
|
6554
6694
|
}
|
|
6555
6695
|
} catch {}
|
|
6556
|
-
for (let [e, n] of
|
|
6696
|
+
for (let [e, n] of Xu) if (A(C(t, e))) return n;
|
|
6557
6697
|
}
|
|
6558
6698
|
return "npm";
|
|
6559
|
-
},
|
|
6699
|
+
}, $u = /* @__PURE__ */ new Set([
|
|
6560
6700
|
"node_modules",
|
|
6561
6701
|
".git",
|
|
6562
6702
|
"dist",
|
|
@@ -6568,8 +6708,8 @@ replicas = 1
|
|
|
6568
6708
|
".turbo",
|
|
6569
6709
|
".cache",
|
|
6570
6710
|
".output"
|
|
6571
|
-
]),
|
|
6572
|
-
for (let t of
|
|
6711
|
+
]), ed = 4, td = (e) => {
|
|
6712
|
+
for (let t of Zu(e)) {
|
|
6573
6713
|
if (A(C(t, "pnpm-workspace.yaml")) || A(C(t, "pnpm-workspace.yml"))) return t;
|
|
6574
6714
|
let e = C(t, "package.json");
|
|
6575
6715
|
if (A(e)) try {
|
|
@@ -6577,10 +6717,10 @@ replicas = 1
|
|
|
6577
6717
|
if (Array.isArray(n) ? n.length > 0 : typeof n == "object" && n) return t;
|
|
6578
6718
|
} catch {}
|
|
6579
6719
|
}
|
|
6580
|
-
},
|
|
6720
|
+
}, nd = (e) => {
|
|
6581
6721
|
let t = [], n = (e, r) => {
|
|
6582
6722
|
let i = C(e, "package.json");
|
|
6583
|
-
if (A(i) && t.push(i), r >=
|
|
6723
|
+
if (A(i) && t.push(i), r >= ed) return;
|
|
6584
6724
|
let a;
|
|
6585
6725
|
try {
|
|
6586
6726
|
a = Fe(e);
|
|
@@ -6588,7 +6728,7 @@ replicas = 1
|
|
|
6588
6728
|
return;
|
|
6589
6729
|
}
|
|
6590
6730
|
for (let t of a) {
|
|
6591
|
-
if (t.startsWith(".") ||
|
|
6731
|
+
if (t.startsWith(".") || $u.has(t)) continue;
|
|
6592
6732
|
let i = C(e, t);
|
|
6593
6733
|
try {
|
|
6594
6734
|
if (!Ie(i).isDirectory()) continue;
|
|
@@ -6599,7 +6739,7 @@ replicas = 1
|
|
|
6599
6739
|
}
|
|
6600
6740
|
};
|
|
6601
6741
|
return n(T(e), 0), t;
|
|
6602
|
-
},
|
|
6742
|
+
}, rd = (e) => {
|
|
6603
6743
|
try {
|
|
6604
6744
|
return nt("git", ["status", "--porcelain"], {
|
|
6605
6745
|
cwd: e,
|
|
@@ -6608,7 +6748,7 @@ replicas = 1
|
|
|
6608
6748
|
} catch {
|
|
6609
6749
|
return !1;
|
|
6610
6750
|
}
|
|
6611
|
-
},
|
|
6751
|
+
}, id = /^\d+\.\d+\.\d+/, ad = (e, t) => {
|
|
6612
6752
|
try {
|
|
6613
6753
|
let n = nt(e, [...t], {
|
|
6614
6754
|
encoding: "utf8",
|
|
@@ -6621,14 +6761,14 @@ replicas = 1
|
|
|
6621
6761
|
if (!n) return;
|
|
6622
6762
|
if (n.startsWith("{")) {
|
|
6623
6763
|
let e = JSON.parse(n).version;
|
|
6624
|
-
return typeof e == "string" &&
|
|
6764
|
+
return typeof e == "string" && id.test(e) ? e : void 0;
|
|
6625
6765
|
}
|
|
6626
6766
|
let r = n.split("\n").map((e) => e.trim()).filter(Boolean).pop();
|
|
6627
|
-
return r &&
|
|
6767
|
+
return r && id.test(r) ? r : void 0;
|
|
6628
6768
|
} catch {
|
|
6629
6769
|
return;
|
|
6630
6770
|
}
|
|
6631
|
-
},
|
|
6771
|
+
}, od = () => {
|
|
6632
6772
|
try {
|
|
6633
6773
|
let e = nt("yarn", ["--version"], {
|
|
6634
6774
|
encoding: "utf8",
|
|
@@ -6642,7 +6782,7 @@ replicas = 1
|
|
|
6642
6782
|
} catch {
|
|
6643
6783
|
return 1;
|
|
6644
6784
|
}
|
|
6645
|
-
},
|
|
6785
|
+
}, sd = (e, t, n) => [...t === "pnpm" ? [["pnpm", [
|
|
6646
6786
|
"view",
|
|
6647
6787
|
e,
|
|
6648
6788
|
"version"
|
|
@@ -6667,17 +6807,17 @@ replicas = 1
|
|
|
6667
6807
|
"view",
|
|
6668
6808
|
e,
|
|
6669
6809
|
"version"
|
|
6670
|
-
]]],
|
|
6671
|
-
for (let [n, r] of
|
|
6672
|
-
let e =
|
|
6810
|
+
]]], cd = (e, t = "npm") => {
|
|
6811
|
+
for (let [n, r] of sd(e, t, t === "yarn" ? od() : 1)) {
|
|
6812
|
+
let e = ad(n, r);
|
|
6673
6813
|
if (e) return e;
|
|
6674
6814
|
}
|
|
6675
|
-
},
|
|
6815
|
+
}, ld = (e) => JSON.parse(N(e, "utf8")), ud = (e) => {
|
|
6676
6816
|
let t = C(e, "node_modules", "@voltro", "cli", "package.json");
|
|
6677
6817
|
if (!A(t)) return;
|
|
6678
|
-
let n =
|
|
6818
|
+
let n = ld(t).version;
|
|
6679
6819
|
return typeof n == "string" ? n : void 0;
|
|
6680
|
-
},
|
|
6820
|
+
}, dd = (e) => {
|
|
6681
6821
|
let t = [];
|
|
6682
6822
|
for (let n of ["dependencies", "devDependencies"]) {
|
|
6683
6823
|
let r = e[n];
|
|
@@ -6688,7 +6828,7 @@ replicas = 1
|
|
|
6688
6828
|
});
|
|
6689
6829
|
}
|
|
6690
6830
|
return t;
|
|
6691
|
-
},
|
|
6831
|
+
}, fd = (e, t, n) => dd(e).map(({ name: e, spec: r }) => Ju.test(r) ? {
|
|
6692
6832
|
name: e,
|
|
6693
6833
|
from: r,
|
|
6694
6834
|
to: r,
|
|
@@ -6697,22 +6837,22 @@ replicas = 1
|
|
|
6697
6837
|
name: e,
|
|
6698
6838
|
from: r,
|
|
6699
6839
|
to: `${n ? "" : /^[\^~]/.exec(r)?.[0] ?? ""}${t}`
|
|
6700
|
-
}),
|
|
6840
|
+
}), pd = (e, t) => {
|
|
6701
6841
|
for (let n of t) if (!n.skipped) for (let t of ["dependencies", "devDependencies"]) {
|
|
6702
6842
|
let r = e[t];
|
|
6703
6843
|
r && n.name in r && (r[n.name] = n.to);
|
|
6704
6844
|
}
|
|
6705
|
-
},
|
|
6845
|
+
}, md = (e, t, n) => e.map(({ path: e, pkg: r }) => ({
|
|
6706
6846
|
path: e,
|
|
6707
|
-
entries:
|
|
6708
|
-
})).filter((e) => e.entries.length > 0),
|
|
6847
|
+
entries: fd(r, t, n)
|
|
6848
|
+
})).filter((e) => e.entries.length > 0), hd = (e, t) => {
|
|
6709
6849
|
let n = new Map(e.map((e) => [e.path, e])), r = [];
|
|
6710
6850
|
for (let e of t) {
|
|
6711
6851
|
let t = n.get(e.path);
|
|
6712
|
-
t && (
|
|
6852
|
+
t && (pd(t.pkg, e.entries), r.push(t));
|
|
6713
6853
|
}
|
|
6714
6854
|
return r;
|
|
6715
|
-
},
|
|
6855
|
+
}, gd = (e) => {
|
|
6716
6856
|
let t, n, r = process.cwd(), i = [];
|
|
6717
6857
|
for (let a = 0; a < e.length; a++) {
|
|
6718
6858
|
let o = e[a];
|
|
@@ -6741,22 +6881,22 @@ replicas = 1
|
|
|
6741
6881
|
...t === void 0 ? {} : { to: t },
|
|
6742
6882
|
...n === void 0 ? {} : { from: n }
|
|
6743
6883
|
};
|
|
6744
|
-
},
|
|
6745
|
-
let n = t.latestVersion ??
|
|
6884
|
+
}, _d = "voltro update [app] [flags]\n\nUpgrade an app to a newer framework release: bump every @voltro/* dependency,\ninstall, and run the codemods shipped with the target version.\n\nIn a workspace (pnpm-workspace.yaml, or a package.json \"workspaces\" field),\nEVERY member package.json that declares @voltro/* is bumped in lockstep and the\ninstall runs once at the workspace root — so api / web / shared packages never\nend up on different framework versions.\n\nFlags:\n --to <version> Target version (default: the latest published version).\n --from <version> Source version — overrides the detected installed version.\n Use it after a hand-edited bump so the codemods for the\n delta you actually crossed still run.\n --root <dir> App directory to update (default: the current directory).\n A positional [app] does the same.\n --dry-run Print the plan — every package.json that would be bumped —\n and write nothing. Allowed on a dirty tree.\n --force Proceed on a dirty working tree, and re-run even when the\n installed version already equals the target.\n --exact Pin exact versions (drop the ^ / ~ range prefix).\n --codemods-only Run ONLY the codemods for [from, to] against the installed\n tree — no version bump, no install. The recovery path after\n a manual bump, or after a failed install. Alias:\n --run-codemods.\n -h, --help Print this help.\n\nExamples:\n voltro update\n voltro update --to 0.6.0 --dry-run\n voltro update --codemods-only --from 0.5.0 --to 0.6.0\n\nAfter updating: run `voltro db apply` (NOT db migrate) to reconcile changed\nframework tables, then your typecheck.", vd = (e) => e.includes("--help") || e.includes("-h"), yd = async (e, t = {}) => {
|
|
6885
|
+
let n = t.latestVersion ?? cd, r = t.isGitClean ?? rd, i = t.install ?? ((e, t) => it(e, ["install"], {
|
|
6746
6886
|
cwd: t,
|
|
6747
6887
|
stdio: "inherit"
|
|
6748
6888
|
}).status ?? 1);
|
|
6749
|
-
if (
|
|
6750
|
-
let a =
|
|
6889
|
+
if (vd(e)) return console.log(_d), 0;
|
|
6890
|
+
let a = gd(e), o = C(a.root, "package.json");
|
|
6751
6891
|
if (!A(o)) return console.error(`voltro update: no package.json at ${a.root}`), 1;
|
|
6752
|
-
let s =
|
|
6892
|
+
let s = ld(o), c = dd(s);
|
|
6753
6893
|
if (c.length === 0) return console.error("voltro update: no @voltro/* dependencies here — not a Voltro app."), 1;
|
|
6754
6894
|
if (!a.dryRun && !a.force && !r(a.root)) return console.error("voltro update: working tree is not clean. Commit/stash first so you can review the"), console.error(" codemod diff — or re-run with --force (not recommended) or --dry-run (preview only)."), 1;
|
|
6755
|
-
let l =
|
|
6895
|
+
let l = td(a.root), u = l ?? a.root, d = () => ud(a.root) ?? (l ? ud(l) : void 0), f = a.from ?? d() ?? /^\d+\.\d+\.\d+$/.exec(c.find((e) => e.name === "@voltro/cli")?.spec.replace(/^[\^~]/, "") ?? "")?.[0];
|
|
6756
6896
|
if (!f) return console.error("voltro update: could not determine the source framework version."), console.error(" Run your package manager install first, or pass --from <version>."), 1;
|
|
6757
|
-
let p =
|
|
6897
|
+
let p = Qu(a.root), m = a.to ?? (a.codemodsOnly ? d() : void 0) ?? n("@voltro/cli", p);
|
|
6758
6898
|
if (!m) return console.error(`voltro update: could not resolve the latest @voltro/cli version via ${p}.`), console.error(" Pin an explicit target with --to <version>."), 1;
|
|
6759
|
-
if (a.codemodsOnly) return f === m ? (console.log(`voltro update: --codemods-only with from === to (${m}) — no delta, nothing to apply.`), console.log(" Pass --from <earlier-version> to re-run the codemods you skipped."), 0) : (console.log(`voltro update: re-applying codemods ${f} → ${m} (no version bump)…`),
|
|
6899
|
+
if (a.codemodsOnly) return f === m ? (console.log(`voltro update: --codemods-only with from === to (${m}) — no delta, nothing to apply.`), console.log(" Pass --from <earlier-version> to re-run the codemods you skipped."), 0) : (console.log(`voltro update: re-applying codemods ${f} → ${m} (no version bump)…`), xd([
|
|
6760
6900
|
"--root",
|
|
6761
6901
|
a.root,
|
|
6762
6902
|
"--from",
|
|
@@ -6766,7 +6906,7 @@ replicas = 1
|
|
|
6766
6906
|
...a.dryRun ? ["--dry-run"] : []
|
|
6767
6907
|
]));
|
|
6768
6908
|
if (f === m && !a.force) return console.log(`voltro update: already on ${m} — nothing to do.`), console.log(" (Bumped @voltro/* by hand? Re-run the skipped codemods with"), console.log(" `voltro update --codemods-only --from <earlier-version>`.)"), 0;
|
|
6769
|
-
let h = [o, ...l ?
|
|
6909
|
+
let h = [o, ...l ? nd(l) : []], g = [], _ = /* @__PURE__ */ new Set();
|
|
6770
6910
|
for (let e of h) if (!_.has(e)) {
|
|
6771
6911
|
if (_.add(e), e === o) {
|
|
6772
6912
|
g.push({
|
|
@@ -6778,11 +6918,11 @@ replicas = 1
|
|
|
6778
6918
|
try {
|
|
6779
6919
|
g.push({
|
|
6780
6920
|
path: e,
|
|
6781
|
-
pkg:
|
|
6921
|
+
pkg: ld(e)
|
|
6782
6922
|
});
|
|
6783
6923
|
} catch {}
|
|
6784
6924
|
}
|
|
6785
|
-
let v =
|
|
6925
|
+
let v = md(g, m, a.exact);
|
|
6786
6926
|
console.log(`voltro update: ${f} → ${m}`);
|
|
6787
6927
|
let y = v.length > 1;
|
|
6788
6928
|
l && console.log(` workspace: ${l} (${v.length} package.json with @voltro/* deps)`);
|
|
@@ -6793,7 +6933,7 @@ replicas = 1
|
|
|
6793
6933
|
for (let n of e.entries.filter((e) => e.skipped)) console.log(`${t}${n.name}: kept (${n.skipped})`);
|
|
6794
6934
|
}
|
|
6795
6935
|
if (console.log(` package manager: ${p}`), console.log(` install runs in: ${u}`), console.log(` codemods: applied from ${m} after install`), a.dryRun) return console.log("\n(dry-run — nothing written. Codemods are resolved from the target version and"), console.log(" only listed/applied after install; re-run without --dry-run to upgrade.)"), 0;
|
|
6796
|
-
for (let e of
|
|
6936
|
+
for (let e of hd(g, v)) Le(e.path, JSON.stringify(e.pkg, null, 2) + "\n");
|
|
6797
6937
|
console.log(`\nInstalling with ${p} in ${u}…`);
|
|
6798
6938
|
let ee = i(p, u);
|
|
6799
6939
|
if (ee !== 0) return console.error(`\nvoltro update: ${p} install failed in ${u}.`), console.error(` • package.json was bumped to ${m} (${v.length} file${v.length === 1 ? "" : "s"}).`), console.error(" • CODEMODS WERE NOT APPLIED — they ship inside the target version, which the"), console.error(" failed install did not put on disk, so there was nothing to run."), console.error(" Fix the install, re-run it, then apply the codemods you are missing:"), console.error(` voltro update --codemods-only --from ${f} --to ${m}`), ee;
|
|
@@ -6813,7 +6953,7 @@ replicas = 1
|
|
|
6813
6953
|
stdio: "inherit"
|
|
6814
6954
|
});
|
|
6815
6955
|
if (e.status !== 0) return e.status ?? 1;
|
|
6816
|
-
} else console.log("\nApplying codemods (in-process — installed bin not found)…"), await
|
|
6956
|
+
} else console.log("\nApplying codemods (in-process — installed bin not found)…"), await xd([
|
|
6817
6957
|
"--root",
|
|
6818
6958
|
a.root,
|
|
6819
6959
|
"--from",
|
|
@@ -6822,7 +6962,7 @@ replicas = 1
|
|
|
6822
6962
|
m
|
|
6823
6963
|
]);
|
|
6824
6964
|
return console.log("\n✓ update complete. Next:"), console.log(" • voltro db apply # reconcile any changed framework tables (NOT db migrate)"), console.log(" • <your typecheck> # verify the codemods + your code compile against the new API"), 0;
|
|
6825
|
-
},
|
|
6965
|
+
}, bd = (e) => {
|
|
6826
6966
|
let t = (t) => {
|
|
6827
6967
|
let n = e.indexOf(t);
|
|
6828
6968
|
return n >= 0 ? e[n + 1] : void 0;
|
|
@@ -6833,8 +6973,8 @@ replicas = 1
|
|
|
6833
6973
|
to: t("--to") ?? "0.0.0",
|
|
6834
6974
|
dryRun: e.includes("--dry-run")
|
|
6835
6975
|
};
|
|
6836
|
-
},
|
|
6837
|
-
let t =
|
|
6976
|
+
}, xd = async (e) => {
|
|
6977
|
+
let t = bd(e), n = await qu({
|
|
6838
6978
|
root: t.root,
|
|
6839
6979
|
from: t.from,
|
|
6840
6980
|
to: t.to,
|
|
@@ -6851,18 +6991,18 @@ replicas = 1
|
|
|
6851
6991
|
}
|
|
6852
6992
|
}
|
|
6853
6993
|
return t.dryRun && console.log("\n(dry-run — no files written)"), 0;
|
|
6854
|
-
},
|
|
6994
|
+
}, Sd = k({ scope: "voltro:test" }), Cd = async (e) => {
|
|
6855
6995
|
let t = T(e.find((e) => !e.startsWith("-")) ?? process.cwd());
|
|
6856
|
-
|
|
6996
|
+
Sd.info("running vitest", { root: t });
|
|
6857
6997
|
let n = await (await import("vitest/node")).startVitest("test", [], {
|
|
6858
6998
|
root: t,
|
|
6859
6999
|
watch: !1,
|
|
6860
7000
|
passWithNoTests: !0
|
|
6861
7001
|
});
|
|
6862
7002
|
return n ? (await n.close(), +!n.state.getFiles().every((e) => e.result?.state !== "fail")) : 1;
|
|
6863
|
-
},
|
|
7003
|
+
}, wd = class extends Me.TaggedError("BundleError") {}, Td = 0, Ed = (e) => C(at(), `voltro-sls-${e}-${process.pid}-${Td++}.mjs`), Dd = (e) => E.tryPromise({
|
|
6864
7004
|
try: async () => {
|
|
6865
|
-
let t =
|
|
7005
|
+
let t = Ed(x(e).replace(/\W+/g, "-"));
|
|
6866
7006
|
await nn.build({
|
|
6867
7007
|
entryPoints: [e],
|
|
6868
7008
|
outfile: t,
|
|
@@ -6879,12 +7019,12 @@ replicas = 1
|
|
|
6879
7019
|
await Je(t, { force: !0 });
|
|
6880
7020
|
}
|
|
6881
7021
|
},
|
|
6882
|
-
catch: (t) => new
|
|
7022
|
+
catch: (t) => new wd({
|
|
6883
7023
|
file: e,
|
|
6884
7024
|
message: t instanceof Error ? t.message : String(t)
|
|
6885
7025
|
})
|
|
6886
|
-
}),
|
|
6887
|
-
let t = yield*
|
|
7026
|
+
}), Od = (e) => e === "browser" ? "browser" : e === "neutral" ? "neutral" : "node", kd = (e) => E.gen(function* () {
|
|
7027
|
+
let t = yield* Dd(e.sourceFile), n = C(e.outDir, t.name), r = C(n, e.platform.esbuild.entryFile ?? (e.platform.esbuild.format === "esm" ? "index.mjs" : "index.js"));
|
|
6888
7028
|
return yield* E.tryPromise({
|
|
6889
7029
|
try: async () => {
|
|
6890
7030
|
await Ge(n, { recursive: !0 }), await nn.build({
|
|
@@ -6896,7 +7036,7 @@ replicas = 1
|
|
|
6896
7036
|
},
|
|
6897
7037
|
outfile: r,
|
|
6898
7038
|
bundle: !0,
|
|
6899
|
-
platform:
|
|
7039
|
+
platform: Od(e.platform.esbuild.platform),
|
|
6900
7040
|
format: e.platform.esbuild.format,
|
|
6901
7041
|
...e.platform.esbuild.targetEs ? { target: e.platform.esbuild.targetEs } : {},
|
|
6902
7042
|
...e.platform.esbuild.conditions ? { conditions: [...e.platform.esbuild.conditions] } : {},
|
|
@@ -6905,7 +7045,7 @@ replicas = 1
|
|
|
6905
7045
|
logLevel: "silent"
|
|
6906
7046
|
});
|
|
6907
7047
|
},
|
|
6908
|
-
catch: (t) => new
|
|
7048
|
+
catch: (t) => new wd({
|
|
6909
7049
|
file: e.sourceFile,
|
|
6910
7050
|
message: t instanceof Error ? t.message : String(t)
|
|
6911
7051
|
})
|
|
@@ -6915,32 +7055,32 @@ replicas = 1
|
|
|
6915
7055
|
dir: n,
|
|
6916
7056
|
...t.runtime ? { runtime: t.runtime } : {}
|
|
6917
7057
|
};
|
|
6918
|
-
}),
|
|
7058
|
+
}), Ad = (e, t = {}) => E.async((n) => {
|
|
6919
7059
|
let r;
|
|
6920
7060
|
return rn(e, t).then((t) => {
|
|
6921
7061
|
r = t, console.log(`Serving ${e.length} function(s) on http://${t.host}:${t.port}`);
|
|
6922
7062
|
for (let e of t.routes) console.log(` ▸ ${e.name} ${e.method} http://${t.host}:${t.port}${e.path}`);
|
|
6923
7063
|
console.log(" (Ctrl-C to stop)");
|
|
6924
7064
|
}).catch((e) => n(E.fail(e instanceof Error ? e : Error(String(e))))), E.promise(() => r ? r.close() : Promise.resolve());
|
|
6925
|
-
}),
|
|
7065
|
+
}), jd = (e) => JSON.stringify(e), Md = (e, t) => {
|
|
6926
7066
|
let n = [
|
|
6927
|
-
`name = ${
|
|
6928
|
-
`main = ${
|
|
6929
|
-
`compatibility_date = ${
|
|
7067
|
+
`name = ${jd(e.name)}`,
|
|
7068
|
+
`main = ${jd(x(e.file))}`,
|
|
7069
|
+
`compatibility_date = ${jd(t.compatibilityDate ?? "2024-09-23")}`
|
|
6930
7070
|
];
|
|
6931
7071
|
t.nodeCompat && n.push("compatibility_flags = [\"nodejs_compat\"]"), n.push(`workers_dev = ${t.workersDev === !1 ? "false" : "true"}`);
|
|
6932
7072
|
let r = t.vars ?? {}, i = Object.keys(r);
|
|
6933
7073
|
if (i.length > 0) {
|
|
6934
7074
|
n.push("", "[vars]");
|
|
6935
|
-
for (let e of i) n.push(`${e} = ${
|
|
7075
|
+
for (let e of i) n.push(`${e} = ${jd(r[e])}`);
|
|
6936
7076
|
}
|
|
6937
7077
|
return n.join("\n") + "\n";
|
|
6938
|
-
},
|
|
7078
|
+
}, Nd = /https:\/\/[^\s'"()<>]+workers\.dev[^\s'"()<>]*/, Pd = (e) => ({
|
|
6939
7079
|
...an,
|
|
6940
7080
|
deploy: (t, n) => E.gen(function* () {
|
|
6941
7081
|
let r = n.options ?? {}, i = C(t.dir, "wrangler.toml");
|
|
6942
7082
|
yield* E.tryPromise({
|
|
6943
|
-
try: () => Ye(i,
|
|
7083
|
+
try: () => Ye(i, Md(t, r), "utf8"),
|
|
6944
7084
|
catch: (e) => new L({
|
|
6945
7085
|
target: "cloudflare",
|
|
6946
7086
|
message: `failed to write wrangler.toml: ${String(e)}`
|
|
@@ -6979,17 +7119,17 @@ replicas = 1
|
|
|
6979
7119
|
target: "cloudflare",
|
|
6980
7120
|
message: `wrangler deploy failed (exit ${e.exitCode})`,
|
|
6981
7121
|
detail: e.stderr
|
|
6982
|
-
}))), l =
|
|
7122
|
+
}))), l = Nd.exec(c.stdout)?.[0];
|
|
6983
7123
|
return {
|
|
6984
7124
|
target: "cloudflare",
|
|
6985
7125
|
name: t.name,
|
|
6986
7126
|
...l ? { url: l } : {}
|
|
6987
7127
|
};
|
|
6988
7128
|
})
|
|
6989
|
-
}),
|
|
6990
|
-
let n = [`handler=${
|
|
7129
|
+
}), Fd = /https:\/\/[^\s'"()<>]+\.fnc\.[a-z0-9-]+\.scw\.cloud[^\s'"()<>]*/, Id = "handler.handle", Ld = (e, t) => {
|
|
7130
|
+
let n = [`handler=${Id}`, "http-option=enabled"], r = e.runtime;
|
|
6991
7131
|
return r?.memoryMb !== void 0 && n.push(`memory-limit=${r.memoryMb}`), r?.timeoutSeconds !== void 0 && n.push(`timeout=${r.timeoutSeconds}s`), r?.minScale !== void 0 && n.push(`min-scale=${r.minScale}`), r?.maxScale !== void 0 && n.push(`max-scale=${r.maxScale}`), t && n.push(`privacy=${t}`), n;
|
|
6992
|
-
},
|
|
7132
|
+
}, Rd = (e, t) => E.try({
|
|
6993
7133
|
try: () => {
|
|
6994
7134
|
let n = e.trim();
|
|
6995
7135
|
if (!n) return;
|
|
@@ -7001,14 +7141,14 @@ replicas = 1
|
|
|
7001
7141
|
message: "could not parse `scw function list` output",
|
|
7002
7142
|
detail: e instanceof Error ? e.message : String(e)
|
|
7003
7143
|
})
|
|
7004
|
-
}),
|
|
7144
|
+
}), zd = (e) => ({
|
|
7005
7145
|
...sn,
|
|
7006
7146
|
deploy: (t, n) => E.gen(function* () {
|
|
7007
7147
|
let r = n.options ?? {}, i = C(t.dir, "function.zip"), a = r.runtime ?? "node22", o = r.namespaceId;
|
|
7008
7148
|
if (n.dryRun) return yield* E.logInfo("dry-run: would deploy Scaleway Function", {
|
|
7009
7149
|
name: t.name,
|
|
7010
7150
|
zip: `zip -r -q ${i} . (cwd ${t.dir})`,
|
|
7011
|
-
ensure: `scw function function create|update name=${t.name} runtime=${a} ${
|
|
7151
|
+
ensure: `scw function function create|update name=${t.name} runtime=${a} ${Ld(t, r.privacy).join(" ")}`,
|
|
7012
7152
|
deploy: `scw function deploy name=${t.name} runtime=${a} zip-file=${i}${o ? ` namespace-id=${o}` : ""}`
|
|
7013
7153
|
}), {
|
|
7014
7154
|
target: "scaleway",
|
|
@@ -7037,7 +7177,7 @@ replicas = 1
|
|
|
7037
7177
|
i,
|
|
7038
7178
|
"."
|
|
7039
7179
|
], { cwd: t.dir }).pipe(E.mapError(s("zip")));
|
|
7040
|
-
let c = yield*
|
|
7180
|
+
let c = yield* Rd((yield* e.exec("scw", [
|
|
7041
7181
|
"function",
|
|
7042
7182
|
"function",
|
|
7043
7183
|
"list",
|
|
@@ -7052,7 +7192,7 @@ replicas = 1
|
|
|
7052
7192
|
"update",
|
|
7053
7193
|
c,
|
|
7054
7194
|
`runtime=${a}`,
|
|
7055
|
-
...
|
|
7195
|
+
...Ld(t, r.privacy)
|
|
7056
7196
|
], { env: n.env }).pipe(E.mapError(s("scw function update"))) : yield* e.exec("scw", [
|
|
7057
7197
|
"function",
|
|
7058
7198
|
"function",
|
|
@@ -7060,7 +7200,7 @@ replicas = 1
|
|
|
7060
7200
|
`namespace-id=${o}`,
|
|
7061
7201
|
`name=${t.name}`,
|
|
7062
7202
|
`runtime=${a}`,
|
|
7063
|
-
...
|
|
7203
|
+
...Ld(t, r.privacy)
|
|
7064
7204
|
], { env: n.env }).pipe(E.mapError(s("scw function create")));
|
|
7065
7205
|
let l = yield* e.exec("scw", [
|
|
7066
7206
|
"function",
|
|
@@ -7069,7 +7209,7 @@ replicas = 1
|
|
|
7069
7209
|
`namespace-id=${o}`,
|
|
7070
7210
|
`runtime=${a}`,
|
|
7071
7211
|
`zip-file=${i}`
|
|
7072
|
-
], { env: n.env }).pipe(E.mapError(s("scw function deploy"))), u =
|
|
7212
|
+
], { env: n.env }).pipe(E.mapError(s("scw function deploy"))), u = Fd.exec(l.stdout)?.[0];
|
|
7073
7213
|
return {
|
|
7074
7214
|
target: "scaleway",
|
|
7075
7215
|
name: t.name,
|
|
@@ -7077,14 +7217,14 @@ replicas = 1
|
|
|
7077
7217
|
...u ? { url: u } : {}
|
|
7078
7218
|
};
|
|
7079
7219
|
})
|
|
7080
|
-
}),
|
|
7220
|
+
}), Bd = (e, t) => `# AUTO-GENERATED by @voltro/serverless — self-hosted Node function image.
|
|
7081
7221
|
FROM node:22-slim
|
|
7082
7222
|
WORKDIR /app
|
|
7083
7223
|
COPY ${e} ./
|
|
7084
7224
|
ENV PORT=${t}
|
|
7085
7225
|
EXPOSE ${t}
|
|
7086
7226
|
CMD ["node", "${e}"]
|
|
7087
|
-
`,
|
|
7227
|
+
`, Vd = (e, t, n) => `# ${e} — self-hosted serverless function
|
|
7088
7228
|
|
|
7089
7229
|
Built by \`voltro serverless\`. This folder is a complete, runnable artifact — the
|
|
7090
7230
|
same handler that would run on Cloudflare/Scaleway, on your own infra.
|
|
@@ -7127,16 +7267,16 @@ ${e}.example.com {
|
|
|
7127
7267
|
|
|
7128
7268
|
To run ALL of a project's functions in ONE process instead of a per-function
|
|
7129
7269
|
image, use \`voltro serverless serve\` from the project root.
|
|
7130
|
-
`,
|
|
7270
|
+
`, Hd = (e, t) => E.tryPromise({
|
|
7131
7271
|
try: async () => {
|
|
7132
7272
|
let n = x(e.file);
|
|
7133
|
-
return await Ye(C(e.dir, "Dockerfile"),
|
|
7273
|
+
return await Ye(C(e.dir, "Dockerfile"), Bd(n, t), "utf8"), await Ye(C(e.dir, "README.md"), Vd(e.name, n, t), "utf8"), ["Dockerfile", "README.md"];
|
|
7134
7274
|
},
|
|
7135
7275
|
catch: (e) => new L({
|
|
7136
7276
|
target: "node",
|
|
7137
7277
|
message: `failed to write self-host kit: ${String(e)}`
|
|
7138
7278
|
})
|
|
7139
|
-
}),
|
|
7279
|
+
}), Ud = () => ({
|
|
7140
7280
|
...on,
|
|
7141
7281
|
deploy: (e, t) => E.gen(function* () {
|
|
7142
7282
|
let n = (t.options ?? {}).port ?? 8910, r = x(e.file), i = {
|
|
@@ -7148,23 +7288,23 @@ image, use \`voltro serverless serve\` from the project root.
|
|
|
7148
7288
|
return t.dryRun ? (yield* E.logInfo("dry-run: would emit self-hosted Node artifact + kit (Dockerfile, README)", i), {
|
|
7149
7289
|
target: "node",
|
|
7150
7290
|
name: e.name
|
|
7151
|
-
}) : (yield*
|
|
7291
|
+
}) : (yield* Hd(e, n), yield* E.logInfo("self-hosted Node artifact + kit ready", i), {
|
|
7152
7292
|
target: "node",
|
|
7153
7293
|
name: e.name,
|
|
7154
7294
|
url: `http://localhost:${n}`
|
|
7155
7295
|
});
|
|
7156
7296
|
})
|
|
7157
|
-
}),
|
|
7297
|
+
}), Wd = [
|
|
7158
7298
|
"node",
|
|
7159
7299
|
"cloudflare",
|
|
7160
7300
|
"scaleway"
|
|
7161
|
-
],
|
|
7301
|
+
], Gd = (e) => Wd.includes(e), Kd = (e, t) => {
|
|
7162
7302
|
switch (e) {
|
|
7163
|
-
case "node": return
|
|
7164
|
-
case "cloudflare": return
|
|
7165
|
-
case "scaleway": return
|
|
7303
|
+
case "node": return Ud();
|
|
7304
|
+
case "cloudflare": return Pd(t);
|
|
7305
|
+
case "scaleway": return zd(t);
|
|
7166
7306
|
}
|
|
7167
|
-
},
|
|
7307
|
+
}, qd = class extends Me.TaggedError("CommandError") {}, Jd = (e, t) => [e, ...t].join(" "), Yd = {
|
|
7168
7308
|
exec: (e, t, n) => E.async((r) => {
|
|
7169
7309
|
let i = rt(e, [...t], {
|
|
7170
7310
|
cwd: n?.cwd,
|
|
@@ -7182,8 +7322,8 @@ image, use \`voltro serverless serve\` from the project root.
|
|
|
7182
7322
|
a += String(e);
|
|
7183
7323
|
}), i.stderr?.on("data", (e) => {
|
|
7184
7324
|
o += String(e);
|
|
7185
|
-
}), i.on("error", (n) => r(E.fail(new
|
|
7186
|
-
command:
|
|
7325
|
+
}), i.on("error", (n) => r(E.fail(new qd({
|
|
7326
|
+
command: Jd(e, t),
|
|
7187
7327
|
exitCode: -1,
|
|
7188
7328
|
stderr: n.message
|
|
7189
7329
|
})))), i.on("close", (n) => {
|
|
@@ -7192,8 +7332,8 @@ image, use \`voltro serverless serve\` from the project root.
|
|
|
7192
7332
|
exitCode: i,
|
|
7193
7333
|
stdout: a,
|
|
7194
7334
|
stderr: o
|
|
7195
|
-
}) : E.fail(new
|
|
7196
|
-
command:
|
|
7335
|
+
}) : E.fail(new qd({
|
|
7336
|
+
command: Jd(e, t),
|
|
7197
7337
|
exitCode: i,
|
|
7198
7338
|
stderr: o || a
|
|
7199
7339
|
})));
|
|
@@ -7205,7 +7345,7 @@ image, use \`voltro serverless serve\` from the project root.
|
|
|
7205
7345
|
let n = rt(process.platform === "win32" ? "where" : "which", [e], { stdio: "ignore" });
|
|
7206
7346
|
n.on("error", () => t(E.succeed(!1))), n.on("close", (e) => t(E.succeed(e === 0)));
|
|
7207
7347
|
})
|
|
7208
|
-
}, Q = (e) => E.sync(() => console.log(e)),
|
|
7348
|
+
}, Q = (e) => E.sync(() => console.log(e)), Xd = (e, t) => {
|
|
7209
7349
|
let n = "node", r = C(t, ".voltro", "serverless"), i = !1, a = {}, o = [], s;
|
|
7210
7350
|
for (let c = 0; c < e.length; c++) {
|
|
7211
7351
|
let l = e[c];
|
|
@@ -7240,7 +7380,7 @@ image, use \`voltro serverless serve\` from the project root.
|
|
|
7240
7380
|
default: l.startsWith("-") ? s = `unknown flag '${l}'` : o.push(l);
|
|
7241
7381
|
}
|
|
7242
7382
|
}
|
|
7243
|
-
return
|
|
7383
|
+
return Gd(n) || (s = `unknown --target '${n}' (one of: ${Wd.join(", ")})`, n = "node"), {
|
|
7244
7384
|
target: n,
|
|
7245
7385
|
out: r,
|
|
7246
7386
|
dryRun: i,
|
|
@@ -7248,7 +7388,7 @@ image, use \`voltro serverless serve\` from the project root.
|
|
|
7248
7388
|
positional: o,
|
|
7249
7389
|
error: s
|
|
7250
7390
|
};
|
|
7251
|
-
},
|
|
7391
|
+
}, Zd = (e, t) => e.length > 0 ? E.succeed(e.map((e) => T(t, e))) : Hl(t), Qd = () => Q([
|
|
7252
7392
|
"voltro serverless <list|dev|serve|build|deploy> [options] [files…]",
|
|
7253
7393
|
"",
|
|
7254
7394
|
" list discover *.serverless.ts files",
|
|
@@ -7258,7 +7398,7 @@ image, use \`voltro serverless serve\` from the project root.
|
|
|
7258
7398
|
" deploy [--target <id>] ship: node → self-host artifact, cloudflare/scaleway → vendor",
|
|
7259
7399
|
"",
|
|
7260
7400
|
"Options:",
|
|
7261
|
-
` --target <id> ${
|
|
7401
|
+
` --target <id> ${Wd.join(" | ")} (default node)`,
|
|
7262
7402
|
" --out <dir> artifact dir (default .voltro/serverless)",
|
|
7263
7403
|
" --dry-run bundle, then print the deploy plan",
|
|
7264
7404
|
" --port <n> dev/serve: listen port (default 8910)",
|
|
@@ -7268,7 +7408,7 @@ image, use \`voltro serverless serve\` from the project root.
|
|
|
7268
7408
|
" --node-compat Cloudflare: add nodejs_compat flag",
|
|
7269
7409
|
" --compat-date <date> Cloudflare: compatibility_date",
|
|
7270
7410
|
" --runtime <r> Scaleway: node20 | node22"
|
|
7271
|
-
].join("\n")).pipe(E.as(0)),
|
|
7411
|
+
].join("\n")).pipe(E.as(0)), $d = (e) => {
|
|
7272
7412
|
let t = 8910, n, r = [], i;
|
|
7273
7413
|
for (let a = 0; a < e.length; a++) {
|
|
7274
7414
|
let o = e[a];
|
|
@@ -7280,13 +7420,13 @@ image, use \`voltro serverless serve\` from the project root.
|
|
|
7280
7420
|
files: r,
|
|
7281
7421
|
error: i
|
|
7282
7422
|
};
|
|
7283
|
-
},
|
|
7284
|
-
let { port: r, host: i, files: a, error: o } =
|
|
7423
|
+
}, ef = (e, t, n) => E.gen(function* () {
|
|
7424
|
+
let { port: r, host: i, files: a, error: o } = $d(e);
|
|
7285
7425
|
if (o) return yield* Q(`voltro serverless ${n.label}: ${o}`), 2;
|
|
7286
7426
|
let s = a.length > 0 ? a.map((e) => T(t, e)) : yield* Hl(t);
|
|
7287
7427
|
if (s.length === 0) return yield* Q("No *.serverless.ts function found."), 0;
|
|
7288
7428
|
if (n.single && s.length > 1) return yield* Q(`voltro serverless dev: multiple functions found — name one (or use \`serve\`):\n${s.map((e) => ` ${w(t, e)}`).join("\n")}`), 2;
|
|
7289
|
-
let c = yield* E.forEach(s, (e) =>
|
|
7429
|
+
let c = yield* E.forEach(s, (e) => Dd(e).pipe(E.map((e) => ({
|
|
7290
7430
|
ok: !0,
|
|
7291
7431
|
d: e
|
|
7292
7432
|
})), E.catchAll((e) => E.succeed({
|
|
@@ -7297,36 +7437,36 @@ image, use \`voltro serverless serve\` from the project root.
|
|
|
7297
7437
|
let u = c.flatMap((e) => e.ok ? [e.d] : []);
|
|
7298
7438
|
if (u.length === 0) return 1;
|
|
7299
7439
|
let d = i ?? n.defaultHost;
|
|
7300
|
-
return yield*
|
|
7440
|
+
return yield* Ad(u, {
|
|
7301
7441
|
port: r,
|
|
7302
7442
|
...d ? { host: d } : {}
|
|
7303
7443
|
}).pipe(E.catchAll((e) => E.as(Q(`server error: ${e.message}`), void 0))), 0;
|
|
7304
|
-
}),
|
|
7444
|
+
}), tf = (e) => E.gen(function* () {
|
|
7305
7445
|
let [t, ...n] = e, r = process.cwd();
|
|
7306
|
-
if (t === void 0 || t === "help" || t === "--help" || t === "-h") return yield*
|
|
7307
|
-
if (t === "dev") return yield*
|
|
7446
|
+
if (t === void 0 || t === "help" || t === "--help" || t === "-h") return yield* Qd();
|
|
7447
|
+
if (t === "dev") return yield* ef(n, r, {
|
|
7308
7448
|
single: !0,
|
|
7309
7449
|
defaultHost: "127.0.0.1",
|
|
7310
7450
|
label: "dev"
|
|
7311
7451
|
});
|
|
7312
|
-
if (t === "serve") return yield*
|
|
7452
|
+
if (t === "serve") return yield* ef(n, r, {
|
|
7313
7453
|
single: !1,
|
|
7314
7454
|
defaultHost: "0.0.0.0",
|
|
7315
7455
|
label: "serve"
|
|
7316
7456
|
});
|
|
7317
7457
|
if (t !== "list" && t !== "build" && t !== "deploy") return yield* Q(`voltro serverless: unknown subcommand '${t}'`), 2;
|
|
7318
|
-
let i =
|
|
7458
|
+
let i = Xd(n, r);
|
|
7319
7459
|
if (i.error) return yield* Q(`voltro serverless: ${i.error}`), 2;
|
|
7320
|
-
let a = yield*
|
|
7460
|
+
let a = yield* Zd(i.positional, r);
|
|
7321
7461
|
if (a.length === 0) return yield* Q("No *.serverless.ts functions found."), 0;
|
|
7322
7462
|
if (t === "list") {
|
|
7323
7463
|
yield* Q(`Found ${a.length} serverless function(s):`);
|
|
7324
7464
|
for (let e of a) yield* Q(` ${w(r, e)}`);
|
|
7325
7465
|
return 0;
|
|
7326
7466
|
}
|
|
7327
|
-
let o =
|
|
7467
|
+
let o = Yd, s = Kd(i.target, o), c = C(i.out, s.id), l = 0;
|
|
7328
7468
|
for (let e of a) {
|
|
7329
|
-
let n = yield*
|
|
7469
|
+
let n = yield* kd({
|
|
7330
7470
|
platform: s,
|
|
7331
7471
|
sourceFile: e,
|
|
7332
7472
|
outDir: c
|
|
@@ -7344,7 +7484,7 @@ image, use \`voltro serverless serve\` from the project root.
|
|
|
7344
7484
|
if (t === "build") {
|
|
7345
7485
|
if (s.id === "node") {
|
|
7346
7486
|
let e = typeof i.options.port == "number" ? i.options.port : 8910;
|
|
7347
|
-
yield*
|
|
7487
|
+
yield* Hd(n.b, e).pipe(E.catchAll(() => E.void));
|
|
7348
7488
|
}
|
|
7349
7489
|
yield* Q(` ✓ bundled ${n.b.name} → ${w(r, n.b.file)} [${s.id}]`);
|
|
7350
7490
|
continue;
|
|
@@ -7368,25 +7508,25 @@ image, use \`voltro serverless serve\` from the project root.
|
|
|
7368
7508
|
yield* Q(` ✓ ${t === "deploy" ? "deployed" : "built"} ${n.b.name} [${s.id}]${u}`);
|
|
7369
7509
|
}
|
|
7370
7510
|
return +(l > 0);
|
|
7371
|
-
}),
|
|
7511
|
+
}), nf = (e) => i(tf(e), { scope: "voltro:serverless" }), rf = async (e) => {
|
|
7372
7512
|
try {
|
|
7373
7513
|
return await We(e), !0;
|
|
7374
7514
|
} catch {
|
|
7375
7515
|
return !1;
|
|
7376
7516
|
}
|
|
7377
|
-
},
|
|
7517
|
+
}, af = "# AUTO-GENERATED by @voltro/cli — hashed assets are immutable for a year.\n/assets/*\n Cache-Control: public, max-age=31536000, immutable\n", of = "# AUTO-GENERATED by @voltro/cli — single-page-app fallback.\n/* /index.html 200\n", sf = (e, t) => E.promise(async () => {
|
|
7378
7518
|
let n = [], r = C(e, "_headers");
|
|
7379
|
-
if (await
|
|
7519
|
+
if (await rf(r) || (await Ye(r, af, "utf8"), n.push("_headers")), t) {
|
|
7380
7520
|
let t = C(e, "_redirects");
|
|
7381
|
-
await
|
|
7521
|
+
await rf(t) || (await Ye(t, of, "utf8"), n.push("_redirects"));
|
|
7382
7522
|
}
|
|
7383
7523
|
return n;
|
|
7384
|
-
}),
|
|
7524
|
+
}), cf = /https:\/\/[^\s'"()<>]+\.pages\.dev[^\s'"()<>]*/, lf = (e) => ({
|
|
7385
7525
|
id: "cloudflare-pages",
|
|
7386
7526
|
label: "Cloudflare Pages",
|
|
7387
7527
|
deploy: (t, n) => E.gen(function* () {
|
|
7388
7528
|
let r = n.options ?? {};
|
|
7389
|
-
yield*
|
|
7529
|
+
yield* sf(t, n.spaFallback ?? !1);
|
|
7390
7530
|
let i = [
|
|
7391
7531
|
"pages",
|
|
7392
7532
|
"deploy",
|
|
@@ -7419,7 +7559,7 @@ image, use \`voltro serverless serve\` from the project root.
|
|
|
7419
7559
|
host: "cloudflare-pages",
|
|
7420
7560
|
message: `wrangler pages deploy failed (exit ${e.exitCode})`,
|
|
7421
7561
|
detail: e.stderr
|
|
7422
|
-
}))), c =
|
|
7562
|
+
}))), c = cf.exec(s.stdout)?.[0];
|
|
7423
7563
|
return {
|
|
7424
7564
|
host: "cloudflare-pages",
|
|
7425
7565
|
filesUploaded: 0,
|
|
@@ -7427,7 +7567,7 @@ image, use \`voltro serverless serve\` from the project root.
|
|
|
7427
7567
|
...c ? { url: c } : {}
|
|
7428
7568
|
};
|
|
7429
7569
|
})
|
|
7430
|
-
}),
|
|
7570
|
+
}), uf = (e) => (e.match(/^upload:/gm) ?? []).length, df = (e) => ({
|
|
7431
7571
|
id: "s3",
|
|
7432
7572
|
label: "S3-compatible bucket (aws s3 sync)",
|
|
7433
7573
|
deploy: (t, n) => E.gen(function* () {
|
|
@@ -7484,24 +7624,24 @@ image, use \`voltro serverless serve\` from the project root.
|
|
|
7484
7624
|
}))), u = yield* l(s, "aws s3 sync (assets)"), d = yield* l(c, "aws s3 sync (html)");
|
|
7485
7625
|
return {
|
|
7486
7626
|
host: "s3",
|
|
7487
|
-
filesUploaded:
|
|
7627
|
+
filesUploaded: uf(u.stdout) + uf(d.stdout),
|
|
7488
7628
|
filesSkipped: 0,
|
|
7489
7629
|
...r.websiteUrl ? { url: r.websiteUrl } : {}
|
|
7490
7630
|
};
|
|
7491
7631
|
})
|
|
7492
|
-
}),
|
|
7632
|
+
}), ff = (e) => {
|
|
7493
7633
|
try {
|
|
7494
7634
|
let t = JSON.parse(e);
|
|
7495
7635
|
return t.ssl_url ?? t.url ?? t.deploy_url;
|
|
7496
7636
|
} catch {
|
|
7497
7637
|
return;
|
|
7498
7638
|
}
|
|
7499
|
-
},
|
|
7639
|
+
}, pf = (e) => ({
|
|
7500
7640
|
id: "netlify",
|
|
7501
7641
|
label: "Netlify",
|
|
7502
7642
|
deploy: (t, n) => E.gen(function* () {
|
|
7503
7643
|
let r = n.options ?? {};
|
|
7504
|
-
yield*
|
|
7644
|
+
yield* sf(t, n.spaFallback ?? !1);
|
|
7505
7645
|
let i = [
|
|
7506
7646
|
"deploy",
|
|
7507
7647
|
"--dir",
|
|
@@ -7524,7 +7664,7 @@ image, use \`voltro serverless serve\` from the project root.
|
|
|
7524
7664
|
host: "netlify",
|
|
7525
7665
|
message: "`netlify` CLI not found on PATH (install: npm i -g netlify-cli)"
|
|
7526
7666
|
}));
|
|
7527
|
-
let a =
|
|
7667
|
+
let a = ff((yield* e.exec("netlify", i, { env: n.env }).pipe(E.mapError((e) => new R({
|
|
7528
7668
|
host: "netlify",
|
|
7529
7669
|
message: `netlify deploy failed (exit ${e.exitCode})`,
|
|
7530
7670
|
detail: e.stderr
|
|
@@ -7536,17 +7676,17 @@ image, use \`voltro serverless serve\` from the project root.
|
|
|
7536
7676
|
...a ? { url: a } : {}
|
|
7537
7677
|
};
|
|
7538
7678
|
})
|
|
7539
|
-
}),
|
|
7679
|
+
}), mf = [
|
|
7540
7680
|
"cloudflare-pages",
|
|
7541
7681
|
"s3",
|
|
7542
7682
|
"netlify"
|
|
7543
|
-
],
|
|
7683
|
+
], hf = (e) => mf.includes(e), gf = (e, t) => {
|
|
7544
7684
|
switch (e) {
|
|
7545
|
-
case "cloudflare-pages": return
|
|
7546
|
-
case "s3": return
|
|
7547
|
-
case "netlify": return
|
|
7685
|
+
case "cloudflare-pages": return lf(t);
|
|
7686
|
+
case "s3": return df(t);
|
|
7687
|
+
case "netlify": return pf(t);
|
|
7548
7688
|
}
|
|
7549
|
-
}, $ = (e) => E.sync(() => console.log(e)),
|
|
7689
|
+
}, $ = (e) => E.sync(() => console.log(e)), _f = (e) => E.promise(() => We(e).then(() => !0, () => !1)), vf = (e, t) => {
|
|
7550
7690
|
let n = "", r = T(t, "dist"), i = t, a = !1, o = !1, s = !1, c = {}, l;
|
|
7551
7691
|
for (let u = 0; u < e.length; u++) {
|
|
7552
7692
|
let d = e[u];
|
|
@@ -7600,7 +7740,7 @@ image, use \`voltro serverless serve\` from the project root.
|
|
|
7600
7740
|
options: c,
|
|
7601
7741
|
error: l
|
|
7602
7742
|
};
|
|
7603
|
-
},
|
|
7743
|
+
}, yf = (e, t) => E.gen(function* () {
|
|
7604
7744
|
return (yield* E.promise(() => Ke(C(e, ".voltro-build.json"), "utf8").then((e) => {
|
|
7605
7745
|
try {
|
|
7606
7746
|
let t = JSON.parse(e).profile;
|
|
@@ -7609,14 +7749,14 @@ image, use \`voltro serverless serve\` from the project root.
|
|
|
7609
7749
|
return;
|
|
7610
7750
|
}
|
|
7611
7751
|
}, () => void 0))) ?? (yield* Mn(t));
|
|
7612
|
-
}),
|
|
7752
|
+
}), bf = () => $([
|
|
7613
7753
|
"voltro static <hosts|deploy> [options]",
|
|
7614
7754
|
"",
|
|
7615
7755
|
" hosts list supported static hosts",
|
|
7616
7756
|
" deploy --host <id> deploy ./dist to a host",
|
|
7617
7757
|
"",
|
|
7618
7758
|
"Options:",
|
|
7619
|
-
` --host <id> ${
|
|
7759
|
+
` --host <id> ${mf.join(" | ")}`,
|
|
7620
7760
|
" --dir <dir> static dir to deploy (default dist)",
|
|
7621
7761
|
" --app <dir> web app source root for the render-mode gate (default cwd)",
|
|
7622
7762
|
" --allow-dynamic deploy even with ssr/isr pages (they become client-rendered)",
|
|
@@ -7628,25 +7768,25 @@ image, use \`voltro serverless serve\` from the project root.
|
|
|
7628
7768
|
" --branch <name> cloudflare-pages: branch",
|
|
7629
7769
|
" --site-id <id> netlify: site",
|
|
7630
7770
|
" --website-url <url> s3: public URL to report"
|
|
7631
|
-
].join("\n")).pipe(E.as(0)),
|
|
7771
|
+
].join("\n")).pipe(E.as(0)), xf = (e) => E.gen(function* () {
|
|
7632
7772
|
let [t, ...n] = e, r = process.cwd();
|
|
7633
|
-
if (t === void 0 || t === "help" || t === "--help" || t === "-h") return yield*
|
|
7773
|
+
if (t === void 0 || t === "help" || t === "--help" || t === "-h") return yield* bf();
|
|
7634
7774
|
if (t === "hosts") {
|
|
7635
7775
|
yield* $("Supported static hosts:");
|
|
7636
|
-
for (let e of
|
|
7776
|
+
for (let e of mf) yield* $(` ${e}`);
|
|
7637
7777
|
return 0;
|
|
7638
7778
|
}
|
|
7639
7779
|
if (t !== "deploy") return yield* $(`voltro static: unknown subcommand '${t}'`), 2;
|
|
7640
|
-
let i =
|
|
7780
|
+
let i = vf(n, r);
|
|
7641
7781
|
if (i.error) return yield* $(`voltro static: ${i.error}`), 2;
|
|
7642
|
-
if (!
|
|
7643
|
-
if (!(yield*
|
|
7644
|
-
let a = yield*
|
|
7782
|
+
if (!hf(i.host)) return yield* $(`voltro static deploy: --host must be one of ${mf.join(", ")}`), 2;
|
|
7783
|
+
if (!(yield* _f(i.dir))) return yield* $(`voltro static deploy: directory not found: ${i.dir} (run \`voltro build\` first?)`), 1;
|
|
7784
|
+
let a = yield* yf(i.dir, i.app);
|
|
7645
7785
|
if (!a.staticSafe) {
|
|
7646
7786
|
if (!i.allowDynamic) return yield* $(`voltro static deploy: "${w(process.cwd(), i.app) || "."}" is NOT pure-static —`), a.counts.ssr > 0 && (yield* $(` • ${a.counts.ssr} ssr page(s): need a runtime; a CDN can't render them`)), a.counts.isr > 0 && (yield* $(` • ${a.counts.isr} isr page(s): need a runtime for revalidation`)), a.dynamicMissing.length > 0 && (yield* $(` • ${a.dynamicMissing.length} dynamic route(s) without getStaticPaths → no artifact built (missing on a CDN): ${a.dynamicMissing.join(", ")}`)), yield* $(" → Serve those on a runtime (`voltro start` / a container), OR add getStaticPaths /"), yield* $(" set the pages to `static` / `spa`. To ship anyway (ssr/isr become client-rendered), pass --allow-dynamic."), 2;
|
|
7647
7787
|
yield* $(" ⚠ --allow-dynamic: ssr/isr pages will be client-rendered only (no server first-paint).");
|
|
7648
7788
|
}
|
|
7649
|
-
let o =
|
|
7789
|
+
let o = gf(i.host, Yd), s = {
|
|
7650
7790
|
env: process.env,
|
|
7651
7791
|
options: i.options,
|
|
7652
7792
|
spaFallback: i.spaFallback,
|
|
@@ -7661,7 +7801,7 @@ image, use \`voltro serverless serve\` from the project root.
|
|
|
7661
7801
|
if (!c.ok) return yield* $(` ✗ ${o.label}: ${c.message}`), 1;
|
|
7662
7802
|
let l = c.r.url ? ` → ${c.r.url}` : i.dryRun ? " (dry-run)" : "", u = i.dryRun ? "" : ` (${c.r.filesUploaded} uploaded)`;
|
|
7663
7803
|
return yield* $(` ✓ deployed ${i.dir} to ${o.label}${u}${l}`), 0;
|
|
7664
|
-
}),
|
|
7804
|
+
}), Sf = [
|
|
7665
7805
|
{
|
|
7666
7806
|
name: "list-templates",
|
|
7667
7807
|
summary: "List available app templates (kind, summary, tags).",
|
|
@@ -7732,7 +7872,7 @@ image, use \`voltro serverless serve\` from the project root.
|
|
|
7732
7872
|
name: "test",
|
|
7733
7873
|
summary: "Run vitest against the app at the cwd (auto-discovers *.test.ts/tsx).",
|
|
7734
7874
|
status: "wired",
|
|
7735
|
-
run:
|
|
7875
|
+
run: Cd
|
|
7736
7876
|
},
|
|
7737
7877
|
{
|
|
7738
7878
|
name: "cache",
|
|
@@ -7759,7 +7899,7 @@ image, use \`voltro serverless serve\` from the project root.
|
|
|
7759
7899
|
run: async (e) => {
|
|
7760
7900
|
let t = e.find((e) => !e.startsWith("-")) ?? process.cwd();
|
|
7761
7901
|
if (e.includes("--preflight")) return Or(T(t), !0);
|
|
7762
|
-
let n = await
|
|
7902
|
+
let n = await m(T(t));
|
|
7763
7903
|
return n.ran ? n.exitCode : Ee(e);
|
|
7764
7904
|
}
|
|
7765
7905
|
},
|
|
@@ -7809,13 +7949,13 @@ image, use \`voltro serverless serve\` from the project root.
|
|
|
7809
7949
|
name: "serverless",
|
|
7810
7950
|
summary: "Bundle + deploy standalone *.serverless.ts functions to a function host. Subcommands: list, build, deploy [--target cloudflare|scaleway] [--dry-run].",
|
|
7811
7951
|
status: "wired",
|
|
7812
|
-
run:
|
|
7952
|
+
run: nf
|
|
7813
7953
|
},
|
|
7814
7954
|
{
|
|
7815
7955
|
name: "static",
|
|
7816
7956
|
summary: "Deploy a pre-built static site (./dist) to a cheap external host. Subcommands: hosts, deploy --host cloudflare-pages|s3|netlify [--spa] [--dry-run].",
|
|
7817
7957
|
status: "wired",
|
|
7818
|
-
run: (e) =>
|
|
7958
|
+
run: (e) => i(xf(e), { scope: "voltro:static" })
|
|
7819
7959
|
},
|
|
7820
7960
|
{
|
|
7821
7961
|
name: "db",
|
|
@@ -7857,14 +7997,14 @@ image, use \`voltro serverless serve\` from the project root.
|
|
|
7857
7997
|
name: "update",
|
|
7858
7998
|
summary: "Upgrade the app to the latest framework: bump every @voltro/* dependency (across ALL workspace members, install once at the workspace root), then run the codemods shipped with the target version. Flags: --to <version>, --from <version>, --codemods-only, --dry-run, --force, --exact, --help. After: run `voltro db apply`.",
|
|
7859
7999
|
status: "wired",
|
|
7860
|
-
run:
|
|
8000
|
+
run: yd
|
|
7861
8001
|
},
|
|
7862
8002
|
{
|
|
7863
8003
|
name: "_apply-codemods",
|
|
7864
8004
|
summary: "Internal: apply shipped codemods for a framework version jump (re-exec target of `voltro update`).",
|
|
7865
8005
|
status: "wired",
|
|
7866
8006
|
hidden: !0,
|
|
7867
|
-
run:
|
|
8007
|
+
run: xd
|
|
7868
8008
|
},
|
|
7869
8009
|
{
|
|
7870
8010
|
name: "embeddings",
|
|
@@ -7882,7 +8022,7 @@ image, use \`voltro serverless serve\` from the project root.
|
|
|
7882
8022
|
name: "agents-md",
|
|
7883
8023
|
summary: "Write the framework-tailored AGENTS.md into the project root (use --force to overwrite).",
|
|
7884
8024
|
status: "wired",
|
|
7885
|
-
run:
|
|
8025
|
+
run: y
|
|
7886
8026
|
},
|
|
7887
8027
|
{
|
|
7888
8028
|
name: "schedule-manifest",
|
|
@@ -7936,7 +8076,7 @@ image, use \`voltro serverless serve\` from the project root.
|
|
|
7936
8076
|
name: "help",
|
|
7937
8077
|
summary: "Print this help.",
|
|
7938
8078
|
status: "wired",
|
|
7939
|
-
run: async (e) => (
|
|
8079
|
+
run: async (e) => (Cf(), 0)
|
|
7940
8080
|
},
|
|
7941
8081
|
{
|
|
7942
8082
|
name: "version",
|
|
@@ -7944,18 +8084,18 @@ image, use \`voltro serverless serve\` from the project root.
|
|
|
7944
8084
|
status: "wired",
|
|
7945
8085
|
run: async () => (console.log("framework cli v0.0.0 (scaffold)"), 0)
|
|
7946
8086
|
}
|
|
7947
|
-
],
|
|
7948
|
-
let e =
|
|
8087
|
+
], Cf = () => {
|
|
8088
|
+
let e = Sf.filter((e) => !e.hidden), t = e.reduce((e, t) => Math.max(e, t.name.length), 0);
|
|
7949
8089
|
console.log("framework <command> [args]"), console.log(), console.log("Commands:");
|
|
7950
8090
|
for (let n of e) {
|
|
7951
8091
|
let e = " ".repeat(t - n.name.length + 2);
|
|
7952
8092
|
console.log(` ${n.name}${e}${n.summary}`);
|
|
7953
8093
|
}
|
|
7954
|
-
},
|
|
8094
|
+
}, wf = async (e) => {
|
|
7955
8095
|
let [t, ...n] = e;
|
|
7956
|
-
if (!t) return
|
|
7957
|
-
let r =
|
|
8096
|
+
if (!t) return Cf(), 0;
|
|
8097
|
+
let r = Sf.find((e) => e.name === t);
|
|
7958
8098
|
return r ? r.run(n) : (console.error(`framework: unknown command '${t}'`), console.error("run 'voltro help' for available commands"), 2);
|
|
7959
8099
|
};
|
|
7960
8100
|
//#endregion
|
|
7961
|
-
export { Ka as i,
|
|
8101
|
+
export { Ka as i, wf as n, Cf as r, Sf as t };
|