@voltro/cli 0.45.0 → 0.47.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 +206 -0
- package/dist/apiBuild-BsooZpw2.js +2 -0
- package/dist/{apiBuild-CDQBNRDx.js → apiBuild-FpHCWiv6.js} +2 -2
- package/dist/bin.d.ts +8 -0
- package/dist/bin.js +1 -1
- package/dist/{build-yvsLG77U.js → build-zVygXxGB.js} +8 -8
- package/dist/{checkCommand-lrzwOzV1.js → checkCommand-B2Fw73lu.js} +1 -1
- package/dist/{checkCommand-Boxov8lr.js → checkCommand-D0dAKciE.js} +4 -4
- package/dist/{codegen-sbN1Y8PB.js → codegen-CrMXs4hb.js} +176 -162
- package/dist/codegen-DiMn2KkZ.js +2 -0
- package/dist/{codegenCommand-CQOLytL-.js → codegenCommand-BTtsnRus.js} +16 -16
- package/dist/{codemodRunner-5ZhDH3rB.js → codemodRunner-DSZjgyCL.js} +8 -0
- package/dist/{commands-CEkVoFM5.js → commands-BrFKxnYW.js} +24 -24
- package/dist/{dashboardCommand-0ahyp-zA.js → dashboardCommand-D9SjDc8E.js} +3 -3
- package/dist/{dataCommand-D4IlZcih.js → dataCommand-Dl11q14e.js} +271 -230
- package/dist/dbCommand-BUD4Fd8v.js +2 -0
- package/dist/{dbCommand-B237qI-j.js → dbCommand-jbrmzwW_.js} +110 -110
- package/dist/{dev-P4HyeY9W.js → dev-CaIfZnw5.js} +1 -1
- package/dist/{dev-DAM5CnAa.js → dev-RjB7eE_B.js} +2081 -2058
- package/dist/devActivity.d.ts +8 -0
- package/dist/doctorCommand-5zv6PN-G.js +2 -0
- package/dist/{doctorCommand-DW2cwAvC.js → doctorCommand-D7X29cw6.js} +16 -16
- package/dist/{doctorSourceRelations-CPjSwYuZ.js → doctorSourceRelations-Dd48LPvO.js} +15 -10
- package/dist/{dormancyCommand-BqQz7lbM.js → dormancyCommand-BGOP27fz.js} +1 -1
- package/dist/{embeddingsCommand-DJyArpU4.js → embeddingsCommand-D72E22bw.js} +1 -1
- package/dist/{envCommand-CviRZx1L.js → envCommand-BHSxz6wC.js} +2 -2
- package/dist/{evalCommand-6RUfPen4.js → evalCommand-Db01Kbng.js} +24 -24
- package/dist/{evolveCommand-qdlP-R9G.js → evolveCommand-C2ofGGlz.js} +2 -2
- package/dist/{frameworkTableAssembly-oMPBKqlE.js → frameworkTableAssembly-BvZ0Lil_.js} +97 -89
- package/dist/frameworkTableAssembly-DDKtwsy2.js +2 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.js +1 -1
- package/dist/{infoCommand-CNWPSUcW.js → infoCommand-CuNl9cbh.js} +1 -1
- package/dist/inspectState.d.ts +8 -0
- package/dist/interruptedReplace-C1ZI84xi.js +27 -0
- package/dist/interruptedReplace-DNJ7MKph.js +2 -0
- package/dist/{migrate-DN47p2PG.js → migrate-odCPGHPq.js} +27 -27
- package/dist/{runtimeTrace-BDZSt9W_.js → runtimeTrace-C_OKr0jY.js} +1 -1
- package/dist/{sdkgen-sNaD3oZB.js → sdkgen-D9trW7sl.js} +1 -1
- package/dist/{seedRunner-IdHEprqf.js → seedRunner-Dgsiwk_e.js} +59 -59
- package/dist/serveCommand-BU0wfV6V.js +1931 -0
- package/dist/serveCommand-Bwrn_9Fn.js +2 -0
- package/dist/serveEntry.d.ts +8 -0
- package/dist/serveEntry.js +1 -1
- package/dist/{start-Ds3xyn8R.js → start-7HcSIKEp.js} +1 -1
- package/dist/{start-BAlGcjF5.js → start-DvlYDyAr.js} +1 -1
- package/dist/startEntry.d.ts +8 -0
- package/dist/startEntry.js +1 -1
- package/dist/startup.d.ts +8 -0
- package/dist/{test-CHb7UwvE.js → test-rXFq4S76.js} +1 -1
- package/dist/{updateCommand-rCnhaj84.js → updateCommand-BlyXavoG.js} +1 -1
- package/dist/updateCommand-CT5AvVg7.js +2 -0
- package/dist/{webDev-101csg6Q.js → webDev-B4IEMB0n.js} +6 -6
- package/dist/webDev-B79ji8M5.js +2 -0
- package/dist/{webhooksCommand-C0iZZfaI.js → webhooksCommand-BqcWcbuW.js} +1 -1
- package/package.json +23 -17
- package/templates/AGENTS.md +1 -1
- package/templates/agent-docs/_index.md +1 -1
- package/templates/agent-docs/cli.md +166 -2
- package/templates/agent-docs/data.md +70 -4
- package/templates/agent-docs/whats-new.md +14 -87
- package/templates/apps/api-ai/package.json +7 -7
- package/templates/apps/api-auth/package.json +8 -8
- package/templates/apps/api-backend/package.json +7 -7
- package/templates/apps/api-backend-deactivation/package.json +7 -7
- package/templates/apps/api-backend-mail/package.json +8 -8
- package/templates/apps/api-backend-mariadb/package.json +9 -9
- package/templates/apps/api-backend-sqlite/package.json +8 -8
- package/templates/apps/api-backend-storage/package.json +8 -8
- package/templates/apps/api-cms/package.json +10 -10
- package/templates/apps/api-collab/package.json +8 -8
- package/templates/apps/api-data-advanced/package.json +8 -8
- package/templates/apps/api-durable/package.json +8 -8
- package/templates/apps/api-feature-flags/package.json +9 -9
- package/templates/apps/api-governance/package.json +8 -8
- package/templates/apps/api-kv/package.json +8 -8
- package/templates/apps/api-moderation/package.json +8 -8
- package/templates/apps/api-observability/package.json +8 -8
- package/templates/apps/api-ratelimit/package.json +8 -8
- package/templates/apps/api-rbac/package.json +8 -8
- package/templates/apps/api-rest/package.json +7 -7
- package/templates/apps/api-saas/package.json +11 -11
- package/templates/apps/api-saas-starter/package.json +10 -10
- package/templates/apps/api-search/package.json +8 -8
- package/templates/apps/api-status/package.json +8 -8
- package/templates/apps/api-versioning/package.json +8 -8
- package/templates/apps/api-webhooks/package.json +9 -9
- package/templates/apps/changelog/package.json +6 -6
- package/templates/apps/edge-functions/package.json +2 -2
- package/templates/apps/frontend-admin/package.json +8 -8
- package/templates/apps/frontend-app/package.json +9 -9
- package/templates/apps/frontend-auth/package.json +8 -8
- package/templates/apps/frontend-blank/package.json +7 -7
- package/templates/apps/frontend-cms/package.json +9 -9
- package/templates/apps/frontend-collab/package.json +10 -10
- package/templates/apps/frontend-contact/package.json +7 -7
- package/templates/apps/frontend-dashboard/package.json +7 -7
- package/templates/apps/frontend-docs/package.json +7 -7
- package/templates/apps/frontend-i18n/package.json +6 -6
- package/templates/apps/frontend-landing/package.json +7 -7
- package/templates/apps/frontend-portal/package.json +8 -8
- package/templates/apps/frontend-saas/package.json +8 -8
- package/templates/apps/frontend-spa/package.json +7 -7
- package/templates/apps/frontend-ssr/package.json +7 -7
- package/templates/apps/frontend-ssr-api/package.json +8 -8
- package/templates/apps/frontend-static-blog/package.json +6 -6
- package/templates/apps/frontend-status/package.json +8 -8
- package/templates/apps/mobile-app/package.json +4 -4
- package/dist/apiBuild-yJCqJYQ8.js +0 -2
- package/dist/codegen-DcE2li1i.js +0 -2
- package/dist/dbCommand-BvQeKQOb.js +0 -2
- package/dist/doctorCommand-2K1dIzYk.js +0 -2
- package/dist/frameworkTableAssembly-DgylYh9_.js +0 -2
- package/dist/serveCommand-BBhT2U94.js +0 -1885
- package/dist/serveCommand-DY2jLy0o.js +0 -2
- package/dist/updateCommand-BH6EGuCc.js +0 -2
- package/dist/webDev-BLKBO34K.js +0 -2
|
@@ -5,18 +5,18 @@ import { n as i } from "./appModuleLoader-C9r9mxZt.js";
|
|
|
5
5
|
import { a, i as o, n as s, t as c } from "./cliArgs-D4p8n7EE.js";
|
|
6
6
|
import { r as l } from "./dialectDriver-czCHYpeH.js";
|
|
7
7
|
import { a as u } from "./connectionConfig-Bk9IC7D0.js";
|
|
8
|
-
import { i as d, n as f, r as p, s as m, t as h } from "./seedRunner-
|
|
9
|
-
import { n as g, s as _, y as v } from "./frameworkTableAssembly-
|
|
8
|
+
import { i as d, n as f, r as p, s as m, t as h } from "./seedRunner-Dgsiwk_e.js";
|
|
9
|
+
import { n as g, s as _, y as v } from "./frameworkTableAssembly-BvZ0Lil_.js";
|
|
10
10
|
import { b as y, x as b } from "./fileConventions-Cof68_BL.js";
|
|
11
11
|
import { r as x, t as S } from "./inspectGateHint-BjnFubmH.js";
|
|
12
12
|
import { basename as ee, join as C, relative as w, resolve as T } from "node:path";
|
|
13
13
|
import { promises as E, writeSync as te } from "node:fs";
|
|
14
14
|
import { pathToFileURL as D } from "node:url";
|
|
15
15
|
import { createLogger as O } from "@voltro/logger";
|
|
16
|
-
import {
|
|
17
|
-
import {
|
|
18
|
-
import {
|
|
19
|
-
import {
|
|
16
|
+
import { actorsTable as k, branchNamespaceName as ne, decodeFieldValue as re, encodeFieldValue as ie, frameworkTables as ae, isEncrypted as A, isMigrationDefinition as oe, isRawEncoding as se, makeNamespaceBranchExecutor as ce, provisionBranch as le, quoteIdent as ue, registerCoreTables as de, resolveBranchMechanism as fe, teardownBranch as pe } from "@voltro/database";
|
|
17
|
+
import { Effect as j } from "effect";
|
|
18
|
+
import { SqlClient as M } from "@effect/sql";
|
|
19
|
+
import { DEFAULT_CDC_CHANNEL as me, applyPlan as he, applySchema as ge, assessRollingDeployGate as _e, branchRehearsalExitCode as ve, declaredSnapshot as ye, destructiveScope as be, fingerprintSchema as xe, formatBranchRehearsal as Se, ignoreTablesFromEnv as N, introspectSchema as P, pendingFileMigrationIds as Ce, planMigrations as F, recordUpToDate as we, rehearseMigrationOnBranch as Te, rollbackFileBasedMigration as Ee, rollingDeployUnsafeOps as De, runFileBasedMigrations as Oe, shortFingerprint as I, squashMigrationPlans as ke, unblockLossy as Ae } from "@voltro/database/sql";
|
|
20
20
|
import { InMemoryDataStore as je, makeFieldCipher as Me } from "@voltro/runtime";
|
|
21
21
|
import { createHash as Ne } from "node:crypto";
|
|
22
22
|
//#region src/adoptPlan.ts
|
|
@@ -237,11 +237,11 @@ var Pe = (e) => typeof e != "string", Fe = (e, t, n, r) => {
|
|
|
237
237
|
}, Qe = (e, t, n, r) => {
|
|
238
238
|
let i = `WHERE ${Ge(t, n)}`, a = We(t, n).replace(/^LOWER\((.*)\)$/s, "$1");
|
|
239
239
|
return n === "mssql" ? `SELECT TOP (${r}) ${a} AS v FROM ${e}\n ${i}` : `SELECT ${a} AS v FROM ${e}\n ${i}\n LIMIT ${r}`;
|
|
240
|
-
}, $e = async (e, t, n, r, i) => (await
|
|
240
|
+
}, $e = async (e, t, n, r, i) => (await j.runPromise(e.unsafe(Qe(t, n, r, i)))).map((e) => {
|
|
241
241
|
let t = Object.values(e)[0];
|
|
242
242
|
return typeof t == "string" ? t : JSON.stringify(t ?? null);
|
|
243
243
|
}), et = async (e, t) => {
|
|
244
|
-
let n = await
|
|
244
|
+
let n = await j.runPromise(e.unsafe(t));
|
|
245
245
|
return Number(Object.values(n[0] ?? { n: 0 })[0] ?? 0);
|
|
246
246
|
}, tt = async (e, t, n, r) => {
|
|
247
247
|
let i = [];
|
|
@@ -323,7 +323,7 @@ var Pe = (e) => typeof e != "string", Fe = (e, t, n, r) => {
|
|
|
323
323
|
t.warn("migration: failed to import", { file: r }, e);
|
|
324
324
|
continue;
|
|
325
325
|
}
|
|
326
|
-
let i = (e.default &&
|
|
326
|
+
let i = (e.default && oe(e.default) ? e.default : void 0) ?? Object.values(e).find(oe);
|
|
327
327
|
if (!i) {
|
|
328
328
|
t.warn("migration: no defineMigration export", { file: r });
|
|
329
329
|
continue;
|
|
@@ -343,12 +343,12 @@ var Pe = (e) => typeof e != "string", Fe = (e, t, n, r) => {
|
|
|
343
343
|
return [...n].sort((e, t) => e.definition.id < t.definition.id ? -1 : 1);
|
|
344
344
|
}, ot = async (e) => {
|
|
345
345
|
let t = (process.env.DB_DIALECT ?? "postgres").toLowerCase(), n = t === "memory" ? "postgres" : t, r = n, i = t === "memory" ? void 0 : await l(n).then((e) => e.retryFilter, () => void 0);
|
|
346
|
-
return
|
|
347
|
-
}, st = (e) =>
|
|
348
|
-
let e = yield* (yield*
|
|
346
|
+
return j.runPromise(ge(ae, r, void 0, i === void 0 ? {} : { retryFilter: i }).pipe(j.provide(e)));
|
|
347
|
+
}, st = (e) => j.runPromise(j.gen(function* () {
|
|
348
|
+
let e = yield* (yield* M.SqlClient)`SELECT id, status, hash, "appliedAt" FROM "_voltro_migrations"`.pipe(j.orElseSucceed(() => []));
|
|
349
349
|
return new Map(e.map((e) => [e.id, e]));
|
|
350
|
-
}).pipe(
|
|
351
|
-
yield* (yield*
|
|
350
|
+
}).pipe(j.provide(e))), z = (e, t) => j.runPromise(j.gen(function* () {
|
|
351
|
+
yield* (yield* M.SqlClient)`
|
|
352
352
|
INSERT INTO "_voltro_migrations"
|
|
353
353
|
(id, name, hash, status, "appliedAt", "durationMs", "errorMessage", "errorStack")
|
|
354
354
|
VALUES
|
|
@@ -363,7 +363,7 @@ var Pe = (e) => typeof e != "string", Fe = (e, t, n, r) => {
|
|
|
363
363
|
"errorStack" = EXCLUDED."errorStack",
|
|
364
364
|
"updatedAt" = now()
|
|
365
365
|
`;
|
|
366
|
-
}).pipe(
|
|
366
|
+
}).pipe(j.provide(e))), ct = async (e, t, n) => {
|
|
367
367
|
if (e.length === 0) return {
|
|
368
368
|
applied: [],
|
|
369
369
|
failed: null,
|
|
@@ -405,7 +405,7 @@ var Pe = (e) => typeof e != "string", Fe = (e, t, n, r) => {
|
|
|
405
405
|
for (let e of s.definition.steps) {
|
|
406
406
|
let n = Date.now();
|
|
407
407
|
try {
|
|
408
|
-
await
|
|
408
|
+
await j.runPromise(e.apply.pipe(j.provide(t))), l.push({
|
|
409
409
|
stepName: e.name,
|
|
410
410
|
status: "applied",
|
|
411
411
|
durationMs: Date.now() - n
|
|
@@ -491,7 +491,7 @@ var Pe = (e) => typeof e != "string", Fe = (e, t, n, r) => {
|
|
|
491
491
|
for (let n = e.definition.steps.length - 1; n >= 0; n--) {
|
|
492
492
|
let o = e.definition.steps[n], s = Date.now();
|
|
493
493
|
try {
|
|
494
|
-
await
|
|
494
|
+
await j.runPromise(o.undo.pipe(j.provide(t))), i.push({
|
|
495
495
|
stepName: o.name,
|
|
496
496
|
status: "applied",
|
|
497
497
|
durationMs: Date.now() - s
|
|
@@ -602,10 +602,10 @@ var Pe = (e) => typeof e != "string", Fe = (e, t, n, r) => {
|
|
|
602
602
|
}, _t = (e, t, n) => {
|
|
603
603
|
if (e == null) return;
|
|
604
604
|
let r = typeof e == "string" ? e : String(e);
|
|
605
|
-
if (r === "" ||
|
|
606
|
-
let i =
|
|
605
|
+
if (r === "" || A(r)) return;
|
|
606
|
+
let i = ie(t, r), a;
|
|
607
607
|
try {
|
|
608
|
-
a =
|
|
608
|
+
a = re(t, i);
|
|
609
609
|
} catch (e) {
|
|
610
610
|
throw Error(`${n.table}.${n.column}: the value could not be read back the way the app reads it (${e.message ?? String(e)}). Nothing was written.`);
|
|
611
611
|
}
|
|
@@ -628,18 +628,18 @@ var Pe = (e) => typeof e != "string", Fe = (e, t, n, r) => {
|
|
|
628
628
|
" the column may hold a mix while you deploy. Run this again afterwards to",
|
|
629
629
|
" catch anything written in between — it skips what is already encrypted."
|
|
630
630
|
].join("\n"), Ct = (e, t, n) => {
|
|
631
|
-
if (typeof e != "string" || !
|
|
631
|
+
if (typeof e != "string" || !A(e)) return;
|
|
632
632
|
let r;
|
|
633
633
|
try {
|
|
634
|
-
r =
|
|
634
|
+
r = se(t, e);
|
|
635
635
|
} catch {
|
|
636
636
|
return;
|
|
637
637
|
}
|
|
638
638
|
if (r !== !0) return;
|
|
639
|
-
let i =
|
|
639
|
+
let i = re(t, e);
|
|
640
640
|
if (typeof i != "string") return;
|
|
641
|
-
let a =
|
|
642
|
-
if (
|
|
641
|
+
let a = ie(t, i);
|
|
642
|
+
if (re(t, a) !== i) throw Error(`${n.table}.${n.column}: re-encoding did not round-trip. Nothing was written.`);
|
|
643
643
|
return a;
|
|
644
644
|
}, wt = (e, t, n) => e === "sqlite" ? `SELECT NULL AS n FROM pragma_table_info('${t.table}') WHERE name = '${t.column}'` : `SELECT character_maximum_length AS n FROM information_schema.columns\n WHERE ${n} AND table_name = '${t.table}' AND column_name = '${t.column}'`, Tt = (e) => {
|
|
645
645
|
if (e == null) return;
|
|
@@ -692,7 +692,7 @@ var Pe = (e) => typeof e != "string", Fe = (e, t, n, r) => {
|
|
|
692
692
|
let e = (process.env.DB_DIALECT ?? "postgres").toLowerCase();
|
|
693
693
|
if (e === "memory") throw new r("voltro db: subcommands require a real dialect, not DB_DIALECT=memory.");
|
|
694
694
|
return e;
|
|
695
|
-
}, G = (e) =>
|
|
695
|
+
}, G = (e) => ue(e, W()), K = (e) => e === "mysql" || e === "mariadb" ? "table_schema = DATABASE()" : e === "mssql" ? "table_schema = SCHEMA_NAME()" : "table_schema = 'public'", q = async () => (await l(W())).makeSqlLayer(U()), At = async (e) => {
|
|
696
696
|
let t = H(e), n = e.includes("--dry-run"), r = await at(await V(t, it), B);
|
|
697
697
|
if (r.length === 0) return B.info("no migrations found", { root: t }), 0;
|
|
698
698
|
if (n) {
|
|
@@ -785,9 +785,9 @@ var Pe = (e) => typeof e != "string", Fe = (e, t, n, r) => {
|
|
|
785
785
|
return n;
|
|
786
786
|
}, Lt = (e) => {
|
|
787
787
|
let t = new Map(e.map((e) => [e.tableName, e]));
|
|
788
|
-
t.has("actors") || t.set("actors",
|
|
788
|
+
t.has("actors") || t.set("actors", k);
|
|
789
789
|
let n = t.get("actors"), r = t.get("tenants");
|
|
790
|
-
return
|
|
790
|
+
return de({
|
|
791
791
|
actors: () => n,
|
|
792
792
|
...r === void 0 ? {} : { tenants: () => r }
|
|
793
793
|
}), [...t.values()];
|
|
@@ -799,19 +799,19 @@ var Pe = (e) => typeof e != "string", Fe = (e, t, n, r) => {
|
|
|
799
799
|
}
|
|
800
800
|
return [...t.values()];
|
|
801
801
|
}, zt = (e) => {
|
|
802
|
-
let t =
|
|
802
|
+
let t = be(process.env.VOLTRO_DESTRUCTIVE_OK);
|
|
803
803
|
if (t === void 0 || !e.operations.filter((e) => e.blocked).every((e) => e.classification === "lossy")) return {
|
|
804
804
|
plan: e,
|
|
805
805
|
acknowledged: !1
|
|
806
806
|
};
|
|
807
|
-
let n =
|
|
807
|
+
let n = Ae(e, t);
|
|
808
808
|
return {
|
|
809
809
|
plan: n,
|
|
810
810
|
acknowledged: !n.operations.some((e) => e.blocked)
|
|
811
811
|
};
|
|
812
|
-
}, J = async (e, t) =>
|
|
812
|
+
}, J = async (e, t) => j.runPromise(t.pipe(j.provide(e))), Y = async (e) => {
|
|
813
813
|
try {
|
|
814
|
-
return await J(e,
|
|
814
|
+
return await J(e, M.SqlClient.pipe(j.flatMap(P)));
|
|
815
815
|
} catch (e) {
|
|
816
816
|
let t = String(e?.message ?? e);
|
|
817
817
|
if (Ot(e) || /connection error/i.test(t)) {
|
|
@@ -901,7 +901,7 @@ var Pe = (e) => typeof e != "string", Fe = (e, t, n, r) => {
|
|
|
901
901
|
if (i === void 0 || a === void 0) continue;
|
|
902
902
|
let o = 0;
|
|
903
903
|
try {
|
|
904
|
-
let e = await J(t,
|
|
904
|
+
let e = await J(t, M.SqlClient.pipe(j.flatMap((e) => e.unsafe(`SELECT COUNT(*) AS n FROM ${ue(i, W())}`))));
|
|
905
905
|
o = Number(Object.values(e[0] ?? { n: 0 })[0] ?? 0);
|
|
906
906
|
} catch {
|
|
907
907
|
continue;
|
|
@@ -915,9 +915,9 @@ var Pe = (e) => typeof e != "string", Fe = (e, t, n, r) => {
|
|
|
915
915
|
}
|
|
916
916
|
}, Ut = async (e, t) => {
|
|
917
917
|
if (W() !== "postgres") return;
|
|
918
|
-
let n =
|
|
918
|
+
let n = me, r;
|
|
919
919
|
try {
|
|
920
|
-
r = await J(t,
|
|
920
|
+
r = await J(t, M.SqlClient.pipe(j.flatMap((t) => m(t, e, n))));
|
|
921
921
|
} catch {
|
|
922
922
|
return;
|
|
923
923
|
}
|
|
@@ -925,7 +925,7 @@ var Pe = (e) => typeof e != "string", Fe = (e, t, n, r) => {
|
|
|
925
925
|
if (a.length === 0) return;
|
|
926
926
|
B.info(i.missing.length + i.stale.length > 0 ? `db apply: installing change triggers on ${i.missing.length} table(s)` + (i.stale.length > 0 ? `, removing ${i.stale.length} stale one(s)` : "") + (i.functionOutdated ? ", replacing an outdated notify function" : "") : "db apply: replacing an outdated change-notify function (no table drift)");
|
|
927
927
|
let o = 0;
|
|
928
|
-
for (let e of a) await J(t,
|
|
928
|
+
for (let e of a) await J(t, M.SqlClient.pipe(j.flatMap((t) => t.unsafe(e)))), o += 1;
|
|
929
929
|
B.info(`db apply: change triggers converged (${o} statement(s))`, {
|
|
930
930
|
installed: i.missing.length,
|
|
931
931
|
removed: i.stale.length,
|
|
@@ -940,17 +940,17 @@ var Pe = (e) => typeof e != "string", Fe = (e, t, n, r) => {
|
|
|
940
940
|
for (let t of e.operations) console.log(Vt(t));
|
|
941
941
|
console.log(), console.log(` safe: ${t.safe} needs-default: ${t.needsDefault} needs-backfill: ${t.needsBackfill}`), console.log(` rename: ${t.needsRenameAnnotation} lossy: ${t.lossy} blocked: ${t.blocked}`), console.log(` fingerprint: ${e.fromFingerprint.slice(0, 16)} → ${e.toFingerprint.slice(0, 16)}\n`), Wt(e);
|
|
942
942
|
}, Wt = (e) => {
|
|
943
|
-
let t =
|
|
943
|
+
let t = De(e.operations);
|
|
944
944
|
if (t.length !== 0) {
|
|
945
945
|
console.log(` ⚠ ${t.length} operation(s) UNSAFE under a rolling deploy`), console.log(" (old + new instances overlap → old code breaks against the new schema):");
|
|
946
946
|
for (let e of t) console.log(` • ${e.op.op.kind}: ${e.reason}`), console.log(` → ${e.remedy}`);
|
|
947
947
|
console.log(" Deploy with a maintenance window / scale-to-zero, or split into"), console.log(" expand → deploy → contract. See docs: deployment/production-hardening.\n");
|
|
948
948
|
}
|
|
949
949
|
}, Gt = (e, t) => {
|
|
950
|
-
let n =
|
|
950
|
+
let n = _e({
|
|
951
951
|
enabled: process.env.VOLTRO_ROLLING_DEPLOY === "1",
|
|
952
952
|
forced: t.includes("--force"),
|
|
953
|
-
unsafeCount:
|
|
953
|
+
unsafeCount: De(e.operations).length
|
|
954
954
|
});
|
|
955
955
|
return n.refuse ? (B.error(`db apply: ${n.message}`), !0) : (n.warnForced && B.warn(`db apply: ${n.message}`), !1);
|
|
956
956
|
}, Kt = (e) => {
|
|
@@ -965,7 +965,7 @@ var Pe = (e) => typeof e != "string", Fe = (e, t, n, r) => {
|
|
|
965
965
|
let n = await g({ root: e });
|
|
966
966
|
return Lt(Rt([
|
|
967
967
|
...t,
|
|
968
|
-
...
|
|
968
|
+
...ae,
|
|
969
969
|
...n
|
|
970
970
|
]));
|
|
971
971
|
}, Q = async (e, t, n) => {
|
|
@@ -1005,11 +1005,11 @@ var Pe = (e) => typeof e != "string", Fe = (e, t, n, r) => {
|
|
|
1005
1005
|
if (!i.ok) return B.error(`db plan --against: remote returned ${i.status}`, { url: e }), x(i.status) && console.error(` ${S(i.status)}`), 1;
|
|
1006
1006
|
let a = (await i.json()).drift?.liveSnapshot;
|
|
1007
1007
|
if (!a) return B.error("db plan --against: remote inspect payload missing drift.liveSnapshot", { url: e }), 1;
|
|
1008
|
-
let s =
|
|
1008
|
+
let s = F({
|
|
1009
1009
|
declared: r,
|
|
1010
1010
|
live: a,
|
|
1011
1011
|
dialect: W(),
|
|
1012
|
-
...
|
|
1012
|
+
...N(),
|
|
1013
1013
|
...t === void 0 ? {} : { onlineAfter: t }
|
|
1014
1014
|
});
|
|
1015
1015
|
return console.log(`\n[--against ${e}] — diff vs remote live schema:\n`), X(s), s.summary.blocked > 0 ? 2 : 0;
|
|
@@ -1017,11 +1017,11 @@ var Pe = (e) => typeof e != "string", Fe = (e, t, n, r) => {
|
|
|
1017
1017
|
return B.error(`db plan --against: ${e.message}`), 1;
|
|
1018
1018
|
}
|
|
1019
1019
|
}
|
|
1020
|
-
let a = await Y(await q()), o =
|
|
1020
|
+
let a = await Y(await q()), o = F({
|
|
1021
1021
|
declared: r,
|
|
1022
1022
|
live: a,
|
|
1023
1023
|
dialect: W(),
|
|
1024
|
-
...
|
|
1024
|
+
...N(),
|
|
1025
1025
|
...t === void 0 ? {} : { onlineAfter: t }
|
|
1026
1026
|
});
|
|
1027
1027
|
return e.includes("--json") ? (te(1, `${JSON.stringify(o, null, 2)}\n`), o.summary.blocked > 0 ? 2 : 0) : (X(o), o.summary.blocked > 0 ? 2 : 0);
|
|
@@ -1036,13 +1036,13 @@ var Pe = (e) => typeof e != "string", Fe = (e, t, n, r) => {
|
|
|
1036
1036
|
if (!Array.isArray(r?.operations) || typeof r?.fromFingerprint != "string" || typeof r?.toFingerprint != "string") return B.error(`db apply --plan: '${e}' is not a valid plan file (expected the output of \`voltro db plan --json\`).`), 1;
|
|
1037
1037
|
let i = await Z(n);
|
|
1038
1038
|
if (i === void 0) return B.warn("db apply --plan: no schema files found", { root: n }), 1;
|
|
1039
|
-
let a = await q(), o = await J(a,
|
|
1039
|
+
let a = await q(), o = await J(a, M.SqlClient.pipe(j.flatMap((e) => Ce(e, n)))).catch(() => []);
|
|
1040
1040
|
if (o.length > 0) return B.error(`db apply --plan: refusing — ${o.length} pending file-based migration(s).`), console.error(` ${o.join("\n ")}`), console.error(""), console.error(" These perform the changes a state diff cannot infer, so they change the shape"), console.error(" this plan was computed against. Apply them and regenerate the plan:"), console.error(""), console.error(" voltro db files ."), console.error(" voltro db plan --json > plan.json"), console.error(" voltro db apply --plan plan.json"), 1;
|
|
1041
|
-
let c = await Y(a), l =
|
|
1041
|
+
let c = await Y(a), l = F({
|
|
1042
1042
|
declared: i,
|
|
1043
1043
|
live: c,
|
|
1044
1044
|
dialect: W(),
|
|
1045
|
-
...
|
|
1045
|
+
...N()
|
|
1046
1046
|
});
|
|
1047
1047
|
if (l.fromFingerprint !== r.fromFingerprint) return B.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=${l.fromFingerprint.slice(0, 16)}`), console.error(" Regenerate against the current live schema: `voltro db plan --json > plan.json`"), 2;
|
|
1048
1048
|
if (l.toFingerprint !== r.toFingerprint) return B.error("db apply --plan: refusing — the declared schema differs from what this plan targets."), console.error(` plan.to=${r.toFingerprint.slice(0, 16)} declared=${l.toFingerprint.slice(0, 16)}`), console.error(" The schema files changed since the plan was generated. Regenerate the plan."), 2;
|
|
@@ -1050,7 +1050,7 @@ var Pe = (e) => typeof e != "string", Fe = (e, t, n, r) => {
|
|
|
1050
1050
|
if (d.summary.blocked > 0 && !u.acknowledged) return X(d), B.error(`db apply --plan: refusing — ${l.summary.blocked} blocked operation(s). See the fix hints above.`), process.env.VOLTRO_DESTRUCTIVE_OK !== void 0 && (B.error(" VOLTRO_DESTRUCTIVE_OK is set but did not cover this plan — it only relaxes"), B.error(" `lossy` operations, and only the tables it names. Anything else stays refused.")), 2;
|
|
1051
1051
|
if (u.acknowledged && B.warn("db apply --plan: proceeding with acknowledged lossy operation(s) (VOLTRO_DESTRUCTIVE_OK)"), Gt(d, t)) return 2;
|
|
1052
1052
|
if (d.operations.length === 0) {
|
|
1053
|
-
let e = await J(a,
|
|
1053
|
+
let e = await J(a, M.SqlClient.pipe(j.flatMap((e) => we(e, d, {
|
|
1054
1054
|
appliedBy: process.env.USER ? `cli:${process.env.USER}` : "cli:plan",
|
|
1055
1055
|
environment: $(),
|
|
1056
1056
|
source: "file"
|
|
@@ -1058,17 +1058,17 @@ var Pe = (e) => typeof e != "string", Fe = (e, t, n, r) => {
|
|
|
1058
1058
|
return B.info(e === "recorded" ? `db apply --plan: schema is up to date — no DDL to apply, recorded fingerprint=${d.toFingerprint.slice(0, 16)} (change triggers are reconciled separately below)` : "db apply --plan: schema is up to date — no DDL to apply (change triggers are reconciled separately below)"), Q(n, i, a);
|
|
1059
1059
|
}
|
|
1060
1060
|
X(d);
|
|
1061
|
-
let f = s(t, "--note"), p = await J(a,
|
|
1061
|
+
let f = s(t, "--note"), p = await J(a, M.SqlClient.pipe(j.flatMap((e) => he(e, d, {
|
|
1062
1062
|
declared: i,
|
|
1063
1063
|
appliedBy: process.env.USER ? `cli:${process.env.USER}` : "cli:plan",
|
|
1064
1064
|
environment: $(),
|
|
1065
1065
|
source: "file",
|
|
1066
1066
|
...f ? { notes: f } : {},
|
|
1067
|
-
replan: (e) =>
|
|
1067
|
+
replan: (e) => P(e).pipe(j.map((e) => F({
|
|
1068
1068
|
declared: i,
|
|
1069
1069
|
live: e,
|
|
1070
1070
|
dialect: W(),
|
|
1071
|
-
...
|
|
1071
|
+
...N()
|
|
1072
1072
|
})))
|
|
1073
1073
|
}))));
|
|
1074
1074
|
return B.info(`db apply --plan: applied ${p.appliedOps} op(s) in ${p.durationMs}ms`, {
|
|
@@ -1090,11 +1090,11 @@ var Pe = (e) => typeof e != "string", Fe = (e, t, n, r) => {
|
|
|
1090
1090
|
if (a === void 0) return B.warn("db apply: no schema files found", { root: n }), 1;
|
|
1091
1091
|
let o = await q(), c = await mn(n, o);
|
|
1092
1092
|
if ("failed" in c) return B.error("db apply: a file-based migration FAILED — the schema diff was NOT run"), console.error(c.failed), console.error("Fix the migration and re-run. `voltro db files` runs them alone."), 1;
|
|
1093
|
-
let l = await Y(o), u =
|
|
1093
|
+
let l = await Y(o), u = F({
|
|
1094
1094
|
declared: a,
|
|
1095
1095
|
live: l,
|
|
1096
1096
|
dialect: W(),
|
|
1097
|
-
...
|
|
1097
|
+
...N(),
|
|
1098
1098
|
...r === void 0 ? {} : { onlineAfter: r }
|
|
1099
1099
|
});
|
|
1100
1100
|
X(u), await Ht(u, o);
|
|
@@ -1103,24 +1103,24 @@ var Pe = (e) => typeof e != "string", Fe = (e, t, n, r) => {
|
|
|
1103
1103
|
if (d.acknowledged && B.warn(`db apply: proceeding with ${u.summary.blocked} acknowledged lossy operation(s) (VOLTRO_DESTRUCTIVE_OK)`), Gt(f, e)) return 2;
|
|
1104
1104
|
if (f.operations.length === 0) {
|
|
1105
1105
|
B.info("db apply: schema is up to date — no DDL to apply (change triggers are reconciled separately below)");
|
|
1106
|
-
let t = await J(o,
|
|
1106
|
+
let t = await J(o, M.SqlClient.pipe(j.flatMap((e) => we(e, f, {
|
|
1107
1107
|
appliedBy: process.env.USER ? `cli:${process.env.USER}` : "cli:apply",
|
|
1108
1108
|
environment: $(),
|
|
1109
1109
|
source: "auto-diff"
|
|
1110
1110
|
}))));
|
|
1111
1111
|
return t === "recorded" && B.info(`db apply: recorded fingerprint=${f.toFingerprint.slice(0, 16)} (0 operations)`), await ln(o), s(e, "--note") !== void 0 && t !== "recorded" && (B.warn("db apply: --note was ignored — this schema is already the latest recorded one, so there is no new history row to attach it to."), console.error("To record that the CURRENT live schema is the accepted baseline, use `voltro db drift --accept`.")), Q(n, a, o);
|
|
1112
1112
|
}
|
|
1113
|
-
let p = s(e, "--note"), m = await J(o,
|
|
1113
|
+
let p = s(e, "--note"), m = await J(o, M.SqlClient.pipe(j.flatMap((e) => he(e, f, {
|
|
1114
1114
|
declared: a,
|
|
1115
1115
|
appliedBy: process.env.USER ? `cli:${process.env.USER}` : "cli:user",
|
|
1116
1116
|
environment: $(),
|
|
1117
1117
|
source: "auto-diff",
|
|
1118
1118
|
...p ? { notes: p } : {},
|
|
1119
|
-
replan: (e) =>
|
|
1119
|
+
replan: (e) => P(e).pipe(j.map((e) => F({
|
|
1120
1120
|
declared: a,
|
|
1121
1121
|
live: e,
|
|
1122
1122
|
dialect: W(),
|
|
1123
|
-
...
|
|
1123
|
+
...N(),
|
|
1124
1124
|
...r === void 0 ? {} : { onlineAfter: r }
|
|
1125
1125
|
})))
|
|
1126
1126
|
}))));
|
|
@@ -1177,7 +1177,7 @@ var Pe = (e) => typeof e != "string", Fe = (e, t, n, r) => {
|
|
|
1177
1177
|
root: t,
|
|
1178
1178
|
hint: "looked for *.entity.ts / *.schema.ts / schema.ts"
|
|
1179
1179
|
}), 1;
|
|
1180
|
-
let f = U(), p =
|
|
1180
|
+
let f = U(), p = fe({
|
|
1181
1181
|
seed: n,
|
|
1182
1182
|
...f.url === void 0 ? {} : { dbUrl: f.url },
|
|
1183
1183
|
...i === void 0 ? {} : { prefer: i }
|
|
@@ -1185,22 +1185,22 @@ var Pe = (e) => typeof e != "string", Fe = (e, t, n, r) => {
|
|
|
1185
1185
|
if (p === "neon-cow") return B.error("voltro db branch: this connection resolves to the Neon copy-on-write mechanism, which the CLI cannot execute."), console.error(" A Neon CoW branch is a single call to Neon's branch REST API and needs a Neon API token;"), console.error(" the framework ships the PLAN, and the cloud control plane executes it."), console.error(" Re-run with `--prefer namespace` to rehearse on a schema-per-branch copy instead"), console.error(` (portable, no vendor API — it copies ${n === "copy" ? "every row" : "the schema only"}).`), 1;
|
|
1186
1186
|
let m = f.schema ?? "public", h = s(e, "--name") ?? ee(t), g = s(e, "--pr"), _ = g === void 0 ? 0 : Number(g);
|
|
1187
1187
|
if (!Number.isInteger(_) || _ < 0) throw new r(`voltro db branch: --pr must be a non-negative integer, got "${String(g)}"`);
|
|
1188
|
-
let v =
|
|
1188
|
+
let v = ne(h, _), y = await l(u), b = y.makeSqlLayer(f), x = y.makeSqlLayer({
|
|
1189
1189
|
...f,
|
|
1190
1190
|
schema: v
|
|
1191
|
-
}), S = await Y(b), C =
|
|
1191
|
+
}), S = await Y(b), C = F({
|
|
1192
1192
|
declared: d,
|
|
1193
1193
|
live: S,
|
|
1194
1194
|
dialect: u,
|
|
1195
|
-
...
|
|
1195
|
+
...N(),
|
|
1196
1196
|
...c === void 0 ? {} : { onlineAfter: c }
|
|
1197
|
-
}), w = S.tables.map((e) => e.name), T = Qt(S), E = $t(S), D =
|
|
1197
|
+
}), w = S.tables.map((e) => e.name), T = Qt(S), E = $t(S), D = ce({ run: (e) => J(b, M.SqlClient.pipe(j.flatMap((t) => t.unsafe(e)), j.asVoid)) }), O = async () => F({
|
|
1198
1198
|
declared: d,
|
|
1199
1199
|
live: await Y(x),
|
|
1200
1200
|
dialect: u,
|
|
1201
|
-
...
|
|
1201
|
+
...N(),
|
|
1202
1202
|
...c === void 0 ? {} : { onlineAfter: c }
|
|
1203
|
-
}),
|
|
1203
|
+
}), k = await Te({
|
|
1204
1204
|
branchId: v,
|
|
1205
1205
|
mechanism: p,
|
|
1206
1206
|
branchedTables: w.length,
|
|
@@ -1210,7 +1210,7 @@ var Pe = (e) => typeof e != "string", Fe = (e, t, n, r) => {
|
|
|
1210
1210
|
o || B.info(`db branch: ${e}`);
|
|
1211
1211
|
},
|
|
1212
1212
|
provision: async () => {
|
|
1213
|
-
await
|
|
1213
|
+
await le({
|
|
1214
1214
|
appSlug: h,
|
|
1215
1215
|
prNumber: _,
|
|
1216
1216
|
seed: n,
|
|
@@ -1225,23 +1225,23 @@ var Pe = (e) => typeof e != "string", Fe = (e, t, n, r) => {
|
|
|
1225
1225
|
fidelityPlan: async () => en(C, await O()),
|
|
1226
1226
|
plan: O,
|
|
1227
1227
|
apply: async (e) => {
|
|
1228
|
-
await J(x,
|
|
1228
|
+
await J(x, M.SqlClient.pipe(j.flatMap((t) => he(t, e, {
|
|
1229
1229
|
declared: d,
|
|
1230
1230
|
appliedBy: "cli:db-branch",
|
|
1231
1231
|
environment: $(),
|
|
1232
1232
|
source: "auto-diff",
|
|
1233
1233
|
notes: `migration rehearsal on branch ${v}`,
|
|
1234
|
-
replan: () =>
|
|
1234
|
+
replan: () => j.promise(O)
|
|
1235
1235
|
}))));
|
|
1236
1236
|
},
|
|
1237
1237
|
replan: async () => await O(),
|
|
1238
1238
|
teardown: async () => {
|
|
1239
|
-
await
|
|
1239
|
+
await pe(v, "namespace", D);
|
|
1240
1240
|
}
|
|
1241
1241
|
});
|
|
1242
|
-
return o ? te(1, `${JSON.stringify(
|
|
1242
|
+
return o ? te(1, `${JSON.stringify(k, null, 2)}\n`) : console.log(`\n${Se(k)}\n`), ve(k);
|
|
1243
1243
|
}, an = async (e) => {
|
|
1244
|
-
let t = Math.max(1, Number(s(e, "--limit") ?? "20")), n = await J(await q(),
|
|
1244
|
+
let t = Math.max(1, Number(s(e, "--limit") ?? "20")), n = await J(await q(), M.SqlClient.pipe(j.flatMap((e) => e`
|
|
1245
1245
|
SELECT ${e("id")}, ${e("fingerprint")}, ${e("operations")},
|
|
1246
1246
|
${e("appliedBy")}, ${e("environment")}, ${e("source")},
|
|
1247
1247
|
${e("durationMs")}, ${e("notes")}, ${e("appliedAt")}
|
|
@@ -1256,13 +1256,13 @@ var Pe = (e) => typeof e != "string", Fe = (e, t, n, r) => {
|
|
|
1256
1256
|
try {
|
|
1257
1257
|
t = JSON.parse(un(e.operations)).length;
|
|
1258
1258
|
} catch {}
|
|
1259
|
-
console.log(` ${e.id} fp=${
|
|
1259
|
+
console.log(` ${e.id} fp=${I(e.fingerprint)} env=${e.environment} src=${e.source} ${t} op(s) ${e.durationMs}ms ${dn(e.appliedAt)} by=${e.appliedBy}`), e.notes && console.log(` [2mnote: ${e.notes}[0m`);
|
|
1260
1260
|
}
|
|
1261
1261
|
return console.log(), 0;
|
|
1262
1262
|
}, on = async (e) => {
|
|
1263
1263
|
let t = e[0];
|
|
1264
1264
|
if (!t) return console.error("voltro db restore-snapshot <plan-id>"), console.error(" Renames soft-dropped columns/tables from a plan back to their original names."), console.error(" Requires the plan to have been applied with VOLTRO_SOFT_DROP=1."), 2;
|
|
1265
|
-
let n = await q(), r = await J(n,
|
|
1265
|
+
let n = await q(), r = await J(n, M.SqlClient.pipe(j.flatMap((e) => e`SELECT ${e("id")}, ${e("operations")}
|
|
1266
1266
|
FROM ${e("_voltro_migration_plans")} WHERE ${e("id")} = ${t}`)));
|
|
1267
1267
|
if (r.length === 0) return console.error(`restore-snapshot: plan '${t}' not found`), 1;
|
|
1268
1268
|
let i;
|
|
@@ -1281,7 +1281,7 @@ var Pe = (e) => typeof e != "string", Fe = (e, t, n, r) => {
|
|
|
1281
1281
|
if (a.length === 0 && o.length === 0) return console.log(`restore-snapshot: plan '${t}' has no drop-column / drop-table ops to restore`), 0;
|
|
1282
1282
|
let s = 0;
|
|
1283
1283
|
for (let e of a) {
|
|
1284
|
-
let t = await J(n,
|
|
1284
|
+
let t = await J(n, M.SqlClient.pipe(j.flatMap((t) => t`
|
|
1285
1285
|
SELECT column_name FROM information_schema.columns
|
|
1286
1286
|
WHERE ${t.unsafe(K(W()))}
|
|
1287
1287
|
AND table_name = ${e.table}
|
|
@@ -1293,11 +1293,11 @@ var Pe = (e) => typeof e != "string", Fe = (e, t, n, r) => {
|
|
|
1293
1293
|
continue;
|
|
1294
1294
|
}
|
|
1295
1295
|
let r = t[0].column_name;
|
|
1296
|
-
await J(n,
|
|
1296
|
+
await J(n, M.SqlClient.pipe(j.flatMap((t) => t.unsafe(`ALTER TABLE ${G(e.table)} RENAME COLUMN ${G(r)} TO ${G(e.column)}`)))), s++, console.log(` ↩ restored ${e.table}.${e.column} (from ${r})`);
|
|
1297
1297
|
}
|
|
1298
1298
|
let c = 0;
|
|
1299
1299
|
for (let e of o) {
|
|
1300
|
-
let t = await J(n,
|
|
1300
|
+
let t = await J(n, M.SqlClient.pipe(j.flatMap((t) => t`
|
|
1301
1301
|
SELECT table_name FROM information_schema.tables
|
|
1302
1302
|
WHERE ${t.unsafe(K(W()))}
|
|
1303
1303
|
AND table_name LIKE ${e.table + "__dropped_%"}
|
|
@@ -1308,7 +1308,7 @@ var Pe = (e) => typeof e != "string", Fe = (e, t, n, r) => {
|
|
|
1308
1308
|
continue;
|
|
1309
1309
|
}
|
|
1310
1310
|
let r = t[0].table_name;
|
|
1311
|
-
await J(n,
|
|
1311
|
+
await J(n, M.SqlClient.pipe(j.flatMap((t) => t.unsafe(`ALTER TABLE ${G(r)} RENAME TO ${G(e.table)}`)))), c++, console.log(` ↩ restored table ${e.table} (from ${r})`);
|
|
1312
1312
|
}
|
|
1313
1313
|
return console.log(`\n✓ restored ${s} column(s) + ${c} table(s) from plan '${t}'\n`), 0;
|
|
1314
1314
|
}, sn = async (e) => {
|
|
@@ -1316,10 +1316,10 @@ var Pe = (e) => typeof e != "string", Fe = (e, t, n, r) => {
|
|
|
1316
1316
|
if (!t) return console.error("voltro db gc-snapshots --before <date> [--dry-run]"), console.error(" Permanently drops soft-dropped columns/tables (<name>__dropped_<ts>) older than <date>."), console.error(" <date> is ISO — e.g. 2026-01-01 or 2026-01-01T00:00:00Z. NOT reversible."), 2;
|
|
1317
1317
|
let n = t.replace(/[^0-9]/g, "");
|
|
1318
1318
|
if (n.length < 8) return console.error(`gc-snapshots: --before must be at least a full date (YYYY-MM-DD), got "${t}"`), 2;
|
|
1319
|
-
let r = (n + "00000000000000").slice(0, 14), i = e.includes("--dry-run"), a = await q(), o = await J(a,
|
|
1319
|
+
let r = (n + "00000000000000").slice(0, 14), i = e.includes("--dry-run"), a = await q(), o = await J(a, M.SqlClient.pipe(j.flatMap((e) => e`
|
|
1320
1320
|
SELECT table_name, column_name FROM information_schema.columns
|
|
1321
1321
|
WHERE ${e.unsafe(K(W()))} AND column_name LIKE ${"%__dropped_%"}
|
|
1322
|
-
`))), c = await J(a,
|
|
1322
|
+
`))), c = await J(a, M.SqlClient.pipe(j.flatMap((e) => e`
|
|
1323
1323
|
SELECT table_name FROM information_schema.tables
|
|
1324
1324
|
WHERE ${e.unsafe(K(W()))} AND table_name LIKE ${"%__dropped_%"}
|
|
1325
1325
|
`))), l = (e) => {
|
|
@@ -1328,11 +1328,11 @@ var Pe = (e) => typeof e != "string", Fe = (e, t, n, r) => {
|
|
|
1328
1328
|
}, u = 0;
|
|
1329
1329
|
for (let e of o) {
|
|
1330
1330
|
let t = l(e.column_name);
|
|
1331
|
-
t === null || t >= r || (console.log(` ${i ? "[dry-run] would drop column" : "dropping column"} ${e.table_name}.${e.column_name}`), i || await J(a,
|
|
1331
|
+
t === null || t >= r || (console.log(` ${i ? "[dry-run] would drop column" : "dropping column"} ${e.table_name}.${e.column_name}`), i || await J(a, M.SqlClient.pipe(j.flatMap((t) => t.unsafe(`ALTER TABLE ${G(e.table_name)} DROP COLUMN ${G(e.column_name)}`)))), u++);
|
|
1332
1332
|
}
|
|
1333
1333
|
for (let e of c) {
|
|
1334
1334
|
let t = l(e.table_name);
|
|
1335
|
-
t === null || t >= r || (console.log(` ${i ? "[dry-run] would drop table" : "dropping table"} ${e.table_name}`), i || await J(a,
|
|
1335
|
+
t === null || t >= r || (console.log(` ${i ? "[dry-run] would drop table" : "dropping table"} ${e.table_name}`), i || await J(a, M.SqlClient.pipe(j.flatMap((t) => t.unsafe(`DROP TABLE ${G(e.table_name)}`)))), u++);
|
|
1336
1336
|
}
|
|
1337
1337
|
return console.log(`\n${i ? `[dry-run] ${u} snapshot(s) would be dropped` : `✓ dropped ${u} snapshot(s)`} (older than ${r}).\n`), 0;
|
|
1338
1338
|
}, cn = async (e) => {
|
|
@@ -1342,23 +1342,23 @@ var Pe = (e) => typeof e != "string", Fe = (e, t, n, r) => {
|
|
|
1342
1342
|
if (Number.isNaN(new Date(n).getTime())) return console.error(`voltro db squash: --before '${n}' is not a valid ISO date`), 2;
|
|
1343
1343
|
let r = s(e, "--note"), i = H(e), a = await Z(i);
|
|
1344
1344
|
if (a === void 0) return B.warn("db squash: no schema files found", { root: i }), 1;
|
|
1345
|
-
let o =
|
|
1345
|
+
let o = xe(ye(a)), c = await q();
|
|
1346
1346
|
try {
|
|
1347
|
-
let e = await J(c,
|
|
1347
|
+
let e = await J(c, ke({
|
|
1348
1348
|
before: n,
|
|
1349
1349
|
fingerprint: o,
|
|
1350
1350
|
appliedBy: process.env.USER ?? "cli",
|
|
1351
1351
|
environment: $(),
|
|
1352
1352
|
...r === void 0 ? {} : { note: r }
|
|
1353
1353
|
}));
|
|
1354
|
-
return console.log(`\n✓ squashed ${e.squashedCount} migration plan(s)\n snapshot id: ${e.snapshotId}\n fingerprint: ${
|
|
1354
|
+
return console.log(`\n✓ squashed ${e.squashedCount} migration plan(s)\n snapshot id: ${e.snapshotId}\n fingerprint: ${I(e.snapshotFingerprint)}\n`), 0;
|
|
1355
1355
|
} catch (e) {
|
|
1356
1356
|
return console.error(`squash refused: ${e.message}`), 1;
|
|
1357
1357
|
}
|
|
1358
1358
|
}, ln = async (e) => {
|
|
1359
1359
|
try {
|
|
1360
|
-
let t = await Y(e), n =
|
|
1361
|
-
await J(e,
|
|
1360
|
+
let t = await Y(e), n = xe(t);
|
|
1361
|
+
await J(e, M.SqlClient.pipe(j.flatMap((e) => e`
|
|
1362
1362
|
UPDATE ${e("_voltro_migration_plans")}
|
|
1363
1363
|
SET ${e("liveFingerprint")} = ${n}
|
|
1364
1364
|
WHERE ${e("id")} = (
|
|
@@ -1380,23 +1380,23 @@ var Pe = (e) => typeof e != "string", Fe = (e, t, n, r) => {
|
|
|
1380
1380
|
accept: !0,
|
|
1381
1381
|
reason: "converged"
|
|
1382
1382
|
}, pn = async (e) => {
|
|
1383
|
-
let t = e.includes("--accept"), n = await q(), r = await J(n,
|
|
1383
|
+
let t = e.includes("--accept"), n = await q(), r = await J(n, M.SqlClient.pipe(j.flatMap((e) => e`
|
|
1384
1384
|
SELECT * FROM ${e("_voltro_migration_plans")}
|
|
1385
1385
|
ORDER BY ${e("appliedAt")} DESC
|
|
1386
1386
|
LIMIT 1
|
|
1387
|
-
`))), i = await Y(n), a =
|
|
1388
|
-
if (r.length === 0) return B.info("db drift: no _voltro_migration_plans rows yet"), console.log(`live user-schema fingerprint: ${
|
|
1387
|
+
`))), i = await Y(n), a = xe(i);
|
|
1388
|
+
if (r.length === 0) return B.info("db drift: no _voltro_migration_plans rows yet"), console.log(`live user-schema fingerprint: ${I(a)}`), console.log("No baseline to compare against. Run `voltro db apply` to lock in the current state."), 0;
|
|
1389
1389
|
let o = r[0];
|
|
1390
|
-
if (o.liveFingerprint === null || o.liveFingerprint === void 0) return B.warn("db drift: no drift baseline recorded yet — cannot compare"), console.log(), console.log(` last applied: ${o.id} at ${dn(o.appliedAt)}`), console.log(` live now: ${
|
|
1391
|
-
if (o.liveFingerprint === a) return B.info(`db drift: live matches last applied (${
|
|
1390
|
+
if (o.liveFingerprint === null || o.liveFingerprint === void 0) return B.warn("db drift: no drift baseline recorded yet — cannot compare"), console.log(), console.log(` last applied: ${o.id} at ${dn(o.appliedAt)}`), console.log(` live now: ${I(a)}`), console.log(), console.log("That row was written before the framework recorded a live-schema baseline,"), console.log("and the value it does carry is the DECLARED snapshot's hash — not comparable"), console.log("with a live one. Run `voltro db apply` once to establish the baseline (a no-op"), console.log("apply backfills it too); use `voltro db plan` meanwhile, which compares declared"), console.log("against live directly."), console.log(), console.log("Exit code 3 — NOT 0. \"Did not compare\" is not \"clean\", and a gate on the exit"), console.log("code has to be able to tell them apart."), 3;
|
|
1391
|
+
if (o.liveFingerprint === a) return B.info(`db drift: live matches last applied (${I(a)})`), 0;
|
|
1392
1392
|
let s = await (async () => {
|
|
1393
1393
|
try {
|
|
1394
1394
|
let t = await Z(H(e));
|
|
1395
|
-
return t === void 0 ? void 0 :
|
|
1395
|
+
return t === void 0 ? void 0 : F({
|
|
1396
1396
|
declared: t,
|
|
1397
1397
|
live: i,
|
|
1398
1398
|
dialect: W(),
|
|
1399
|
-
...
|
|
1399
|
+
...N()
|
|
1400
1400
|
}).operations;
|
|
1401
1401
|
} catch {
|
|
1402
1402
|
return;
|
|
@@ -1410,7 +1410,7 @@ var Pe = (e) => typeof e != "string", Fe = (e, t, n, r) => {
|
|
|
1410
1410
|
for (let e of s.slice(0, 10)) console.log(` - ${e.op.kind} ${"table" in e.op ? `[${e.op.table}]` : ""}`);
|
|
1411
1411
|
return s.length > 10 && console.log(` … and ${s.length - 10} more`), console.log(), console.log("`--accept` records the CURRENT live schema as the applied baseline. It is for a"), console.log("change that already landed out of band and left the schema correct — not for one"), console.log("that has not landed. Run `voltro db apply` instead; it writes a real baseline."), 4;
|
|
1412
1412
|
}
|
|
1413
|
-
return await J(n,
|
|
1413
|
+
return await J(n, M.SqlClient.pipe(j.flatMap((e) => e`
|
|
1414
1414
|
UPDATE ${e("_voltro_migration_plans")}
|
|
1415
1415
|
SET ${e("liveFingerprint")} = ${a}
|
|
1416
1416
|
WHERE ${e("id")} = (
|
|
@@ -1419,13 +1419,13 @@ var Pe = (e) => typeof e != "string", Fe = (e, t, n, r) => {
|
|
|
1419
1419
|
ORDER BY ${e("appliedAt")} DESC LIMIT 1
|
|
1420
1420
|
) AS ${e("newest")}
|
|
1421
1421
|
)
|
|
1422
|
-
`))), B.info(`db drift: accepted the live schema as the baseline (${
|
|
1422
|
+
`))), B.info(`db drift: accepted the live schema as the baseline (${I(a)})`), console.log(), console.log("`voltro db plan` reports 0 operations against this schema, so the live state already"), console.log("matches your declaration — only the ledger did not know. It does now."), console.log(), console.log("No history entry was invented: the latest row's baseline was updated in place,"), console.log("because no migration ran."), 0;
|
|
1423
1423
|
}
|
|
1424
|
-
return B.error("db drift: live schema DIVERGED from last applied state"), console.log(), console.log(` baseline: ${
|
|
1424
|
+
return B.error("db drift: live schema DIVERGED from last applied state"), console.log(), console.log(` baseline: ${I(o.liveFingerprint)} at ${dn(o.appliedAt)} (${o.id})`), console.log(` live now: ${I(a)}`), console.log(), console.log("Something changed the live schema after the last apply. This command can see"), console.log("THAT it changed, not what or who — the fingerprints are hashes, not a diff."), console.log(), s === void 0 ? (console.log("No schema files found here, so the declared side could not be compared."), console.log("Run `voltro db plan` from your project root for the actual difference."), 4) : s.length === 0 ? (console.log("Your DECLARED schema is already satisfied — `voltro db plan` reports 0 operations"), console.log("against this database. So the live schema is not wrong, only unrecorded: something"), console.log("applied a change without going through the planner (a hand-run ALTER, a DBA"), console.log("window, a restored dump), or it touched a table your code does not declare."), console.log(), console.log("If that was deliberate and the schema is right, record it:"), console.log(), console.log(" voltro db drift --accept"), console.log(), console.log("It updates the latest ledger row's baseline to the live schema and invents no"), console.log("history entry. Drift then measures from here."), 4) : (console.log(`\`voltro db plan\` reports ${s.length} operation(s) still pending against your`), console.log("declared schema, so this is not merely an unrecorded change — run it for the diff,"), console.log("then `voltro db apply`, which writes a fresh baseline of its own."), 4);
|
|
1425
1425
|
}, mn = async (e, t) => {
|
|
1426
1426
|
let n = $();
|
|
1427
1427
|
try {
|
|
1428
|
-
let r = await J(t,
|
|
1428
|
+
let r = await J(t, M.SqlClient.pipe(j.flatMap((t) => Oe(t, {
|
|
1429
1429
|
projectRoot: e,
|
|
1430
1430
|
env: n,
|
|
1431
1431
|
appliedBy: process.env.USER ? `cli:${process.env.USER}` : "cli:user"
|
|
@@ -1436,8 +1436,8 @@ var Pe = (e) => typeof e != "string", Fe = (e, t, n, r) => {
|
|
|
1436
1436
|
}
|
|
1437
1437
|
}, hn = async (e) => {
|
|
1438
1438
|
let t = H(e), n = await q(), r = $();
|
|
1439
|
-
await J(n,
|
|
1440
|
-
let i = await J(n,
|
|
1439
|
+
await J(n, ge(ae, W(), void 0, { retryFilter: (await l(W())).retryFilter }));
|
|
1440
|
+
let i = await J(n, M.SqlClient.pipe(j.flatMap((e) => Oe(e, {
|
|
1441
1441
|
projectRoot: t,
|
|
1442
1442
|
env: r,
|
|
1443
1443
|
appliedBy: process.env.USER ? `cli:${process.env.USER}` : "cli:user"
|
|
@@ -1450,7 +1450,7 @@ var Pe = (e) => typeof e != "string", Fe = (e, t, n, r) => {
|
|
|
1450
1450
|
let n = H(e), r = c(e, Dt);
|
|
1451
1451
|
if (!r) return B.error("voltro db rollback-file <migration-id>"), 2;
|
|
1452
1452
|
if ((process.env.NODE_ENV ?? "").toLowerCase() === "production") return B.error("voltro db rollback-file: refusing on prod — schema rollback runs as an explicit deploy step." + t()), 3;
|
|
1453
|
-
let i = await J(await q(),
|
|
1453
|
+
let i = await J(await q(), M.SqlClient.pipe(j.flatMap((e) => Ee(e, {
|
|
1454
1454
|
projectRoot: n,
|
|
1455
1455
|
id: r
|
|
1456
1456
|
}))));
|
|
@@ -1529,14 +1529,14 @@ export default defineMigration({
|
|
|
1529
1529
|
into: r,
|
|
1530
1530
|
map: o.map,
|
|
1531
1531
|
...o.leaveUnset ? { leaveUnset: o.leaveUnset } : {}
|
|
1532
|
-
}, c = W(), l = await q(), u = await J(l,
|
|
1532
|
+
}, c = W(), l = await q(), u = await J(l, M.SqlClient.pipe(j.flatMap(P))), d = (e) => u.tables.find((t) => t.name === e)?.columns.map((e) => ({
|
|
1533
1533
|
name: e.name,
|
|
1534
1534
|
nullable: e.nullable,
|
|
1535
1535
|
hasDefault: e.defaultValue !== void 0 && e.defaultValue !== null
|
|
1536
1536
|
})), f = d(n), p = d(r);
|
|
1537
1537
|
if (f === void 0) return console.error(`voltro db adopt: '${n}' does not exist in the database`), 1;
|
|
1538
1538
|
if (p === void 0) return console.error(`voltro db adopt: '${r}' does not exist in the database — boot once so the plugin's table is created`), 1;
|
|
1539
|
-
let m = async (e) => await J(l,
|
|
1539
|
+
let m = async (e) => await J(l, M.SqlClient.pipe(j.flatMap((t) => t.unsafe(e)))), h = async (e) => Number(Object.values((await m(`SELECT COUNT(*) AS n FROM "${e}"`))[0] ?? { n: 0 })[0] ?? 0), g = Fe(s, f, p, await h(r));
|
|
1540
1540
|
for (let e of Le(s, g, await h(n))) console.log(e);
|
|
1541
1541
|
if (g.fatal) return 1;
|
|
1542
1542
|
if (!e.includes("--apply")) return console.log(""), console.log(" (dry run — nothing written. Re-run with --apply.)"), 0;
|
|
@@ -1555,7 +1555,7 @@ export default defineMigration({
|
|
|
1555
1555
|
column: o
|
|
1556
1556
|
});
|
|
1557
1557
|
}
|
|
1558
|
-
let i = [...Ue, ...n], a = await J(await q(),
|
|
1558
|
+
let i = [...Ue, ...n], a = await J(await q(), M.SqlClient.pipe(j.flatMap((e) => j.promise(() => tt(e, t, i, G)))));
|
|
1559
1559
|
return console.log(nt(a, t)), rt(a);
|
|
1560
1560
|
},
|
|
1561
1561
|
"encrypt-column": async (e) => {
|
|
@@ -1568,15 +1568,15 @@ export default defineMigration({
|
|
|
1568
1568
|
if (d.length === 0) throw new r("voltro db encrypt-column: name at least one <table>.<column>");
|
|
1569
1569
|
let f = await q(), p = [];
|
|
1570
1570
|
for (let e of d) {
|
|
1571
|
-
let a = G(e.table), o = G(e.column), l = await J(f,
|
|
1572
|
-
let i = await
|
|
1571
|
+
let a = G(e.table), o = G(e.column), l = await J(f, M.SqlClient.pipe(j.flatMap((n) => j.promise(async () => {
|
|
1572
|
+
let i = await j.runPromise(n.unsafe(wt(t, e, K(t))));
|
|
1573
1573
|
if (i.length === 0) throw new r(`voltro db encrypt-column: ${e.table}.${e.column} does not exist on this database`);
|
|
1574
1574
|
return Tt(Object.values(i[0])[0]);
|
|
1575
|
-
})))), d = await J(f,
|
|
1576
|
-
for (let e of d) typeof e.v != "string" ||
|
|
1575
|
+
})))), d = await J(f, M.SqlClient.pipe(j.flatMap((e) => j.promise(async () => await j.runPromise(e.unsafe(`SELECT ${G("id")} AS id, ${o} AS v FROM ${a}`)))))), m = 0;
|
|
1576
|
+
for (let e of d) typeof e.v != "string" || A(e.v) || (m = Math.max(m, yt(e.v)));
|
|
1577
1577
|
let h = mt(m, l);
|
|
1578
1578
|
if (!h.fits) return console.error(` ✗ ${ht(e, h)}`), 1;
|
|
1579
|
-
if (bt(d.map((e) => e.v).find((e) => typeof e == "string" &&
|
|
1579
|
+
if (bt(d.map((e) => e.v).find((e) => typeof e == "string" && A(e)), u) === !1) return console.error(` ✗ ${xt(e, c)}`), 1;
|
|
1580
1580
|
let g = d.filter((t) => _t(t.v, u, e) !== void 0 || Ct(t.v, u, e) !== void 0).length;
|
|
1581
1581
|
if (!n && !i) return console.error(` ✗ ${e.table}.${e.column}: ${g} row(s) would be rewritten in place. Re-run with --yes, or --dry-run to see the counts without writing.`), 1;
|
|
1582
1582
|
let _ = 0, v = 0, y = 0, b = 0, x = [];
|
|
@@ -1585,7 +1585,7 @@ export default defineMigration({
|
|
|
1585
1585
|
y += 1;
|
|
1586
1586
|
continue;
|
|
1587
1587
|
}
|
|
1588
|
-
if (typeof t.v == "string" &&
|
|
1588
|
+
if (typeof t.v == "string" && A(t.v)) {
|
|
1589
1589
|
let n = Ct(t.v, u, e);
|
|
1590
1590
|
if (n === void 0) {
|
|
1591
1591
|
_ += 1;
|
|
@@ -1609,8 +1609,8 @@ export default defineMigration({
|
|
|
1609
1609
|
}
|
|
1610
1610
|
if (!n && x.length > 0) for (let t = 0; t < x.length; t += s) {
|
|
1611
1611
|
let n = x.slice(t, t + s);
|
|
1612
|
-
await J(f,
|
|
1613
|
-
for (let r of n) await
|
|
1612
|
+
await J(f, M.SqlClient.pipe(j.flatMap((t) => j.promise(async () => {
|
|
1613
|
+
for (let r of n) await j.runPromise(t`UPDATE ${t(e.table)} SET ${t(e.column)} = ${r.value} WHERE ${t("id")} = ${r.id}`);
|
|
1614
1614
|
})))), B.info(`encrypt-column ${e.table}.${e.column}: ${Math.min(t + n.length, x.length)}/${x.length}`);
|
|
1615
1615
|
}
|
|
1616
1616
|
p.push({
|