@voltro/cli 0.12.0 → 0.13.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 +93 -0
- package/dist/{apiBuild-GefjNI5d.js → apiBuild-B6_ehbem.js} +3 -3
- package/dist/apiBuild-Bzpb383i.js +2 -0
- package/dist/bin.js +3 -3
- package/dist/{commands-BmNi1RgZ.js → commands-DYOuGlEC.js} +1668 -1371
- package/dist/dbCommand-ADD4mrTI.js +2 -0
- package/dist/{dbCommand-DNrkb58g.js → dbCommand-DIOJQwsq.js} +71 -57
- package/dist/{dev-d0LjACxE.js → dev-Fb9BmavX.js} +1483 -1414
- package/dist/dev-xdijqojc.js +3 -0
- package/dist/{seedRunner-DZmhoqNt.js → frameworkTableAssembly-CYlrafoK.js} +110 -331
- package/dist/frameworkTableAssembly-XvKO7wQt.js +2 -0
- package/dist/index.js +1 -1
- package/dist/{inspectMetrics-uEfIS1vp.js → inspectMetrics-DOiiII34.js} +302 -293
- package/dist/seedRunner-D6eu-u5U.js +229 -0
- package/dist/{serveCommand-B2-YV9TU.js → serveCommand-CqYxzBZR.js} +368 -367
- package/dist/serveEntry.js +3 -3
- package/dist/{start-DKcQd52a.js → start-CjG_0xhR.js} +1 -1
- package/dist/startEntry.js +2 -2
- package/package.json +17 -17
- package/templates/AGENTS.md +1 -1
- package/templates/agent-docs/_index.md +1 -1
- package/templates/agent-docs/authentication.md +36 -0
- package/templates/agent-docs/cli.md +78 -4
- package/templates/agent-docs/configuration.md +48 -0
- package/templates/agent-docs/database/migrations.md +32 -0
- package/templates/agent-docs/database/transactions.md +31 -0
- package/templates/agent-docs/testing.md +24 -0
- package/templates/agent-docs/whats-new.md +41 -137
- 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-deactivation/tests/users.deactivate.test.ts +1 -1
- 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-data-advanced/tests/queries.test.ts +6 -1
- package/templates/apps/api-durable/package.json +8 -8
- package/templates/apps/api-feature-flags/package.json +9 -9
- package/templates/apps/api-governance/app.config.ts +0 -1
- package/templates/apps/api-governance/package.json +8 -8
- package/templates/apps/api-kv/package.json +8 -8
- package/templates/apps/api-kv/tests/sync.test.ts +2 -2
- 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/README.md +53 -14
- package/templates/apps/api-rbac/app.config.ts +24 -26
- package/templates/apps/api-rbac/authz.ts +76 -0
- package/templates/apps/api-rbac/database/schema.ts +23 -6
- package/templates/apps/api-rbac/mutations/notes.create.mutation.server.ts +7 -5
- package/templates/apps/api-rbac/mutations/notes.create.mutation.ts +15 -8
- package/templates/apps/api-rbac/mutations/notes.delete.mutation.server.ts +54 -0
- package/templates/apps/api-rbac/mutations/notes.delete.mutation.ts +43 -0
- package/templates/apps/api-rbac/mutations/teams.rename.mutation.server.ts +19 -0
- package/templates/apps/api-rbac/mutations/teams.rename.mutation.ts +37 -0
- package/templates/apps/api-rbac/package.json +8 -8
- package/templates/apps/api-rbac/queries/notes.list.query.server.ts +12 -0
- package/templates/apps/api-rbac/queries/notes.list.query.ts +26 -0
- package/templates/apps/api-rbac/template.json +2 -2
- package/templates/apps/api-rbac/tests/authz.test.ts +233 -0
- 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 +9 -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-s7swuEU5.js +0 -2
- package/dist/dbCommand-Bt6BCG7g.js +0 -2
- package/dist/dev-YHbHmeXt.js +0 -3
- package/templates/apps/api-rbac/tests/notes.create.test.ts +0 -80
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { i as e, n as t, r as n, s as r, t as i } from "./seedRunner-D6eu-u5U.js";
|
|
2
|
+
import { t as a, u as o } from "./frameworkTableAssembly-CYlrafoK.js";
|
|
2
3
|
import { a as s, n as c, t as l } from "./cliArgs-qdZSElM3.js";
|
|
3
4
|
import { basename as u, join as d, relative as f, resolve as p } from "node:path";
|
|
4
5
|
import { pathToFileURL as m } from "node:url";
|
|
@@ -321,7 +322,7 @@ var k = class extends Error {
|
|
|
321
322
|
let e = (process.env.DB_DIALECT ?? "postgres").toLowerCase();
|
|
322
323
|
if (e === "memory") throw new k("voltro db: subcommands require a real dialect, not DB_DIALECT=memory.");
|
|
323
324
|
return e;
|
|
324
|
-
}, W = async () => (await
|
|
325
|
+
}, W = async () => (await r(U())).makeSqlLayer(B()), fe = async (e) => {
|
|
325
326
|
let t = z(e), n = e.includes("--dry-run"), r = await j(await R(t, A), L);
|
|
326
327
|
if (r.length === 0) return L.info("no migrations found", { root: t }), 0;
|
|
327
328
|
if (n) {
|
|
@@ -357,17 +358,17 @@ var k = class extends Error {
|
|
|
357
358
|
console.log(` ${t} ${e.id} [${e.status}] ${e.name}${r}${n}`);
|
|
358
359
|
}
|
|
359
360
|
return 0;
|
|
360
|
-
}, he = async (
|
|
361
|
-
let
|
|
362
|
-
if (
|
|
361
|
+
}, he = async (e) => {
|
|
362
|
+
let t = (c(e, "--store") ?? process.env.DB_DIALECT ?? "postgres").toLowerCase();
|
|
363
|
+
if (t === "memory") return L.warn("voltro db seed: using in-memory store (explicit opt-in via --store memory / DB_DIALECT=memory)"), L.warn(" rows written by this run will NOT persist beyond the process. set DB_DIALECT=postgres or unset to seed the real DB."), {
|
|
363
364
|
store: new ne(),
|
|
364
365
|
dispose: async () => {},
|
|
365
366
|
dialectId: "memory"
|
|
366
367
|
};
|
|
367
|
-
let
|
|
368
|
-
L.info(`voltro db seed: target store=${
|
|
369
|
-
let i = await
|
|
370
|
-
sqlLayer:
|
|
368
|
+
let n = await r(t);
|
|
369
|
+
L.info(`voltro db seed: target store=${n.id} — rows will persist`);
|
|
370
|
+
let i = await n.makeStore({
|
|
371
|
+
sqlLayer: n.makeSqlLayer(B()),
|
|
371
372
|
changeStrategy: "inline"
|
|
372
373
|
}), a = i;
|
|
373
374
|
return {
|
|
@@ -375,14 +376,14 @@ var k = class extends Error {
|
|
|
375
376
|
dispose: async () => {
|
|
376
377
|
typeof a.close == "function" && await a.close(5e3);
|
|
377
378
|
},
|
|
378
|
-
dialectId:
|
|
379
|
+
dialectId: n.id
|
|
379
380
|
};
|
|
380
|
-
}, ge = async (
|
|
381
|
-
let
|
|
382
|
-
if (l.length === 0) return L.info("no seeds found", { root:
|
|
383
|
-
let { store: u, dispose: d, dialectId: f } = await he(
|
|
381
|
+
}, ge = async (r) => {
|
|
382
|
+
let a = z(r), o = c(r, "--id"), s = c(r, "--lifecycle"), l = await t(await R(a, i), L);
|
|
383
|
+
if (l.length === 0) return L.info("no seeds found", { root: a }), 0;
|
|
384
|
+
let { store: u, dispose: d, dialectId: f } = await he(r);
|
|
384
385
|
try {
|
|
385
|
-
return
|
|
386
|
+
return o ? +((await e(l, o, u, L)).status === "failed") : +((await n((s ? l.filter((e) => e.definition.lifecycle === s) : l.filter((e) => e.definition.lifecycle === "boot")).map((e) => ({
|
|
386
387
|
...e,
|
|
387
388
|
definition: {
|
|
388
389
|
...e.definition,
|
|
@@ -395,7 +396,7 @@ var k = class extends Error {
|
|
|
395
396
|
});
|
|
396
397
|
}
|
|
397
398
|
}, _e = (e) => typeof e == "object" && !!e && "tableName" in e && "fields" in e && typeof e.tableName == "string", G = async (e) => {
|
|
398
|
-
let t = await R(e,
|
|
399
|
+
let t = await R(e, o), n = [];
|
|
399
400
|
for (let r of t) {
|
|
400
401
|
let t;
|
|
401
402
|
try {
|
|
@@ -519,21 +520,21 @@ var k = class extends Error {
|
|
|
519
520
|
if (!Number.isInteger(n) || n < 0) throw Error(`--online-after / VOLTRO_ONLINE_THRESHOLD must be a non-negative integer, got "${t}"`);
|
|
520
521
|
return n;
|
|
521
522
|
}, be = async (e) => {
|
|
522
|
-
let
|
|
523
|
-
if (
|
|
524
|
-
root:
|
|
523
|
+
let t = Z(e), n = z(e), r = await G(n);
|
|
524
|
+
if (r.length === 0) return L.warn("db plan: no schema files found", {
|
|
525
|
+
root: n,
|
|
525
526
|
hint: "looked for *.entity.ts / *.schema.ts / schema.ts"
|
|
526
527
|
}), 1;
|
|
527
|
-
let
|
|
528
|
-
...
|
|
528
|
+
let i = await a({ root: n }), o = K(q([
|
|
529
|
+
...r,
|
|
529
530
|
...y,
|
|
530
|
-
...
|
|
531
|
+
...i
|
|
531
532
|
])), s = c(e, "--against");
|
|
532
533
|
if (s) {
|
|
533
|
-
let
|
|
534
|
+
let n = s, r = c(e, "--token") ?? process.env.VOLTRO_INSPECT_TOKEN, i = { accept: "application/json" };
|
|
534
535
|
r && (i.authorization = `Bearer ${r}`);
|
|
535
536
|
try {
|
|
536
|
-
let e =
|
|
537
|
+
let e = n.endsWith("/_voltro/inspect/migrations") ? n : `${n.replace(/\/+$/, "")}/_voltro/inspect/migrations`, r = await fetch(e, { headers: i });
|
|
537
538
|
if (!r.ok) return L.error(`db plan --against: remote returned ${r.status}`, { url: e }), 1;
|
|
538
539
|
let a = (await r.json()).drift?.liveSnapshot;
|
|
539
540
|
if (!a) return L.error("db plan --against: remote inspect payload missing drift.liveSnapshot", { url: e }), 1;
|
|
@@ -542,7 +543,7 @@ var k = class extends Error {
|
|
|
542
543
|
live: a,
|
|
543
544
|
dialect: U(),
|
|
544
545
|
...w(),
|
|
545
|
-
...
|
|
546
|
+
...t === void 0 ? {} : { onlineAfter: t }
|
|
546
547
|
});
|
|
547
548
|
return console.log(`\n[--against ${e}] — diff vs remote live schema:\n`), X(s), s.summary.blocked > 0 ? 2 : 0;
|
|
548
549
|
} catch (e) {
|
|
@@ -554,22 +555,22 @@ var k = class extends Error {
|
|
|
554
555
|
live: await Y(await W()),
|
|
555
556
|
dialect: U(),
|
|
556
557
|
...w(),
|
|
557
|
-
...
|
|
558
|
+
...t === void 0 ? {} : { onlineAfter: t }
|
|
558
559
|
});
|
|
559
560
|
return e.includes("--json") ? (te(1, `${JSON.stringify(l, null, 2)}\n`), l.summary.blocked > 0 ? 2 : 0) : (X(l), l.summary.blocked > 0 ? 2 : 0);
|
|
560
|
-
}, xe = async (e,
|
|
561
|
-
let
|
|
561
|
+
}, xe = async (e, t, n) => {
|
|
562
|
+
let r;
|
|
562
563
|
try {
|
|
563
564
|
let t = await g.readFile(p(e), "utf8");
|
|
564
|
-
|
|
565
|
+
r = JSON.parse(t);
|
|
565
566
|
} catch (t) {
|
|
566
567
|
return L.error(`db apply --plan: cannot read/parse plan file '${e}': ${t.message}`), 1;
|
|
567
568
|
}
|
|
568
|
-
if (!Array.isArray(
|
|
569
|
-
let
|
|
570
|
-
if (
|
|
571
|
-
let o = await
|
|
572
|
-
...
|
|
569
|
+
if (!Array.isArray(r?.operations) || typeof r?.fromFingerprint != "string" || typeof r?.toFingerprint != "string") return L.error(`db apply --plan: '${e}' is not a valid plan file (expected the output of \`voltro db plan --json\`).`), 1;
|
|
570
|
+
let i = await G(n);
|
|
571
|
+
if (i.length === 0) return L.warn("db apply --plan: no schema files found", { root: n }), 1;
|
|
572
|
+
let o = await a({ root: n }), s = K(q([
|
|
573
|
+
...i,
|
|
573
574
|
...y,
|
|
574
575
|
...o
|
|
575
576
|
])), l = await W();
|
|
@@ -580,30 +581,36 @@ var k = class extends Error {
|
|
|
580
581
|
dialect: U(),
|
|
581
582
|
...w()
|
|
582
583
|
});
|
|
583
|
-
if (u.fromFingerprint !==
|
|
584
|
-
if (u.toFingerprint !==
|
|
584
|
+
if (u.fromFingerprint !== r.fromFingerprint) return L.error("db apply --plan: refusing — the live schema has drifted since this plan was generated."), console.error(` plan.from=${r.fromFingerprint.slice(0, 16)} live=${u.fromFingerprint.slice(0, 16)}`), console.error(" Regenerate against the current live schema: `voltro db plan --json > plan.json`"), 2;
|
|
585
|
+
if (u.toFingerprint !== r.toFingerprint) return L.error("db apply --plan: refusing — the declared schema differs from what this plan targets."), console.error(` plan.to=${r.toFingerprint.slice(0, 16)} declared=${u.toFingerprint.slice(0, 16)}`), console.error(" The schema files changed since the plan was generated. Regenerate the plan."), 2;
|
|
585
586
|
if (u.summary.blocked > 0) return X(u), L.error(`db apply --plan: refusing — ${u.summary.blocked} blocked operation(s). See the fix hints above.`), 2;
|
|
586
587
|
if (u.operations.length === 0) return L.info("db apply --plan: schema is up to date — nothing to apply"), 0;
|
|
587
588
|
X(u);
|
|
588
|
-
let d = (process.env.NODE_ENV ?? "dev").toLowerCase(), f = c(
|
|
589
|
+
let d = (process.env.NODE_ENV ?? "dev").toLowerCase(), f = c(t, "--note"), m = await J(l, _.SqlClient.pipe(h.flatMap((e) => x(e, u, {
|
|
589
590
|
declared: s,
|
|
590
591
|
appliedBy: process.env.USER ? `cli:${process.env.USER}` : "cli:plan",
|
|
591
592
|
environment: d === "production" ? "prod" : d === "staging" ? "staging" : "dev",
|
|
592
593
|
source: "file",
|
|
593
|
-
...f ? { notes: f } : {}
|
|
594
|
+
...f ? { notes: f } : {},
|
|
595
|
+
replan: () => h.promise(() => Y(l)).pipe(h.map((e) => T({
|
|
596
|
+
declared: s,
|
|
597
|
+
live: e,
|
|
598
|
+
dialect: U(),
|
|
599
|
+
...w()
|
|
600
|
+
})))
|
|
594
601
|
}))));
|
|
595
|
-
return L.info(`db apply --plan: applied ${
|
|
602
|
+
return L.info(`db apply --plan: applied ${m.appliedOps} op(s) in ${m.durationMs}ms`, {
|
|
596
603
|
id: m.id,
|
|
597
604
|
fingerprint: m.fingerprint.slice(0, 16)
|
|
598
605
|
}), 0;
|
|
599
606
|
}, Se = async (e) => {
|
|
600
|
-
let
|
|
601
|
-
if (
|
|
607
|
+
let t = z(e), n = Z(e), r = c(e, "--plan");
|
|
608
|
+
if (r) return xe(r, e, t);
|
|
602
609
|
if ((process.env.NODE_ENV ?? "").toLowerCase() === "production") return L.error("voltro db apply: refusing — auto-apply on prod is not allowed."), console.error("In production, schema changes go through `voltro db plan --json > plan.json`"), console.error("then `voltro db apply --plan plan.json` as an explicit step in your deploy pipeline."), 3;
|
|
603
|
-
let
|
|
604
|
-
if (
|
|
605
|
-
let o = await
|
|
606
|
-
...
|
|
610
|
+
let i = await G(t);
|
|
611
|
+
if (i.length === 0) return L.warn("db apply: no schema files found", { root: t }), 1;
|
|
612
|
+
let o = await a({ root: t }), s = K(q([
|
|
613
|
+
...i,
|
|
607
614
|
...y,
|
|
608
615
|
...o
|
|
609
616
|
])), l = await W();
|
|
@@ -613,7 +620,7 @@ var k = class extends Error {
|
|
|
613
620
|
live: await Y(l),
|
|
614
621
|
dialect: U(),
|
|
615
622
|
...w(),
|
|
616
|
-
...
|
|
623
|
+
...n === void 0 ? {} : { onlineAfter: n }
|
|
617
624
|
});
|
|
618
625
|
if (X(u), u.summary.blocked > 0) return L.error(`db apply: refusing — ${u.summary.blocked} blocked operation(s). See the fix hints above.`), 2;
|
|
619
626
|
if (u.operations.length === 0) return L.info("db apply: schema is up to date — nothing to apply"), 0;
|
|
@@ -622,9 +629,16 @@ var k = class extends Error {
|
|
|
622
629
|
appliedBy: process.env.USER ? `cli:${process.env.USER}` : "cli:user",
|
|
623
630
|
environment: (process.env.NODE_ENV ?? "dev").toLowerCase() === "staging" ? "staging" : "dev",
|
|
624
631
|
source: "auto-diff",
|
|
625
|
-
...d ? { notes: d } : {}
|
|
632
|
+
...d ? { notes: d } : {},
|
|
633
|
+
replan: () => h.promise(() => Y(l)).pipe(h.map((e) => T({
|
|
634
|
+
declared: s,
|
|
635
|
+
live: e,
|
|
636
|
+
dialect: U(),
|
|
637
|
+
...w(),
|
|
638
|
+
...n === void 0 ? {} : { onlineAfter: n }
|
|
639
|
+
})))
|
|
626
640
|
}))));
|
|
627
|
-
return L.info(`db apply: applied ${
|
|
641
|
+
return L.info(`db apply: applied ${f.appliedOps} op(s) in ${f.durationMs}ms`, {
|
|
628
642
|
id: f.id,
|
|
629
643
|
fingerprint: f.fingerprint.slice(0, 16)
|
|
630
644
|
}), 0;
|
|
@@ -724,24 +738,24 @@ var k = class extends Error {
|
|
|
724
738
|
}
|
|
725
739
|
return console.log(`\n${i ? `[dry-run] ${u} snapshot(s) would be dropped` : `✓ dropped ${u} snapshot(s)`} (older than ${r}).\n`), 0;
|
|
726
740
|
}, Q = async (e) => {
|
|
727
|
-
let
|
|
728
|
-
if (!
|
|
729
|
-
let
|
|
730
|
-
if (Number.isNaN(new Date(
|
|
731
|
-
let
|
|
732
|
-
if (o.length === 0) return L.warn("db squash: no schema files found", { root:
|
|
733
|
-
let s = await
|
|
741
|
+
let t = c(e, "--before");
|
|
742
|
+
if (!t) return console.error("voltro db squash --before <iso-date> [--note \"<text>\"]"), 2;
|
|
743
|
+
let n = t;
|
|
744
|
+
if (Number.isNaN(new Date(n).getTime())) return console.error(`voltro db squash: --before '${n}' is not a valid ISO date`), 2;
|
|
745
|
+
let r = c(e, "--note"), i = z(e), o = await G(i);
|
|
746
|
+
if (o.length === 0) return L.warn("db squash: no schema files found", { root: i }), 1;
|
|
747
|
+
let s = await a({ root: i }), l = C(ae(K(q([
|
|
734
748
|
...o,
|
|
735
749
|
...y,
|
|
736
750
|
...s
|
|
737
751
|
])))), u = await W();
|
|
738
752
|
try {
|
|
739
753
|
let e = await J(u, se({
|
|
740
|
-
before:
|
|
754
|
+
before: n,
|
|
741
755
|
fingerprint: l,
|
|
742
756
|
appliedBy: process.env.USER ?? "cli",
|
|
743
757
|
environment: process.env.NODE_ENV === "production" ? "prod" : "dev",
|
|
744
|
-
...
|
|
758
|
+
...r === void 0 ? {} : { note: r }
|
|
745
759
|
}));
|
|
746
760
|
return console.log(`\n✓ squashed ${e.squashedCount} migration plan(s)\n snapshot id: ${e.snapshotId}\n fingerprint: ${O(e.snapshotFingerprint)}\n`), 0;
|
|
747
761
|
} catch (e) {
|