@voltro/data-transfer 0.40.0 → 0.42.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,17 +1,17 @@
1
1
  import { Cause as e, Data as t, Effect as n, Exit as r, Metric as i, MetricBoundaries as a, Schedule as o, Schema as s, Stream as c } from "effect";
2
- import { eq as l, inSet as u, isNotNull as d, or as f, streamTable as p } from "@voltro/database";
3
- import { fingerprintSchema as m } from "@voltro/database/sql";
4
- import { createCipheriv as h, createDecipheriv as g, createHash as _, createHmac as v, randomBytes as y, scrypt as b } from "node:crypto";
5
- import { STORAGE_REFS_TABLE as x, fromNodeReadable as S, getObjectStream as C, putObjectStream as ee, toNodeReadable as te } from "@voltro/plugin-storage";
2
+ import { classifyConstraintViolation as l, eq as u, extractDbCause as d, inSet as f, isNotNull as p, or as m, streamTable as h } from "@voltro/database";
3
+ import { fingerprintSchema as g } from "@voltro/database/sql";
4
+ import { createCipheriv as _, createDecipheriv as v, createHash as y, createHmac as ee, randomBytes as b, scrypt as x } from "node:crypto";
5
+ import { STORAGE_REFS_TABLE as S, fromNodeReadable as C, getObjectStream as te, putObjectStream as ne, toNodeReadable as re } from "@voltro/plugin-storage";
6
6
  import * as w from "node:zlib";
7
- import { PassThrough as T, Readable as ne } from "node:stream";
8
- import { copyFile as re, createReadStream as E, createWriteStream as D, existsSync as ie, unlinkSync as ae } from "node:fs";
9
- import { mkdir as oe, readdir as se, stat as ce } from "node:fs/promises";
10
- import { basename as le, delimiter as ue, dirname as de, join as O, resolve as fe, sep as pe } from "node:path";
11
- import { promisify as me } from "node:util";
12
- import { spawn as he } from "node:child_process";
7
+ import { PassThrough as ie, Readable as ae } from "node:stream";
8
+ import { copyFile as oe, createReadStream as T, createWriteStream as E, existsSync as se, unlinkSync as ce } from "node:fs";
9
+ import { mkdir as D, readdir as le, stat as ue } from "node:fs/promises";
10
+ import { basename as de, delimiter as fe, dirname as pe, join as O, resolve as me, sep as he } from "node:path";
11
+ import { promisify as ge } from "node:util";
12
+ import { spawn as _e } from "node:child_process";
13
13
  //#region src/consistency.ts
