@voltro/cli 0.36.0 → 0.38.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.
Files changed (126) hide show
  1. package/CHANGELOG.md +182 -0
  2. package/dist/{apiBuild-DiE9zcj6.js → apiBuild-CvacV4zA.js} +2 -2
  3. package/dist/apiBuild-ttSDDOGp.js +2 -0
  4. package/dist/{baselineCommand-DIttzO8A.js → baselineCommand-C6NMt-oa.js} +1 -4
  5. package/dist/baselineCommand-Cfw2Afwm.js +2 -0
  6. package/dist/bin.js +1 -1
  7. package/dist/bootRefusal-pgvDxlrU.js +7 -0
  8. package/dist/{build-DBe6c7qC.js → build-_LoTC1s0.js} +31 -31
  9. package/dist/{checkCommand-BhG0gmUD.js → checkCommand-Pjk5sBl2.js} +3 -3
  10. package/dist/{checkCommand-BTA6P3Yr.js → checkCommand-wibtQx-N.js} +1 -1
  11. package/dist/{cloudCmd-Cvv5HGaZ.js → cloudCmd-NQSwe_Qk.js} +1 -1
  12. package/dist/{codegen-CYM3Zqrf.js → codegen-GYYcdpCg.js} +2 -2
  13. package/dist/codegen-uYrrDzQv.js +2 -0
  14. package/dist/{codegenCommand-DH-8ZXzR.js → codegenCommand-C60m_LCp.js} +2 -2
  15. package/dist/{codemodRunner-DjQGrdmg.js → codemodRunner-CXgQ-ecJ.js} +339 -167
  16. package/dist/{commands-Bp7utV-7.js → commands-DaZVi9wi.js} +74 -73
  17. package/dist/{dashboardCommand-D5Jwjmr1.js → dashboardCommand-Dxy_kmoW.js} +3 -3
  18. package/dist/{dataCommand-DnCm0B2C.js → dataCommand-D6-Ha2lf.js} +2 -2
  19. package/dist/{dbCommand-O8HA63s2.js → dbCommand-C4UW8cVN.js} +353 -351
  20. package/dist/dbCommand-CC-qNzpz.js +2 -0
  21. package/dist/{dev-BSFTgCQ5.js → dev-CAOoXOkc.js} +1 -1
  22. package/dist/{dev-Dc4cpmRl.js → dev-E7Eo5GHc.js} +262 -261
  23. package/dist/doctorCommand-Cjl8Yii8.js +2 -0
  24. package/dist/{doctorCommand-CNFtt3nR.js → doctorCommand-gmDyALFL.js} +10 -10
  25. package/dist/{dormancyCommand-6F6NsJKf.js → dormancyCommand-CE6wG8lj.js} +1 -1
  26. package/dist/{embeddingsCommand-DRRdneJD.js → embeddingsCommand-C3uAuf6N.js} +1 -1
  27. package/dist/{envCommand-TZzcyqZ-.js → envCommand-DzuWh8ya.js} +19 -19
  28. package/dist/{evolveCommand-iU35TPjT.js → evolveCommand-DPLqcYb2.js} +2 -2
  29. package/dist/index.js +2 -2
  30. package/dist/{infoCommand-unqisJGp.js → infoCommand-CmczGj_l.js} +1 -1
  31. package/dist/inspectGateHint-BF6608UT.js +4 -0
  32. package/dist/{metaCommands-7MJfZ5cf.js → metaCommands-CIoQNlaQ.js} +1 -1
  33. package/dist/{migrate-BV7I-ZHZ.js → migrate-RwgUWXfc.js} +1 -1
  34. package/dist/{privacyCommand-C-Df56U_.js → privacyCommand-XejDMvmu.js} +4 -3
  35. package/dist/{probeCommand-CZfaaUOZ.js → probeCommand-BPEpwT32.js} +40 -39
  36. package/dist/{projectScaffold-DmzEKHib.js → projectScaffold-CxgtJvlb.js} +1 -1
  37. package/dist/{projectScaffold-LMMtaavR.js → projectScaffold-DDgWbNLe.js} +2 -2
  38. package/dist/{runtimeTrace-D5LJ_N55.js → runtimeTrace-6jfznSzr.js} +1 -1
  39. package/dist/{sdkgen-82xVuvbt.js → sdkgen-CEJZZQUA.js} +1 -1
  40. package/dist/serveCommand-DNRF2nDI.js +2 -0
  41. package/dist/{serveCommand-VVGcIMIw.js → serveCommand-DnY4VS3D.js} +541 -540
  42. package/dist/serveEntry.js +1 -1
  43. package/dist/{start-BgN62boB.js → start-CidwCcjl.js} +1 -1
  44. package/dist/{start-T4VesWiM.js → start-RCh6qKFe.js} +24 -24
  45. package/dist/startEntry.js +1 -1
  46. package/dist/startup.d.ts +40 -1
  47. package/dist/startup.js +2 -2
  48. package/dist/startupRunner-CEqQq7ax.js +108 -0
  49. package/dist/subcommandNames-CKG5Dz3a.js +27 -0
  50. package/dist/{templates-De8IR5-c.js → templates-BR-fb4SP.js} +1 -4
  51. package/dist/{test-CI6iDsYc.js → test-DIQ0jlkQ.js} +1 -1
  52. package/dist/updateCommand-B0J_T9Vs.js +2 -0
  53. package/dist/{updateCommand-CwnUK_mf.js → updateCommand-CmksX7m_.js} +1 -1
  54. package/dist/{webDev-Dybxew86.js → webDev-BKdD7c_a.js} +689 -691
  55. package/dist/webDev-CcJfdSjl2.js +2 -0
  56. package/dist/{webhooksCommand-di1CJVzu.js → webhooksCommand-BHeaF1ZJ.js} +1 -1
  57. package/package.json +35 -17
  58. package/templates/AGENTS.md +1 -1
  59. package/templates/agent-docs/_index.md +1 -1
  60. package/templates/agent-docs/cli.md +16 -0
  61. package/templates/agent-docs/data.md +30 -0
  62. package/templates/agent-docs/plugins/audit.md +50 -0
  63. package/templates/agent-docs/plugins/auth.md +4 -6
  64. package/templates/agent-docs/reference.md +3 -2
  65. package/templates/agent-docs/whats-new.md +59 -35
  66. package/templates/apps/api-ai/package.json +7 -7
  67. package/templates/apps/api-auth/package.json +8 -8
  68. package/templates/apps/api-backend/package.json +7 -7
  69. package/templates/apps/api-backend-deactivation/package.json +7 -7
  70. package/templates/apps/api-backend-mail/package.json +8 -8
  71. package/templates/apps/api-backend-mariadb/package.json +9 -9
  72. package/templates/apps/api-backend-sqlite/package.json +8 -8
  73. package/templates/apps/api-backend-storage/package.json +8 -8
  74. package/templates/apps/api-cms/package.json +10 -10
  75. package/templates/apps/api-cms/tests/content.write.test.ts +16 -2
  76. package/templates/apps/api-collab/mutations/documents.setBody.mutation.server.ts +11 -5
  77. package/templates/apps/api-collab/package.json +8 -8
  78. package/templates/apps/api-collab/tests/documents.setBody.test.ts +8 -2
  79. package/templates/apps/api-data-advanced/package.json +8 -8
  80. package/templates/apps/api-durable/package.json +8 -8
  81. package/templates/apps/api-feature-flags/package.json +9 -9
  82. package/templates/apps/api-governance/package.json +8 -8
  83. package/templates/apps/api-kv/package.json +8 -8
  84. package/templates/apps/api-moderation/package.json +8 -8
  85. package/templates/apps/api-observability/package.json +8 -8
  86. package/templates/apps/api-ratelimit/package.json +8 -8
  87. package/templates/apps/api-rbac/package.json +8 -8
  88. package/templates/apps/api-rest/package.json +7 -7
  89. package/templates/apps/api-saas/package.json +11 -11
  90. package/templates/apps/api-saas-starter/package.json +10 -10
  91. package/templates/apps/api-search/package.json +8 -8
  92. package/templates/apps/api-status/package.json +8 -8
  93. package/templates/apps/api-versioning/mutations/documents.update.mutation.server.ts +7 -5
  94. package/templates/apps/api-versioning/package.json +8 -8
  95. package/templates/apps/api-webhooks/package.json +9 -9
  96. package/templates/apps/changelog/package.json +6 -6
  97. package/templates/apps/edge-functions/package.json +2 -2
  98. package/templates/apps/frontend-admin/package.json +8 -8
  99. package/templates/apps/frontend-app/package.json +9 -9
  100. package/templates/apps/frontend-auth/package.json +8 -8
  101. package/templates/apps/frontend-blank/package.json +7 -7
  102. package/templates/apps/frontend-cms/package.json +9 -9
  103. package/templates/apps/frontend-collab/package.json +10 -10
  104. package/templates/apps/frontend-contact/package.json +7 -7
  105. package/templates/apps/frontend-dashboard/package.json +7 -7
  106. package/templates/apps/frontend-docs/package.json +7 -7
  107. package/templates/apps/frontend-i18n/package.json +6 -6
  108. package/templates/apps/frontend-landing/package.json +7 -7
  109. package/templates/apps/frontend-portal/package.json +8 -8
  110. package/templates/apps/frontend-saas/package.json +8 -8
  111. package/templates/apps/frontend-spa/package.json +7 -7
  112. package/templates/apps/frontend-ssr/package.json +7 -7
  113. package/templates/apps/frontend-ssr-api/package.json +8 -8
  114. package/templates/apps/frontend-static-blog/package.json +6 -6
  115. package/templates/apps/frontend-status/package.json +8 -8
  116. package/templates/apps/mobile-app/package.json +3 -3
  117. package/templates/patches/@effect__cluster@0.60.0.patch +51 -3
  118. package/dist/apiBuild-ZEZnCXn2.js +0 -2
  119. package/dist/baselineCommand-C2ClWZN3.js +0 -2
  120. package/dist/codegen-ChBi_hVa.js +0 -2
  121. package/dist/dbCommand-DS4b97Is.js +0 -2
  122. package/dist/doctorCommand-BYffQc0s.js +0 -2
  123. package/dist/serveCommand-CEBVP36A.js +0 -2
  124. package/dist/startupRunner-DPGFchOa.js +0 -71
  125. package/dist/updateCommand-CSBXVsYq.js +0 -2
  126. package/dist/webDev-BcykISYQ2.js +0 -2
@@ -1,24 +1,26 @@
1
- import { n as e, r as t } from "./nodeEnvironment-cGFAj1J8.js";
2
- import { t as n } from "./cliError-BmdYnghb.js";
3
- import { n as r } from "./appModuleLoader-C9r9mxZt.js";
4
- import { a as i, i as a, n as o, t as s } from "./cliArgs-D4p8n7EE.js";
5
- import { r as c } from "./dialectDriver-CgXnDfec.js";
6
- import { a as l } from "./connectionConfig-UFlIEiys.js";
7
- import { i as u, n as d, r as f, s as p, t as m } from "./seedRunner-ZmLSqNe2.js";
8
- import { n as h, s as g, y as _ } from "./frameworkTableAssembly-oMPBKqlE.js";
9
- import { b as v, x as y } from "./fileConventions-Cof68_BL.js";
10
- import { basename as b, join as x, relative as S, resolve as C } from "node:path";
11
- import { promises as w, writeSync as ee } from "node:fs";
12
- import { pathToFileURL as T } from "node:url";
13
- import { createLogger as te } from "@voltro/logger";
14
- import { Effect as E } from "effect";
15
- import { SqlClient as D } from "@effect/sql";
16
- import { DEFAULT_CDC_CHANNEL as ne, applyPlan as re, applySchema as O, assessRollingDeployGate as k, branchRehearsalExitCode as ie, declaredSnapshot as A, destructiveScope as ae, fingerprintSchema as oe, formatBranchRehearsal as se, ignoreTablesFromEnv as j, introspectSchema as ce, pendingFileMigrationIds as le, planMigrations as M, recordUpToDate as ue, rehearseMigrationOnBranch as de, rollbackFileBasedMigration as fe, rollingDeployUnsafeOps as pe, runFileBasedMigrations as me, shortFingerprint as N, squashMigrationPlans as he, unblockLossy as ge } from "@voltro/database/sql";
17
- import { actorsTable as _e, branchNamespaceName as ve, frameworkTables as P, isEncrypted as F, isMigrationDefinition as ye, makeNamespaceBranchExecutor as be, provisionBranch as xe, quoteIdent as Se, registerCoreTables as Ce, resolveBranchMechanism as we, teardownBranch as Te } from "@voltro/database";
18
- import { InMemoryDataStore as Ee, makeFieldCipher as De } from "@voltro/runtime";
19
- import { createHash as Oe } from "node:crypto";
1
+ import { t as e } from "./subcommandNames-CKG5Dz3a.js";
2
+ import { n as t, r as n } from "./nodeEnvironment-cGFAj1J8.js";
3
+ import { t as r } from "./cliError-BmdYnghb.js";
4
+ import { n as i } from "./appModuleLoader-C9r9mxZt.js";
5
+ import { a, i as o, n as s, t as c } from "./cliArgs-D4p8n7EE.js";
6
+ import { r as l } from "./dialectDriver-CgXnDfec.js";
7
+ import { a as u } from "./connectionConfig-UFlIEiys.js";
8
+ import { i as d, n as f, r as p, s as m, t as h } from "./seedRunner-ZmLSqNe2.js";
9
+ import { n as g, s as _, y as v } from "./frameworkTableAssembly-oMPBKqlE.js";
10
+ import { b as y, x as b } from "./fileConventions-Cof68_BL.js";
11
+ import { n as ee, t as x } from "./inspectGateHint-BF6608UT.js";
12
+ import { basename as te, join as S, relative as C, resolve as w } from "node:path";
13
+ import { promises as T, writeSync as ne } from "node:fs";
14
+ import { pathToFileURL as E } from "node:url";
15
+ import { createLogger as D } from "@voltro/logger";
16
+ import { Effect as O } from "effect";
17
+ import { SqlClient as k } from "@effect/sql";
18
+ import { DEFAULT_CDC_CHANNEL as A, applyPlan as re, applySchema as ie, assessRollingDeployGate as ae, branchRehearsalExitCode as oe, declaredSnapshot as se, destructiveScope as ce, fingerprintSchema as le, formatBranchRehearsal as ue, ignoreTablesFromEnv as j, introspectSchema as de, pendingFileMigrationIds as fe, planMigrations as M, recordUpToDate as pe, rehearseMigrationOnBranch as me, rollbackFileBasedMigration as he, rollingDeployUnsafeOps as ge, runFileBasedMigrations as _e, shortFingerprint as N, squashMigrationPlans as ve, unblockLossy as ye } from "@voltro/database/sql";
19
+ import { actorsTable as be, branchNamespaceName as xe, frameworkTables as Se, isEncrypted as P, isMigrationDefinition as Ce, makeNamespaceBranchExecutor as we, provisionBranch as Te, quoteIdent as Ee, registerCoreTables as De, resolveBranchMechanism as Oe, teardownBranch as ke } from "@voltro/database";
20
+ import { InMemoryDataStore as Ae, makeFieldCipher as je } from "@voltro/runtime";
21
+ import { createHash as Me } from "node:crypto";
20
22
  //#region src/adoptPlan.ts