14
- var ge = (e) => {
14
+ var ve = (e) => {
15
15
  switch (e) {
16
16
  case "postgres": return ["SET TRANSACTION ISOLATION LEVEL REPEATABLE READ"];
17
17
  case "mysql":
@@ -21,7 +21,7 @@ var ge = (e) => {
21
21
  case "turso": return [];
22
22
  default: return [];
23
23
  }
24
- }, _e = {
24
+ }, ye = {
25
25
  email: { fake: "email" },
26
26
  fullName: { fake: "fullName" },
27
27
  firstName: { fake: "firstName" },
@@ -36,7 +36,7 @@ var ge = (e) => {
36
36
  date: "dateShift",
37
37
  secret: "null",
38
38
  freeText: "redact"
39
- }, ve = (e) => {
39
+ }, k = (e) => {
40
40
  let t = {};
41
41
  for (let n of e.tables) {
42
42
  let e = {};
@@ -48,15 +48,15 @@ var ge = (e) => {
48
48
  t[n.name] = e;
49
49
  }
50
50
  return t;
51
- }, ye = (e, t, n, r) => {
51
+ }, be = (e, t, n, r) => {
52
52
  let i = r.columns?.[`${e}.${t}`];
53
53
  if (i) return i;
54
54
  if (n?.sensitive) {
55
55
  let e = n.sensitive.class;
56
- return r.classes?.[e] ?? _e[e] ?? "redact";
56
+ return r.classes?.[e] ?? ye[e] ?? "redact";
57
57
  }
58
58
  return n?.safe ? r.onSafe ?? "keep" : n?.columnType === "id" || n?.columnType === "reference" ? "keep" : r.onUnclassified ?? "error";
59
- }, k = (e, t) => v("sha256", e).update(t == null ? "∅" : String(t)).digest(), A = (e, t) => e.readUInt32BE(t * 4 % (e.length - 4)), j = [
59
+ }, A = (e, t) => ee("sha256", e).update(t == null ? "∅" : String(t)).digest(), j = (e, t) => e.readUInt32BE(t * 4 % (e.length - 4)), M = [
60
60
  "Ada",
61
61
  "Alan",
62
62
  "Grace",
@@ -69,7 +69,7 @@ var ge = (e) => {
69
69
  "Guido",
70
70
  "Margaret",
71
71
  "Bjarne"
72
- ], M = [
72
+ ], xe = [
73
73
  "Lovelace",
74
74
  "Turing",
75
75
  "Hopper",
@@ -82,7 +82,7 @@ var ge = (e) => {
82
82
  "Rossum",
83
83
  "Hamilton",
84
84
  "Stroustrup"
85
- ], be = [
85
+ ], Se = [
86
86
  "Maple",
87
87
  "Oak",
88
88
  "Cedar",
@@ -91,7 +91,7 @@ var ge = (e) => {
91
91
  "Birch",
92
92
  "Willow",
93
93
  "Ash"
94
- ], xe = [
94
+ ], Ce = [
95
95
  "Initech",
96
96
  "Hooli",
97
97
  "Umbrella",
@@ -100,23 +100,23 @@ var ge = (e) => {
100
100
  "Soylent",
101
101
  "Stark",
102
102
  "Wayne"
103
- ], N = (e, t, n) => e[A(t, n) % e.length], Se = (e, t, n) => {
104
- let r = k(n, `${e}:${String(t)}`), i = A(r, 1) % 1e4;
103
+ ], N = (e, t, n) => e[j(t, n) % e.length], we = (e, t, n) => {
104
+ let r = A(n, `${e}:${String(t)}`), i = j(r, 1) % 1e4;
105
105
  switch (e) {
106
- case "email": return `${N(j, r, 0).toLowerCase()}.${N(M, r, 2).toLowerCase()}${i}@example.com`;
107
- case "fullName": return `${N(j, r, 0)} ${N(M, r, 1)}`;
108
- case "firstName": return N(j, r, 0);
109
- case "lastName": return N(M, r, 1);
110
- case "username": return `${N(j, r, 0).toLowerCase()}${i}`;
111
- case "phone": return `+1${String(A(r, 0) % 1e10).padStart(10, "0")}`;
112
- case "address": return `${A(r, 0) % 9899 + 100} ${N(be, r, 1)} St`;
113
- case "company": return N(xe, r, 0);
106
+ case "email": return `${N(M, r, 0).toLowerCase()}.${N(xe, r, 2).toLowerCase()}${i}@example.com`;
107
+ case "fullName": return `${N(M, r, 0)} ${N(xe, r, 1)}`;
108
+ case "firstName": return N(M, r, 0);
109
+ case "lastName": return N(xe, r, 1);
110
+ case "username": return `${N(M, r, 0).toLowerCase()}${i}`;
111
+ case "phone": return `+1${String(j(r, 0) % 1e10).padStart(10, "0")}`;
112
+ case "address": return `${j(r, 0) % 9899 + 100} ${N(Se, r, 1)} St`;
113
+ case "company": return N(Ce, r, 0);
114
114
  case "url": return `https://example.com/${r.toString("hex").slice(0, 12)}`;
115
- case "ip": return `${A(r, 0) % 256}.${A(r, 1) % 256}.${A(r, 2) % 256}.${A(r, 3) % 254 + 1}`;
116
- case "creditCard": return Ce(`4${r.toString("hex").replace(/\D/g, "").padEnd(14, "0").slice(0, 14)}`);
115
+ case "ip": return `${j(r, 0) % 256}.${j(r, 1) % 256}.${j(r, 2) % 256}.${j(r, 3) % 254 + 1}`;
116
+ case "creditCard": return Te(`4${r.toString("hex").replace(/\D/g, "").padEnd(14, "0").slice(0, 14)}`);
117
117
  default: return `${e}_${r.toString("hex").slice(0, 8)}`;
118
118
  }
119
- }, Ce = (e) => {
119
+ }, Te = (e) => {
120
120
  let t = e.slice(0, 15).split("").map(Number), n = 0;
121
121
  t.forEach((e, t) => {
122
122
  let r = e;
@@ -124,26 +124,45 @@ var ge = (e) => {
124
124
  });
125
125
  let r = (10 - n % 10) % 10;
126
126
  return e.slice(0, 15) + String(r);
127
- }, we = 864e5, Te = (e, t) => {
127
+ }, Ee = 864e5, De = (e, t) => {
128
128
  let n = e instanceof Date ? e.getTime() : Date.parse(String(e));
129
129
  if (Number.isNaN(n)) return e;
130
- let r = A(k(t, "date-shift-offset"), 0) % 730 - 365, i = new Date(n + r * we);
130
+ let r = j(A(t, "date-shift-offset"), 0) % 730 - 365, i = new Date(n + r * Ee);
131
131
  return e instanceof Date ? i : i.toISOString();
132
- }, Ee = (e, t) => {
132
+ }, Oe = (e, t) => {
133
133
  if (t.value === null || t.value === void 0) return null;
134
134
  if (e === "error") throw Error(`masking: unresolved 'error' action for ${t.table}.${t.column}`);
135
- return e === "keep" ? t.value : e === "null" ? null : e === "redact" ? t.columnType === "text" || typeof t.value == "string" ? "[redacted]" : null : e === "hash" ? k(t.seed, t.value).toString("hex").slice(0, 16) : e === "dateShift" ? Te(t.value, t.seed) : typeof e == "object" && "fake" in e ? Se(e.fake, t.value, t.seed) : typeof e == "object" && "custom" in e ? e.custom(t) : t.value;
136
- }, De = (e, t, n) => {
137
- let r = {}, i = [];
138
- for (let a of e) for (let e of a.columns) {
139
- let o = `${a.name}.${e.name}`, s = ye(a.name, e.name, t[a.name]?.[e.name], n);
140
- s === "error" ? i.push(o) : r[o] = s;
135
+ if (e === "keep") return t.value;
136
+ if (e === "null") return null;
137
+ if (e === "redact") return t.columnType === "text" || typeof t.value == "string" ? "[redacted]" : null;
138
+ if (e === "hash") return A(t.seed, t.value).toString("hex").slice(0, 16);
139
+ if (e === "dateShift") return De(t.value, t.seed);
140
+ if (typeof e == "object" && "fake" in e) return we(e.fake, t.value, t.seed);
141
+ if (typeof e == "object" && "custom" in e) return e.custom(t);
142
+ throw Error(`masking: '${t.table}.${t.column}' resolved to an action this build does not understand (${JSON.stringify(e)}). Refusing to copy the value through. Valid actions: 'keep' | 'null' | 'redact' | 'hash' | 'dateShift' | { fake: '<class>' } | { custom: fn }.`);
143
+ }, ke = (e) => typeof e == "string" ? e === "keep" || e === "null" || e === "redact" || e === "hash" || e === "dateShift" || e === "error" : typeof e != "object" || !e ? !1 : "fake" in e ? typeof e.fake == "string" : "custom" in e && typeof e.custom == "function", Ae = (e, t, n) => {
144
+ let r = {}, i = [], a = [];
145
+ for (let o of e) for (let e of o.columns) {
146
+ let s = `${o.name}.${e.name}`, c = be(o.name, e.name, t[o.name]?.[e.name], n);
147
+ if (c === "error") {
148
+ i.push(s);
149
+ continue;
150
+ }
151
+ if (!ke(c)) {
152
+ a.push({
153
+ column: s,
154
+ action: c
155
+ });
156
+ continue;
157
+ }
158
+ r[s] = c;
141
159
  }
142
160
  return {
143
161
  actions: r,
144
- unclassified: i
162
+ unclassified: i,
163
+ invalid: a
145
164
  };
146
- }, Oe = [
165
+ }, je = [
147
166
  {
148
167
  name: "email",
149
168
  re: /[\w.+-]+@[\w-]+\.[\w.-]+/
@@ -160,7 +179,7 @@ var ge = (e) => {
160
179
  name: "creditCard",
161
180
  re: /\b(?:\d[ -]?){13,16}\b/
162
181
  }
163
- ], ke = (e, t, n) => {
182
+ ], Me = (e, t, n) => {
164
183
  let r = [], i = /* @__PURE__ */ new Set();
165
184
  for (let [a, o] of Object.entries(n)) {
166
185
  if (!a.startsWith(`${t}.`) || o !== "keep") continue;
@@ -168,7 +187,7 @@ var ge = (e) => {
168
187
  for (let a of e) {
169
188
  let e = a[n];
170
189
  if (typeof e != "string" || e.length === 0) continue;
171
- let o = Oe.find((t) => t.re.test(e));
190
+ let o = je.find((t) => t.re.test(e));
172
191
  if (o && !i.has(n)) {
173
192
  i.add(n), r.push({
174
193
  table: t,
@@ -181,9 +200,9 @@ var ge = (e) => {
181
200
  }
182
201
  }
183
202
  return r;
184
- }, P = (e, t, n, r, i) => {
203
+ }, Ne = (e, t, n, r, i) => {
185
204
  let a = {};
186
- for (let [o, s] of Object.entries(e)) a[o] = Ee(n[`${t}.${o}`] ?? "keep", {
205
+ for (let [o, s] of Object.entries(e)) a[o] = Oe(n[`${t}.${o}`] ?? "keep", {
187
206
  value: s,
188
207
  table: t,
189
208
  column: o,
@@ -191,24 +210,24 @@ var ge = (e) => {
191
210
  ...i?.[o] ? { columnType: i[o] } : {}
192
211
  });
193
212
  return a;
194
- }, F = class extends s.TaggedError()("BundleError", {
213
+ }, P = class extends s.TaggedError()("BundleError", {
195
214
  reason: s.String,
196
215
  path: s.optional(s.String)
197
- }) {}, Ae = class extends s.TaggedError()("CodecError", {
216
+ }) {}, Pe = class extends s.TaggedError()("CodecError", {
198
217
  table: s.String,
199
218
  reason: s.String
200
- }) {}, I = class extends s.TaggedError()("IntegrityError", {
219
+ }) {}, F = class extends s.TaggedError()("IntegrityError", {
201
220
  what: s.String,
202
221
  expected: s.String,
203
222
  actual: s.String
204
- }) {}, je = class extends t.TaggedError("CompressionError") {}, Me = class extends s.TaggedError()("ScopeError", { reason: s.String }) {}, Ne = class extends s.TaggedError()("DanglingReferenceError", {
223
+ }) {}, Fe = class extends t.TaggedError("CompressionError") {}, I = class extends s.TaggedError()("ScopeError", { reason: s.String }) {}, Ie = class extends s.TaggedError()("DanglingReferenceError", {
205
224
  rows: s.Array(s.Struct({
206
225
  table: s.String,
207
226
  id: s.String,
208
227
  reason: s.String
209
228
  })),
210
229
  totalCount: s.Number
211
- }) {}, Pe = class extends s.TaggedError()("SchemaDriftError", {
230
+ }) {}, Le = class extends s.TaggedError()("SchemaDriftError", {
212
231
  bundleFingerprint: s.String,
213
232
  targetFingerprint: s.String,
214
233
  diff: s.Array(s.String)
@@ -217,36 +236,39 @@ var ge = (e) => {
217
236
  let e = this.stderr?.trim();
218
237
  return `${this.tool}: ${this.reason}${e ? `\n${e}` : ""}`;
219
238
  }
220
- }, Fe = class extends s.TaggedError()("MaskingError", { unclassified: s.Array(s.String) }) {}, Ie = class extends s.TaggedError()("ImportModeError", {
239
+ }, Re = class extends s.TaggedError()("MaskingError", {
240
+ unclassified: s.Array(s.String),
241
+ invalidActions: s.optional(s.Array(s.String))
242
+ }) {}, ze = class extends s.TaggedError()("ImportModeError", {
221
243
  mode: s.String,
222
244
  reason: s.String
223
- }) {}, Le = class extends s.TaggedError()("CrossDialectError", {
245
+ }) {}, Be = class extends s.TaggedError()("CrossDialectError", {
224
246
  sourceDialect: s.String,
225
247
  targetDialect: s.String,
226
248
  blocking: s.Array(s.String)
227
- }) {}, R = (e, t) => e.tables.find((e) => e.name === t)?.columns.find((e) => e.type === "id")?.name ?? "id", Re = (e, t) => (e.tables.find((e) => e.name === t)?.columns ?? []).filter((e) => e.references).map((e) => ({
249
+ }) {}, R = (e, t) => e.tables.find((e) => e.name === t)?.columns.find((e) => e.type === "id")?.name ?? "id", Ve = (e, t) => (e.tables.find((e) => e.name === t)?.columns ?? []).filter((e) => e.references).map((e) => ({
228
250
  col: e.name,
229
251
  refTable: e.references.table
230
252
  })), z = (e, t, r) => n.gen(function* () {
231
- let i = r.maxDepth ?? 12, a = new Set(r.pinned ?? []), o = /* @__PURE__ */ new Map(), s = /* @__PURE__ */ new Map(), l = /* @__PURE__ */ new Map(), d = (e) => {
253
+ let i = r.maxDepth ?? 12, a = new Set(r.pinned ?? []), o = /* @__PURE__ */ new Map(), s = /* @__PURE__ */ new Map(), l = /* @__PURE__ */ new Map(), u = (e) => {
232
254
  let t = s.get(e) ?? /* @__PURE__ */ new Set();
233
255
  return s.set(e, t), t;
234
- }, m = (e, t) => {
256
+ }, d = (e, t) => {
235
257
  if (t == null || a.has(e) || s.get(e)?.has(t)) return;
236
258
  let n = l.get(e) ?? /* @__PURE__ */ new Set();
237
259
  n.add(t), l.set(e, n);
238
- }, h = (e, t, n) => {
239
- let r = d(e), i = a.has(e) ? void 0 : o.get(e) ?? (() => {
260
+ }, p = (e, t, n) => {
261
+ let r = u(e), i = a.has(e) ? void 0 : o.get(e) ?? (() => {
240
262
  let t = /* @__PURE__ */ new Set();
241
263
  return o.set(e, t), t;
242
264
  })();
243
265
  return (e) => {
244
266
  r.add(e[t]), i?.add(e[t]);
245
- for (let t of n) m(t.refTable, e[t.col]);
267
+ for (let t of n) d(t.refTable, e[t.col]);
246
268
  };
247
269
  }, g = (r, i) => {
248
- let a = h(r, R(t, r), Re(t, r));
249
- return c.runForEach(p(e, {
270
+ let a = p(r, R(t, r), Ve(t, r));
271
+ return c.runForEach(h(e, {
250
272
  table: r,
251
273
  pk: R(t, r),
252
274
  ...i === void 0 ? {} : { where: i }
@@ -257,7 +279,7 @@ var ge = (e) => {
257
279
  l.clear();
258
280
  for (let [n, r] of e) {
259
281
  let e = [...r].filter((e) => !s.get(n)?.has(e));
260
- e.length !== 0 && (yield* g(n, u(R(t, n), e)));
282
+ e.length !== 0 && (yield* g(n, f(R(t, n), e)));
261
283
  }
262
284
  }
263
285
  });
@@ -272,58 +294,60 @@ var ge = (e) => {
272
294
  refTable: e.references?.table
273
295
  })).filter((t) => !!t.refTable && e.has(t.refTable) && (s.get(t.refTable)?.size ?? 0) > 0);
274
296
  if (a.length === 0) continue;
275
- let o = s.get(t)?.size ?? 0, c = a.map((e) => u(e.col, [...s.get(e.refTable)]));
276
- yield* g(t, c.length === 1 ? c[0] : f(...c)), (s.get(t)?.size ?? 0) > o && !e.has(t) && r.push(t), (s.get(t)?.size ?? 0) > o && (n = !0);
297
+ let o = s.get(t)?.size ?? 0, c = a.map((e) => f(e.col, [...s.get(e.refTable)]));
298
+ yield* g(t, c.length === 1 ? c[0] : m(...c)), (s.get(t)?.size ?? 0) > o && !e.has(t) && r.push(t), (s.get(t)?.size ?? 0) > o && (n = !0);
277
299
  }
278
300
  for (let t of r) e.add(t);
279
301
  if (yield* _, !n) break;
280
302
  }
281
303
  }
282
304
  return o;
283
- }), ze = (e, t) => ({
305
+ }), He = (e, t) => ({
284
306
  tables: [...e.keys()],
285
307
  predicateFor: (n) => {
286
308
  let r = e.get(n);
287
- return r ? u(R(t, n), [...r]) : void 0;
309
+ return r ? f(R(t, n), [...r]) : void 0;
288
310
  }
289
- }), B = "tenantId", Be = (e, t, r) => n.gen(function* () {
311
+ }), B = "tenantId", V = (e, t, r) => n.gen(function* () {
290
312
  let i = t.tables.map((e) => e.name), a = new Map(t.tables.map((e) => [e.name, e]));
291
313
  if (e.kind === "all") return {
292
314
  tables: i,
293
315
  predicateFor: () => void 0
294
316
  };
295
317
  if (e.kind === "tables") {
296
- let t = new Set(e.tables ?? []);
318
+ let t = e.tables ?? [], r = new Set(i), a = t.filter((e) => !r.has(e));
319
+ if (a.length > 0) return yield* n.fail(new I({ reason: `scope { kind: 'tables' } names ${a.length} table(s) that are not in the schema: ${a.join(", ")}. Refusing to write a bundle that silently omits them. Known tables: ${i.length}.` }));
320
+ let o = new Set(t);
297
321
  return {
298
- tables: i.filter((e) => t.has(e)),
322
+ tables: i.filter((e) => o.has(e)),
299
323
  predicateFor: () => void 0
300
324
  };
301
325
  }
302
326
  let o = e.tenantId;
303
- if (o === void 0 || o === "") return yield* n.fail(new Me({ reason: "scope { kind: 'tenant' } requires a tenantId — pass --tenant <id> (CLI) or scope.tenantId (API). Refusing to fall back to an unfiltered export." }));
327
+ if (o === void 0 || o === "") return yield* n.fail(new I({ reason: "scope { kind: 'tenant' } requires a tenantId — pass --tenant <id> (CLI) or scope.tenantId (API). Refusing to fall back to an unfiltered export." }));
304
328
  let s = r.tenantTables ? r.tenantTables.filter((e) => a.has(e)) : i.filter((e) => a.get(e)?.columns.some((e) => e.name === B) ?? !1);
305
- if (s.length === 0) return yield* n.fail(new Me({ reason: r.tenantTables ? "tenant scope: none of the provided tenantTables exist in the schema — nothing to filter." : `tenant scope: no table carries a '${B}' column — nothing to filter. A tenant export of a schema without tenant-scoped tables would be the full database; refusing.` }));
329
+ if (s.length === 0) return yield* n.fail(new I({ reason: r.tenantTables ? "tenant scope: none of the provided tenantTables exist in the schema — nothing to filter." : `tenant scope: no table carries a '${B}' column — nothing to filter. A tenant export of a schema without tenant-scoped tables would be the full database; refusing.` }));
306
330
  let c = yield* z(r.store, t, {
307
- seeds: Object.fromEntries(s.map((e) => [e, l(B, o)])),
331
+ seeds: Object.fromEntries(s.map((e) => [e, u(B, o)])),
308
332
  pinned: s,
309
333
  children: { roots: s }
310
- }), d = [...c.entries()].filter(([, e]) => e.size > 0).map(([e]) => e), f = new Set(s);
334
+ }), l = [...c.entries()].filter(([, e]) => e.size > 0).map(([e]) => e), d = new Set(s);
311
335
  return {
312
- tables: [...s, ...d],
313
- predicateFor: (e) => f.has(e) ? l(B, o) : c.has(e) ? u(R(t, e), [...c.get(e)]) : void 0
336
+ tables: [...s, ...l],
337
+ predicateFor: (e) => d.has(e) ? u(B, o) : c.has(e) ? f(R(t, e), [...c.get(e)]) : void 0
314
338
  };
315
- }), Ve = (e, t) => ({
339
+ }), Ue = (e, t) => ({
316
340
  list: t,
317
- open: (t) => C(e, t)
318
- }), He = (e) => ({
319
- write: (t, n, r) => ee(e, t, n, r),
341
+ open: (t) => te(e, t)
342
+ }), We = (e) => ({
343
+ write: (t, n, r) => ne(e, t, n, r),
320
344
  has: (t) => e.head(t).pipe(n.map((e) => e !== null))
321
- }), Ue = (e, t) => n.tryPromise({
345
+ }), Ge = (e, t) => n.tryPromise({
322
346
  try: async () => {
323
347
  let { createWriteStream: n } = await import("node:fs"), r = await import("node:fs/promises"), { createHash: i, randomUUID: a } = await import("node:crypto"), { pipeline: o } = await import("node:stream/promises"), { Transform: s } = await import("node:stream"), c = await import("node:path"), l = c.join(t, `.tmp-${a()}`), u = i("sha256"), d = 0, f = new s({ transform(e, t, n) {
324
348
  u.update(e), d += e.length, n(null, e);
325
349
  } });
326
- await o(await te(e.stream), f, n(l));
350
+ await o(await re(e.stream), f, n(l));
327
351
  let p = u.digest("hex"), m = c.join(t, p);
328
352
  try {
329
353
  await r.access(m), await r.rm(l, { force: !0 });
@@ -336,23 +360,23 @@ var ge = (e) => {
336
360
  contentType: e.contentType
337
361
  };
338
362
  },
339
- catch: (e) => new F({
363
+ catch: (e) => new P({
340
364
  reason: `asset write failed: ${String(e?.message ?? e)}`,
341
365
  path: t
342
366
  })
343
- }), We = (e, t, r) => n.gen(function* () {
344
- let i = yield* n.promise(() => import("node:path")), { createReadStream: a } = yield* n.promise(() => import("node:fs")), { createHash: o } = yield* n.promise(() => import("node:crypto")), s = i.join(t, r.sha256), l = o("sha256"), u = S("bundle", () => a(s)).pipe(c.tap((e) => n.sync(() => l.update(e))));
367
+ }), Ke = (e, t, r) => n.gen(function* () {
368
+ let i = yield* n.promise(() => import("node:path")), { createReadStream: a } = yield* n.promise(() => import("node:fs")), { createHash: o } = yield* n.promise(() => import("node:crypto")), s = i.join(t, r.sha256), l = o("sha256"), u = C("bundle", () => a(s)).pipe(c.tap((e) => n.sync(() => l.update(e))));
345
369
  yield* e.write(r.key, u, {
346
370
  contentType: r.contentType,
347
371
  totalSize: r.size
348
372
  });
349
373
  let d = l.digest("hex");
350
- if (d !== r.sha256) return yield* n.fail(new I({
374
+ if (d !== r.sha256) return yield* n.fail(new F({
351
375
  what: `asset ${r.key}`,
352
376
  expected: r.sha256,
353
377
  actual: d
354
378
  }));
355
- }), Ge = () => typeof w.createZstdCompress == "function", Ke = (e) => e === "none" ? "none" : e === "gzip" ? "gzip" : Ge() ? "zstd" : "gzip", qe = (e) => e === "zstd" ? ".zst" : e === "gzip" ? ".gz" : "", Je = (e) => e === "zstd" ? w.createZstdCompress() : e === "gzip" ? w.createGzip() : new T(), Ye = (e) => e === "zstd" ? w.createZstdDecompress() : e === "gzip" ? w.createGunzip() : new T(), Xe = 1, Ze = s.Struct({
379
+ }), qe = () => typeof w.createZstdCompress == "function", Je = (e) => e === "none" ? "none" : e === "gzip" ? "gzip" : qe() ? "zstd" : "gzip", Ye = (e) => e === "zstd" ? ".zst" : e === "gzip" ? ".gz" : "", Xe = (e) => e === "zstd" ? w.createZstdCompress() : e === "gzip" ? w.createGzip() : new ie(), Ze = (e) => e === "zstd" ? w.createZstdDecompress() : e === "gzip" ? w.createGunzip() : new ie(), Qe = 1, $e = s.Struct({
356
380
  name: s.String,
357
381
  file: s.String,
358
382
  rowCount: s.Number,
@@ -362,11 +386,11 @@ var ge = (e) => {
362
386
  value: s.String
363
387
  }),
364
388
  primaryKey: s.String
365
- }), Qe = s.Struct({
389
+ }), et = s.Struct({
366
390
  kind: s.Literal("all", "tenant", "tables"),
367
391
  tenantId: s.optional(s.String),
368
392
  tables: s.optional(s.Array(s.String))
369
- }), $e = s.Struct({
393
+ }), tt = s.Struct({
370
394
  count: s.Number,
371
395
  totalBytes: s.Number,
372
396
  index: s.optional(s.String)
@@ -377,23 +401,23 @@ s.Struct({
377
401
  size: s.Number,
378
402
  contentType: s.String
379
403
  });
380
- var et = s.Struct({
404
+ var nt = s.Struct({
381
405
  formatVersion: s.Number,
382
406
  createdAt: s.String,
383
407
  source: s.Struct({
384
408
  dialect: s.String,
385
409
  schemaFingerprint: s.String
386
410
  }),
387
- scope: Qe,
411
+ scope: et,
388
412
  consistency: s.Literal("live", "snapshot"),
389
413
  compression: s.Literal("zstd", "gzip", "none"),
390
- tables: s.Array(Ze),
391
- assets: $e,
414
+ tables: s.Array($e),
415
+ assets: tt,
392
416
  masking: s.optional(s.Struct({
393
417
  policyId: s.optional(s.String),
394
418
  transformed: s.Array(s.String)
395
419
  }))
396
- }), tt = s.encodeSync(s.parseJson(et)), nt = s.decodeUnknownSync(s.parseJson(et)), V = "manifest.json", rt = "README.md", it = "data", H = "assets", U = "assets/index.ndjson", at = ".ledger.json", ot = (e) => e.kind === "tenant" ? `tenant \`${e.tenantId}\`` : e.kind === "tables" ? `tables \`${(e.tables ?? []).join(", ")}\`` : "all tables", st = (e, t) => {
420
+ }), rt = s.encodeSync(s.parseJson(nt)), it = s.decodeUnknownSync(s.parseJson(nt)), H = "manifest.json", at = "README.md", U = "data", W = "assets", G = "assets/index.ndjson", ot = ".ledger.json", st = (e) => e.kind === "tenant" ? `tenant \`${e.tenantId}\`` : e.kind === "tables" ? `tables \`${(e.tables ?? []).join(", ")}\`` : "all tables", ct = (e, t) => {
397
421
  let n = e.tables.reduce((e, t) => e + t.rowCount, 0), r = e.masking ? `✅ **Masked at the source** — ${e.masking.transformed.length} column(s) transformed${e.masking.policyId ? ` (policy \`${e.masking.policyId}\`)` : ""}. Personal data was replaced with realistic, referentially-consistent fakes before any byte was written.` : "⚠️ **NOT masked — this bundle contains REAL data (PII included).** Treat it as production data: do not copy it into a lower environment or share it without review. To produce a safe copy, re-export under a masking profile (`--profile`).", i = e.masking && e.masking.transformed.length > 0 ? `\n\nMasked columns: ${e.masking.transformed.map((e) => `\`${e}\``).join(", ")}.` : "", a = e.assets.count > 0 ? `${e.assets.count} object(s), ${e.assets.totalBytes} bytes` : "none", o = e.tables.map((e) => `| \`${e.name}\` | ${e.rowCount} |`).join("\n");
398
422
  return `# Voltro data export
399
423
 
@@ -407,7 +431,7 @@ The machine-readable manifest is \`manifest.json\`; this file is a human summary
407
431
  | **Format version** | ${e.formatVersion} |
408
432
  | **Consistency** | ${e.consistency} |
409
433
  | **Compression** | ${e.compression} |
410
- | **Scope** | ${ot(e.scope)} |
434
+ | **Scope** | ${st(e.scope)} |
411
435
  | **Tables** | ${e.tables.length} |
412
436
  | **Rows (total)** | ${n} |
413
437
  | **Assets** | ${a} |
@@ -432,39 +456,39 @@ voltro data import <this-directory>
432
456
  voltro data import <this-directory> --target api --api-url <url> --token <secret>
433
457
  \`\`\`
434
458
  `;
435
- }, ct = i.counter("voltro_data_transfer_rows", { description: "Rows exported/imported by @voltro/data-transfer, tagged by phase + table." }), lt = a.exponential({
459
+ }, lt = i.counter("voltro_data_transfer_rows", { description: "Rows exported/imported by @voltro/data-transfer, tagged by phase + table." }), ut = a.exponential({
436
460
  start: .01,
437
461
  factor: 2,
438
462
  count: 16
439
- }), ut = i.histogram("voltro_data_transfer_table_seconds", lt, "Per-table export/import duration in seconds, tagged by phase."), W = (e, t) => {
463
+ }), dt = i.histogram("voltro_data_transfer_table_seconds", ut, "Per-table export/import duration in seconds, tagged by phase."), K = (e, t) => {
440
464
  if (e) try {
441
465
  e(t);
442
466
  } catch {}
443
- }, dt = (e, t, r, a, o, s) => n.Do.pipe(n.bind("start", () => n.clockWith((e) => e.currentTimeMillis)), n.bind("result", () => s), n.tap(({ start: r, result: a }) => n.clockWith((e) => e.currentTimeMillis).pipe(n.flatMap((s) => n.zipRight(ut.pipe(i.tagged("phase", e), i.update((s - r) / 1e3)), ct.pipe(i.tagged("phase", e), i.tagged("table", t), i.update(o(a))))))), n.map(({ result: e }) => e), n.withSpan(`data-transfer.${e}.table`, { attributes: {
467
+ }, ft = (e, t, r, a, o, s) => n.Do.pipe(n.bind("start", () => n.clockWith((e) => e.currentTimeMillis)), n.bind("result", () => s), n.tap(({ start: r, result: a }) => n.clockWith((e) => e.currentTimeMillis).pipe(n.flatMap((s) => n.zipRight(dt.pipe(i.tagged("phase", e), i.update((s - r) / 1e3)), lt.pipe(i.tagged("phase", e), i.tagged("table", t), i.update(o(a))))))), n.map(({ result: e }) => e), n.withSpan(`data-transfer.${e}.table`, { attributes: {
444
468
  table: t,
445
469
  index: r,
446
470
  tableCount: a,
447
471
  phase: e
448
- } })), ft = () => ({
472
+ } })), pt = () => ({
449
473
  tables: {},
450
474
  assets: {}
451
- }), G = (e) => n.tryPromise(async () => {
475
+ }), mt = (e) => n.tryPromise(async () => {
452
476
  let t = await (await import("node:fs/promises")).readFile(e, "utf8");
453
477
  return JSON.parse(t);
454
- }).pipe(n.orElseSucceed(ft)), K = (e, t) => n.tryPromise({
478
+ }).pipe(n.orElseSucceed(pt)), q = (e, t) => n.tryPromise({
455
479
  try: async () => {
456
480
  let n = await import("node:fs/promises"), { randomUUID: r } = await import("node:crypto"), i = `${e}.tmp-${r()}`;
457
481
  await n.writeFile(i, JSON.stringify(t)), await n.rename(i, e);
458
482
  },
459
- catch: (t) => new F({
483
+ catch: (t) => new P({
460
484
  reason: `ledger write failed: ${String(t?.message ?? t)}`,
461
485
  path: e
462
486
  })
463
- }), pt = (e, t) => t in e.tables, mt = (e, t) => t in e.assets, ht = /* @__PURE__ */ new Set([
487
+ }), ht = (e, t) => t in e.tables, gt = (e, t) => t in e.assets, _t = /* @__PURE__ */ new Set([
464
488
  "json",
465
489
  "array",
466
490
  "vector"
467
- ]), gt = (e) => typeof e == "object" && !!e && !Array.isArray(e) && typeof e.$v == "string", _t = (e) => Buffer.from(e).toString("base64"), vt = (e) => new Uint8Array(Buffer.from(e, "base64")), yt = (e) => e instanceof Date ? e.toISOString() : typeof e == "number" ? new Date(e).toISOString() : String(e), bt = (e, t) => e == null ? null : t !== void 0 && ht.has(t) ? e : t === "bytes" ? _t(e) : t === "timestamp" || t === "date" ? yt(e) : typeof e == "bigint" ? {
491
+ ]), vt = (e) => typeof e == "object" && !!e && !Array.isArray(e) && typeof e.$v == "string", yt = (e) => Buffer.from(e).toString("base64"), bt = (e) => new Uint8Array(Buffer.from(e, "base64")), xt = (e) => e instanceof Date ? e.toISOString() : typeof e == "number" ? new Date(e).toISOString() : String(e), St = (e, t) => e == null ? null : t !== void 0 && _t.has(t) ? e : t === "bytes" ? yt(e) : t === "timestamp" || t === "date" ? xt(e) : typeof e == "bigint" ? {
468
492
  $v: "bigint",
469
493
  d: e.toString()
470
494
  } : typeof e == "number" && !Number.isFinite(e) ? {
@@ -475,30 +499,30 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
475
499
  d: e.toISOString()
476
500
  } : e instanceof Uint8Array ? {
477
501
  $v: "bytes",
478
- d: _t(e)
479
- } : e, xt = (e) => {
502
+ d: yt(e)
503
+ } : e, Ct = (e) => {
480
504
  switch (e.$v) {
481
505
  case "bigint": return BigInt(e.d);
482
506
  case "number": return Number(e.d);
483
507
  case "date": return new Date(e.d);
484
- case "bytes": return vt(e.d);
508
+ case "bytes": return bt(e.d);
485
509
  default: return e;
486
510
  }
487
- }, St = (e, t) => e == null ? null : t !== void 0 && ht.has(t) ? e : gt(e) ? xt(e) : t === "bytes" ? vt(e) : t === "timestamp" || t === "date" ? new Date(e) : e, Ct = (e, t) => {
511
+ }, wt = (e, t) => e == null ? null : t !== void 0 && _t.has(t) ? e : vt(e) ? Ct(e) : t === "bytes" ? bt(e) : t === "timestamp" || t === "date" ? new Date(e) : e, Tt = (e, t) => {
488
512
  let n = {};
489
- for (let [r, i] of Object.entries(e)) n[r] = bt(i, t[r]);
513
+ for (let [r, i] of Object.entries(e)) n[r] = St(i, t[r]);
490
514
  return n;
491
- }, wt = (e, t) => {
515
+ }, Et = (e, t) => {
492
516
  let n = {};
493
- for (let [r, i] of Object.entries(e)) n[r] = St(i, t[r]);
517
+ for (let [r, i] of Object.entries(e)) n[r] = wt(i, t[r]);
494
518
  return n;
495
- }, Tt = new TextEncoder(), Et = (e, t) => e.pipe(c.map((e) => Tt.encode(`${JSON.stringify(Ct(e, t))}\n`))), Dt = (e, t, r) => e.pipe(c.decodeText(), c.splitLines, c.filter((e) => e.trim().length > 0), c.mapEffect((e) => n.try({
496
- try: () => wt(JSON.parse(e), r),
497
- catch: (e) => new Ae({
519
+ }, Dt = new TextEncoder(), Ot = (e, t) => e.pipe(c.map((e) => Dt.encode(`${JSON.stringify(Tt(e, t))}\n`))), kt = (e, t, r) => e.pipe(c.decodeText(), c.splitLines, c.filter((e) => e.trim().length > 0), c.mapEffect((e) => n.try({
520
+ try: () => Et(JSON.parse(e), r),
521
+ catch: (e) => new Pe({
498
522
  table: t,
499
523
  reason: String(e?.message ?? e)
500
524
  })
501
- }))), q = (e, t) => {
525
+ }))), At = (e, t) => {
502
526
  let n = new Set(e), r = /* @__PURE__ */ new Map();
503
527
  for (let e of t.tables) {
504
528
  if (!n.has(e.name)) continue;
@@ -518,11 +542,34 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
518
542
  };
519
543
  for (let t of e) n.has(t) && s(t);
520
544
  return i;
521
- }, Ot = (e, t) => {
545
+ }, J = (e) => {
546
+ let t = e, n = [];
547
+ typeof t?._tag == "string" && t._tag !== "" && n.push(t._tag);
548
+ let r = typeof t?.message == "string" ? t.message.trim() : "";
549
+ if (r === "" ? t?.cause !== void 0 && t.cause !== null && n.push(J(t.cause)) : n.push(r), n.length === 0) {
550
+ let t = String(e ?? "").trim();
551
+ return t === "" || t === "[object Object]" ? jt(e) : t;
552
+ }
553
+ return n.join(": ");
554
+ }, jt = (e) => {
555
+ try {
556
+ let t = JSON.stringify(e);
557
+ return t === void 0 || t === "{}" ? "unknown error (no message, cause or tag)" : t;
558
+ } catch {
559
+ return "unknown error (not serialisable)";
560
+ }
561
+ }, Mt = (e, t) => {
522
562
  let n = e.tables.find((e) => e.name === t), r = {};
523
563
  for (let e of n?.columns ?? []) r[e.name] = e.type;
524
564
  return r;
525
- }, kt = (e, t) => e.tables.find((e) => e.name === t)?.columns.find((e) => e.type === "id")?.name ?? "id", At = (e, t, r) => n.tryPromise({
565
+ }, Nt = (e, t) => {
566
+ let n = e.tables.find((e) => e.name === t);
567
+ if (n === void 0) return { refusal: `${t}: not in the schema snapshot, so its primary key is unknown.` };
568
+ let r = n.columns.find((e) => e.type === "id");
569
+ if (r !== void 0) return { column: r.name };
570
+ let i = n.indexes.find((e) => e.name === `${t}_pkey`)?.columns ?? n.primaryKey ?? [];
571
+ return i.length === 1 ? { column: i[0] } : i.length > 1 ? { refusal: `${t}: composite primary key (${i.join(", ")}). Keyset export orders by ONE column; ordering by the first alone would split equal values across pages and drop or duplicate rows. Exclude this table from the scope, or give it a single-column key.` } : { refusal: `${t}: no primary key, so there is no stable order to paginate by. A keyset export would return rows in an order the database may change between pages. Exclude this table from the scope.` };
572
+ }, Pt = (e, t, r) => n.tryPromise({
526
573
  try: async () => {
527
574
  let { createWriteStream: n } = await import("node:fs"), i = await import("node:fs/promises"), { createHash: a, randomUUID: o } = await import("node:crypto"), { pipeline: s } = await import("node:stream/promises"), { Readable: l, Transform: u } = await import("node:stream"), d = a("sha256"), f = 0, p = new u({ transform(e, t, n) {
528
575
  d.update(e);
@@ -531,7 +578,7 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
531
578
  n(null, e);
532
579
  } }), m = l.fromWeb(c.toReadableStream(e)), h = `${t}.tmp-${o()}`;
533
580
  try {
534
- await s(m, p, Je(r), n(h)), await i.rename(h, t);
581
+ await s(m, p, Xe(r), n(h)), await i.rename(h, t);
535
582
  } catch (e) {
536
583
  throw await i.rm(h, { force: !0 }).catch(() => {}), e;
537
584
  }
@@ -540,115 +587,120 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
540
587
  checksum: d.digest("hex")
541
588
  };
542
589
  },
543
- catch: (e) => new F({
544
- reason: `write table failed: ${String(e?.message ?? e)}`,
590
+ catch: (e) => new P({
591
+ reason: `write table failed: ${J(e)}`,
545
592
  path: t
546
593
  })
547
- }), jt = (e, t) => n.tryPromise({
594
+ }), Ft = (e, t) => n.tryPromise({
548
595
  try: async () => {
549
596
  await (await import("node:fs/promises")).appendFile(e, `${t}\n`);
550
597
  },
551
- catch: (t) => new F({
552
- reason: `append failed: ${String(t?.message ?? t)}`,
598
+ catch: (t) => new P({
599
+ reason: `append failed: ${J(t)}`,
553
600
  path: e
554
601
  })
555
- }), Mt = (e, t) => n.gen(function* () {
556
- let n = [], r = t.ordered.length;
557
- for (let i = 0; i < t.ordered.length; i++) {
558
- let a = t.ordered[i], o = Ot(t.snapshot, a), s = kt(t.snapshot, a), l = `${it}/${a}.ndjson${qe(t.compression)}`;
559
- if (pt(t.ledger, a)) {
560
- let e = t.ledger.tables[a];
561
- W(t.onProgress, {
602
+ }), It = (e, t) => n.gen(function* () {
603
+ let r = [], i = t.ordered.length;
604
+ for (let a = 0; a < t.ordered.length; a++) {
605
+ let o = t.ordered[a], s = Mt(t.snapshot, o), l = Nt(t.snapshot, o);
606
+ if ("refusal" in l) return yield* n.fail(new I({ reason: `export: ${l.refusal}` }));
607
+ let u = l.column, d = `${U}/${o}.ndjson${Ye(t.compression)}`;
608
+ if (ht(t.ledger, o)) {
609
+ let e = t.ledger.tables[o];
610
+ K(t.onProgress, {
562
611
  phase: "export",
563
- table: a,
564
- index: i,
565
- tableCount: r,
612
+ table: o,
613
+ index: a,
614
+ tableCount: i,
566
615
  event: "done",
567
616
  rowsDone: e.rowCount,
568
617
  total: e.rowCount
569
- }), n.push({
570
- name: a,
571
- file: l,
618
+ }), r.push({
619
+ name: o,
620
+ file: d,
572
621
  rowCount: e.rowCount,
573
622
  checksum: e.checksum,
574
- columnTypes: o,
575
- primaryKey: s
623
+ columnTypes: s,
624
+ primaryKey: u
576
625
  });
577
626
  continue;
578
627
  }
579
- W(t.onProgress, {
628
+ K(t.onProgress, {
580
629
  phase: "export",
581
- table: a,
582
- index: i,
583
- tableCount: r,
630
+ table: o,
631
+ index: a,
632
+ tableCount: i,
584
633
  event: "start",
585
634
  rowsDone: 0
586
635
  });
587
- let u = t.resolved.predicateFor(a), d = p(e, {
588
- table: a,
589
- pk: s,
636
+ let f = t.resolved.predicateFor(o), p = h(e, {
637
+ table: o,
638
+ pk: u,
590
639
  chunkSize: t.chunkSize,
591
640
  retry: t.retry,
592
- ...u === void 0 ? {} : { where: u }
593
- }), f = t.mask ? d.pipe(c.map((e) => P(e, a, t.mask.actions, t.mask.seed, o))) : d, { rowCount: m, checksum: h } = yield* dt("export", a, i, r, (e) => e.rowCount, At(Et(f, o), t.bundleFile(l), t.compression));
594
- t.ledger.tables[a] = {
595
- rowCount: m,
596
- checksum: h
597
- }, yield* K(t.ledgerPath, t.ledger), W(t.onProgress, {
641
+ ...f === void 0 ? {} : { where: f }
642
+ }), m = t.mask ? p.pipe(c.map((e) => Ne(e, o, t.mask.actions, t.mask.seed, s))) : p, { rowCount: g, checksum: _ } = yield* ft("export", o, a, i, (e) => e.rowCount, Pt(Ot(m, s), t.bundleFile(d), t.compression));
643
+ t.ledger.tables[o] = {
644
+ rowCount: g,
645
+ checksum: _
646
+ }, yield* q(t.ledgerPath, t.ledger), K(t.onProgress, {
598
647
  phase: "export",
599
- table: a,
600
- index: i,
601
- tableCount: r,
648
+ table: o,
649
+ index: a,
650
+ tableCount: i,
602
651
  event: "done",
603
- rowsDone: m,
604
- total: m
605
- }), n.push({
606
- name: a,
607
- file: l,
608
- rowCount: m,
609
- checksum: h,
610
- columnTypes: o,
611
- primaryKey: s
652
+ rowsDone: g,
653
+ total: g
654
+ }), r.push({
655
+ name: o,
656
+ file: d,
657
+ rowCount: g,
658
+ checksum: _,
659
+ columnTypes: s,
660
+ primaryKey: u
612
661
  });
613
662
  }
614
- return n;
615
- }), Nt = (e) => ({
663
+ return r;
664
+ }), Lt = (e) => ({
616
665
  _tag: "RawSqlFragment",
617
666
  strings: [e],
618
667
  values: []
619
- }), Pt = (t, i, a) => n.tryPromise({
668
+ }), Rt = (t, i, a) => n.tryPromise({
620
669
  try: () => t.transactional(async (t) => {
621
- if (t.raw) for (let e of ge(i)) await t.raw(Nt(e));
670
+ if (t.raw) for (let e of ve(i)) await t.raw(Lt(e));
622
671
  let o = await n.runPromiseExit(a(t));
623
672
  if (r.isFailure(o)) throw Error(e.pretty(o.cause));
624
673
  return o.value;
625
674
  }),
626
- catch: (e) => e instanceof F ? e : new F({ reason: `snapshot export failed: ${String(e?.message ?? e)}` })
627
- }), Ft = (e) => n.gen(function* () {
628
- let t = e.scope ?? { kind: "all" }, r = Ke(e.compression), i = e.chunkSize ?? 1e3, a = e.retryTimes ?? 5, s = o.exponential("50 millis").pipe(o.jittered, o.intersect(o.recurs(a))), l = yield* n.promise(() => import("node:path")), u = (t) => l.join(e.outDir, t);
675
+ catch: (e) => e instanceof P ? e : new P({ reason: `snapshot export failed: ${J(e)}` })
676
+ }), zt = (e) => n.gen(function* () {
677
+ let t = e.scope ?? { kind: "all" }, r = Je(e.compression), i = e.chunkSize ?? 1e3, a = e.retryTimes ?? 5, s = o.exponential("50 millis").pipe(o.jittered, o.intersect(o.recurs(a))), l = yield* n.promise(() => import("node:path")), u = (t) => l.join(e.outDir, t);
629
678
  yield* n.tryPromise({
630
679
  try: async () => {
631
680
  let t = await import("node:fs/promises");
632
- await t.mkdir(u(it), { recursive: !0 }), e.assets && await t.mkdir(u(H), { recursive: !0 });
681
+ await t.mkdir(u(U), { recursive: !0 }), e.assets && await t.mkdir(u(W), { recursive: !0 });
633
682
  },
634
- catch: (t) => new F({
635
- reason: `mkdir failed: ${String(t?.message ?? t)}`,
683
+ catch: (t) => new P({
684
+ reason: `mkdir failed: ${J(t)}`,
636
685
  path: e.outDir
637
686
  })
638
687
  });
639
- let d = u(at), f = yield* G(d), p = e.subset ? ze(yield* z(e.store, e.snapshot, e.subset), e.snapshot) : yield* Be(t, e.snapshot, {
688
+ let d = u(ot), f = yield* mt(d), p = e.subset ? He(yield* z(e.store, e.snapshot, e.subset), e.snapshot) : yield* V(t, e.snapshot, {
640
689
  store: e.store,
641
690
  ...e.tenantTables ? { tenantTables: e.tenantTables } : {}
642
- }), h = q(p.tables, e.snapshot), g = e.consistency ?? "live", _, v;
691
+ }), m = At(p.tables, e.snapshot), h = e.consistency ?? "live", _, v;
643
692
  if (e.masking) {
644
- let t = e.classification ?? ve(e.snapshot), r = De(h.map((t) => ({
693
+ let t = e.classification ?? k(e.snapshot), r = Ae(m.map((t) => ({
645
694
  name: t,
646
695
  columns: (e.snapshot.tables.find((e) => e.name === t)?.columns ?? []).map((e) => ({
647
696
  name: e.name,
648
697
  type: e.type
649
698
  }))
650
699
  })), t, e.masking);
651
- if (r.unclassified.length > 0) return yield* n.fail(new Fe({ unclassified: r.unclassified }));
700
+ if (r.unclassified.length > 0 || r.invalid.length > 0) return yield* n.fail(new Re({
701
+ unclassified: r.unclassified,
702
+ ...r.invalid.length > 0 ? { invalidActions: r.invalid.map((e) => `${e.column}: ${JSON.stringify(e.action)}`) } : {}
703
+ }));
652
704
  v = {
653
705
  actions: r.actions,
654
706
  seed: e.masking.seed
@@ -661,7 +713,7 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
661
713
  }
662
714
  let y = {
663
715
  snapshot: e.snapshot,
664
- ordered: h,
716
+ ordered: m,
665
717
  resolved: p,
666
718
  compression: r,
667
719
  chunkSize: i,
@@ -671,34 +723,34 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
671
723
  bundleFile: u,
672
724
  ...v ? { mask: v } : {},
673
725
  ...e.onProgress ? { onProgress: e.onProgress } : {}
674
- }, b = g === "snapshot" ? yield* Pt(e.store, e.dialect, (e) => Mt(e, y)) : yield* Mt(e.store, y), x = 0, S = 0;
726
+ }, ee = h === "snapshot" ? yield* Rt(e.store, e.dialect, (e) => It(e, y)) : yield* It(e.store, y), b = 0, x = 0;
675
727
  if (e.assets) {
676
- let t = u(U);
677
- yield* c.runForEach(e.assets.list(), (r) => r.key in f.assets ? n.void : e.assets.open(r.key).pipe(n.flatMap((e) => Ue(e, u(H))), n.flatMap((e) => {
728
+ let t = u(G);
729
+ yield* c.runForEach(e.assets.list(), (r) => r.key in f.assets ? n.void : e.assets.open(r.key).pipe(n.flatMap((e) => Ge(e, u(W))), n.flatMap((e) => {
678
730
  let i = {
679
731
  key: r.key,
680
732
  sha256: e.sha256,
681
733
  size: e.size,
682
734
  contentType: e.contentType
683
735
  };
684
- return x++, S += e.size, f.assets[r.key] = !0, jt(t, JSON.stringify(i)).pipe(n.andThen(K(d, f)));
685
- }))).pipe(n.mapError((e) => e instanceof F ? e : new F({ reason: `asset export failed: ${String(e)}` })));
736
+ return b++, x += e.size, f.assets[r.key] = !0, Ft(t, JSON.stringify(i)).pipe(n.andThen(q(d, f)));
737
+ }))).pipe(n.mapError((e) => e instanceof P ? e : new P({ reason: `asset export failed: ${String(e)}` })));
686
738
  }
687
- let C = {
739
+ let S = {
688
740
  formatVersion: 1,
689
741
  createdAt: e.createdAt ?? (/* @__PURE__ */ new Date()).toISOString(),
690
742
  source: {
691
743
  dialect: e.dialect,
692
- schemaFingerprint: m(e.snapshot)
744
+ schemaFingerprint: g(e.snapshot)
693
745
  },
694
746
  scope: t,
695
- consistency: g,
747
+ consistency: h,
696
748
  compression: r,
697
- tables: b,
698
- assets: x > 0 ? {
699
- count: x,
700
- totalBytes: S,
701
- index: U
749
+ tables: ee,
750
+ assets: b > 0 ? {
751
+ count: b,
752
+ totalBytes: x,
753
+ index: G
702
754
  } : {
703
755
  count: 0,
704
756
  totalBytes: 0
@@ -707,23 +759,23 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
707
759
  };
708
760
  return yield* n.tryPromise({
709
761
  try: async () => {
710
- await (await import("node:fs/promises")).writeFile(u(V), tt(C));
762
+ await (await import("node:fs/promises")).writeFile(u(H), rt(S));
711
763
  },
712
- catch: (e) => new F({
713
- reason: `manifest write failed: ${String(e?.message ?? e)}`,
714
- path: V
764
+ catch: (e) => new P({
765
+ reason: `manifest write failed: ${J(e)}`,
766
+ path: H
715
767
  })
716
768
  }), yield* n.tryPromise({
717
769
  try: async () => {
718
770
  let e = await import("node:fs/promises"), t = await import("node:os");
719
- await e.writeFile(u(rt), st(C, { hostname: t.hostname() }));
771
+ await e.writeFile(u(at), ct(S, { hostname: t.hostname() }));
720
772
  },
721
- catch: (e) => new F({
722
- reason: `readme write failed: ${String(e?.message ?? e)}`,
723
- path: rt
773
+ catch: (e) => new P({
774
+ reason: `readme write failed: ${J(e)}`,
775
+ path: at
724
776
  })
725
- }), C;
726
- }), It = (e) => {
777
+ }), S;
778
+ }), Bt = (e) => {
727
779
  switch (e) {
728
780
  case "id":
729
781
  case "text":
@@ -742,12 +794,12 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
742
794
  case "raw": return "raw";
743
795
  default: return "string";
744
796
  }
745
- }, Lt = {
797
+ }, Vt = {
746
798
  vector: /* @__PURE__ */ new Set(["postgres"]),
747
799
  array: /* @__PURE__ */ new Set(["postgres"]),
748
800
  interval: /* @__PURE__ */ new Set(["postgres"])
749
- }, Rt = (e, t, n, r) => {
750
- let i = It(n);
801
+ }, Ht = (e, t, n, r) => {
802
+ let i = Bt(n);
751
803
  if (i === "raw") return {
752
804
  table: e,
753
805
  column: t,
@@ -755,7 +807,7 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
755
807
  severity: "block",
756
808
  reason: `raw() is verbatim source-dialect SQL — it cannot be assumed valid on ${r}`
757
809
  };
758
- let a = Lt[i];
810
+ let a = Vt[i];
759
811
  return !a || a.has(r) ? null : i === "array" || i === "interval" ? {
760
812
  table: e,
761
813
  column: t,
@@ -769,55 +821,87 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
769
821
  severity: "block",
770
822
  reason: `${i} columns require a ${[...a].join("/")} target; ${r} has no compatible column type`
771
823
  };
772
- }, zt = (e, t, n) => {
824
+ }, Ut = (e, t, n) => {
773
825
  if (t === n) return [];
774
826
  let r = [];
775
827
  for (let t of e) for (let [e, i] of Object.entries(t.columnTypes)) {
776
- let a = Rt(t.name, e, i, n);
828
+ let a = Ht(t.name, e, i, n);
777
829
  a && r.push(a);
778
830
  }
779
831
  return r;
780
- }, Bt = (e) => `[${e.severity}] ${e.table}.${e.column} (${e.type}): ${e.reason}`, Vt = (e, t) => new Map((e.tables.find((e) => e.name === t)?.columns ?? []).map((e) => [e.name, e.type])), Ht = (e, t) => {
781
- let n = [], r = new Set(e.tables.map((e) => e.name)), i = new Set(t.tables.map((e) => e.name));
782
- for (let e of [...r].filter((e) => !i.has(e)).sort()) n.push(`table '${e}' is in the bundle but MISSING from the target`);
783
- for (let e of [...i].filter((e) => !r.has(e)).sort()) n.push(`table '${e}' is in the target but NOT in the bundle (import leaves it untouched)`);
784
- for (let a of [...r].filter((e) => i.has(e)).sort()) {
785
- let r = Vt(e, a), i = Vt(t, a);
786
- for (let [e] of r) i.has(e) || n.push(`${a}.${e}: in the bundle, MISSING from the target`);
787
- for (let [e] of i) r.has(e) || n.push(`${a}.${e}: in the target, not in the bundle`);
788
- for (let [e, t] of r) {
789
- let r = i.get(e);
790
- r !== void 0 && r !== t && n.push(`${a}.${e}: type '${t}' (bundle) vs '${r}' (target)`);
832
+ }, Wt = (e) => `[${e.severity}] ${e.table}.${e.column} (${e.type}): ${e.reason}`, Gt = (e) => {
833
+ let t = e.constraint ?? e.column, n = t === void 0 ? "" : ` ${t}`;
834
+ switch (e.kind) {
835
+ case "foreignKey": return `foreign key${n}: the referenced row does not exist (import it first, or check the bundle's table order)`;
836
+ case "foreignKeyInUse": return `foreign key${n}: the row is still referenced by other rows`;
837
+ case "unique": return `unique constraint${n}: a row with this value already exists`;
838
+ case "notNull": return `not-null constraint${n}: the column requires a value`;
839
+ case "check": return `check constraint${n}: the row does not satisfy it`;
840
+ }
841
+ }, Kt = (e) => {
842
+ let t = [e.dbCode, e.dbErrno ?? e.dbNumber].filter((e) => e !== void 0).map(String);
843
+ return t.length > 0 ? t.join("/") : void 0;
844
+ }, qt = (e) => {
845
+ let t = d(e), n = l(t), r = Kt(t), i = r === void 0 ? "" : ` [${r}]`;
846
+ if (n !== void 0) return `${Gt(n)}${i}`;
847
+ let a = typeof t.dbMessage == "string" ? t.dbMessage : void 0, o = e?.message, s = typeof o == "string" && o.length > 0 ? o : String(e), c = a !== void 0 && a !== s && !a.startsWith("SqlError:") ? a : s, u = c === "Failed to execute statement" ? `the database refused the write and the driver gave no detail${i}` : `${c}${i}`;
848
+ return u.length <= 300 ? u : `${u.slice(0, 300)}…`;
849
+ }, Jt = (e, t) => e.tables.find((e) => e.name === t), Yt = (e, t) => new Map((Jt(e, t)?.columns ?? []).map((e) => [e.name, e])), Xt = (e, t) => {
850
+ let n = [];
851
+ for (let r of [...e.tables].sort((e, t) => e.name.localeCompare(t.name))) {
852
+ if (Jt(t, r.name) === void 0) {
853
+ n.push(`table '${r.name}' is in the bundle but MISSING from the target — its rows have nowhere to go`);
854
+ continue;
791
855
  }
856
+ let e = Yt(t, r.name), i = new Map(r.columns.map((e) => [e.name, e]));
857
+ for (let [t, a] of i) {
858
+ let i = e.get(t);
859
+ if (i === void 0) {
860
+ n.push(`${r.name}.${t}: in the bundle, MISSING from the target — the value has nowhere to go`);
861
+ continue;
862
+ }
863
+ i.type !== a.type && n.push(`${r.name}.${t}: type '${a.type}' (bundle) vs '${i.type}' (target)`);
864
+ }
865
+ for (let [t, a] of e) i.has(t) || !a.nullable && !a.hasDefault && n.push(`${r.name}.${t}: the target requires it (NOT NULL, no default) and the bundle carries no value — every row of this table would fail`);
792
866
  }
793
- return n.length > 30 ? [...n.slice(0, 30), `… and ${n.length - 30} more difference(s)`] : n.length > 0 ? n : ["the schema shape differs (indexes, nullability, or defaults) — the specific change is below the table/column granularity shown here"];
794
- }, Ut = (e, t, n) => {
795
- let r = m(t);
796
- return r === e ? {
867
+ return n.length > 30 ? [...n.slice(0, 30), `… and ${n.length - 30} more difference(s)`] : n;
868
+ }, Zt = (e, t, n) => {
869
+ let r = g(t);
870
+ if (r === e || n === void 0) return {
797
871
  drifted: !1,
798
872
  bundleFingerprint: e,
799
873
  targetFingerprint: r,
800
874
  diff: []
801
- } : {
802
- drifted: !0,
875
+ };
876
+ let i = Xt(n, t);
877
+ return {
878
+ drifted: i.length > 0,
803
879
  bundleFingerprint: e,
804
880
  targetFingerprint: r,
805
- diff: n ? Ht(n, t) : ["the target schema fingerprint does not match the bundle (no source schema available to itemise the diff — the manifest records only the fingerprint)"]
881
+ diff: i
806
882
  };
807
- }, Wt = (e) => n.tryPromise({
883
+ }, Qt = (e) => n.tryPromise({
808
884
  try: async () => {
809
885
  let t = await import("node:fs/promises"), n = await import("node:path");
810
- return nt(await t.readFile(n.join(e, V), "utf8"));
886
+ return it(await t.readFile(n.join(e, H), "utf8"));
811
887
  },
812
- catch: (e) => new F({
888
+ catch: (e) => new P({
813
889
  reason: `manifest read/parse failed: ${String(e?.message ?? e)}`,
814
- path: V
890
+ path: H
815
891
  })
816
- }), Gt = (t) => n.gen(function* () {
817
- let i = yield* n.promise(() => import("node:path")), a = yield* Wt(t.bundleDir);
818
- if (a.formatVersion !== 1) return yield* n.fail(new F({ reason: `unsupported bundle formatVersion ${a.formatVersion} (expected 1)` }));
892
+ }), $t = (t) => n.gen(function* () {
893
+ let i = yield* n.promise(() => import("node:path")), a = yield* Qt(t.bundleDir);
894
+ if (a.formatVersion !== 1) return yield* n.fail(new P({ reason: `unsupported bundle formatVersion ${a.formatVersion} (expected 1)` }));
895
+ if (t.tables !== void 0) {
896
+ let e = new Set(a.tables.map((e) => e.name)), r = t.tables.filter((t) => !e.has(t));
897
+ if (r.length > 0) return yield* n.fail(new P({ reason: `--tables names ${r.length} table(s) this bundle does not carry: ${r.join(", ")}. The bundle carries: ${[...e].sort().join(", ")}.` }));
898
+ }
899
+ let o = t.tables === void 0 ? void 0 : new Set(t.tables), s = o === void 0 ? a : {
900
+ ...a,
901
+ tables: a.tables.filter((e) => o.has(e.name))
902
+ };
819
903
  if (t.targetSnapshot) {
820
- let e = { tables: a.tables.map((e) => ({
904
+ let e = { tables: s.tables.map((e) => ({
821
905
  name: e.name,
822
906
  indexes: [],
823
907
  columns: Object.entries(e.columnTypes).map(([e, t]) => ({
@@ -827,9 +911,9 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
827
911
  unique: !1,
828
912
  hasDefault: !1
829
913
  }))
830
- })) }, r = Ut(a.source.schemaFingerprint, t.targetSnapshot, e);
914
+ })) }, r = Zt(s.source.schemaFingerprint, t.targetSnapshot, e);
831
915
  if (r.drifted) {
832
- if (!t.force) return yield* n.fail(new Pe({
916
+ if (!t.force) return yield* n.fail(new Le({
833
917
  bundleFingerprint: r.bundleFingerprint,
834
918
  targetFingerprint: r.targetFingerprint,
835
919
  diff: r.diff
@@ -837,45 +921,46 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
837
921
  t.onWarn?.(`schema drift: the target schema (fingerprint ${r.targetFingerprint.slice(0, 16)}) differs from the bundle's source (${r.bundleFingerprint.slice(0, 16)}); importing anyway (--force). ${r.diff.join("; ")}`);
838
922
  }
839
923
  }
840
- if (t.targetDialect && t.targetDialect !== a.source.dialect) {
841
- let e = zt(a.tables, a.source.dialect, t.targetDialect).filter((e) => e.severity === "block");
842
- if (e.length > 0 && !t.allowIncompatible) return yield* n.fail(new Le({
843
- sourceDialect: a.source.dialect,
924
+ if (t.targetDialect && t.targetDialect !== s.source.dialect) {
925
+ let e = Ut(s.tables, s.source.dialect, t.targetDialect).filter((e) => e.severity === "block");
926
+ if (e.length > 0 && !t.allowIncompatible) return yield* n.fail(new Be({
927
+ sourceDialect: s.source.dialect,
844
928
  targetDialect: t.targetDialect,
845
- blocking: e.map(Bt)
929
+ blocking: e.map(Wt)
846
930
  }));
847
931
  }
848
- let o = t.verify ?? !0, s = t.mode ?? "upsert", l = t.onConflict ?? "skip", u = t.ledgerPath ?? i.join(t.bundleDir, ".import..ledger.json"), f = yield* G(u);
849
- if (s === "replace" && a.scope.kind !== "all") return yield* n.fail(new Ie({
850
- mode: s,
851
- reason: `replace refuses a partial bundle (scope='${a.scope.kind}') — truncating would delete rows not in the bundle. Use --mode upsert, or re-export with full scope.`
932
+ let l = t.verify ?? !0, u = t.mode ?? "upsert", d = t.onConflict ?? "skip", f = t.ledgerPath ?? i.join(t.bundleDir, ".import..ledger.json"), m = yield* mt(f);
933
+ if (u === "replace" && s.scope.kind !== "all") return yield* n.fail(new ze({
934
+ mode: u,
935
+ reason: `replace refuses a partial bundle (scope='${s.scope.kind}') — truncating would delete rows not in the bundle. Use --mode upsert, or re-export with full scope.`
852
936
  }));
853
- let p = (e, t, n) => {
937
+ if (t.dryRun === !0) return s;
938
+ let h = (e, t, n) => {
854
939
  let r = t.name, i = t.primaryKey;
855
- return s === "append" ? l === "fail" ? e.insert(r, n) : e.insertIgnore(r, n, { conflictColumns: [i] }) : s === "replace" ? e.insert(r, n) : e.upsert(r, n, { conflictColumns: [i] });
856
- }, m = (e, t) => n.tryPromise({
940
+ return u === "append" ? d === "fail" ? e.insert(r, n) : e.insertIgnore(r, n, { conflictColumns: [i] }) : u === "replace" ? e.insert(r, n) : e.upsert(r, n, { conflictColumns: [i] });
941
+ }, g = (e, t, r = !0) => n.tryPromise({
857
942
  try: e,
858
- catch: (e) => String(e?.message ?? e)
859
- }).pipe(n.map(() => !0), n.catchAll((e) => n.sync(() => (t.reason = e, !1)))), h = (e) => {
943
+ catch: (e) => qt(e)
944
+ }).pipe(n.map(() => !0), n.catchAll((e) => n.sync(() => (r && (t.reason = e), !1)))), _ = (e) => {
860
945
  let t = Object.entries(e.entry.columnTypes).filter(([t, n]) => n === "reference" && e.row[t] !== null && e.row[t] !== void 0).map(([e]) => e);
861
946
  if (t.length !== 0) return {
862
947
  ...e.row,
863
948
  ...Object.fromEntries(t.map((e) => [e, null]))
864
949
  };
865
- }, g = (e, t) => n.gen(function* () {
950
+ }, v = (e, t) => n.gen(function* () {
866
951
  let r = t, i = [], a = !0;
867
952
  for (; r.length > 0 && a;) {
868
953
  a = !1;
869
954
  let t = [];
870
- for (let n of r) (yield* m(() => p(e, n.entry, n.row), n)) ? a = !0 : t.push(n);
955
+ for (let n of r) (yield* g(() => h(e, n.entry, n.row), n)) ? a = !0 : t.push(n);
871
956
  if (!a && t.length > 0) for (let n = t.length - 1; n >= 0; n--) {
872
- let r = t[n], o = h(r);
873
- o !== void 0 && (yield* m(() => p(e, r.entry, o), r)) && (i.push(r), t.splice(n, 1), a = !0);
957
+ let r = t[n], o = _(r);
958
+ o !== void 0 && (yield* g(() => h(e, r.entry, o), r, !1)) && (i.push(r), t.splice(n, 1), a = !0);
874
959
  }
875
960
  r = t;
876
961
  }
877
- for (let t of i) (yield* m(() => e.upsert(t.entry.name, t.row, { conflictColumns: [t.entry.primaryKey] }), t)) || (r = [...r, t]);
878
- if (r.length > 0) return yield* n.fail(new Ne({
962
+ for (let t of i) (yield* g(() => e.upsert(t.entry.name, t.row, { conflictColumns: [t.entry.primaryKey] }), t)) || (r = [...r, t]);
963
+ if (r.length > 0) return yield* n.fail(new Ie({
879
964
  rows: r.slice(0, 20).map((e) => ({
880
965
  table: e.entry.name,
881
966
  id: String(e.row[e.entry.primaryKey]),
@@ -883,59 +968,59 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
883
968
  })),
884
969
  totalCount: r.length
885
970
  }));
886
- }), _ = (e, r) => n.gen(function* () {
887
- if (s === "replace" && !(r && f.truncated)) {
888
- for (let t of [...a.tables].reverse()) yield* n.tryPromise({
889
- try: () => e.deleteMany(t.name, { where: d(t.primaryKey) }),
890
- catch: (e) => new F({ reason: `truncate ${t.name} failed: ${String(e?.message ?? e)}` })
971
+ }), y = (e, r) => n.gen(function* () {
972
+ if (u === "replace" && !(r && m.truncated)) {
973
+ for (let t of [...s.tables].reverse()) yield* n.tryPromise({
974
+ try: () => e.deleteMany(t.name, { where: p(t.primaryKey) }),
975
+ catch: (e) => new P({ reason: `truncate ${t.name} failed: ${String(e?.message ?? e)}` })
891
976
  });
892
- r && (f.truncated = !0, yield* K(u, f));
977
+ r && (m.truncated = !0, yield* q(f, m));
893
978
  }
894
- let l = [], m = [], h = a.tables.length;
895
- for (let d = 0; d < a.tables.length; d++) {
896
- let g = a.tables[d];
897
- if (r && g.name in f.tables) {
898
- W(t.onProgress, {
979
+ let a = [], o = [], d = [], g = s.tables.length;
980
+ for (let p = 0; p < s.tables.length; p++) {
981
+ let _ = s.tables[p];
982
+ if (r && _.name in m.tables) {
983
+ d.push(_.name), K(t.onProgress, {
899
984
  phase: "import",
900
- table: g.name,
901
- index: d,
902
- tableCount: h,
985
+ table: _.name,
986
+ index: p,
987
+ tableCount: g,
903
988
  event: "done",
904
- rowsDone: f.tables[g.name].rowCount,
905
- total: g.rowCount
989
+ rowsDone: m.tables[_.name].rowCount,
990
+ total: _.rowCount
906
991
  });
907
992
  continue;
908
993
  }
909
- let _ = i.join(t.bundleDir, g.file);
910
- W(t.onProgress, {
994
+ let v = i.join(t.bundleDir, _.file);
995
+ K(t.onProgress, {
911
996
  phase: "import",
912
- table: g.name,
913
- index: d,
914
- tableCount: h,
997
+ table: _.name,
998
+ index: p,
999
+ tableCount: g,
915
1000
  event: "start",
916
1001
  rowsDone: 0,
917
- total: g.rowCount
1002
+ total: _.rowCount
918
1003
  });
919
- let v = l.length, y = n.gen(function* () {
920
- let { createHash: r } = yield* n.promise(() => import("node:crypto")), i = r("sha256"), o = 0, u = S("bundle", () => E(_).pipe(Ye(a.compression))).pipe(c.tap((e) => n.sync(() => i.update(e)))), d = async (t) => {
1004
+ let y = a.length, ee = n.gen(function* () {
1005
+ let { createHash: r } = yield* n.promise(() => import("node:crypto")), i = r("sha256"), o = 0, l = C("bundle", () => T(v).pipe(Ze(s.compression))).pipe(c.tap((e) => n.sync(() => i.update(e)))), d = async (t) => {
921
1006
  let n = {
922
- entry: g,
1007
+ entry: _,
923
1008
  row: t,
924
1009
  reason: ""
925
1010
  };
926
1011
  try {
927
- await p(e, g, t);
1012
+ await h(e, _, t);
928
1013
  } catch (e) {
929
- n.reason = String(e?.message ?? e), l.push(n);
1014
+ n.reason = qt(e), a.push(n);
930
1015
  }
931
1016
  }, f = yield* n.promise(async () => {
932
1017
  let n = t.copyLoader;
933
1018
  if (!n || n.dialect !== "postgres" || t.atomic) return !1;
934
- if (s === "replace") return !0;
935
- if (s !== "upsert") return !1;
1019
+ if (u === "replace") return !0;
1020
+ if (u !== "upsert") return !1;
936
1021
  try {
937
1022
  return (await e.query({
938
- table: g.name,
1023
+ table: _.name,
939
1024
  predicate: void 0,
940
1025
  order: [],
941
1026
  take: 1,
@@ -945,25 +1030,25 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
945
1030
  } catch {
946
1031
  return !1;
947
1032
  }
948
- }), m = Object.keys(g.columnTypes), h = Math.max(1, t.copyBatchSize ?? 5e3), v = [], y = async () => {
949
- if (v.length === 0) return;
950
- let e = v;
951
- v = [];
1033
+ }), p = Object.keys(_.columnTypes), m = Math.max(1, t.copyBatchSize ?? 5e3), g = [], y = async () => {
1034
+ if (g.length === 0) return;
1035
+ let e = g;
1036
+ g = [];
952
1037
  try {
953
1038
  await t.copyLoader.copyInto({
954
- table: g.name,
955
- columns: m,
956
- columnTypes: g.columnTypes,
1039
+ table: _.name,
1040
+ columns: p,
1041
+ columnTypes: _.columnTypes,
957
1042
  rows: e
958
1043
  });
959
1044
  } catch (n) {
960
- f = !1, t.onWarn?.(`bulk COPY into ${g.name} failed (${String(n?.message ?? n)}); falling back to per-row writes for this table`);
1045
+ f = !1, t.onWarn?.(`bulk COPY into ${_.name} failed (${String(n?.message ?? n)}); falling back to per-row writes for this table`);
961
1046
  for (let t of e) await d(t);
962
1047
  }
963
1048
  };
964
- return yield* c.runForEach(Dt(u, g.name, g.columnTypes), (e) => n.promise(async () => {
1049
+ return yield* c.runForEach(kt(l, _.name, _.columnTypes), (e) => n.promise(async () => {
965
1050
  if (o++, f) {
966
- v.push(e), v.length >= h && await y();
1051
+ g.push(e), g.length >= m && await y();
967
1052
  return;
968
1053
  }
969
1054
  await d(e);
@@ -971,71 +1056,75 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
971
1056
  rowCount: o,
972
1057
  checksum: i.digest("hex")
973
1058
  };
974
- }), { rowCount: b, checksum: x } = yield* dt("import", g.name, d, h, (e) => e.rowCount, y);
975
- if (o) {
976
- if (x !== g.checksum) return yield* n.fail(new I({
977
- what: `table ${g.name} checksum`,
978
- expected: g.checksum,
1059
+ }), { rowCount: b, checksum: x } = yield* ft("import", _.name, p, g, (e) => e.rowCount, ee);
1060
+ if (l) {
1061
+ if (x !== _.checksum) return yield* n.fail(new F({
1062
+ what: `table ${_.name} checksum`,
1063
+ expected: _.checksum,
979
1064
  actual: x
980
1065
  }));
981
- if (b !== g.rowCount) return yield* n.fail(new I({
982
- what: `table ${g.name} rowCount`,
983
- expected: String(g.rowCount),
1066
+ if (b !== _.rowCount) return yield* n.fail(new F({
1067
+ what: `table ${_.name} rowCount`,
1068
+ expected: String(_.rowCount),
984
1069
  actual: String(b)
985
1070
  }));
986
1071
  }
987
- W(t.onProgress, {
1072
+ K(t.onProgress, {
988
1073
  phase: "import",
989
- table: g.name,
990
- index: d,
991
- tableCount: h,
1074
+ table: _.name,
1075
+ index: p,
1076
+ tableCount: g,
992
1077
  event: "done",
993
1078
  rowsDone: b,
994
- total: g.rowCount
995
- }), r && (l.length > v ? m.push({
996
- name: g.name,
1079
+ total: _.rowCount
1080
+ }), r && (a.length > y ? o.push({
1081
+ name: _.name,
997
1082
  rowCount: b
998
- }) : (f.tables[g.name] = {
1083
+ }) : (m.tables[_.name] = {
999
1084
  rowCount: b,
1000
- checksum: g.checksum
1001
- }, yield* K(u, f)));
1085
+ checksum: _.checksum
1086
+ }, yield* q(f, m)));
1002
1087
  }
1003
- if (l.length > 0 && (yield* g(e, l)), r && m.length > 0) {
1004
- for (let e of m) {
1005
- let t = a.tables.find((t) => t.name === e.name);
1006
- f.tables[e.name] = {
1088
+ if (a.length > 0 && (yield* v(e, a)), r && o.length > 0) {
1089
+ for (let e of o) {
1090
+ let t = s.tables.find((t) => t.name === e.name);
1091
+ m.tables[e.name] = {
1007
1092
  rowCount: e.rowCount,
1008
1093
  checksum: t.checksum
1009
1094
  };
1010
1095
  }
1011
- yield* K(u, f);
1096
+ yield* q(f, m);
1097
+ }
1098
+ if (d.length > 0) {
1099
+ let e = d.length === s.tables.length;
1100
+ t.onWarn?.(`resume: ${d.length} of ${s.tables.length} table(s) were already applied by an earlier run of THIS bundle directory, so this run wrote NO rows for them${e ? " — that is every table in the bundle, so nothing was written at all" : ""}. Tables: ${d.join(", ")}. Delete ${f} to force a full re-import.`);
1012
1101
  }
1013
1102
  });
1014
1103
  if (t.atomic ? yield* n.tryPromise({
1015
1104
  try: () => t.store.transactional(async (t) => {
1016
- let i = await n.runPromiseExit(_(t, !1));
1105
+ let i = await n.runPromiseExit(y(t, !1));
1017
1106
  if (r.isFailure(i)) throw Error(e.pretty(i.cause));
1018
1107
  }),
1019
- catch: (e) => new F({ reason: `atomic import failed (rolled back): ${String(e?.message ?? e)}` })
1020
- }) : yield* _(t.store, !0), t.assets && a.assets.index && !t.assetsAlreadyRestored) {
1021
- let e = t.assets, r = i.join(t.bundleDir, H), o = i.join(t.bundleDir, a.assets.index ?? "assets/index.ndjson"), s = S("bundle", () => E(o)).pipe(c.decodeText(), c.splitLines, c.filter((e) => e.trim().length > 0), c.map((e) => JSON.parse(e)));
1022
- yield* c.runForEach(s, (t) => t.key in f.assets ? n.void : We(e, r, t).pipe(n.andThen(n.sync(() => {
1023
- f.assets[t.key] = !0;
1024
- })), n.andThen(K(u, f))));
1108
+ catch: (e) => new P({ reason: `atomic import failed (rolled back): ${String(e?.message ?? e)}` })
1109
+ }) : yield* y(t.store, !0), t.assets && s.assets.index && !t.assetsAlreadyRestored) {
1110
+ let e = t.assets, r = i.join(t.bundleDir, W), a = i.join(t.bundleDir, s.assets.index ?? "assets/index.ndjson"), o = C("bundle", () => T(a)).pipe(c.decodeText(), c.splitLines, c.filter((e) => e.trim().length > 0), c.map((e) => JSON.parse(e)));
1111
+ yield* c.runForEach(o, (t) => t.key in m.assets ? n.void : Ke(e, r, t).pipe(n.andThen(n.sync(() => {
1112
+ m.assets[t.key] = !0;
1113
+ })), n.andThen(q(f, m))));
1025
1114
  }
1026
- return a;
1027
- }), Kt = (e) => e, qt = (e) => {
1115
+ return s;
1116
+ }), en = (e) => e, tn = (e) => {
1028
1117
  if (e.allowLive || e.liveInstance === null || e.sameTarget === "different") return { refuse: !1 };
1029
1118
  let t = e.targetLabel === void 0 ? "" : ` Target: ${e.targetLabel}.`, n = e.sameTarget === "same" ? " That instance is connected to the SAME database." : " We could not confirm which database that instance is connected to, so this is refused on the conservative reading — an older instance, or one whose connection could not be parsed, reports nothing to compare.";
1030
1119
  return {
1031
1120
  refuse: !0,
1032
1121
  message: `refusing to write into a target with a LIVE instance (${e.liveInstance}).${t}${n} A direct import is an uncoordinated concurrent writer — readers see partial state, the reactive layer either storms or goes stale, and rows race with live writes. Re-run with --allow-live to override, or use a live-safe strategy (shadow-swap for replace, or the api target).`
1033
1122
  };
1034
- }, J = Buffer.from("VBUNDLE2"), Y = 0, Jt = 1, Yt = 2, Xt = 32, Zt = async (e) => {
1123
+ }, Y = Buffer.from("VBUNDLE2"), nn = 0, rn = 1, an = 2, on = 32, sn = async (e) => {
1035
1124
  let t = [], n = async (r) => {
1036
1125
  let i;
1037
1126
  try {
1038
- i = await se(O(e, r), { withFileTypes: !0 });
1127
+ i = await le(O(e, r), { withFileTypes: !0 });
1039
1128
  } catch {
1040
1129
  return;
1041
1130
  }
@@ -1045,22 +1134,22 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
1045
1134
  }
1046
1135
  };
1047
1136
  return await n(""), t.sort();
1048
- }, Qt = (e, t) => {
1137
+ }, cn = (e, t) => {
1049
1138
  let n = Buffer.from(e, "utf8"), r = Buffer.alloc(5 + n.length + 8);
1050
- return r.writeUInt8(Jt, 0), r.writeUInt32BE(n.length, 1), n.copy(r, 5), r.writeBigUInt64BE(BigInt(t), 5 + n.length), r;
1051
- }, $t = (e, t, n) => {
1139
+ return r.writeUInt8(rn, 0), r.writeUInt32BE(n.length, 1), n.copy(r, 5), r.writeBigUInt64BE(BigInt(t), 5 + n.length), r;
1140
+ }, ln = (e, t, n) => {
1052
1141
  let r = Buffer.from(e, "utf8"), i = Buffer.from(t, "utf8"), a = Buffer.alloc(5 + r.length + 2 + i.length + 8), o = 0;
1053
- return a.writeUInt8(Yt, o), o += 1, a.writeUInt32BE(r.length, o), o += 4, r.copy(a, o), o += r.length, a.writeUInt16BE(i.length, o), o += 2, i.copy(a, o), o += i.length, a.writeBigUInt64BE(BigInt(n), o), a;
1142
+ return a.writeUInt8(an, o), o += 1, a.writeUInt32BE(r.length, o), o += 4, r.copy(a, o), o += r.length, a.writeUInt16BE(i.length, o), o += 2, i.copy(a, o), o += i.length, a.writeBigUInt64BE(BigInt(n), o), a;
1054
1143
  };
1055
- async function* en(e) {
1056
- yield new Uint8Array(J);
1057
- for (let t of await Zt(e.dir)) {
1058
- let n = O(e.dir, t), r = await ce(n);
1059
- if (yield new Uint8Array(Qt(t, r.size)), r.size > 0) for await (let e of E(n)) yield new Uint8Array(e);
1144
+ async function* un(e) {
1145
+ yield new Uint8Array(Y);
1146
+ for (let t of await sn(e.dir)) {
1147
+ let n = O(e.dir, t), r = await ue(n);
1148
+ if (yield new Uint8Array(cn(t, r.size)), r.size > 0) for await (let e of T(n)) yield new Uint8Array(e);
1060
1149
  }
1061
1150
  if (e.blobs) for await (let t of e.blobs.list()) {
1062
- yield new Uint8Array($t(t.key, t.contentType, t.size));
1063
- let n = _("sha256"), r = 0;
1151
+ yield new Uint8Array(ln(t.key, t.contentType, t.size));
1152
+ let n = y("sha256"), r = 0;
1064
1153
  for await (let i of e.blobs.open(t.key)) {
1065
1154
  let e = Buffer.from(i);
1066
1155
  n.update(e), r += e.length, yield new Uint8Array(e);
@@ -1068,11 +1157,11 @@ async function* en(e) {
1068
1157
  if (r !== t.size) throw Error(`blob '${t.key}' size mismatch: header ${t.size}, streamed ${r}`);
1069
1158
  yield new Uint8Array(n.digest());
1070
1159
  }
1071
- yield new Uint8Array(Buffer.from([Y]));
1160
+ yield new Uint8Array(Buffer.from([nn]));
1072
1161
  }
1073
- var tn = (e, t) => new Promise((n, r) => e.write(t, (e) => e ? r(e) : n())), nn = (e) => new Promise((t) => e.end(t)), rn = async (e, t) => {
1074
- let n = fe(t.dir);
1075
- await oe(n, { recursive: !0 });
1162
+ var dn = (e, t) => new Promise((n, r) => e.write(t, (e) => e ? r(e) : n())), fn = (e) => new Promise((t) => e.end(t)), pn = async (e, t) => {
1163
+ let n = me(t.dir);
1164
+ await D(n, { recursive: !0 });
1076
1165
  let r = Buffer.alloc(0), i = e[Symbol.asyncIterator](), a = !1, o = async () => {
1077
1166
  let { value: e, done: t } = await i.next();
1078
1167
  return t ? (a = !0, !1) : (r = r.length === 0 ? Buffer.from(e) : Buffer.concat([r, Buffer.from(e)]), !0);
@@ -1083,28 +1172,28 @@ var tn = (e, t) => new Promise((n, r) => e.write(t, (e) => e ? r(e) : n())), nn
1083
1172
  return r = r.subarray(e), t;
1084
1173
  };
1085
1174
  try {
1086
- if (await s(J.length), !c(J.length).equals(J)) throw Error("not a bundle archive (bad magic)");
1175
+ if (await s(Y.length), !c(Y.length).equals(Y)) throw Error("not a bundle archive (bad magic)");
1087
1176
  for (;;) {
1088
1177
  await s(1);
1089
1178
  let e = c(1).readUInt8(0);
1090
- if (e === Y) return;
1091
- if (e === Jt) {
1179
+ if (e === nn) return;
1180
+ if (e === rn) {
1092
1181
  await s(4);
1093
1182
  let e = c(4).readUInt32BE(0);
1094
1183
  await s(e);
1095
1184
  let t = c(e).toString("utf8");
1096
1185
  await s(8);
1097
- let i = c(8).readBigUInt64BE(0), a = fe(n, t);
1098
- if (a !== n && !a.startsWith(n + pe)) throw Error(`archive path '${t}' escapes the destination`);
1099
- await oe(de(a), { recursive: !0 });
1100
- let o = D(a);
1186
+ let i = c(8).readBigUInt64BE(0), a = me(n, t);
1187
+ if (a !== n && !a.startsWith(n + he)) throw Error(`archive path '${t}' escapes the destination`);
1188
+ await D(pe(a), { recursive: !0 });
1189
+ let o = E(a);
1101
1190
  for (; i > 0n;) {
1102
1191
  r.length === 0 && await s(1);
1103
1192
  let e = i < BigInt(r.length) ? Number(i) : r.length;
1104
- await tn(o, c(e)), i -= BigInt(e);
1193
+ await dn(o, c(e)), i -= BigInt(e);
1105
1194
  }
1106
- await nn(o);
1107
- } else if (e === Yt) {
1195
+ await fn(o);
1196
+ } else if (e === an) {
1108
1197
  await s(4);
1109
1198
  let e = c(4).readUInt32BE(0);
1110
1199
  await s(e);
@@ -1114,24 +1203,24 @@ var tn = (e, t) => new Promise((n, r) => e.write(t, (e) => e ? r(e) : n())), nn
1114
1203
  await s(i);
1115
1204
  let a = c(i).toString("utf8");
1116
1205
  await s(8);
1117
- let o = c(8).readBigUInt64BE(0), l = await t.blobs.has(n), u = _("sha256"), d = new T(), f = l ? Promise.resolve() : t.blobs.write(n, d, {
1206
+ let o = c(8).readBigUInt64BE(0), l = await t.blobs.has(n), u = y("sha256"), d = new ie(), f = l ? Promise.resolve() : t.blobs.write(n, d, {
1118
1207
  contentType: a,
1119
1208
  size: Number(o)
1120
1209
  }), p = o;
1121
1210
  for (; p > 0n;) {
1122
1211
  r.length === 0 && await s(1);
1123
1212
  let e = p < BigInt(r.length) ? Number(p) : r.length, t = c(e);
1124
- u.update(t), l || await tn(d, t), p -= BigInt(e);
1213
+ u.update(t), l || await dn(d, t), p -= BigInt(e);
1125
1214
  }
1126
- l ? d.destroy() : await nn(d), await f, await s(Xt);
1127
- let m = c(Xt);
1215
+ l ? d.destroy() : await fn(d), await f, await s(on);
1216
+ let m = c(on);
1128
1217
  if (!u.digest().equals(m)) throw Error(`blob '${n}' failed integrity (sha mismatch)`);
1129
1218
  } else throw Error(`unknown bundle entry kind ${e}`);
1130
1219
  }
1131
1220
  } finally {
1132
1221
  a || await Promise.resolve(i.return?.()).catch(() => void 0);
1133
1222
  }
1134
- }, an = async (e, t) => {
1223
+ }, mn = async (e, t) => {
1135
1224
  let n = new Set(t), r = /* @__PURE__ */ new Map(), i = Buffer.alloc(0), a = e[Symbol.asyncIterator](), o = async () => {
1136
1225
  let { value: e, done: t } = await a.next();
1137
1226
  return !t && (i = i.length === 0 ? Buffer.from(e) : Buffer.concat([i, Buffer.from(e)]), !0);
@@ -1150,11 +1239,11 @@ var tn = (e, t) => new Promise((n, r) => e.write(t, (e) => e ? r(e) : n())), nn
1150
1239
  }
1151
1240
  return Buffer.concat(t);
1152
1241
  };
1153
- if (!await s(J.length) || !c(J.length).equals(J)) throw Error("not a bundle archive (bad magic)");
1242
+ if (!await s(Y.length) || !c(Y.length).equals(Y)) throw Error("not a bundle archive (bad magic)");
1154
1243
  for (; await s(1);) {
1155
1244
  let e = c(1).readUInt8(0);
1156
- if (e === Y || e === Yt) break;
1157
- if (e !== Jt) throw Error(`unknown bundle entry kind ${e}`);
1245
+ if (e === nn || e === an) break;
1246
+ if (e !== rn) throw Error(`unknown bundle entry kind ${e}`);
1158
1247
  if (!await s(4)) break;
1159
1248
  let t = c(4).readUInt32BE(0);
1160
1249
  if (!await s(t)) break;
@@ -1164,20 +1253,20 @@ var tn = (e, t) => new Promise((n, r) => e.write(t, (e) => e ? r(e) : n())), nn
1164
1253
  if (a === null || n.has(i) && (r.set(i, a), n.delete(i), n.size === 0)) break;
1165
1254
  }
1166
1255
  return r;
1167
- }, on = (e, t) => rn(e, {
1256
+ }, hn = (e, t) => pn(e, {
1168
1257
  dir: t,
1169
- blobs: sn(t)
1170
- }), sn = (e) => {
1258
+ blobs: gn(t)
1259
+ }), gn = (e) => {
1171
1260
  let t = /* @__PURE__ */ new Set();
1172
1261
  return {
1173
1262
  has: async (e) => t.has(e),
1174
1263
  write: async (n, r, i) => {
1175
1264
  let a = await import("node:fs/promises"), { pipeline: o } = await import("node:stream/promises"), { Transform: s } = await import("node:stream"), c = O(e, "assets");
1176
- await oe(c, { recursive: !0 });
1177
- let l = _("sha256"), u = 0, d = new s({ transform(e, t, n) {
1265
+ await D(c, { recursive: !0 });
1266
+ let l = y("sha256"), u = 0, d = new s({ transform(e, t, n) {
1178
1267
  l.update(e), u += e.length, n(null, e);
1179
1268
  } }), f = O(c, `.tmp-${Date.now()}-${t.size}`);
1180
- await o(r, d, D(f));
1269
+ await o(r, d, E(f));
1181
1270
  let p = l.digest("hex");
1182
1271
  await a.rename(f, O(c, p)), await a.appendFile(O(c, "index.ndjson"), `${JSON.stringify({
1183
1272
  key: n,
@@ -1187,33 +1276,33 @@ var tn = (e, t) => new Promise((n, r) => e.write(t, (e) => e ? r(e) : n())), nn
1187
1276
  })}\n`), t.add(n);
1188
1277
  }
1189
1278
  };
1190
- }, cn = me(b), ln = Buffer.from("VENC1\0\0\0"), un = 32, dn = 16, fn = 7, X = 16, pn = 262144, Z = {
1279
+ }, _n = ge(x), vn = Buffer.from("VENC1\0\0\0"), yn = 32, bn = 16, xn = 7, X = 16, Sn = 262144, Z = {
1191
1280
  N: 32768,
1192
1281
  r: 8,
1193
1282
  p: 1
1194
- }, mn = 134217728, Q = 43, hn = (e, t, n) => {
1283
+ }, Cn = 134217728, Q = 43, wn = (e, t, n) => {
1195
1284
  let r = Buffer.alloc(12);
1196
- return e.copy(r, 0, 0, fn), r.writeUInt32BE(t >>> 0, fn), r.writeUInt8(+!!n, 11), r;
1285
+ return e.copy(r, 0, 0, xn), r.writeUInt32BE(t >>> 0, xn), r.writeUInt8(+!!n, 11), r;
1197
1286
  };
1198
- async function* gn(e, t) {
1287
+ async function* Tn(e, t) {
1199
1288
  if (!t) throw Error("encryptStream: a non-empty passphrase is required");
1200
- let n = y(dn), r = y(fn), i = await cn(t, n, un, {
1289
+ let n = b(bn), r = b(xn), i = await _n(t, n, yn, {
1201
1290
  ...Z,
1202
- maxmem: mn
1291
+ maxmem: Cn
1203
1292
  }), a = Buffer.alloc(Q);
1204
- ln.copy(a, 0), a.writeUInt32BE(Z.N, 8), a.writeUInt32BE(Z.r, 12), a.writeUInt32BE(Z.p, 16), n.copy(a, 20), r.copy(a, 36), yield new Uint8Array(a);
1293
+ vn.copy(a, 0), a.writeUInt32BE(Z.N, 8), a.writeUInt32BE(Z.r, 12), a.writeUInt32BE(Z.p, 16), n.copy(a, 20), r.copy(a, 36), yield new Uint8Array(a);
1205
1294
  let o = 0, s = (e, t) => {
1206
- let n = h("aes-256-gcm", i, hn(r, o, t));
1295
+ let n = _("aes-256-gcm", i, wn(r, o, t));
1207
1296
  o === 0 && n.setAAD(a);
1208
1297
  let s = Buffer.concat([n.update(e), n.final()]), c = n.getAuthTag();
1209
1298
  o++;
1210
1299
  let l = Buffer.alloc(5 + s.length + X);
1211
1300
  return l.writeUInt8(+!!t, 0), l.writeUInt32BE(s.length + X, 1), s.copy(l, 5), c.copy(l, 5 + s.length), new Uint8Array(l);
1212
1301
  }, c = Buffer.alloc(0);
1213
- for await (let t of e) for (c = c.length === 0 ? Buffer.from(t) : Buffer.concat([c, Buffer.from(t)]); c.length > pn;) yield s(c.subarray(0, pn), !1), c = c.subarray(pn);
1302
+ for await (let t of e) for (c = c.length === 0 ? Buffer.from(t) : Buffer.concat([c, Buffer.from(t)]); c.length > Sn;) yield s(c.subarray(0, Sn), !1), c = c.subarray(Sn);
1214
1303
  yield s(c, !0);
1215
1304
  }
1216
- async function* _n(e, t) {
1305
+ async function* En(e, t) {
1217
1306
  if (!t) throw Error("decryptStream: a non-empty passphrase is required");
1218
1307
  let n = e[Symbol.asyncIterator](), r = Buffer.alloc(0), i = !1, a = async () => {
1219
1308
  let { value: e, done: t } = await n.next();
@@ -1224,12 +1313,12 @@ async function* _n(e, t) {
1224
1313
  };
1225
1314
  if (!await o(Q)) throw Error("encrypted bundle truncated (no header)");
1226
1315
  let s = r.subarray(0, Q);
1227
- if (!s.subarray(0, 8).equals(ln)) throw Error("not an encrypted bundle (bad magic / wrong passphrase target)");
1228
- let c = s.readUInt32BE(8), l = s.readUInt32BE(12), u = s.readUInt32BE(16), d = Buffer.from(s.subarray(20, 36)), f = Buffer.from(s.subarray(36, Q)), p = await cn(t, d, un, {
1316
+ if (!s.subarray(0, 8).equals(vn)) throw Error("not an encrypted bundle (bad magic / wrong passphrase target)");
1317
+ let c = s.readUInt32BE(8), l = s.readUInt32BE(12), u = s.readUInt32BE(16), d = Buffer.from(s.subarray(20, 36)), f = Buffer.from(s.subarray(36, Q)), p = await _n(t, d, yn, {
1229
1318
  N: c,
1230
1319
  r: l,
1231
1320
  p: u,
1232
- maxmem: mn
1321
+ maxmem: Cn
1233
1322
  });
1234
1323
  r = r.subarray(Q);
1235
1324
  let m = 0, h = !1;
@@ -1244,7 +1333,7 @@ async function* _n(e, t) {
1244
1333
  if (!await o(5 + t)) throw Error("encrypted bundle truncated (frame body)");
1245
1334
  let n = r.subarray(5, 5 + t - X), i = r.subarray(5 + t - X, 5 + t);
1246
1335
  r = r.subarray(5 + t);
1247
- let a = g("aes-256-gcm", p, hn(f, m, e));
1336
+ let a = v("aes-256-gcm", p, wn(f, m, e));
1248
1337
  m === 0 && a.setAAD(s), a.setAuthTag(i);
1249
1338
  let c = Buffer.concat([a.update(n), a.final()]);
1250
1339
  m++, e && (h = !0), c.length > 0 && (yield new Uint8Array(c));
@@ -1252,7 +1341,7 @@ async function* _n(e, t) {
1252
1341
  }
1253
1342
  //#endregion
1254
1343
  //#region src/blobStorage.ts
1255
- var vn = (e, t) => ({
1344
+ var Dn = (e, t) => ({
1256
1345
  list: () => {
1257
1346
  let e = t();
1258
1347
  return { async *[Symbol.asyncIterator]() {
@@ -1265,29 +1354,29 @@ var vn = (e, t) => ({
1265
1354
  } };
1266
1355
  },
1267
1356
  open: (t) => ({ async *[Symbol.asyncIterator]() {
1268
- let r = await n.runPromise(C(e, t)), i = await te(r.stream);
1357
+ let r = await n.runPromise(te(e, t)), i = await re(r.stream);
1269
1358
  for await (let e of i) yield e instanceof Uint8Array ? e : new Uint8Array(e);
1270
1359
  } })
1271
- }), yn = (e, t) => vn(e, () => p(t, {
1272
- table: x,
1360
+ }), On = (e, t) => Dn(e, () => h(t, {
1361
+ table: S,
1273
1362
  chunkSize: 500
1274
1363
  }).pipe(c.map((e) => ({
1275
1364
  key: String(e.key),
1276
1365
  contentType: String(e.contentType ?? "application/octet-stream"),
1277
1366
  size: Number(e.size ?? 0)
1278
- })))), bn = (e) => ({
1367
+ })))), kn = (e) => ({
1279
1368
  has: (t) => n.runPromise(e.head(t).pipe(n.map((e) => e !== null))),
1280
1369
  write: async (t, r, i) => {
1281
- let a = S("storage", () => ne.from(r));
1282
- await n.runPromise(ee(e, t, a, {
1370
+ let a = C("storage", () => ae.from(r));
1371
+ await n.runPromise(ne(e, t, a, {
1283
1372
  contentType: i.contentType,
1284
1373
  totalSize: i.size
1285
1374
  }));
1286
1375
  }
1287
- }), xn = (e, t) => {
1376
+ }), An = (e, t) => {
1288
1377
  let n = t === "dump" ? "mariadb-dump" : "mariadb", r = t === "dump" ? "mysqldump" : "mysql";
1289
- return e === "mariadb" && Sn(n) ? n : r;
1290
- }, Sn = (e) => (process.env.PATH ?? "").split(ue).filter((e) => e !== "").some((t) => ie(O(t, e))), Cn = (e) => {
1378
+ return e === "mariadb" && jn(n) ? n : r;
1379
+ }, jn = (e) => (process.env.PATH ?? "").split(fe).filter((e) => e !== "").some((t) => se(O(t, e))), Mn = (e) => {
1291
1380
  switch (e) {
1292
1381
  case "postgres": return "db.dump";
1293
1382
  case "mysql":
@@ -1297,7 +1386,7 @@ var vn = (e, t) => ({
1297
1386
  case "mssql": return "db.bacpac";
1298
1387
  default: return "db.dump";
1299
1388
  }
1300
- }, wn = (e) => e.filename ?? e.database ?? ((e.url ?? "").replace(/^file:/, "") || "app.sqlite"), $ = (e) => {
1389
+ }, Nn = (e) => e.filename ?? e.database ?? ((e.url ?? "").replace(/^file:/, "") || "app.sqlite"), $ = (e) => {
1301
1390
  if (e.host || e.database) return {
1302
1391
  host: e.host ?? "localhost",
1303
1392
  port: e.port ?? 3306,
@@ -1313,7 +1402,7 @@ var vn = (e, t) => ({
1313
1402
  password: decodeURIComponent(t.password) || "",
1314
1403
  database: t.pathname.replace(/^\//, "") || ""
1315
1404
  };
1316
- }, Tn = (e) => `Server=${e.host},${e.port};Database=${e.database};User ID=${e.username};Password=${e.password};TrustServerCertificate=True`, En = (e, t, n) => {
1405
+ }, Pn = (e) => `Server=${e.host},${e.port};Database=${e.database};User ID=${e.username};Password=${e.password};TrustServerCertificate=True`, Fn = (e, t, n) => {
1317
1406
  switch (e) {
1318
1407
  case "postgres": {
1319
1408
  if (t.url) return {
@@ -1360,7 +1449,7 @@ var vn = (e, t) => ({
1360
1449
  let r = $(t);
1361
1450
  return {
1362
1451
  kind: "spawn",
1363
- tool: xn(e, "dump"),
1452
+ tool: An(e, "dump"),
1364
1453
  args: [
1365
1454
  "--single-transaction",
1366
1455
  "--routines",
@@ -1382,7 +1471,7 @@ var vn = (e, t) => ({
1382
1471
  case "sqlite":
1383
1472
  case "turso": return {
1384
1473
  kind: "copy",
1385
- from: wn(t),
1474
+ from: Nn(t),
1386
1475
  to: n
1387
1476
  };
1388
1477
  case "mssql": return {
@@ -1390,7 +1479,7 @@ var vn = (e, t) => ({
1390
1479
  tool: "sqlpackage",
1391
1480
  args: [
1392
1481
  "/Action:Export",
1393
- `/SourceConnectionString:${Tn($({
1482
+ `/SourceConnectionString:${Pn($({
1394
1483
  ...t,
1395
1484
  port: t.port ?? 1433
1396
1485
  }))}`,
@@ -1403,7 +1492,7 @@ var vn = (e, t) => ({
1403
1492
  reason: `no native backup for dialect '${e}'`
1404
1493
  });
1405
1494
  }
1406
- }, Dn = (e, t, n) => {
1495
+ }, In = (e, t, n) => {
1407
1496
  switch (e) {
1408
1497
  case "postgres": {
1409
1498
  if (t.url) return {
@@ -1448,7 +1537,7 @@ var vn = (e, t) => ({
1448
1537
  let r = $(t);
1449
1538
  return {
1450
1539
  kind: "spawn",
1451
- tool: xn(e, "client"),
1540
+ tool: An(e, "client"),
1452
1541
  args: [
1453
1542
  "--protocol=TCP",
1454
1543
  "-h",
@@ -1467,14 +1556,14 @@ var vn = (e, t) => ({
1467
1556
  case "turso": return {
1468
1557
  kind: "copy",
1469
1558
  from: n,
1470
- to: wn(t)
1559
+ to: Nn(t)
1471
1560
  };
1472
1561
  case "mssql": return {
1473
1562
  kind: "spawn",
1474
1563
  tool: "sqlpackage",
1475
1564
  args: [
1476
1565
  "/Action:Import",
1477
- `/TargetConnectionString:${Tn($({
1566
+ `/TargetConnectionString:${Pn($({
1478
1567
  ...t,
1479
1568
  port: t.port ?? 1433
1480
1569
  }))}`,
@@ -1487,13 +1576,13 @@ var vn = (e, t) => ({
1487
1576
  reason: `no native restore for dialect '${e}'`
1488
1577
  });
1489
1578
  }
1490
- }, On = (e) => e.kind === "copy" ? n.async((t) => {
1491
- re(e.from, e.to, (r) => t(r ? n.fail(new L({
1579
+ }, Ln = (e) => e.kind === "copy" ? n.async((t) => {
1580
+ oe(e.from, e.to, (r) => t(r ? n.fail(new L({
1492
1581
  tool: "copy",
1493
1582
  reason: `copy ${e.from} → ${e.to}: ${r.message}`
1494
1583
  })) : n.void));
1495
1584
  }) : n.async((t) => {
1496
- let r = he(e.tool, [...e.args], {
1585
+ let r = _e(e.tool, [...e.args], {
1497
1586
  env: {
1498
1587
  ...process.env,
1499
1588
  ...e.env
@@ -1506,10 +1595,10 @@ var vn = (e, t) => ({
1506
1595
  }), i = "";
1507
1596
  r.stderr?.on("data", (e) => {
1508
1597
  i += String(e);
1509
- }), e.stdoutFile && r.stdout && r.stdout.pipe(D(e.stdoutFile)), e.stdinFile && r.stdin && E(e.stdinFile).pipe(r.stdin);
1598
+ }), e.stdoutFile && r.stdout && r.stdout.pipe(E(e.stdoutFile)), e.stdinFile && r.stdin && T(e.stdinFile).pipe(r.stdin);
1510
1599
  let a = () => {
1511
1600
  if (e.stdoutFile !== void 0) try {
1512
- ae(e.stdoutFile);
1601
+ ce(e.stdoutFile);
1513
1602
  } catch {}
1514
1603
  };
1515
1604
  r.on("error", (r) => {
@@ -1524,15 +1613,15 @@ var vn = (e, t) => ({
1524
1613
  }
1525
1614
  a(), t(n.fail(new L({
1526
1615
  tool: e.tool,
1527
- reason: `exited with code ${r}` + (e.stdoutFile === void 0 ? "" : ` — the partial ${le(e.stdoutFile)} was removed, so it cannot be mistaken for a backup`),
1616
+ reason: `exited with code ${r}` + (e.stdoutFile === void 0 ? "" : ` — the partial ${de(e.stdoutFile)} was removed, so it cannot be mistaken for a backup`),
1528
1617
  stderr: i.slice(-2e3)
1529
1618
  })));
1530
1619
  });
1531
- }), kn = (e) => typeof e == "object" && e ? "fake" in e ? `fake:${e.fake}` : "custom" : String(e), An = (e) => n.gen(function* () {
1532
- let t = yield* Be(e.scope ?? { kind: "all" }, e.snapshot, {
1620
+ }), Rn = (e) => typeof e == "object" && e ? "fake" in e ? `fake:${e.fake}` : "custom" : String(e), zn = (e) => n.gen(function* () {
1621
+ let t = yield* V(e.scope ?? { kind: "all" }, e.snapshot, {
1533
1622
  store: e.store,
1534
1623
  ...e.tenantTables ? { tenantTables: e.tenantTables } : {}
1535
- }), r = q(t.tables, e.snapshot), i = e.classification ?? ve(e.snapshot), a = e.sampleSize ?? 20, o = De(r.map((t) => ({
1624
+ }), r = At(t.tables, e.snapshot), i = e.classification ?? k(e.snapshot), a = e.sampleSize ?? 20, o = Ae(r.map((t) => ({
1536
1625
  name: t,
1537
1626
  columns: (e.snapshot.tables.find((e) => e.name === t)?.columns ?? []).map((e) => ({
1538
1627
  name: e.name,
@@ -1540,26 +1629,26 @@ var vn = (e, t) => ({
1540
1629
  }))
1541
1630
  })), i, e.masking), s = [], l = [];
1542
1631
  for (let i of r) {
1543
- let r = t.predicateFor(i), u = yield* p(e.store, {
1632
+ let r = t.predicateFor(i), u = yield* h(e.store, {
1544
1633
  table: i,
1545
1634
  chunkSize: a,
1546
1635
  ...r === void 0 ? {} : { where: r }
1547
- }).pipe(c.take(a), c.runCollect, n.map((e) => [...e])), d = u.map((t) => P(t, i, o.actions, e.masking.seed));
1548
- l.push(...ke(d, i, o.actions));
1549
- let f = u[0], m = d[0], h = [];
1550
- if (f && m) for (let [e, t] of Object.entries(o.actions)) {
1636
+ }).pipe(c.take(a), c.runCollect, n.map((e) => [...e])), d = u.map((t) => Ne(t, i, o.actions, e.masking.seed));
1637
+ l.push(...Me(d, i, o.actions));
1638
+ let f = u[0], p = d[0], m = [];
1639
+ if (f && p) for (let [e, t] of Object.entries(o.actions)) {
1551
1640
  if (!e.startsWith(`${i}.`) || t === "keep") continue;
1552
1641
  let n = e.slice(i.length + 1);
1553
- h.push({
1642
+ m.push({
1554
1643
  column: n,
1555
- action: kn(t),
1644
+ action: Rn(t),
1556
1645
  before: f[n],
1557
- after: m[n]
1646
+ after: p[n]
1558
1647
  });
1559
1648
  }
1560
1649
  s.push({
1561
1650
  table: i,
1562
- samples: h
1651
+ samples: m
1563
1652
  });
1564
1653
  }
1565
1654
  return {
@@ -1567,7 +1656,7 @@ var vn = (e, t) => ({
1567
1656
  leaks: l,
1568
1657
  unclassified: o.unclassified
1569
1658
  };
1570
- }), jn = (e, t) => {
1659
+ }), Bn = (e, t) => {
1571
1660
  let n = new Map(t.map((e) => [e.name, e])), r = [], i = {};
1572
1661
  for (let t of e) {
1573
1662
  let e = n.get(t.name);
@@ -1622,7 +1711,7 @@ var vn = (e, t) => ({
1622
1711
  skipColumns: i,
1623
1712
  refuse: r.some((e) => e.verdict === "refuse")
1624
1713
  };
1625
- }, Mn = (e) => {
1714
+ }, Vn = (e) => {
1626
1715
  if (e.findings.length === 0) return [" schema matches the bundle"];
1627
1716
  let t = {
1628
1717
  safe: "✓",
@@ -1633,4 +1722,4 @@ var vn = (e, t) => ({
1633
1722
  return n.push(""), n.push(` discarded: ${r("value-dropped")} defaulted: ${r("filled-by-default")} refused: ${r("refuse")}`), e.refuse && (n.push(""), n.push(" REFUSED — no row was written. These are the differences that would make"), n.push(" imported rows WRONG rather than merely incomplete.")), n;
1634
1723
  };
1635
1724
  //#endregion
1636
- export { H as ASSETS_DIR, U as ASSET_INDEX_FILE, F as BundleError, Ae as CodecError, je as CompressionError, Le as CrossDialectError, it as DATA_DIR, _e as DEFAULT_CLASS_ACTIONS, Ne as DanglingReferenceError, Xe as FORMAT_VERSION, Ie as ImportModeError, I as IntegrityError, at as LEDGER_FILE, V as MANIFEST_FILE, Fe as MaskingError, L as NativeToolError, Pe as SchemaDriftError, Me as ScopeError, Ee as applyAction, qt as assessLiveImport, mt as assetDone, Cn as backupArtifactName, En as backupCommand, It as canonicalType, zt as checkPortability, Ut as checkSchemaDrift, ve as classificationFromSnapshot, jn as classifyImportDrift, qe as compressionExt, z as computeSubsetIds, nt as decodeManifest, wt as decodeRow, St as decodeValue, _n as decryptStream, Kt as defineDataProfile, Ht as diffSnapshots, sn as dirBlobSink, ft as emptyLedger, tt as encodeManifest, Ct as encodeRow, bt as encodeValue, gn as encryptStream, Mn as formatImportDrift, Bt as formatIssue, Ge as hasZstd, Je as makeCompressor, Ye as makeDecompressor, P as maskRow, Dt as ndjsonToRows, en as packBundle, an as peekBundle, Ke as pickCompression, De as planMasking, An as previewMasking, G as readLedger, ye as resolveAction, Be as resolveScope, We as restoreAssetFromCas, Dn as restoreCommand, Et as rowsToNdjson, Ft as runExport, Gt as runImport, On as runNativeStep, ke as scanForLeaks, He as storageAssetSink, Ve as storageAssetSource, bn as storageBlobSink, vn as storageBlobSource, yn as storageRefsBlobSource, ze as subsetToScope, pt as tableDone, q as topoSortTables, rn as unpackBundle, on as unpackBundleToDir, Ue as writeAssetToCas, K as writeLedger };
1725
+ export { W as ASSETS_DIR, G as ASSET_INDEX_FILE, P as BundleError, Pe as CodecError, Fe as CompressionError, Be as CrossDialectError, U as DATA_DIR, ye as DEFAULT_CLASS_ACTIONS, Ie as DanglingReferenceError, Qe as FORMAT_VERSION, ze as ImportModeError, F as IntegrityError, ot as LEDGER_FILE, H as MANIFEST_FILE, Re as MaskingError, L as NativeToolError, Le as SchemaDriftError, I as ScopeError, Oe as applyAction, tn as assessLiveImport, gt as assetDone, Mn as backupArtifactName, Fn as backupCommand, Bt as canonicalType, Ut as checkPortability, Zt as checkSchemaDrift, k as classificationFromSnapshot, Bn as classifyImportDrift, Ye as compressionExt, z as computeSubsetIds, it as decodeManifest, Et as decodeRow, wt as decodeValue, En as decryptStream, en as defineDataProfile, Xt as diffSnapshots, gn as dirBlobSink, pt as emptyLedger, rt as encodeManifest, Tt as encodeRow, St as encodeValue, Tn as encryptStream, Vn as formatImportDrift, Wt as formatIssue, qe as hasZstd, Xe as makeCompressor, Ze as makeDecompressor, Ne as maskRow, kt as ndjsonToRows, un as packBundle, mn as peekBundle, Je as pickCompression, Ae as planMasking, zn as previewMasking, mt as readLedger, be as resolveAction, V as resolveScope, Ke as restoreAssetFromCas, In as restoreCommand, Ot as rowsToNdjson, zt as runExport, $t as runImport, Ln as runNativeStep, Me as scanForLeaks, We as storageAssetSink, Ue as storageAssetSource, kn as storageBlobSink, Dn as storageBlobSource, On as storageRefsBlobSource, He as subsetToScope, ht as tableDone, At as topoSortTables, pn as unpackBundle, hn as unpackBundleToDir, Ge as writeAssetToCas, q as writeLedger };