21
- var ke = (e) => typeof e != "string", Ae = (e, t, n, r) => {
23
+ var Ne = (e) => typeof e != "string", Pe = (e, t, n, r) => {
22
24
  let i = [], a = new Map(t.map((e) => [e.name, e])), o = new Map(n.map((e) => [e.name, e])), s = new Set(e.leaveUnset ?? []);
23
25
  r > 0 && i.push({
24
26
  kind: "target-not-empty",
@@ -35,7 +37,7 @@ var ke = (e) => typeof e != "string", Ae = (e, t, n, r) => {
35
37
  });
36
38
  continue;
37
39
  }
38
- if (ke(n)) {
40
+ if (Ne(n)) {
39
41
  c.push({
40
42
  target: t,
41
43
  source: n.expr,
@@ -78,23 +80,23 @@ var ke = (e) => typeof e != "string", Ae = (e, t, n, r) => {
78
80
  remintIds: f,
79
81
  fatal: i.some((e) => e.fatal)
80
82
  };
81
- }, je = (e, t) => [
83
+ }, Fe = (e, t) => [
82
84
  `back up '${e.from}' to a restorable dump`,
83
85
  `copy rows: INSERT INTO ${e.into} (${t.assignments.map((e) => e.target).join(", ")}) SELECT … FROM ${e.from}`,
84
86
  ...t.remintIds ? ["record old id → new id in a translation table", `rewrite every reference to '${e.from}', JSON columns included`] : [],
85
87
  "verify: row counts match and a sample round-trips",
86
88
  `drop '${e.from}' — LAST, and only after the verify`
87
- ], Me = (e, t, n) => {
89
+ ], Ie = (e, t, n) => {
88
90
  let r = [`adopt · ${e.from} (${n} row(s)) → ${e.into}`, ""];
89
91
  for (let e of t.assignments) r.push(` ${e.target.padEnd(24)} ← ${e.raw ? `${e.source} (raw)` : e.source}`);
90
92
  t.problems.length > 0 && r.push("");
91
93
  for (let e of t.problems) r.push(` ${e.fatal ? "✗" : "⚠"} ${e.detail}`);
92
94
  if (r.push(""), t.fatal) return r.push(" REFUSED — fix the problems above. Nothing was written."), r;
93
95
  r.push(" would run, in this order:");
94
- for (let [n, i] of je(e, t).entries()) r.push(` ${n + 1}. ${i}`);
96
+ for (let [n, i] of Fe(e, t).entries()) r.push(` ${n + 1}. ${i}`);
95
97
  return r;
96
- }, Ne = (e) => e === "mysql" || e === "mariadb" ? (e) => `\`${e}\`` : e === "mssql" ? (e) => `[${e}]` : (e) => `"${e}"`, Pe = (e) => `${e}__adopt_snapshot`, Fe = (e, t, n, r, i) => {
97
- let a = Ne(n), o = Pe(e.from), s = t.assignments.map((e) => e.target), c = t.assignments.map((e) => e.raw ? e.source : a(e.source));
98
+ }, Le = (e) => e === "mysql" || e === "mariadb" ? (e) => `\`${e}\`` : e === "mssql" ? (e) => `[${e}]` : (e) => `"${e}"`, Re = (e) => `${e}__adopt_snapshot`, ze = (e, t, n, r, i) => {
99
+ let a = Le(n), o = Re(e.from), s = t.assignments.map((e) => e.target), c = t.assignments.map((e) => e.raw ? e.source : a(e.source));
98
100
  return i !== void 0 && (s.unshift(r), c.unshift(i)), {
99
101
  snapshot: n === "mssql" ? `SELECT * INTO ${a(o)} FROM ${a(e.from)}` : `CREATE TABLE ${a(o)} AS SELECT * FROM ${a(e.from)}`,
100
102
  copy: `INSERT INTO ${a(e.into)} (${s.map(a).join(", ")}) SELECT ${c.join(", ")} FROM ${a(e.from)}`,
@@ -104,18 +106,18 @@ var ke = (e) => typeof e != "string", Ae = (e, t, n, r) => {
104
106
  drop: `DROP TABLE ${a(e.from)}`,
105
107
  dropSnapshot: `DROP TABLE ${a(o)}`
106
108
  };
107
- }, Ie = (e) => {
109
+ }, Be = (e) => {
108
110
  let t = e[0];
109
111
  if (t === void 0) return 0;
110
112
  let n = t.n ?? t.N ?? Object.values(t)[0];
111
113
  return Number(n ?? 0);
112
- }, Le = async (e, t, n, r, i, a, o = {}) => {
114
+ }, Ve = async (e, t, n, r, i, a, o = {}) => {
113
115
  if (t.fatal) throw Error("adopt: the plan was refused — nothing was run");
114
- let s = Fe(e, t, n, r, i), c = Pe(e.from), l = Ie(await a(s.verifySource));
116
+ let s = ze(e, t, n, r, i), c = Re(e.from), l = Be(await a(s.verifySource));
115
117
  await a(s.snapshot);
116
118
  for (let e of s.translations) await a(e);
117
119
  await a(s.copy);
118
- let u = Ie(await a(s.verifyTarget));
120
+ let u = Be(await a(s.verifyTarget));
119
121
  return u === l ? o.keepSource === !0 ? {
120
122
  copied: u,
121
123
  sourceRows: l,
@@ -135,7 +137,7 @@ var ke = (e) => typeof e != "string", Ae = (e, t, n, r) => {
135
137
  snapshotTable: c,
136
138
  sourceDropped: !1
137
139
  };
138
- }, I = [
140
+ }, F = [
139
141
  "token",
140
142
  "secret",
141
143
  "password",
@@ -144,7 +146,7 @@ var ke = (e) => typeof e != "string", Ae = (e, t, n, r) => {
144
146
  "credential",
145
147
  "privatekey",
146
148
  "private_key"
147
- ], Re = [
149
+ ], He = [
148
150
  {
149
151
  table: "_voltro_audit_log",
150
152
  column: "subject"
@@ -189,7 +191,7 @@ var ke = (e) => typeof e != "string", Ae = (e, t, n, r) => {
189
191
  table: "_voltro_row_history",
190
192
  column: "subjectId"
191
193
  }
192
- ], ze = (e, t) => {
194
+ ], Ue = (e, t) => {
193
195
  switch (t) {
194
196
  case "postgres": return `LOWER(CAST(${e} AS text))`;
195
197
  case "mysql":
@@ -198,17 +200,17 @@ var ke = (e) => typeof e != "string", Ae = (e, t, n, r) => {
198
200
  case "sqlite":
199
201
  case "turso": return `LOWER(CAST(${e} AS TEXT))`;
200
202
  }
201
- }, Be = (e, t, n = I) => n.map((n) => `${ze(e, t)} LIKE '%${n}%'`).join("\n OR "), Ve = ["_omitted", "__redacted"], He = (e, t) => {
203
+ }, We = (e, t, n = F) => n.map((n) => `${Ue(e, t)} LIKE '%${n}%'`).join("\n OR "), Ge = ["_omitted", "__redacted"], Ke = (e, t) => {
202
204
  let n = e.toLowerCase();
203
205
  return t.some((e) => n.includes(e));
204
- }, Ue = (e, t = []) => {
206
+ }, qe = (e, t = []) => {
205
207
  if (Array.isArray(e)) {
206
- for (let n of e) Ue(n, t);
208
+ for (let n of e) qe(n, t);
207
209
  return t;
208
210
  }
209
- if (typeof e == "object" && e) for (let [n, r] of Object.entries(e)) t.push(n), Ue(r, t);
211
+ if (typeof e == "object" && e) for (let [n, r] of Object.entries(e)) t.push(n), qe(r, t);
210
212
  return t;
211
- }, We = (e) => Array.isArray(e) ? e.map(We) : typeof e == "object" && e ? Object.fromEntries(Object.entries(e).map(([e, t]) => [e, Ve.includes(e) ? null : We(t)])) : e, Ge = (e, t = I) => {
213
+ }, Je = (e) => Array.isArray(e) ? e.map(Je) : typeof e == "object" && e ? Object.fromEntries(Object.entries(e).map(([e, t]) => [e, Ge.includes(e) ? null : Je(t)])) : e, Ye = (e, t = F) => {
212
214
  let n;
213
215
  try {
214
216
  n = JSON.parse(e);
@@ -220,33 +222,33 @@ var ke = (e) => typeof e != "string", Ae = (e, t, n, r) => {
220
222
  };
221
223
  }
222
224
  return {
223
- asKey: Ue(n).some((e) => He(e, t)),
224
- redactionMarkerOnly: !He(JSON.stringify(We(n)) ?? "", t),
225
+ asKey: qe(n).some((e) => Ke(e, t)),
226
+ redactionMarkerOnly: !Ke(JSON.stringify(Je(n)) ?? "", t),
225
227
  undecidable: !1
226
228
  };
227
- }, Ke = (e) => ({
229
+ }, Xe = (e) => ({
228
230
  examined: e.length,
229
231
  asKey: e.filter((e) => e.asKey).length,
230
232
  redactionMarkerOnly: e.filter((e) => e.redactionMarkerOnly && !e.asKey).length,
231
233
  undecidable: e.filter((e) => e.undecidable).length
232
- }), L = (e) => {
234
+ }), I = (e) => {
233
235
  let t = e.classification;
234
236
  return t === void 0 || e.hits === void 0 || e.hits === 0 ? !1 : t.examined === e.hits && t.undecidable === 0 && t.asKey === 0 && t.redactionMarkerOnly === e.hits;
235
- }, qe = (e, t, n, r) => {
236
- let i = `WHERE ${Be(t, n)}`, a = ze(t, n).replace(/^LOWER\((.*)\)$/s, "$1");
237
+ }, Ze = (e, t, n, r) => {
238
+ let i = `WHERE ${We(t, n)}`, a = Ue(t, n).replace(/^LOWER\((.*)\)$/s, "$1");
237
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}`;
238
- }, Je = async (e, t, n, r, i) => (await E.runPromise(e.unsafe(qe(t, n, r, i)))).map((e) => {
240
+ }, Qe = async (e, t, n, r, i) => (await O.runPromise(e.unsafe(Ze(t, n, r, i)))).map((e) => {
239
241
  let t = Object.values(e)[0];
240
242
  return typeof t == "string" ? t : JSON.stringify(t ?? null);
241
- }), Ye = async (e, t) => {
242
- let n = await E.runPromise(e.unsafe(t));
243
+ }), L = async (e, t) => {
244
+ let n = await O.runPromise(e.unsafe(t));
243
245
  return Number(Object.values(n[0] ?? { n: 0 })[0] ?? 0);
244
- }, Xe = async (e, t, n, r) => {
246
+ }, $e = async (e, t, n, r) => {
245
247
  let i = [];
246
248
  for (let a of n) {
247
249
  let n = r(a.table), o;
248
250
  try {
249
- o = await Ye(e, `SELECT COUNT(*) AS n FROM ${n}`);
251
+ o = await L(e, `SELECT COUNT(*) AS n FROM ${n}`);
250
252
  } catch {
251
253
  i.push({
252
254
  table: a.table,
@@ -258,9 +260,9 @@ var ke = (e) => typeof e != "string", Ae = (e, t, n, r) => {
258
260
  continue;
259
261
  }
260
262
  try {
261
- let s = await Ye(e, `SELECT COUNT(*) AS n FROM ${n}\n WHERE ${Be(r(a.column), t)}`), c = [];
262
- if (s > 0) for (let i of I) try {
263
- let o = await Ye(e, `SELECT COUNT(*) AS n FROM ${n}\n WHERE ${Be(r(a.column), t, [i])}`);
263
+ let s = await L(e, `SELECT COUNT(*) AS n FROM ${n}\n WHERE ${We(r(a.column), t)}`), c = [];
264
+ if (s > 0) for (let i of F) try {
265
+ let o = await L(e, `SELECT COUNT(*) AS n FROM ${n}\n WHERE ${We(r(a.column), t, [i])}`);
264
266
  o > 0 && c.push({
265
267
  needle: i,
266
268
  rows: o
@@ -268,7 +270,7 @@ var ke = (e) => typeof e != "string", Ae = (e, t, n, r) => {
268
270
  } catch {}
269
271
  let l;
270
272
  if (s > 0) try {
271
- l = Ke((await Je(e, n, r(a.column), t, 500)).map((e) => Ge(e)));
273
+ l = Xe((await Qe(e, n, r(a.column), t, 500)).map((e) => Ye(e)));
272
274
  } catch {}
273
275
  i.push({
274
276
  table: a.table,
@@ -289,8 +291,8 @@ var ke = (e) => typeof e != "string", Ae = (e, t, n, r) => {
289
291
  }
290
292
  }
291
293
  return i;
292
- }, Ze = (e, t) => {
293
- let n = I.length, r = [`credential scan · dialect ${t}`, ""], i = /* @__PURE__ */ new Set();
294
+ }, et = (e, t) => {
295
+ let n = F.length, r = [`credential scan · dialect ${t}`, ""], i = /* @__PURE__ */ new Set();
294
296
  for (let t of e) {
295
297
  if (t.unavailable === "column") {
296
298
  r.push(` · ${t.table}.${t.column} — column is not present on this deployment (${t.scanned} row(s) exist but this column was not scanned)`);
@@ -304,34 +306,34 @@ var ke = (e) => typeof e != "string", Ae = (e, t, n, r) => {
304
306
  r.push(` · ${t.table} — table is EMPTY (0 rows scanned; this is not a clean bill of health)`);
305
307
  continue;
306
308
  }
307
- let e = L(t), n = (t.hits ?? 0) === 0 ? "✓" : e ? "~" : "✗";
309
+ let e = I(t), n = (t.hits ?? 0) === 0 ? "✓" : e ? "~" : "✗";
308
310
  r.push(` ${n} ${t.table}.${t.column} — ${t.hits} of ${t.scanned} row(s) contain a credential-shaped NAME (anywhere in the value)`), (t.matchedNeedles?.length ?? 0) > 0 && r.push(` matched (rows per needle, may overlap): ${t.matchedNeedles.map((e) => `${e.needle} (${e.rows})`).join(", ")}`);
309
311
  let a = t.classification;
310
- a !== void 0 && (r.push(` examined ${a.examined} of ${t.hits} matched row(s)${a.examined < (t.hits ?? 0) ? " (capped at 500)" : ""}: ${a.asKey} as a JSON KEY, ${a.redactionMarkerOnly} only inside a redaction marker${a.undecidable > 0 ? `, ${a.undecidable} not parseable as JSON` : ""}`), e && r.push(` EXPLAINED — every match is \`${Ve.join("` / `")}\`, the framework's own`, " record that a `.sensitive()` column was left OUT. Nothing to purge, nothing to rotate."));
312
+ a !== void 0 && (r.push(` examined ${a.examined} of ${t.hits} matched row(s)${a.examined < (t.hits ?? 0) ? " (capped at 500)" : ""}: ${a.asKey} as a JSON KEY, ${a.redactionMarkerOnly} only inside a redaction marker${a.undecidable > 0 ? `, ${a.undecidable} not parseable as JSON` : ""}`), e && r.push(` EXPLAINED — every match is \`${Ge.join("` / `")}\`, the framework's own`, " record that a `.sensitive()` column was left OUT. Nothing to purge, nothing to rotate."));
311
313
  }
312
- let a = e.reduce((e, t) => e + (L(t) ? 0 : t.hits ?? 0), 0), o = e.reduce((e, t) => e + (L(t) ? t.hits ?? 0 : 0), 0);
314
+ let a = e.reduce((e, t) => e + (I(t) ? 0 : t.hits ?? 0), 0), o = e.reduce((e, t) => e + (I(t) ? t.hits ?? 0 : 0), 0);
313
315
  return r.push(""), o > 0 && r.push(` ${o} row(s) matched only the framework's own redaction markers and are NOT findings.`), a > 0 ? r.push(` ${a} row(s) carry something credential-shaped.`, " Purge them AND rotate the credentials — assume anything written to a log", " table has been read. Then stop putting the credential on the Subject:", " `connectionCredentials(...)` keeps it in the framework vault.") : e.every((e) => e.scanned === void 0 || e.scanned === 0 || e.unavailable !== void 0) ? r.push(" NOTHING WAS SCANNED. This run proves nothing about your data.") : r.push(" No credential-shaped keys found in the rows that exist."), r.push("", ` These are NAME heuristics (${n} of them), not proof. A credential in a`, " column whose key is not credential-shaped — `keyValue`, `pat`, `authz` —", " is invisible here. A clean run means \"no credential-shaped NAME found\",", " which is not the same as \"no credential\".", "", " Run this on EVERY environment. A dev database is not a sample of production."), r.join("\n");
314
- }, Qe = (e) => e.some((e) => (e.hits ?? 0) > 0 && !L(e)) ? 1 : e.every((e) => e.unavailable !== void 0 || e.scanned === void 0 || e.scanned === 0) ? 2 : 0, $e = /\.migration\.ts$/, R = async (e, t) => {
316
+ }, tt = (e) => e.some((e) => (e.hits ?? 0) > 0 && !I(e)) ? 1 : e.every((e) => e.unavailable !== void 0 || e.scanned === void 0 || e.scanned === 0) ? 2 : 0, R = /\.migration\.ts$/, nt = async (e, t) => {
315
317
  let n = [];
316
318
  for (let r of e) {
317
319
  let e;
318
320
  try {
319
- e = await import(T(r).href);
321
+ e = await import(E(r).href);
320
322
  } catch (e) {
321
323
  t.warn("migration: failed to import", { file: r }, e);
322
324
  continue;
323
325
  }
324
- let i = (e.default && ye(e.default) ? e.default : void 0) ?? Object.values(e).find(ye);
326
+ let i = (e.default && Ce(e.default) ? e.default : void 0) ?? Object.values(e).find(Ce);
325
327
  if (!i) {
326
328
  t.warn("migration: no defineMigration export", { file: r });
327
329
  continue;
328
330
  }
329
- i.id !== b(r).replace(/\.migration\.ts$/, "") && t.warn("migration: id does not match filename — id wins for ordering, but rename the file for clarity", {
331
+ i.id !== te(r).replace(/\.migration\.ts$/, "") && t.warn("migration: id does not match filename — id wins for ordering, but rename the file for clarity", {
330
332
  file: r,
331
333
  idInFile: i.id,
332
- idFromFile: b(r).replace(/\.migration\.ts$/, "")
334
+ idFromFile: te(r).replace(/\.migration\.ts$/, "")
333
335
  });
334
- let a = await w.readFile(r, "utf8").catch(() => ""), o = Oe("sha256").update(a).digest("hex").slice(0, 16);
336
+ let a = await T.readFile(r, "utf8").catch(() => ""), o = Me("sha256").update(a).digest("hex").slice(0, 16);
335
337
  n.push({
336
338
  file: r,
337
339
  definition: i,
@@ -339,14 +341,14 @@ var ke = (e) => typeof e != "string", Ae = (e, t, n, r) => {
339
341
  });
340
342
  }
341
343
  return [...n].sort((e, t) => e.definition.id < t.definition.id ? -1 : 1);
342
- }, et = async (e) => {
343
- let t = (process.env.DB_DIALECT ?? "postgres").toLowerCase(), n = t === "memory" ? "postgres" : t, r = n, i = t === "memory" ? void 0 : await c(n).then((e) => e.retryFilter, () => void 0);
344
- return E.runPromise(O(P, r, void 0, i === void 0 ? {} : { retryFilter: i }).pipe(E.provide(e)));
345
- }, tt = (e) => E.runPromise(E.gen(function* () {
346
- let e = yield* (yield* D.SqlClient)`SELECT id, status, hash, "appliedAt" FROM "_voltro_migrations"`.pipe(E.orElseSucceed(() => []));
344
+ }, rt = async (e) => {
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 O.runPromise(ie(Se, r, void 0, i === void 0 ? {} : { retryFilter: i }).pipe(O.provide(e)));
347
+ }, it = (e) => O.runPromise(O.gen(function* () {
348
+ let e = yield* (yield* k.SqlClient)`SELECT id, status, hash, "appliedAt" FROM "_voltro_migrations"`.pipe(O.orElseSucceed(() => []));
347
349
  return new Map(e.map((e) => [e.id, e]));
348
- }).pipe(E.provide(e))), z = (e, t) => E.runPromise(E.gen(function* () {
349
- yield* (yield* D.SqlClient)`
350
+ }).pipe(O.provide(e))), z = (e, t) => O.runPromise(O.gen(function* () {
351
+ yield* (yield* k.SqlClient)`
350
352
  INSERT INTO "_voltro_migrations"
351
353
  (id, name, hash, status, "appliedAt", "durationMs", "errorMessage", "errorStack")
352
354
  VALUES
@@ -361,14 +363,14 @@ var ke = (e) => typeof e != "string", Ae = (e, t, n, r) => {
361
363
  "errorStack" = EXCLUDED."errorStack",
362
364
  "updatedAt" = now()
363
365
  `;
364
- }).pipe(E.provide(e))), nt = async (e, t, n) => {
366
+ }).pipe(O.provide(e))), at = async (e, t, n) => {
365
367
  if (e.length === 0) return {
366
368
  applied: [],
367
369
  failed: null,
368
370
  skipped: []
369
371
  };
370
- await et(t);
371
- let r = await tt(t), i = [], a = [], o = null;
372
+ await rt(t);
373
+ let r = await it(t), i = [], a = [], o = null;
372
374
  for (let s of e) {
373
375
  let e = r.get(s.definition.id);
374
376
  if (e && e.status === "applied") {
@@ -403,7 +405,7 @@ var ke = (e) => typeof e != "string", Ae = (e, t, n, r) => {
403
405
  for (let e of s.definition.steps) {
404
406
  let n = Date.now();
405
407
  try {
406
- await E.runPromise(e.apply.pipe(E.provide(t))), l.push({
408
+ await O.runPromise(e.apply.pipe(O.provide(t))), l.push({
407
409
  stepName: e.name,
408
410
  status: "applied",
409
411
  durationMs: Date.now() - n
@@ -469,9 +471,9 @@ var ke = (e) => typeof e != "string", Ae = (e, t, n, r) => {
469
471
  failed: o,
470
472
  skipped: a
471
473
  };
472
- }, rt = async (e, t, n, r = {}) => {
473
- await et(t);
474
- let i = await tt(t), a = e.filter((e) => i.get(e.definition.id)?.status === "applied");
474
+ }, ot = async (e, t, n, r = {}) => {
475
+ await rt(t);
476
+ let i = await it(t), a = e.filter((e) => i.get(e.definition.id)?.status === "applied");
475
477
  if (a.length === 0) return n.info("migration: nothing to roll back"), {
476
478
  applied: [],
477
479
  failed: null,
@@ -489,7 +491,7 @@ var ke = (e) => typeof e != "string", Ae = (e, t, n, r) => {
489
491
  for (let n = e.definition.steps.length - 1; n >= 0; n--) {
490
492
  let o = e.definition.steps[n], s = Date.now();
491
493
  try {
492
- await E.runPromise(o.undo.pipe(E.provide(t))), i.push({
494
+ await O.runPromise(o.undo.pipe(O.provide(t))), i.push({
493
495
  stepName: o.name,
494
496
  status: "applied",
495
497
  durationMs: Date.now() - s
@@ -540,9 +542,9 @@ var ke = (e) => typeof e != "string", Ae = (e, t, n, r) => {
540
542
  failed: c,
541
543
  skipped: []
542
544
  };
543
- }, it = async (e, t) => {
544
- await et(t);
545
- let n = await tt(t);
545
+ }, st = async (e, t) => {
546
+ await rt(t);
547
+ let n = await it(t);
546
548
  return e.map((e) => {
547
549
  let t = n.get(e.definition.id);
548
550
  return t ? {
@@ -559,7 +561,7 @@ var ke = (e) => typeof e != "string", Ae = (e, t, n, r) => {
559
561
  hashMatches: !0
560
562
  };
561
563
  });
562
- }, at = (e) => {
564
+ }, ct = (e) => {
563
565
  if (!e.failed) return "";
564
566
  let t = e.failed, n = [
565
567
  `✗ Migration failed: ${t.migrationId} / step '${t.error?.stepName ?? "?"}'`,
@@ -572,22 +574,22 @@ var ke = (e) => typeof e != "string", Ae = (e, t, n, r) => {
572
574
  ""
573
575
  ];
574
576
  return e.applied.length > 0 && n.unshift("", `(${e.applied.length} migration(s) applied successfully before the failure.)`), n.join("\n");
575
- }, ot = (e) => {
577
+ }, lt = (e) => {
576
578
  let t = e.split(".");
577
579
  if (t.length !== 2 || !t[0] || !t[1]) throw Error(`voltro db encrypt-column: expected <table>.<column>, got "${e}"`);
578
580
  return {
579
581
  table: t[0],
580
582
  column: t[1]
581
583
  };
582
- }, st = (e) => 49 + 4 * Math.ceil(e / 3), ct = (e, t) => {
583
- let n = st(e);
584
+ }, ut = (e) => 49 + 4 * Math.ceil(e / 3), dt = (e, t) => {
585
+ let n = ut(e);
584
586
  return {
585
587
  longestPlaintextBytes: e,
586
588
  longestCiphertext: n,
587
589
  declaredMaxLength: t,
588
590
  fits: t === void 0 || n <= t
589
591
  };
590
- }, lt = (e, t) => `${e.table}.${e.column} is too narrow: its longest value is ${t.longestPlaintextBytes} byte(s), which encrypts to ${t.longestCiphertext} characters, and the column is declared as ${t.declaredMaxLength}. Widen it first (\`.maxLength(${t.longestCiphertext})\` or more, then \`voltro db apply\`) and run this again. Nothing was written.`, ut = (e, t) => {
592
+ }, ft = (e, t) => `${e.table}.${e.column} is too narrow: its longest value is ${t.longestPlaintextBytes} byte(s), which encrypts to ${t.longestCiphertext} characters, and the column is declared as ${t.declaredMaxLength}. Widen it first (\`.maxLength(${t.longestCiphertext})\` or more, then \`voltro db apply\`) and run this again. Nothing was written.`, pt = (e, t) => {
591
593
  let n = t ? "would encrypt" : "encrypted";
592
594
  return [
593
595
  ` ${e.table}.${e.column}`,
@@ -596,10 +598,10 @@ var ke = (e) => typeof e != "string", Ae = (e, t, n, r) => {
596
598
  ` null / empty ${e.empty}`,
597
599
  ` ${n.padEnd(18)} ${e.encrypted}`
598
600
  ].join("\n");
599
- }, dt = (e, t, n) => {
601
+ }, mt = (e, t, n) => {
600
602
  if (e == null) return;
601
603
  let r = typeof e == "string" ? e : String(e);
602
- if (r === "" || F(r)) return;
604
+ if (r === "" || P(r)) return;
603
605
  let i = t.encrypt(r), a;
604
606
  try {
605
607
  a = t.decrypt(i);
@@ -608,13 +610,13 @@ var ke = (e) => typeof e != "string", Ae = (e, t, n, r) => {
608
610
  }
609
611
  if (a !== r) throw Error(`${n.table}.${n.column}: round-trip mismatch — the cipher did not return what it was given. Nothing was written.`);
610
612
  return i;
611
- }, ft = (e) => Buffer.byteLength(e, "utf8"), pt = (e, t) => {
613
+ }, ht = (e) => Buffer.byteLength(e, "utf8"), gt = (e, t) => {
612
614
  if (e !== void 0) try {
613
615
  return t.decrypt(e), !0;
614
616
  } catch {
615
617
  return !1;
616
618
  }
617
- }, mt = (e, t) => `${e.table}.${e.column} already holds values encrypted with a DIFFERENT key than ${t} — the active key cannot decrypt them. Continuing would encrypt the remaining rows under a second key, and the column would then be readable with neither key alone. Nothing was written. Point ${t} at the key the existing rows were written with.`, ht = (e) => [
619
+ }, _t = (e, t) => `${e.table}.${e.column} already holds values encrypted with a DIFFERENT key than ${t} — the active key cannot decrypt them. Continuing would encrypt the remaining rows under a second key, and the column would then be readable with neither key alone. Nothing was written. Point ${t} at the key the existing rows were written with.`, vt = (e) => [
618
620
  "",
619
621
  " NEXT — this converted the rows that exist. New writes are still plaintext",
620
622
  " until the column carries the modifier:",
@@ -624,7 +626,7 @@ var ke = (e) => typeof e != "string", Ae = (e, t, n, r) => {
624
626
  " Order does not matter: a read returns a non-ciphertext value unchanged, so",
625
627
  " the column may hold a mix while you deploy. Run this again afterwards to",
626
628
  " catch anything written in between — it skips what is already encrypted."
627
- ].join("\n"), B = te({ scope: "voltro:db" }), gt = /* @__PURE__ */ new Set([
629
+ ].join("\n"), B = D({ scope: "voltro:db" }), yt = /* @__PURE__ */ new Set([
628
630
  "node_modules",
629
631
  "dist",
630
632
  "build",
@@ -634,15 +636,15 @@ var ke = (e) => typeof e != "string", Ae = (e, t, n, r) => {
634
636
  ".git"
635
637
  ]), V = async (e, t) => {
636
638
  let n = [], r = async (e) => {
637
- let i = await w.readdir(e, { withFileTypes: !0 }).catch(() => []);
639
+ let i = await T.readdir(e, { withFileTypes: !0 }).catch(() => []);
638
640
  for (let a of i) {
639
- if (gt.has(a.name)) continue;
640
- let i = x(e, a.name);
641
+ if (yt.has(a.name)) continue;
642
+ let i = S(e, a.name);
641
643
  a.isDirectory() ? await r(i) : a.isFile() && t.test(a.name) && n.push(i);
642
644
  }
643
645
  };
644
646
  return await r(e), n;
645
- }, _t = [
647
+ }, bt = [
646
648
  "--against",
647
649
  "--batch",
648
650
  "--before",
@@ -661,23 +663,23 @@ var ke = (e) => typeof e != "string", Ae = (e, t, n, r) => {
661
663
  "--store",
662
664
  "--to",
663
665
  "--token"
664
- ], H = (e) => C(s(e, _t) ?? process.cwd()), U = () => l("migration"), vt = (e) => {
666
+ ], H = (e) => w(c(e, bt) ?? process.cwd()), U = () => u("migration"), xt = (e) => {
665
667
  let t = e;
666
668
  if (typeof t != "object" || !t) return !1;
667
669
  if (t.code === "ERR_OUT_OF_RANGE" || t.cause?.code === "ERR_OUT_OF_RANGE") return !0;
668
670
  let n = `${t.message ?? ""} ${t.cause?.message ?? ""} ${t.stack ?? ""}`;
669
671
  return /ERR_OUT_OF_RANGE|out of range/i.test(n) && /pg-protocol|parseDataRow|buffer-reader|BufferReader/i.test(n);
670
- }, yt = "Live-DB introspection got a corrupt / misaligned response from the database. This happens when `voltro db plan` / `apply` / `drift` / `migrate` runs through a connection POOLER (Supabase Supavisor / PgBouncer) on a LARGE schema — the pooler mis-frames a big catalog response. The introspection already batches by table to keep responses small; if a batch still trips it:\n 1. Lower the batch: set `VOLTRO_INTROSPECT_BATCH` to a smaller number of tables (default 20 — try 5 or 1). This keeps `db plan` on the normal pooler, no direct connection needed.\n 2. Or use a DIRECT (non-pooler) connection: set `DB_DIRECT_URL` (or `DB_MIGRATE_URL`) to the direct database URL — the runtime keeps `DB_URL`, so only the migration path is affected. (Supabase: direct = `db.<project-ref>.supabase.co` [IPv6-only on newer projects]; pooler = `aws-0-<region>.pooler.supabase.com`.)", W = () => {
672
+ }, St = "Live-DB introspection got a corrupt / misaligned response from the database. This happens when `voltro db plan` / `apply` / `drift` / `migrate` runs through a connection POOLER (Supabase Supavisor / PgBouncer) on a LARGE schema — the pooler mis-frames a big catalog response. The introspection already batches by table to keep responses small; if a batch still trips it:\n 1. Lower the batch: set `VOLTRO_INTROSPECT_BATCH` to a smaller number of tables (default 20 — try 5 or 1). This keeps `db plan` on the normal pooler, no direct connection needed.\n 2. Or use a DIRECT (non-pooler) connection: set `DB_DIRECT_URL` (or `DB_MIGRATE_URL`) to the direct database URL — the runtime keeps `DB_URL`, so only the migration path is affected. (Supabase: direct = `db.<project-ref>.supabase.co` [IPv6-only on newer projects]; pooler = `aws-0-<region>.pooler.supabase.com`.)", W = () => {
671
673
  let e = (process.env.DB_DIALECT ?? "postgres").toLowerCase();
672
- if (e === "memory") throw new n("voltro db: subcommands require a real dialect, not DB_DIALECT=memory.");
674
+ if (e === "memory") throw new r("voltro db: subcommands require a real dialect, not DB_DIALECT=memory.");
673
675
  return e;
674
- }, G = (e) => Se(e, W()), K = (e) => e === "mysql" || e === "mariadb" ? "table_schema = DATABASE()" : e === "mssql" ? "table_schema = SCHEMA_NAME()" : "table_schema = 'public'", q = async () => (await c(W())).makeSqlLayer(U()), bt = async (e) => {
675
- let t = H(e), n = e.includes("--dry-run"), r = await R(await V(t, $e), B);
676
+ }, G = (e) => Ee(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()), Ct = async (e) => {
677
+ let t = H(e), n = e.includes("--dry-run"), r = await nt(await V(t, R), B);
676
678
  if (r.length === 0) return B.info("no migrations found", { root: t }), 0;
677
679
  if (n) {
678
680
  let e = /* @__PURE__ */ new Set();
679
681
  try {
680
- let t = await it(r, await q());
682
+ let t = await st(r, await q());
681
683
  e = new Set(t.filter((e) => e.status === "applied").map((e) => e.id));
682
684
  } catch {
683
685
  B.warn("migrate --dry-run: could not read the migration ledger — showing ALL as pending");
@@ -688,33 +690,33 @@ var ke = (e) => typeof e != "string", Ae = (e, t, n, r) => {
688
690
  for (let e of t) console.log(` pending ${e.definition.id}`);
689
691
  return 0;
690
692
  }
691
- let i = await nt(r, await q(), B);
692
- return i.failed ? (process.stderr.write(at(i) + "\n"), 1) : (B.info("migrate complete", {
693
+ let i = await at(r, await q(), B);
694
+ return i.failed ? (process.stderr.write(ct(i) + "\n"), 1) : (B.info("migrate complete", {
693
695
  applied: i.applied.length,
694
696
  skipped: i.skipped.length
695
697
  }), 0);
696
- }, xt = async (e) => {
697
- let t = H(e), n = o(e, "--to"), r = await R(await V(t, $e), B);
698
+ }, wt = async (e) => {
699
+ let t = H(e), n = s(e, "--to"), r = await nt(await V(t, R), B);
698
700
  if (r.length === 0) return B.info("no migrations found", { root: t }), 0;
699
- let i = await rt(r, await q(), B, n ? { to: n } : {});
700
- return i.failed ? (process.stderr.write(at(i) + "\n"), 1) : (B.info("rollback complete", { reverted: i.applied.length }), 0);
701
- }, St = async (e) => {
702
- let t = await R(await V(H(e), $e), B);
701
+ let i = await ot(r, await q(), B, n ? { to: n } : {});
702
+ return i.failed ? (process.stderr.write(ct(i) + "\n"), 1) : (B.info("rollback complete", { reverted: i.applied.length }), 0);
703
+ }, Tt = async (e) => {
704
+ let t = await nt(await V(H(e), R), B);
703
705
  if (t.length === 0) return console.log("no migrations found"), 0;
704
- let n = await it(t, await q());
706
+ let n = await st(t, await q());
705
707
  for (let e of n) {
706
708
  let t = e.status === "applied" ? "✓" : e.status === "failed" ? "✗" : e.status === "reverted" ? "↩" : "·", n = e.hashMatches ? "" : " (hash drift!)", r = e.appliedAt ? ` @ ${e.appliedAt.toISOString()}` : "";
707
709
  console.log(` ${t} ${e.id} [${e.status}] ${e.name}${r}${n}`);
708
710
  }
709
711
  return 0;
710
- }, Ct = async (e) => {
711
- let t = (o(e, "--store") ?? process.env.DB_DIALECT ?? "postgres").toLowerCase();
712
+ }, Et = async (e) => {
713
+ let t = (s(e, "--store") ?? process.env.DB_DIALECT ?? "postgres").toLowerCase();
712
714
  if (t === "memory") return B.warn("voltro db seed: using in-memory store (explicit opt-in via --store memory / DB_DIALECT=memory)"), B.warn(" rows written by this run will NOT persist beyond the process. set DB_DIALECT=postgres or unset to seed the real DB."), {
713
- store: new Ee(),
715
+ store: new Ae(),
714
716
  dispose: async () => {},
715
717
  dialectId: "memory"
716
718
  };
717
- let n = await c(t);
719
+ let n = await l(t);
718
720
  B.info(`voltro db seed: target store=${n.id} — rows will persist`);
719
721
  let r = await n.makeStore({
720
722
  sqlLayer: n.makeSqlLayer(U()),
@@ -727,12 +729,12 @@ var ke = (e) => typeof e != "string", Ae = (e, t, n, r) => {
727
729
  },
728
730
  dialectId: n.id
729
731
  };
730
- }, wt = async (e) => {
731
- let t = H(e), n = o(e, "--id"), r = o(e, "--lifecycle"), i = await d(await V(t, y), B);
732
+ }, Dt = async (e) => {
733
+ let t = H(e), n = s(e, "--id"), r = s(e, "--lifecycle"), i = await f(await V(t, b), B);
732
734
  if (i.length === 0) return B.info("no seeds found", { root: t }), 0;
733
- let { store: a, dispose: s, dialectId: c } = await Ct(e);
735
+ let { store: a, dispose: o, dialectId: c } = await Et(e);
734
736
  try {
735
- return n ? +((await u(i, n, a, B)).status === "failed") : +((await f((r ? i.filter((e) => e.definition.lifecycle === r) : i.filter((e) => e.definition.lifecycle === "boot")).map((e) => ({
737
+ return n ? +((await d(i, n, a, B)).status === "failed") : +((await p((r ? i.filter((e) => e.definition.lifecycle === r) : i.filter((e) => e.definition.lifecycle === "boot")).map((e) => ({
736
738
  ...e,
737
739
  definition: {
738
740
  ...e.definition,
@@ -740,64 +742,64 @@ var ke = (e) => typeof e != "string", Ae = (e, t, n, r) => {
740
742
  }
741
743
  })), a, B, { force: !0 })).filter((e) => e.status === "failed").length > 0);
742
744
  } finally {
743
- await s().catch((e) => {
745
+ await o().catch((e) => {
744
746
  B.warn("voltro db seed: store dispose failed", { error: String(e) });
745
747
  });
746
748
  }
747
- }, Tt = (e) => typeof e == "object" && !!e && "tableName" in e && "fields" in e && typeof e.tableName == "string", Et = async (e) => {
748
- let t = await V(e, v), n = [];
749
+ }, Ot = (e) => typeof e == "object" && !!e && "tableName" in e && "fields" in e && typeof e.tableName == "string", kt = async (e) => {
750
+ let t = await V(e, y), n = [];
749
751
  for (let r of t) {
750
752
  let t;
751
753
  try {
752
- t = await import(T(r).href);
754
+ t = await import(E(r).href);
753
755
  } catch (t) {
754
756
  B.warn("db: failed to import schema file", {
755
- file: S(e, r),
757
+ file: C(e, r),
756
758
  error: String(t)
757
759
  });
758
760
  continue;
759
761
  }
760
- for (let e of Object.values(t)) Tt(e) && n.push(e);
762
+ for (let e of Object.values(t)) Ot(e) && n.push(e);
761
763
  }
762
764
  return n;
763
- }, Dt = (e) => {
765
+ }, At = (e) => {
764
766
  let t = new Map(e.map((e) => [e.tableName, e]));
765
- t.has("actors") || t.set("actors", _e);
767
+ t.has("actors") || t.set("actors", be);
766
768
  let n = t.get("actors"), r = t.get("tenants");
767
- return Ce({
769
+ return De({
768
770
  actors: () => n,
769
771
  ...r === void 0 ? {} : { tenants: () => r }
770
772
  }), [...t.values()];
771
- }, Ot = (e) => {
773
+ }, jt = (e) => {
772
774
  let t = /* @__PURE__ */ new Map();
773
775
  for (let n of e) {
774
776
  let e = n.tableName;
775
777
  e !== void 0 && !t.has(e) && t.set(e, n);
776
778
  }
777
779
  return [...t.values()];
778
- }, kt = (e) => {
779
- let t = ae(process.env.VOLTRO_DESTRUCTIVE_OK);
780
+ }, Mt = (e) => {
781
+ let t = ce(process.env.VOLTRO_DESTRUCTIVE_OK);
780
782
  if (t === void 0 || !e.operations.filter((e) => e.blocked).every((e) => e.classification === "lossy")) return {
781
783
  plan: e,
782
784
  acknowledged: !1
783
785
  };
784
- let n = ge(e, t);
786
+ let n = ye(e, t);
785
787
  return {
786
788
  plan: n,
787
789
  acknowledged: !n.operations.some((e) => e.blocked)
788
790
  };
789
- }, J = async (e, t) => E.runPromise(t.pipe(E.provide(e))), Y = async (e) => {
791
+ }, J = async (e, t) => O.runPromise(t.pipe(O.provide(e))), Y = async (e) => {
790
792
  try {
791
- return await J(e, D.SqlClient.pipe(E.flatMap(ce)));
793
+ return await J(e, k.SqlClient.pipe(O.flatMap(de)));
792
794
  } catch (e) {
793
795
  let t = String(e?.message ?? e);
794
- if (vt(e) || /connection error/i.test(t)) {
795
- let n = /* @__PURE__ */ Error(`${yt}\n\nOriginal error: ${t}`);
796
+ if (xt(e) || /connection error/i.test(t)) {
797
+ let n = /* @__PURE__ */ Error(`${St}\n\nOriginal error: ${t}`);
796
798
  throw n.cause = e, n;
797
799
  }
798
800
  throw e;
799
801
  }
800
- }, At = {
802
+ }, Nt = {
801
803
  safe: "\x1B[32m✓\x1B[0m",
802
804
  "needs-default": "\x1B[32m⊕\x1B[0m",
803
805
  "needs-backfill": "\x1B[33m⊕\x1B[0m",
@@ -805,7 +807,7 @@ var ke = (e) => typeof e != "string", Ae = (e, t, n, r) => {
805
807
  lossy: "\x1B[31m✗\x1B[0m",
806
808
  "online-required": "\x1B[36m◷\x1B[0m",
807
809
  "multi-step": "\x1B[35m⇉\x1B[0m"
808
- }, jt = (e) => {
810
+ }, Pt = (e) => {
809
811
  let t = e.op, n;
810
812
  switch (t.kind) {
811
813
  case "create-table":
@@ -869,9 +871,9 @@ var ke = (e) => typeof e != "string", Ae = (e, t, n, r) => {
869
871
  n = `ALTER TABLE ${t.table} DROP CHECK ${t.column}`;
870
872
  break;
871
873
  }
872
- let r = At[e.classification], i = e.reason ? ` # ${e.reason}` : "", a = e.blocked ? `\n ! ${e.blocked.fix}` : "";
874
+ let r = Nt[e.classification], i = e.reason ? ` # ${e.reason}` : "", a = e.blocked ? `\n ! ${e.blocked.fix}` : "";
873
875
  return ` ${r} ${n}${i}${a}`;
874
- }, Mt = async (e, t) => {
876
+ }, Ft = async (e, t) => {
875
877
  let n = e.operations.filter((e) => e.classification === "needs-default" && e.op.kind === "add-column");
876
878
  if (n.length === 0) return;
877
879
  let r = [];
@@ -880,7 +882,7 @@ var ke = (e) => typeof e != "string", Ae = (e, t, n, r) => {
880
882
  if (i === void 0 || a === void 0) continue;
881
883
  let o = 0;
882
884
  try {
883
- let e = await J(t, D.SqlClient.pipe(E.flatMap((e) => e.unsafe(`SELECT COUNT(*) AS n FROM ${Se(i, W())}`))));
885
+ let e = await J(t, k.SqlClient.pipe(O.flatMap((e) => e.unsafe(`SELECT COUNT(*) AS n FROM ${Ee(i, W())}`))));
884
886
  o = Number(Object.values(e[0] ?? { n: 0 })[0] ?? 0);
885
887
  } catch {
886
888
  continue;
@@ -892,11 +894,11 @@ var ke = (e) => typeof e != "string", Ae = (e, t, n, r) => {
892
894
  for (let e of r) console.log(e);
893
895
  console.log(" (the shape is correct either way — this is the VALUE a state diff cannot know)");
894
896
  }
895
- }, Nt = async (e, t) => {
897
+ }, It = async (e, t) => {
896
898
  if (W() !== "postgres") return;
897
- let n = ne, r;
899
+ let n = A, r;
898
900
  try {
899
- r = await J(t, D.SqlClient.pipe(E.flatMap((t) => p(t, e, n))));
901
+ r = await J(t, k.SqlClient.pipe(O.flatMap((t) => m(t, e, n))));
900
902
  } catch {
901
903
  return;
902
904
  }
@@ -904,7 +906,7 @@ var ke = (e) => typeof e != "string", Ae = (e, t, n, r) => {
904
906
  if (a.length === 0) return;
905
907
  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)");
906
908
  let o = 0;
907
- for (let e of a) await J(t, D.SqlClient.pipe(E.flatMap((t) => t.unsafe(e)))), o += 1;
909
+ for (let e of a) await J(t, k.SqlClient.pipe(O.flatMap((t) => t.unsafe(e)))), o += 1;
908
910
  B.info(`db apply: change triggers converged (${o} statement(s))`, {
909
911
  installed: i.missing.length,
910
912
  removed: i.stale.length,
@@ -916,81 +918,81 @@ var ke = (e) => typeof e != "string", Ae = (e, t, n, r) => {
916
918
  console.log(" (schema is up to date)\n");
917
919
  return;
918
920
  }
919
- for (let t of e.operations) console.log(jt(t));
920
- 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`), Pt(e);
921
- }, Pt = (e) => {
922
- let t = pe(e.operations);
921
+ for (let t of e.operations) console.log(Pt(t));
922
+ 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`), Lt(e);
923
+ }, Lt = (e) => {
924
+ let t = ge(e.operations);
923
925
  if (t.length !== 0) {
924
926
  console.log(` ⚠ ${t.length} operation(s) UNSAFE under a rolling deploy`), console.log(" (old + new instances overlap → old code breaks against the new schema):");
925
927
  for (let e of t) console.log(` • ${e.op.op.kind}: ${e.reason}`), console.log(` → ${e.remedy}`);
926
928
  console.log(" Deploy with a maintenance window / scale-to-zero, or split into"), console.log(" expand → deploy → contract. See docs: deployment/production-hardening.\n");
927
929
  }
928
- }, Ft = (e, t) => {
929
- let n = k({
930
+ }, Rt = (e, t) => {
931
+ let n = ae({
930
932
  enabled: process.env.VOLTRO_ROLLING_DEPLOY === "1",
931
933
  forced: t.includes("--force"),
932
- unsafeCount: pe(e.operations).length
934
+ unsafeCount: ge(e.operations).length
933
935
  });
934
936
  return n.refuse ? (B.error(`db apply: ${n.message}`), !0) : (n.warnForced && B.warn(`db apply: ${n.message}`), !1);
935
- }, It = (e) => {
936
- let t = o(e, "--online-after") ?? process.env.VOLTRO_ONLINE_THRESHOLD;
937
+ }, zt = (e) => {
938
+ let t = s(e, "--online-after") ?? process.env.VOLTRO_ONLINE_THRESHOLD;
937
939
  if (t === void 0) return;
938
940
  let n = Number(t);
939
941
  if (!Number.isInteger(n) || n < 0) throw Error(`--online-after / VOLTRO_ONLINE_THRESHOLD must be a non-negative integer, got "${t}"`);
940
942
  return n;
941
943
  }, Z = async (e) => {
942
- let t = await Et(e);
944
+ let t = await kt(e);
943
945
  if (t.length === 0) return;
944
- let n = await h({ root: e });
945
- return Dt(Ot([
946
+ let n = await g({ root: e });
947
+ return At(jt([
946
948
  ...t,
947
- ...P,
949
+ ...Se,
948
950
  ...n
949
951
  ]));
950
952
  }, Q = async (e, t, n) => {
951
953
  let r;
952
954
  try {
953
- await J(n, _(await g(e), (e, t) => {
955
+ await J(n, v(await _(e), (e, t) => {
954
956
  B.info(`db apply: ${e}`, t ?? {});
955
957
  }));
956
958
  } catch (e) {
957
959
  r = e;
958
960
  }
959
- return await Nt(t, n), r === void 0 ? 0 : (B.error("db apply: a plugin migration FAILED — the schema was applied, the plugin steps were not", { error: r instanceof Error ? r.message : String(r) }), 1);
960
- }, Lt = async (e, t) => {
961
- let n = { close: async () => {} }, r = await V(e, y);
961
+ return await It(t, n), r === void 0 ? 0 : (B.error("db apply: a plugin migration FAILED — the schema was applied, the plugin steps were not", { error: r instanceof Error ? r.message : String(r) }), 1);
962
+ }, Bt = async (e, t) => {
963
+ let n = { close: async () => {} }, r = await V(e, b);
962
964
  if (r.length === 0) return n;
963
- let i = await d(r, B), a = i.filter((e) => e.definition.lifecycle === "onSchemaChange");
965
+ let i = await f(r, B), a = i.filter((e) => e.definition.lifecycle === "onSchemaChange");
964
966
  if (a.length === 0) return n;
965
- let { store: o, dispose: s } = await Ct(t), c = m(i, o, B.child("seeds"));
967
+ let { store: o, dispose: s } = await Et(t), c = h(i, o, B.child("seeds"));
966
968
  return B.info(`db apply: ${a.length} onSchemaChange seed(s) armed for this apply`, { ids: a.map((e) => e.definition.id) }), { close: async () => {
967
969
  c(), await s().catch((e) => {
968
970
  B.warn("db apply: seed store dispose failed", { error: String(e) });
969
971
  });
970
972
  } };
971
- }, Rt = async (e) => {
972
- let t = It(e), n = H(e), r = await Z(n);
973
+ }, Vt = async (e) => {
974
+ let t = zt(e), n = H(e), r = await Z(n);
973
975
  if (r === void 0) return B.warn("db plan: no schema files found", {
974
976
  root: n,
975
977
  hint: "looked for *.entity.ts / *.schema.ts / schema.ts"
976
978
  }), 1;
977
- let i = o(e, "--against");
979
+ let i = s(e, "--against");
978
980
  if (i) {
979
- let n = i, a = o(e, "--token") ?? process.env.VOLTRO_INSPECT_TOKEN, s = { accept: "application/json" };
980
- a && (s.authorization = `Bearer ${a}`);
981
+ let n = i, a = s(e, "--token") ?? process.env.VOLTRO_INSPECT_TOKEN, o = { accept: "application/json" };
982
+ a && (o.authorization = `Bearer ${a}`);
981
983
  try {
982
- let e = n.endsWith("/_voltro/inspect/migrations") ? n : `${n.replace(/\/+$/, "")}/_voltro/inspect/migrations`, i = await fetch(e, { headers: s });
983
- if (!i.ok) return B.error(`db plan --against: remote returned ${i.status}`, { url: e }), 1;
984
+ let e = n.endsWith("/_voltro/inspect/migrations") ? n : `${n.replace(/\/+$/, "")}/_voltro/inspect/migrations`, i = await fetch(e, { headers: o });
985
+ if (!i.ok) return B.error(`db plan --against: remote returned ${i.status}`, { url: e }), ee(i.status) && console.error(` ${x(i.status)}`), 1;
984
986
  let a = (await i.json()).drift?.liveSnapshot;
985
987
  if (!a) return B.error("db plan --against: remote inspect payload missing drift.liveSnapshot", { url: e }), 1;
986
- let o = M({
988
+ let s = M({
987
989
  declared: r,
988
990
  live: a,
989
991
  dialect: W(),
990
992
  ...j(),
991
993
  ...t === void 0 ? {} : { onlineAfter: t }
992
994
  });
993
- return console.log(`\n[--against ${e}] — diff vs remote live schema:\n`), X(o), o.summary.blocked > 0 ? 2 : 0;
995
+ return console.log(`\n[--against ${e}] — diff vs remote live schema:\n`), X(s), s.summary.blocked > 0 ? 2 : 0;
994
996
  } catch (e) {
995
997
  return B.error(`db plan --against: ${e.message}`), 1;
996
998
  }
@@ -1002,11 +1004,11 @@ var ke = (e) => typeof e != "string", Ae = (e, t, n, r) => {
1002
1004
  ...j(),
1003
1005
  ...t === void 0 ? {} : { onlineAfter: t }
1004
1006
  });
1005
- return e.includes("--json") ? (ee(1, `${JSON.stringify(a, null, 2)}\n`), a.summary.blocked > 0 ? 2 : 0) : (X(a), a.summary.blocked > 0 ? 2 : 0);
1006
- }, $ = t, zt = async (e, t, n) => {
1007
+ return e.includes("--json") ? (ne(1, `${JSON.stringify(a, null, 2)}\n`), a.summary.blocked > 0 ? 2 : 0) : (X(a), a.summary.blocked > 0 ? 2 : 0);
1008
+ }, $ = n, Ht = async (e, t, n) => {
1007
1009
  let r;
1008
1010
  try {
1009
- let t = await w.readFile(C(e), "utf8");
1011
+ let t = await T.readFile(w(e), "utf8");
1010
1012
  r = JSON.parse(t);
1011
1013
  } catch (t) {
1012
1014
  return B.error(`db apply --plan: cannot read/parse plan file '${e}': ${t.message}`), 1;
@@ -1014,8 +1016,8 @@ var ke = (e) => typeof e != "string", Ae = (e, t, n, r) => {
1014
1016
  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;
1015
1017
  let i = await Z(n);
1016
1018
  if (i === void 0) return B.warn("db apply --plan: no schema files found", { root: n }), 1;
1017
- let a = await q(), s = await J(a, D.SqlClient.pipe(E.flatMap((e) => le(e, n)))).catch(() => []);
1018
- if (s.length > 0) return B.error(`db apply --plan: refusing — ${s.length} pending file-based migration(s).`), console.error(` ${s.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;
1019
+ let a = await q(), o = await J(a, k.SqlClient.pipe(O.flatMap((e) => fe(e, n)))).catch(() => []);
1020
+ 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;
1019
1021
  let c = M({
1020
1022
  declared: i,
1021
1023
  live: await Y(a),
@@ -1024,11 +1026,11 @@ var ke = (e) => typeof e != "string", Ae = (e, t, n, r) => {
1024
1026
  });
1025
1027
  if (c.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=${c.fromFingerprint.slice(0, 16)}`), console.error(" Regenerate against the current live schema: `voltro db plan --json > plan.json`"), 2;
1026
1028
  if (c.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=${c.toFingerprint.slice(0, 16)}`), console.error(" The schema files changed since the plan was generated. Regenerate the plan."), 2;
1027
- let l = kt(c), u = l.plan;
1029
+ let l = Mt(c), u = l.plan;
1028
1030
  if (u.summary.blocked > 0 && !l.acknowledged) return X(u), B.error(`db apply --plan: refusing — ${c.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;
1029
- if (l.acknowledged && B.warn("db apply --plan: proceeding with acknowledged lossy operation(s) (VOLTRO_DESTRUCTIVE_OK)"), Ft(u, t)) return 2;
1031
+ if (l.acknowledged && B.warn("db apply --plan: proceeding with acknowledged lossy operation(s) (VOLTRO_DESTRUCTIVE_OK)"), Rt(u, t)) return 2;
1030
1032
  if (u.operations.length === 0) {
1031
- let e = await J(a, D.SqlClient.pipe(E.flatMap((e) => ue(e, u, {
1033
+ let e = await J(a, k.SqlClient.pipe(O.flatMap((e) => pe(e, u, {
1032
1034
  appliedBy: process.env.USER ? `cli:${process.env.USER}` : "cli:plan",
1033
1035
  environment: $(),
1034
1036
  source: "file"
@@ -1036,13 +1038,13 @@ var ke = (e) => typeof e != "string", Ae = (e, t, n, r) => {
1036
1038
  return B.info(e === "recorded" ? `db apply --plan: schema is up to date — no DDL to apply, recorded fingerprint=${u.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);
1037
1039
  }
1038
1040
  X(u);
1039
- let d = o(t, "--note"), f = await J(a, D.SqlClient.pipe(E.flatMap((e) => re(e, u, {
1041
+ let d = s(t, "--note"), f = await J(a, k.SqlClient.pipe(O.flatMap((e) => re(e, u, {
1040
1042
  declared: i,
1041
1043
  appliedBy: process.env.USER ? `cli:${process.env.USER}` : "cli:plan",
1042
1044
  environment: $(),
1043
1045
  source: "file",
1044
1046
  ...d ? { notes: d } : {},
1045
- replan: () => E.promise(() => Y(a)).pipe(E.map((e) => M({
1047
+ replan: () => O.promise(() => Y(a)).pipe(O.map((e) => M({
1046
1048
  declared: i,
1047
1049
  live: e,
1048
1050
  dialect: W(),
@@ -1053,48 +1055,48 @@ var ke = (e) => typeof e != "string", Ae = (e, t, n, r) => {
1053
1055
  id: f.id,
1054
1056
  fingerprint: f.fingerprint.slice(0, 16)
1055
1057
  }), Q(n, i, a);
1056
- }, Bt = async (e) => {
1057
- let t = H(e), n = await Lt(t, e);
1058
+ }, Ut = async (e) => {
1059
+ let t = H(e), n = await Bt(t, e);
1058
1060
  try {
1059
- return await Vt(e, t);
1061
+ return await Wt(e, t);
1060
1062
  } finally {
1061
1063
  await n.close();
1062
1064
  }
1063
- }, Vt = async (t, n) => {
1064
- let r = It(t), i = o(t, "--plan");
1065
- if (i) return zt(i, t, n);
1066
- if ((process.env.NODE_ENV ?? "").toLowerCase() === "production") return B.error(`voltro db apply: refusing — auto-apply on prod is not allowed.${e()}`), 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;
1065
+ }, Wt = async (e, n) => {
1066
+ let r = zt(e), i = s(e, "--plan");
1067
+ if (i) return Ht(i, e, n);
1068
+ if ((process.env.NODE_ENV ?? "").toLowerCase() === "production") return B.error(`voltro db apply: refusing — auto-apply on prod is not allowed.${t()}`), 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;
1067
1069
  let a = await Z(n);
1068
1070
  if (a === void 0) return B.warn("db apply: no schema files found", { root: n }), 1;
1069
- let s = await q(), c = await rn(n, s);
1071
+ let o = await q(), c = await sn(n, o);
1070
1072
  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;
1071
1073
  let l = M({
1072
1074
  declared: a,
1073
- live: await Y(s),
1075
+ live: await Y(o),
1074
1076
  dialect: W(),
1075
1077
  ...j(),
1076
1078
  ...r === void 0 ? {} : { onlineAfter: r }
1077
1079
  });
1078
- X(l), await Mt(l, s);
1079
- let u = kt(l), d = u.plan;
1080
+ X(l), await Ft(l, o);
1081
+ let u = Mt(l), d = u.plan;
1080
1082
  if (d.summary.blocked > 0 && !u.acknowledged) return B.error(`db apply: refusing — ${d.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;
1081
- if (u.acknowledged && B.warn(`db apply: proceeding with ${l.summary.blocked} acknowledged lossy operation(s) (VOLTRO_DESTRUCTIVE_OK)`), Ft(d, t)) return 2;
1083
+ if (u.acknowledged && B.warn(`db apply: proceeding with ${l.summary.blocked} acknowledged lossy operation(s) (VOLTRO_DESTRUCTIVE_OK)`), Rt(d, e)) return 2;
1082
1084
  if (d.operations.length === 0) {
1083
1085
  B.info("db apply: schema is up to date — no DDL to apply (change triggers are reconciled separately below)");
1084
- let e = await J(s, D.SqlClient.pipe(E.flatMap((e) => ue(e, d, {
1086
+ let t = await J(o, k.SqlClient.pipe(O.flatMap((e) => pe(e, d, {
1085
1087
  appliedBy: process.env.USER ? `cli:${process.env.USER}` : "cli:apply",
1086
1088
  environment: $(),
1087
1089
  source: "auto-diff"
1088
1090
  }))));
1089
- return e === "recorded" && B.info(`db apply: recorded fingerprint=${d.toFingerprint.slice(0, 16)} (0 operations)`), await Qt(s), o(t, "--note") !== void 0 && e !== "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, s);
1091
+ return t === "recorded" && B.info(`db apply: recorded fingerprint=${d.toFingerprint.slice(0, 16)} (0 operations)`), await tn(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);
1090
1092
  }
1091
- let f = o(t, "--note"), p = await J(s, D.SqlClient.pipe(E.flatMap((e) => re(e, d, {
1093
+ let f = s(e, "--note"), p = await J(o, k.SqlClient.pipe(O.flatMap((e) => re(e, d, {
1092
1094
  declared: a,
1093
1095
  appliedBy: process.env.USER ? `cli:${process.env.USER}` : "cli:user",
1094
1096
  environment: $(),
1095
1097
  source: "auto-diff",
1096
1098
  ...f ? { notes: f } : {},
1097
- replan: () => E.promise(() => Y(s)).pipe(E.map((e) => M({
1099
+ replan: () => O.promise(() => Y(o)).pipe(O.map((e) => M({
1098
1100
  declared: a,
1099
1101
  live: e,
1100
1102
  dialect: W(),
@@ -1105,8 +1107,8 @@ var ke = (e) => typeof e != "string", Ae = (e, t, n, r) => {
1105
1107
  return B.info(`db apply: applied ${p.appliedOps} op(s) in ${p.durationMs}ms`, {
1106
1108
  id: p.id,
1107
1109
  fingerprint: p.fingerprint.slice(0, 16)
1108
- }), Q(n, a, s);
1109
- }, Ht = (e) => {
1110
+ }), Q(n, a, o);
1111
+ }, Gt = (e) => {
1110
1112
  let t = [];
1111
1113
  for (let n of e.tables) for (let e of n.columns) {
1112
1114
  let r = e.references;
@@ -1119,7 +1121,7 @@ var ke = (e) => typeof e != "string", Ae = (e, t, n, r) => {
1119
1121
  });
1120
1122
  }
1121
1123
  return t;
1122
- }, Ut = (e) => {
1124
+ }, Kt = (e) => {
1123
1125
  let t = [];
1124
1126
  for (let n of e.tables) for (let e of n.indexes) e.expression !== !0 && e.name !== `${n.name}_pkey` && e.columns.length !== 0 && t.push({
1125
1127
  table: n.name,
@@ -1128,7 +1130,7 @@ var ke = (e) => typeof e != "string", Ae = (e, t, n, r) => {
1128
1130
  name: e.name
1129
1131
  });
1130
1132
  return t;
1131
- }, Wt = (e, t) => {
1133
+ }, qt = (e, t) => {
1132
1134
  let n = (e) => JSON.stringify(e.op), r = new Set(e.operations.map(n)), i = new Set(t.operations.map(n)), a = [...t.operations.filter((e) => !r.has(n(e))), ...e.operations.filter((e) => !i.has(n(e)))];
1133
1135
  return {
1134
1136
  ...t,
@@ -1138,88 +1140,88 @@ var ke = (e) => typeof e != "string", Ae = (e, t, n, r) => {
1138
1140
  blocked: 0
1139
1141
  }
1140
1142
  };
1141
- }, Gt = (e) => {
1143
+ }, Jt = (e) => {
1142
1144
  if (e === void 0) return "empty";
1143
1145
  if (e === "empty" || e === "copy") return e;
1144
- throw e === "fresh" ? new n("voltro db branch: --seed fresh is not implemented — the branch lifecycle has no executor step that runs boot seeds, so the branch would come up EMPTY while this reported it as seeded. Use --seed copy (the parent's rows) or --seed empty (schema only).") : new n(`voltro db branch: --seed must be one of empty|copy, got "${e}"`);
1145
- }, Kt = (e) => {
1146
+ throw e === "fresh" ? new r("voltro db branch: --seed fresh is not implemented — the branch lifecycle has no executor step that runs boot seeds, so the branch would come up EMPTY while this reported it as seeded. Use --seed copy (the parent's rows) or --seed empty (schema only).") : new r(`voltro db branch: --seed must be one of empty|copy, got "${e}"`);
1147
+ }, Yt = (e) => {
1146
1148
  if (e !== void 0) {
1147
1149
  if (e === "namespace" || e === "neon-cow") return e;
1148
- throw new n(`voltro db branch: --prefer must be one of namespace|neon-cow, got "${e}"`);
1150
+ throw new r(`voltro db branch: --prefer must be one of namespace|neon-cow, got "${e}"`);
1149
1151
  }
1150
- }, qt = async (e) => {
1151
- let t = H(e), r = Gt(o(e, "--seed")), i = Kt(o(e, "--prefer")), a = e.includes("--keep"), s = e.includes("--json"), l = It(e), u = W();
1152
+ }, Xt = async (e) => {
1153
+ let t = H(e), n = Jt(s(e, "--seed")), i = Yt(s(e, "--prefer")), a = e.includes("--keep"), o = e.includes("--json"), c = zt(e), u = W();
1152
1154
  if (u !== "postgres") return B.error(`voltro db branch: not supported on '${u}'.`), console.error(" The branch PLAN is dialect-agnostic; the shipped namespace EXECUTOR is Postgres-only"), console.error(" (CREATE SCHEMA / CREATE TABLE … LIKE … INCLUDING ALL / \"-quoted identifiers)."), console.error(" MySQL, MariaDB, SQLite and SQL Server need their own BranchExecutor — see"), console.error(" makeNamespaceBranchExecutor in @voltro/database."), 1;
1153
1155
  let d = await Z(t);
1154
1156
  if (d === void 0) return B.warn("db branch: no schema files found", {
1155
1157
  root: t,
1156
1158
  hint: "looked for *.entity.ts / *.schema.ts / schema.ts"
1157
1159
  }), 1;
1158
- let f = U(), p = we({
1159
- seed: r,
1160
+ let f = U(), p = Oe({
1161
+ seed: n,
1160
1162
  ...f.url === void 0 ? {} : { dbUrl: f.url },
1161
1163
  ...i === void 0 ? {} : { prefer: i }
1162
1164
  });
1163
- 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 ${r === "copy" ? "every row" : "the schema only"}).`), 1;
1164
- let m = f.schema ?? "public", h = o(e, "--name") ?? b(t), g = o(e, "--pr"), _ = g === void 0 ? 0 : Number(g);
1165
- if (!Number.isInteger(_) || _ < 0) throw new n(`voltro db branch: --pr must be a non-negative integer, got "${String(g)}"`);
1166
- let v = ve(h, _), y = await c(u), x = y.makeSqlLayer(f), S = y.makeSqlLayer({
1165
+ 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;
1166
+ let m = f.schema ?? "public", h = s(e, "--name") ?? te(t), g = s(e, "--pr"), _ = g === void 0 ? 0 : Number(g);
1167
+ if (!Number.isInteger(_) || _ < 0) throw new r(`voltro db branch: --pr must be a non-negative integer, got "${String(g)}"`);
1168
+ let v = xe(h, _), y = await l(u), b = y.makeSqlLayer(f), ee = y.makeSqlLayer({
1167
1169
  ...f,
1168
1170
  schema: v
1169
- }), C = await Y(x), w = M({
1171
+ }), x = await Y(b), S = M({
1170
1172
  declared: d,
1171
- live: C,
1173
+ live: x,
1172
1174
  dialect: u,
1173
1175
  ...j(),
1174
- ...l === void 0 ? {} : { onlineAfter: l }
1175
- }), T = C.tables.map((e) => e.name), te = Ht(C), ne = Ut(C), O = be({ run: (e) => J(x, D.SqlClient.pipe(E.flatMap((t) => t.unsafe(e)), E.asVoid)) }), k = async () => M({
1176
+ ...c === void 0 ? {} : { onlineAfter: c }
1177
+ }), C = x.tables.map((e) => e.name), w = Gt(x), T = Kt(x), E = we({ run: (e) => J(b, k.SqlClient.pipe(O.flatMap((t) => t.unsafe(e)), O.asVoid)) }), D = async () => M({
1176
1178
  declared: d,
1177
- live: await Y(S),
1179
+ live: await Y(ee),
1178
1180
  dialect: u,
1179
1181
  ...j(),
1180
- ...l === void 0 ? {} : { onlineAfter: l }
1181
- }), A = await de({
1182
+ ...c === void 0 ? {} : { onlineAfter: c }
1183
+ }), A = await me({
1182
1184
  branchId: v,
1183
1185
  mechanism: p,
1184
- branchedTables: T.length,
1185
- replayedForeignKeys: te.length,
1186
+ branchedTables: C.length,
1187
+ replayedForeignKeys: w.length,
1186
1188
  keep: a,
1187
1189
  log: (e) => {
1188
- s || B.info(`db branch: ${e}`);
1190
+ o || B.info(`db branch: ${e}`);
1189
1191
  },
1190
1192
  provision: async () => {
1191
- await xe({
1193
+ await Te({
1192
1194
  appSlug: h,
1193
1195
  prNumber: _,
1194
- seed: r,
1195
- tableNames: T,
1196
+ seed: n,
1197
+ tableNames: C,
1196
1198
  parentNamespace: m,
1197
- foreignKeys: te,
1198
- indexNames: ne,
1199
+ foreignKeys: w,
1200
+ indexNames: T,
1199
1201
  prefer: "namespace",
1200
1202
  ...f.url === void 0 ? {} : { dbUrl: f.url }
1201
- }, O);
1203
+ }, E);
1202
1204
  },
1203
- fidelityPlan: async () => Wt(w, await k()),
1204
- plan: k,
1205
+ fidelityPlan: async () => qt(S, await D()),
1206
+ plan: D,
1205
1207
  apply: async (e) => {
1206
- await J(S, D.SqlClient.pipe(E.flatMap((t) => re(t, e, {
1208
+ await J(ee, k.SqlClient.pipe(O.flatMap((t) => re(t, e, {
1207
1209
  declared: d,
1208
1210
  appliedBy: "cli:db-branch",
1209
1211
  environment: $(),
1210
1212
  source: "auto-diff",
1211
1213
  notes: `migration rehearsal on branch ${v}`,
1212
- replan: () => E.promise(k)
1214
+ replan: () => O.promise(D)
1213
1215
  }))));
1214
1216
  },
1215
- replan: async () => await k(),
1217
+ replan: async () => await D(),
1216
1218
  teardown: async () => {
1217
- await Te(v, "namespace", O);
1219
+ await ke(v, "namespace", E);
1218
1220
  }
1219
1221
  });
1220
- return s ? ee(1, `${JSON.stringify(A, null, 2)}\n`) : console.log(`\n${se(A)}\n`), ie(A);
1221
- }, Jt = async (e) => {
1222
- let t = Math.max(1, Number(o(e, "--limit") ?? "20")), n = await J(await q(), D.SqlClient.pipe(E.flatMap((e) => e`
1222
+ return o ? ne(1, `${JSON.stringify(A, null, 2)}\n`) : console.log(`\n${ue(A)}\n`), oe(A);
1223
+ }, Zt = async (e) => {
1224
+ let t = Math.max(1, Number(s(e, "--limit") ?? "20")), n = await J(await q(), k.SqlClient.pipe(O.flatMap((e) => e`
1223
1225
  SELECT ${e("id")}, ${e("fingerprint")}, ${e("operations")},
1224
1226
  ${e("appliedBy")}, ${e("environment")}, ${e("source")},
1225
1227
  ${e("durationMs")}, ${e("notes")}, ${e("appliedAt")}
@@ -1232,20 +1234,20 @@ var ke = (e) => typeof e != "string", Ae = (e, t, n, r) => {
1232
1234
  for (let e of n) {
1233
1235
  let t = 0;
1234
1236
  try {
1235
- t = JSON.parse($t(e.operations)).length;
1237
+ t = JSON.parse(nn(e.operations)).length;
1236
1238
  } catch {}
1237
- console.log(` ${e.id} fp=${N(e.fingerprint)} env=${e.environment} src=${e.source} ${t} op(s) ${e.durationMs}ms ${en(e.appliedAt)} by=${e.appliedBy}`), e.notes && console.log(` [2mnote: ${e.notes}[0m`);
1239
+ console.log(` ${e.id} fp=${N(e.fingerprint)} env=${e.environment} src=${e.source} ${t} op(s) ${e.durationMs}ms ${rn(e.appliedAt)} by=${e.appliedBy}`), e.notes && console.log(` [2mnote: ${e.notes}[0m`);
1238
1240
  }
1239
1241
  return console.log(), 0;
1240
- }, Yt = async (e) => {
1242
+ }, Qt = async (e) => {
1241
1243
  let t = e[0];
1242
1244
  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;
1243
- let n = await q(), r = await J(n, D.SqlClient.pipe(E.flatMap((e) => e`SELECT ${e("id")}, ${e("operations")}
1245
+ let n = await q(), r = await J(n, k.SqlClient.pipe(O.flatMap((e) => e`SELECT ${e("id")}, ${e("operations")}
1244
1246
  FROM ${e("_voltro_migration_plans")} WHERE ${e("id")} = ${t}`)));
1245
1247
  if (r.length === 0) return console.error(`restore-snapshot: plan '${t}' not found`), 1;
1246
1248
  let i;
1247
1249
  try {
1248
- i = JSON.parse($t(r[0].operations));
1250
+ i = JSON.parse(nn(r[0].operations));
1249
1251
  } catch {
1250
1252
  return console.error(`restore-snapshot: plan '${t}' has corrupted operations JSON`), 1;
1251
1253
  }
@@ -1259,7 +1261,7 @@ var ke = (e) => typeof e != "string", Ae = (e, t, n, r) => {
1259
1261
  if (a.length === 0 && o.length === 0) return console.log(`restore-snapshot: plan '${t}' has no drop-column / drop-table ops to restore`), 0;
1260
1262
  let s = 0;
1261
1263
  for (let e of a) {
1262
- let t = await J(n, D.SqlClient.pipe(E.flatMap((t) => t`
1264
+ let t = await J(n, k.SqlClient.pipe(O.flatMap((t) => t`
1263
1265
  SELECT column_name FROM information_schema.columns
1264
1266
  WHERE ${t.unsafe(K(W()))}
1265
1267
  AND table_name = ${e.table}
@@ -1271,11 +1273,11 @@ var ke = (e) => typeof e != "string", Ae = (e, t, n, r) => {
1271
1273
  continue;
1272
1274
  }
1273
1275
  let r = t[0].column_name;
1274
- await J(n, D.SqlClient.pipe(E.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})`);
1276
+ await J(n, k.SqlClient.pipe(O.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})`);
1275
1277
  }
1276
1278
  let c = 0;
1277
1279
  for (let e of o) {
1278
- let t = await J(n, D.SqlClient.pipe(E.flatMap((t) => t`
1280
+ let t = await J(n, k.SqlClient.pipe(O.flatMap((t) => t`
1279
1281
  SELECT table_name FROM information_schema.tables
1280
1282
  WHERE ${t.unsafe(K(W()))}
1281
1283
  AND table_name LIKE ${e.table + "__dropped_%"}
@@ -1286,45 +1288,45 @@ var ke = (e) => typeof e != "string", Ae = (e, t, n, r) => {
1286
1288
  continue;
1287
1289
  }
1288
1290
  let r = t[0].table_name;
1289
- await J(n, D.SqlClient.pipe(E.flatMap((t) => t.unsafe(`ALTER TABLE ${G(r)} RENAME TO ${G(e.table)}`)))), c++, console.log(` ↩ restored table ${e.table} (from ${r})`);
1291
+ await J(n, k.SqlClient.pipe(O.flatMap((t) => t.unsafe(`ALTER TABLE ${G(r)} RENAME TO ${G(e.table)}`)))), c++, console.log(` ↩ restored table ${e.table} (from ${r})`);
1290
1292
  }
1291
1293
  return console.log(`\n✓ restored ${s} column(s) + ${c} table(s) from plan '${t}'\n`), 0;
1292
- }, Xt = async (e) => {
1293
- let t = o(e, "--before");
1294
+ }, $t = async (e) => {
1295
+ let t = s(e, "--before");
1294
1296
  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;
1295
1297
  let n = t.replace(/[^0-9]/g, "");
1296
1298
  if (n.length < 8) return console.error(`gc-snapshots: --before must be at least a full date (YYYY-MM-DD), got "${t}"`), 2;
1297
- let r = (n + "00000000000000").slice(0, 14), i = e.includes("--dry-run"), a = await q(), s = await J(a, D.SqlClient.pipe(E.flatMap((e) => e`
1299
+ let r = (n + "00000000000000").slice(0, 14), i = e.includes("--dry-run"), a = await q(), o = await J(a, k.SqlClient.pipe(O.flatMap((e) => e`
1298
1300
  SELECT table_name, column_name FROM information_schema.columns
1299
1301
  WHERE ${e.unsafe(K(W()))} AND column_name LIKE ${"%__dropped_%"}
1300
- `))), c = await J(a, D.SqlClient.pipe(E.flatMap((e) => e`
1302
+ `))), c = await J(a, k.SqlClient.pipe(O.flatMap((e) => e`
1301
1303
  SELECT table_name FROM information_schema.tables
1302
1304
  WHERE ${e.unsafe(K(W()))} AND table_name LIKE ${"%__dropped_%"}
1303
1305
  `))), l = (e) => {
1304
1306
  let t = /__dropped_(\d{14})$/.exec(e);
1305
1307
  return t ? t[1] : null;
1306
1308
  }, u = 0;
1307
- for (let e of s) {
1309
+ for (let e of o) {
1308
1310
  let t = l(e.column_name);
1309
- t === null || t >= r || (console.log(` ${i ? "[dry-run] would drop column" : "dropping column"} ${e.table_name}.${e.column_name}`), i || await J(a, D.SqlClient.pipe(E.flatMap((t) => t.unsafe(`ALTER TABLE ${G(e.table_name)} DROP COLUMN ${G(e.column_name)}`)))), u++);
1311
+ t === null || t >= r || (console.log(` ${i ? "[dry-run] would drop column" : "dropping column"} ${e.table_name}.${e.column_name}`), i || await J(a, k.SqlClient.pipe(O.flatMap((t) => t.unsafe(`ALTER TABLE ${G(e.table_name)} DROP COLUMN ${G(e.column_name)}`)))), u++);
1310
1312
  }
1311
1313
  for (let e of c) {
1312
1314
  let t = l(e.table_name);
1313
- t === null || t >= r || (console.log(` ${i ? "[dry-run] would drop table" : "dropping table"} ${e.table_name}`), i || await J(a, D.SqlClient.pipe(E.flatMap((t) => t.unsafe(`DROP TABLE ${G(e.table_name)}`)))), u++);
1315
+ t === null || t >= r || (console.log(` ${i ? "[dry-run] would drop table" : "dropping table"} ${e.table_name}`), i || await J(a, k.SqlClient.pipe(O.flatMap((t) => t.unsafe(`DROP TABLE ${G(e.table_name)}`)))), u++);
1314
1316
  }
1315
1317
  return console.log(`\n${i ? `[dry-run] ${u} snapshot(s) would be dropped` : `✓ dropped ${u} snapshot(s)`} (older than ${r}).\n`), 0;
1316
- }, Zt = async (e) => {
1317
- let t = o(e, "--before");
1318
+ }, en = async (e) => {
1319
+ let t = s(e, "--before");
1318
1320
  if (!t) return console.error("voltro db squash --before <iso-date> [--note \"<text>\"]"), 2;
1319
1321
  let n = t;
1320
1322
  if (Number.isNaN(new Date(n).getTime())) return console.error(`voltro db squash: --before '${n}' is not a valid ISO date`), 2;
1321
- let r = o(e, "--note"), i = H(e), a = await Z(i);
1323
+ let r = s(e, "--note"), i = H(e), a = await Z(i);
1322
1324
  if (a === void 0) return B.warn("db squash: no schema files found", { root: i }), 1;
1323
- let s = oe(A(a)), c = await q();
1325
+ let o = le(se(a)), c = await q();
1324
1326
  try {
1325
- let e = await J(c, he({
1327
+ let e = await J(c, ve({
1326
1328
  before: n,
1327
- fingerprint: s,
1329
+ fingerprint: o,
1328
1330
  appliedBy: process.env.USER ?? "cli",
1329
1331
  environment: $(),
1330
1332
  ...r === void 0 ? {} : { note: r }
@@ -1333,10 +1335,10 @@ var ke = (e) => typeof e != "string", Ae = (e, t, n, r) => {
1333
1335
  } catch (e) {
1334
1336
  return console.error(`squash refused: ${e.message}`), 1;
1335
1337
  }
1336
- }, Qt = async (e) => {
1338
+ }, tn = async (e) => {
1337
1339
  try {
1338
- let t = oe(await Y(e));
1339
- await J(e, D.SqlClient.pipe(E.flatMap((e) => e`
1340
+ let t = le(await Y(e));
1341
+ await J(e, k.SqlClient.pipe(O.flatMap((e) => e`
1340
1342
  UPDATE ${e("_voltro_migration_plans")}
1341
1343
  SET ${e("liveFingerprint")} = ${t}
1342
1344
  WHERE ${e("id")} = (
@@ -1348,7 +1350,7 @@ var ke = (e) => typeof e != "string", Ae = (e, t, n, r) => {
1348
1350
  AND ${e("liveFingerprint")} IS NULL
1349
1351
  `)));
1350
1352
  } catch {}
1351
- }, $t = (e) => typeof e == "string" ? e : e == null ? "" : JSON.stringify(e), en = (e) => e instanceof Date ? e.toISOString() : String(e ?? ""), tn = (e) => e === void 0 ? {
1353
+ }, nn = (e) => typeof e == "string" ? e : e == null ? "" : JSON.stringify(e), rn = (e) => e instanceof Date ? e.toISOString() : String(e ?? ""), an = (e) => e === void 0 ? {
1352
1354
  accept: !1,
1353
1355
  reason: "no-declared-schema"
1354
1356
  } : e > 0 ? {
@@ -1357,15 +1359,15 @@ var ke = (e) => typeof e != "string", Ae = (e, t, n, r) => {
1357
1359
  } : {
1358
1360
  accept: !0,
1359
1361
  reason: "converged"
1360
- }, nn = async (e) => {
1361
- let t = e.includes("--accept"), n = await q(), r = await J(n, D.SqlClient.pipe(E.flatMap((e) => e`
1362
+ }, on = async (e) => {
1363
+ let t = e.includes("--accept"), n = await q(), r = await J(n, k.SqlClient.pipe(O.flatMap((e) => e`
1362
1364
  SELECT * FROM ${e("_voltro_migration_plans")}
1363
1365
  ORDER BY ${e("appliedAt")} DESC
1364
1366
  LIMIT 1
1365
- `))), i = await Y(n), a = oe(i);
1367
+ `))), i = await Y(n), a = le(i);
1366
1368
  if (r.length === 0) return B.info("db drift: no _voltro_migration_plans rows yet"), console.log(`live user-schema fingerprint: ${N(a)}`), console.log("No baseline to compare against. Run `voltro db apply` to lock in the current state."), 0;
1367
1369
  let o = r[0];
1368
- 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 ${en(o.appliedAt)}`), console.log(` live now: ${N(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;
1370
+ 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 ${rn(o.appliedAt)}`), console.log(` live now: ${N(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;
1369
1371
  if (o.liveFingerprint === a) return B.info(`db drift: live matches last applied (${N(a)})`), 0;
1370
1372
  let s = await (async () => {
1371
1373
  try {
@@ -1381,14 +1383,14 @@ var ke = (e) => typeof e != "string", Ae = (e, t, n, r) => {
1381
1383
  }
1382
1384
  })();
1383
1385
  if (t) {
1384
- let e = tn(s?.length);
1386
+ let e = an(s?.length);
1385
1387
  if (e.reason === "no-declared-schema") return B.error("db drift --accept: no schema files found — cannot verify the live schema is current."), 1;
1386
1388
  if (!e.accept && s !== void 0) {
1387
1389
  B.error(`db drift --accept: refusing — ${s.length} operation(s) still pending against your declared schema.`), console.log();
1388
1390
  for (let e of s.slice(0, 10)) console.log(` - ${e.op.kind} ${"table" in e.op ? `[${e.op.table}]` : ""}`);
1389
1391
  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;
1390
1392
  }
1391
- return await J(n, D.SqlClient.pipe(E.flatMap((e) => e`
1393
+ return await J(n, k.SqlClient.pipe(O.flatMap((e) => e`
1392
1394
  UPDATE ${e("_voltro_migration_plans")}
1393
1395
  SET ${e("liveFingerprint")} = ${a}
1394
1396
  WHERE ${e("id")} = (
@@ -1399,11 +1401,11 @@ var ke = (e) => typeof e != "string", Ae = (e, t, n, r) => {
1399
1401
  )
1400
1402
  `))), B.info(`db drift: accepted the live schema as the baseline (${N(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;
1401
1403
  }
1402
- return B.error("db drift: live schema DIVERGED from last applied state"), console.log(), console.log(` baseline: ${N(o.liveFingerprint)} at ${en(o.appliedAt)} (${o.id})`), console.log(` live now: ${N(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);
1403
- }, rn = async (e, t) => {
1404
+ return B.error("db drift: live schema DIVERGED from last applied state"), console.log(), console.log(` baseline: ${N(o.liveFingerprint)} at ${rn(o.appliedAt)} (${o.id})`), console.log(` live now: ${N(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);
1405
+ }, sn = async (e, t) => {
1404
1406
  let n = $();
1405
1407
  try {
1406
- let r = await J(t, D.SqlClient.pipe(E.flatMap((t) => me(t, {
1408
+ let r = await J(t, k.SqlClient.pipe(O.flatMap((t) => _e(t, {
1407
1409
  projectRoot: e,
1408
1410
  env: n,
1409
1411
  appliedBy: process.env.USER ? `cli:${process.env.USER}` : "cli:user"
@@ -1412,10 +1414,10 @@ var ke = (e) => typeof e != "string", Ae = (e, t, n, r) => {
1412
1414
  } catch (e) {
1413
1415
  return { failed: e };
1414
1416
  }
1415
- }, an = async (e) => {
1417
+ }, cn = async (e) => {
1416
1418
  let t = H(e), n = await q(), r = $();
1417
- await J(n, O(P, W(), void 0, { retryFilter: (await c(W())).retryFilter }));
1418
- let i = await J(n, D.SqlClient.pipe(E.flatMap((e) => me(e, {
1419
+ await J(n, ie(Se, W(), void 0, { retryFilter: (await l(W())).retryFilter }));
1420
+ let i = await J(n, k.SqlClient.pipe(O.flatMap((e) => _e(e, {
1419
1421
  projectRoot: t,
1420
1422
  env: r,
1421
1423
  appliedBy: process.env.USER ? `cli:${process.env.USER}` : "cli:user"
@@ -1424,16 +1426,16 @@ var ke = (e) => typeof e != "string", Ae = (e, t, n, r) => {
1424
1426
  applied: i.applied.map((e) => `${e.id} (${e.durationMs}ms)`),
1425
1427
  skipped: i.skipped.length
1426
1428
  }), 0);
1427
- }, on = async (t) => {
1428
- let n = H(t), r = s(t, _t);
1429
+ }, ln = async (e) => {
1430
+ let n = H(e), r = c(e, bt);
1429
1431
  if (!r) return B.error("voltro db rollback-file <migration-id>"), 2;
1430
- 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." + e()), 3;
1431
- let i = await J(await q(), D.SqlClient.pipe(E.flatMap((e) => fe(e, {
1432
+ 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;
1433
+ let i = await J(await q(), k.SqlClient.pipe(O.flatMap((e) => he(e, {
1432
1434
  projectRoot: n,
1433
1435
  id: r
1434
1436
  }))));
1435
1437
  return B.info(`db rollback-file: rolled back ${i.id} in ${i.durationMs}ms`), 0;
1436
- }, sn = () => {
1438
+ }, un = () => {
1437
1439
  let e = /* @__PURE__ */ new Date();
1438
1440
  return [
1439
1441
  e.getUTCFullYear(),
@@ -1443,7 +1445,7 @@ var ke = (e) => typeof e != "string", Ae = (e, t, n, r) => {
1443
1445
  String(e.getUTCMinutes()).padStart(2, "0"),
1444
1446
  String(e.getUTCSeconds()).padStart(2, "0")
1445
1447
  ].join("");
1446
- }, cn = (e) => e.trim().toLowerCase().replace(/[^a-z0-9]+/g, "_").replace(/^_+|_+$/g, "") || "migration", ln = (e, t) => `import { defineMigration, SqlClient } from '@voltro/database'
1448
+ }, dn = (e) => e.trim().toLowerCase().replace(/[^a-z0-9]+/g, "_").replace(/^_+|_+$/g, "") || "migration", fn = (e, t) => `import { defineMigration, SqlClient } from '@voltro/database'
1447
1449
  import { Effect } from 'effect'
1448
1450
 
1449
1451
  // A hand-written migration. Reach for this when the DECLARATIVE differ can't
@@ -1475,100 +1477,100 @@ export default defineMigration({
1475
1477
  }),
1476
1478
  ],
1477
1479
  })
1478
- `, un = {
1479
- plan: Rt,
1480
- apply: Bt,
1481
- branch: qt,
1482
- plans: Jt,
1483
- drift: nn,
1484
- files: an,
1485
- "rollback-file": on,
1486
- migrate: bt,
1487
- rollback: xt,
1488
- status: St,
1489
- seed: wt,
1480
+ `, pn = {
1481
+ plan: Vt,
1482
+ apply: Ut,
1483
+ branch: Xt,
1484
+ plans: Zt,
1485
+ drift: on,
1486
+ files: cn,
1487
+ "rollback-file": ln,
1488
+ migrate: Ct,
1489
+ rollback: wt,
1490
+ status: Tt,
1491
+ seed: Dt,
1490
1492
  generate: async (e) => {
1491
- let { value: t, rest: n } = i(e, "--root"), { value: r, rest: a } = i(n, "--name"), o = t ? C(t) : process.cwd(), c = cn(r ?? s(a, []) ?? "migration"), l = `${sn()}_${c}`, u = x(o, "migrations"), d = x(u, `${l}.migration.ts`);
1492
- return await w.mkdir(u, { recursive: !0 }), await w.writeFile(d, ln(l, c), "utf8"), B.info(`created ${S(o, d)}`), console.error("Fill in the apply/undo steps, then run `voltro db migrate` (rollback with `voltro db rollback`)."), console.error("For a plain schema shape change you may not need this — `voltro db apply` diffs declared vs live."), 0;
1493
+ let { value: t, rest: n } = a(e, "--root"), { value: r, rest: i } = a(n, "--name"), o = t ? w(t) : process.cwd(), s = dn(r ?? c(i, []) ?? "migration"), l = `${un()}_${s}`, u = S(o, "migrations"), d = S(u, `${l}.migration.ts`);
1494
+ return await T.mkdir(u, { recursive: !0 }), await T.writeFile(d, fn(l, s), "utf8"), B.info(`created ${C(o, d)}`), console.error("Fill in the apply/undo steps, then run `voltro db migrate` (rollback with `voltro db rollback`)."), console.error("For a plain schema shape change you may not need this — `voltro db apply` diffs declared vs live."), 0;
1493
1495
  },
1494
- squash: Zt,
1495
- "restore-snapshot": Yt,
1496
- "gc-snapshots": Xt,
1496
+ squash: en,
1497
+ "restore-snapshot": Qt,
1498
+ "gc-snapshots": $t,
1497
1499
  adopt: async (e) => {
1498
1500
  let t = (t) => {
1499
1501
  let n = e.indexOf(`--${t}`);
1500
1502
  return n === -1 ? void 0 : e[n + 1];
1501
- }, n = t("from"), i = t("into"), a = t("map");
1502
- if (n === void 0 || i === void 0 || a === void 0) return console.error("voltro db adopt --from <table> --into <table> --map <file.ts> [--apply] [--keep-source]"), console.error(" Dry run unless --apply. The map file default-exports { map, leaveUnset? }."), 1;
1503
- let o = (await r(C(process.cwd(), a))).default;
1503
+ }, n = t("from"), r = t("into"), a = t("map");
1504
+ if (n === void 0 || r === void 0 || a === void 0) return console.error("voltro db adopt --from <table> --into <table> --map <file.ts> [--apply] [--keep-source]"), console.error(" Dry run unless --apply. The map file default-exports { map, leaveUnset? }."), 1;
1505
+ let o = (await i(w(process.cwd(), a))).default;
1504
1506
  if (o?.map === void 0) return console.error(`voltro db adopt: ${a} must default-export { map: { <targetColumn>: <source> } }`), 1;
1505
1507
  let s = {
1506
1508
  from: n,
1507
- into: i,
1509
+ into: r,
1508
1510
  map: o.map,
1509
1511
  ...o.leaveUnset ? { leaveUnset: o.leaveUnset } : {}
1510
- }, c = W(), l = await q(), u = await J(l, D.SqlClient.pipe(E.flatMap(ce))), d = (e) => u.tables.find((t) => t.name === e)?.columns.map((e) => ({
1512
+ }, c = W(), l = await q(), u = await J(l, k.SqlClient.pipe(O.flatMap(de))), d = (e) => u.tables.find((t) => t.name === e)?.columns.map((e) => ({
1511
1513
  name: e.name,
1512
1514
  nullable: e.nullable,
1513
1515
  hasDefault: e.defaultValue !== void 0 && e.defaultValue !== null
1514
- })), f = d(n), p = d(i);
1516
+ })), f = d(n), p = d(r);
1515
1517
  if (f === void 0) return console.error(`voltro db adopt: '${n}' does not exist in the database`), 1;
1516
- if (p === void 0) return console.error(`voltro db adopt: '${i}' does not exist in the database — boot once so the plugin's table is created`), 1;
1517
- let m = async (e) => await J(l, D.SqlClient.pipe(E.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 = Ae(s, f, p, await h(i));
1518
- for (let e of Me(s, g, await h(n))) console.log(e);
1518
+ 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;
1519
+ let m = async (e) => await J(l, k.SqlClient.pipe(O.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 = Pe(s, f, p, await h(r));
1520
+ for (let e of Ie(s, g, await h(n))) console.log(e);
1519
1521
  if (g.fatal) return 1;
1520
1522
  if (!e.includes("--apply")) return console.log(""), console.log(" (dry run — nothing written. Re-run with --apply.)"), 0;
1521
- let _ = await Le(s, g, c, "id", void 0, m, { keepSource: e.includes("--keep-source") });
1523
+ let _ = await Ve(s, g, c, "id", void 0, m, { keepSource: e.includes("--keep-source") });
1522
1524
  return console.log(""), console.log(` copied ${_.copied}/${_.sourceRows} row(s)`), console.log(` snapshot: ${_.snapshotTable} — restore from here, then drop it yourself`), _.verified ? (console.log(_.sourceDropped ? ` dropped ${n}` : ` ${n} left in place (--keep-source)`), 0) : (console.error(" ✗ counts DIFFER — the source was NOT dropped. Compare the two tables before doing anything else."), 1);
1523
1525
  },
1524
1526
  "scan-credentials": async (e) => {
1525
- let t = W(), r = [];
1527
+ let t = W(), n = [];
1526
1528
  for (let t = 0; t < e.length; t += 1) {
1527
1529
  if (e[t] !== "--table") continue;
1528
1530
  let i = e[t + 1];
1529
- if (i === void 0) throw new n("voltro db scan-credentials: --table needs a value");
1531
+ if (i === void 0) throw new r("voltro db scan-credentials: --table needs a value");
1530
1532
  let [a, o = "subject"] = i.split(":");
1531
- r.push({
1533
+ n.push({
1532
1534
  table: a,
1533
1535
  column: o
1534
1536
  });
1535
1537
  }
1536
- let i = [...Re, ...r], a = await J(await q(), D.SqlClient.pipe(E.flatMap((e) => E.promise(() => Xe(e, t, i, G)))));
1537
- return console.log(Ze(a, t)), Qe(a);
1538
+ let i = [...He, ...n], a = await J(await q(), k.SqlClient.pipe(O.flatMap((e) => O.promise(() => $e(e, t, i, G)))));
1539
+ return console.log(et(a, t)), tt(a);
1538
1540
  },
1539
1541
  "encrypt-column": async (e) => {
1540
- let t = W(), r = e.includes("--dry-run"), i = e.includes("--yes"), o = (t) => {
1542
+ let t = W(), n = e.includes("--dry-run"), i = e.includes("--yes"), a = (t) => {
1541
1543
  let n = e.indexOf(t);
1542
1544
  return n >= 0 ? e[n + 1] : void 0;
1543
- }, s = Math.max(1, Number(o("--batch") ?? 500)), c = o("--key-env") ?? "FIELD_ENCRYPTION_KEY", l = process.env[c];
1544
- if (!l) throw new n(`voltro db encrypt-column: ${c} is not set. It must be the SAME key your app runs with (\`governancePlugin({ fieldEncryption: { key } })\`) — encrypting with a different one produces rows the app cannot read. Use --key-env to name a different variable.`);
1545
- let u = De(l), d = a(e, _t).filter((e) => e.includes(".")).map(ot);
1546
- if (d.length === 0) throw new n("voltro db encrypt-column: name at least one <table>.<column>");
1545
+ }, s = Math.max(1, Number(a("--batch") ?? 500)), c = a("--key-env") ?? "FIELD_ENCRYPTION_KEY", l = process.env[c];
1546
+ if (!l) throw new r(`voltro db encrypt-column: ${c} is not set. It must be the SAME key your app runs with (\`governancePlugin({ fieldEncryption: { key } })\`) — encrypting with a different one produces rows the app cannot read. Use --key-env to name a different variable.`);
1547
+ let u = je(l), d = o(e, bt).filter((e) => e.includes(".")).map(lt);
1548
+ if (d.length === 0) throw new r("voltro db encrypt-column: name at least one <table>.<column>");
1547
1549
  let f = await q(), p = [];
1548
1550
  for (let e of d) {
1549
- let a = G(e.table), o = G(e.column), l = await J(f, D.SqlClient.pipe(E.flatMap((r) => E.promise(async () => {
1550
- let i = await E.runPromise(r.unsafe(`SELECT character_maximum_length AS n FROM information_schema.columns\n WHERE ${K(t)} AND table_name = '${e.table}' AND column_name = '${e.column}'`));
1551
- if (i.length === 0) throw new n(`voltro db encrypt-column: ${e.table}.${e.column} does not exist on this database`);
1551
+ let a = G(e.table), o = G(e.column), l = await J(f, k.SqlClient.pipe(O.flatMap((n) => O.promise(async () => {
1552
+ let i = await O.runPromise(n.unsafe(`SELECT character_maximum_length AS n FROM information_schema.columns\n WHERE ${K(t)} AND table_name = '${e.table}' AND column_name = '${e.column}'`));
1553
+ if (i.length === 0) throw new r(`voltro db encrypt-column: ${e.table}.${e.column} does not exist on this database`);
1552
1554
  let a = Object.values(i[0])[0];
1553
1555
  return a == null ? void 0 : Number(a);
1554
- })))), d = await J(f, D.SqlClient.pipe(E.flatMap((e) => E.promise(async () => await E.runPromise(e.unsafe(`SELECT ${G("id")} AS id, ${o} AS v FROM ${a}`)))))), m = 0;
1555
- for (let e of d) typeof e.v != "string" || F(e.v) || (m = Math.max(m, ft(e.v)));
1556
- let h = ct(m, l);
1557
- if (!h.fits) return console.error(` ✗ ${lt(e, h)}`), 1;
1558
- if (pt(d.map((e) => e.v).find((e) => typeof e == "string" && F(e)), u) === !1) return console.error(` ✗ ${mt(e, c)}`), 1;
1559
- let g = d.filter((t) => dt(t.v, u, e) !== void 0).length;
1560
- if (!r && !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;
1556
+ })))), d = await J(f, k.SqlClient.pipe(O.flatMap((e) => O.promise(async () => await O.runPromise(e.unsafe(`SELECT ${G("id")} AS id, ${o} AS v FROM ${a}`)))))), m = 0;
1557
+ for (let e of d) typeof e.v != "string" || P(e.v) || (m = Math.max(m, ht(e.v)));
1558
+ let h = dt(m, l);
1559
+ if (!h.fits) return console.error(` ✗ ${ft(e, h)}`), 1;
1560
+ if (gt(d.map((e) => e.v).find((e) => typeof e == "string" && P(e)), u) === !1) return console.error(` ✗ ${_t(e, c)}`), 1;
1561
+ let g = d.filter((t) => mt(t.v, u, e) !== void 0).length;
1562
+ 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;
1561
1563
  let _ = 0, v = 0, y = 0, b = [];
1562
1564
  for (let t of d) {
1563
1565
  if (t.v === null || t.v === void 0 || t.v === "") {
1564
1566
  v += 1;
1565
1567
  continue;
1566
1568
  }
1567
- if (typeof t.v == "string" && F(t.v)) {
1569
+ if (typeof t.v == "string" && P(t.v)) {
1568
1570
  _ += 1;
1569
1571
  continue;
1570
1572
  }
1571
- let n = dt(t.v, u, e);
1573
+ let n = mt(t.v, u, e);
1572
1574
  if (n === void 0) {
1573
1575
  v += 1;
1574
1576
  continue;
@@ -1578,10 +1580,10 @@ export default defineMigration({
1578
1580
  value: n
1579
1581
  }), y += 1;
1580
1582
  }
1581
- if (!r && b.length > 0) for (let t = 0; t < b.length; t += s) {
1583
+ if (!n && b.length > 0) for (let t = 0; t < b.length; t += s) {
1582
1584
  let n = b.slice(t, t + s);
1583
- await J(f, D.SqlClient.pipe(E.flatMap((t) => E.promise(async () => {
1584
- for (let r of n) await E.runPromise(t`UPDATE ${t(e.table)} SET ${t(e.column)} = ${r.value} WHERE ${t("id")} = ${r.id}`);
1585
+ await J(f, k.SqlClient.pipe(O.flatMap((t) => O.promise(async () => {
1586
+ for (let r of n) await O.runPromise(t`UPDATE ${t(e.table)} SET ${t(e.column)} = ${r.value} WHERE ${t("id")} = ${r.id}`);
1585
1587
  })))), B.info(`encrypt-column ${e.table}.${e.column}: ${Math.min(t + n.length, b.length)}/${b.length}`);
1586
1588
  }
1587
1589
  p.push({
@@ -1593,29 +1595,29 @@ export default defineMigration({
1593
1595
  encrypted: y
1594
1596
  });
1595
1597
  }
1596
- console.log(`field encryption · dialect ${t}${r ? " · DRY RUN, nothing written" : ""}`), console.log("");
1597
- for (let e of p) console.log(ut(e, r));
1598
- return r || console.log(ht(d)), 0;
1598
+ console.log(`field encryption · dialect ${t}${n ? " · DRY RUN, nothing written" : ""}`), console.log("");
1599
+ for (let e of p) console.log(pt(e, n));
1600
+ return n || console.log(vt(d)), 0;
1599
1601
  }
1600
- }, dn = async (e) => {
1601
- let [t, ...n] = e;
1602
- if (!t) {
1602
+ }, mn = (e) => Object.prototype.hasOwnProperty.call(pn, e), hn = async (t) => {
1603
+ let [n, ...r] = t;
1604
+ if (!n) {
1603
1605
  console.error("voltro db <subcommand> [args]"), console.error("subcommands:");
1604
- for (let e of Object.keys(un)) console.error(` ${e}`);
1606
+ for (let e of Object.keys(pn)) console.error(` ${e}`);
1605
1607
  return 1;
1606
1608
  }
1607
- let r = un[t];
1608
- if (!r) return console.error(`voltro db: unknown subcommand '${t}'`), 2;
1609
+ if (!mn(n)) return console.error(`voltro db: unknown subcommand '${n}'`), console.error(` known: ${e.join(", ")}`), 2;
1610
+ let i = pn[n];
1609
1611
  (process.env.DB_DIRECT_URL !== void 0 || process.env.DB_MIGRATE_URL !== void 0) && B.info("using a DIRECT (non-pooler) connection for the db-command path (DB_DIRECT_URL/DB_MIGRATE_URL set)");
1610
- let i = (e) => {
1611
- vt(e) ? B.error(yt) : console.error(e), process.exit(1);
1612
+ let a = (e) => {
1613
+ xt(e) ? B.error(St) : console.error(e), process.exit(1);
1612
1614
  };
1613
- process.on("uncaughtException", i);
1615
+ process.on("uncaughtException", a);
1614
1616
  try {
1615
- return await r(n);
1617
+ return await i(r);
1616
1618
  } finally {
1617
- process.off("uncaughtException", i);
1619
+ process.off("uncaughtException", a);
1618
1620
  }
1619
1621
  };
1620
1622
  //#endregion
1621
- export { Dt as a, tn as i, U as n, vt as o, Et as r, dn as s, yt as t };
1623
+ export { At as a, an as i, U as n, xt as o, kt as r, hn as s, St as t };