@voltro/data-transfer 0.1.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 ADDED
@@ -0,0 +1,1501 @@
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";
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 ie } from "node:fs";
9
+ import { mkdir as ae, readdir as oe, stat as se } from "node:fs/promises";
10
+ import { dirname as ce, join as D, resolve as le, sep as ue } from "node:path";
11
+ import { promisify as de } from "node:util";
12
+ import { spawn as fe } from "node:child_process";
13
+ //#region src/consistency.ts
14
+ var pe = (e) => {
15
+ switch (e) {
16
+ case "postgres": return ["SET TRANSACTION ISOLATION LEVEL REPEATABLE READ"];
17
+ case "mysql":
18
+ case "mariadb": return ["SET TRANSACTION ISOLATION LEVEL REPEATABLE READ"];
19
+ case "mssql": return ["SET TRANSACTION ISOLATION LEVEL SNAPSHOT"];
20
+ case "sqlite":
21
+ case "turso": return [];
22
+ default: return [];
23
+ }
24
+ }, me = {
25
+ email: { fake: "email" },
26
+ fullName: { fake: "fullName" },
27
+ firstName: { fake: "firstName" },
28
+ lastName: { fake: "lastName" },
29
+ username: { fake: "username" },
30
+ phone: { fake: "phone" },
31
+ address: { fake: "address" },
32
+ company: { fake: "company" },
33
+ url: { fake: "url" },
34
+ ip: { fake: "ip" },
35
+ creditCard: { fake: "creditCard" },
36
+ date: "dateShift",
37
+ secret: "null",
38
+ freeText: "redact"
39
+ }, O = (e) => {
40
+ let t = {};
41
+ for (let n of e.tables) {
42
+ let e = {};
43
+ for (let t of n.columns) e[t.name] = {
44
+ ...t.sensitive ? { sensitive: t.sensitive } : {},
45
+ ...t.safe ? { safe: !0 } : {},
46
+ columnType: t.type
47
+ };
48
+ t[n.name] = e;
49
+ }
50
+ return t;
51
+ }, he = (e, t, n, r) => {
52
+ let i = r.columns?.[`${e}.${t}`];
53
+ if (i) return i;
54
+ if (n?.sensitive) {
55
+ let e = n.sensitive.class;
56
+ return r.classes?.[e] ?? me[e] ?? "redact";
57
+ }
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 = [
60
+ "Ada",
61
+ "Alan",
62
+ "Grace",
63
+ "Linus",
64
+ "Ida",
65
+ "Ken",
66
+ "Barbara",
67
+ "Dennis",
68
+ "Radia",
69
+ "Guido",
70
+ "Margaret",
71
+ "Bjarne"
72
+ ], ge = [
73
+ "Lovelace",
74
+ "Turing",
75
+ "Hopper",
76
+ "Torvalds",
77
+ "Rhodes",
78
+ "Thompson",
79
+ "Liskov",
80
+ "Ritchie",
81
+ "Perlman",
82
+ "Rossum",
83
+ "Hamilton",
84
+ "Stroustrup"
85
+ ], _e = [
86
+ "Maple",
87
+ "Oak",
88
+ "Cedar",
89
+ "Pine",
90
+ "Elm",
91
+ "Birch",
92
+ "Willow",
93
+ "Ash"
94
+ ], ve = [
95
+ "Initech",
96
+ "Hooli",
97
+ "Umbrella",
98
+ "Acme",
99
+ "Globex",
100
+ "Soylent",
101
+ "Stark",
102
+ "Wayne"
103
+ ], M = (e, t, n) => e[A(t, n) % e.length], ye = (e, t, n) => {
104
+ let r = k(n, `${e}:${String(t)}`), i = A(r, 1) % 1e4;
105
+ switch (e) {
106
+ case "email": return `${M(j, r, 0).toLowerCase()}.${M(ge, r, 2).toLowerCase()}${i}@example.com`;
107
+ case "fullName": return `${M(j, r, 0)} ${M(ge, r, 1)}`;
108
+ case "firstName": return M(j, r, 0);
109
+ case "lastName": return M(ge, r, 1);
110
+ case "username": return `${M(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} ${M(_e, r, 1)} St`;
113
+ case "company": return M(ve, r, 0);
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 be(`4${r.toString("hex").replace(/\D/g, "").padEnd(14, "0").slice(0, 14)}`);
117
+ default: return `${e}_${r.toString("hex").slice(0, 8)}`;
118
+ }
119
+ }, be = (e) => {
120
+ let t = e.slice(0, 15).split("").map(Number), n = 0;
121
+ t.forEach((e, t) => {
122
+ let r = e;
123
+ (15 - t) % 2 == 1 && (r *= 2, r > 9 && (r -= 9)), n += r;
124
+ });
125
+ let r = (10 - n % 10) % 10;
126
+ return e.slice(0, 15) + String(r);
127
+ }, xe = 864e5, Se = (e, t) => {
128
+ let n = e instanceof Date ? e.getTime() : Date.parse(String(e));
129
+ if (Number.isNaN(n)) return e;
130
+ let r = A(k(t, "date-shift-offset"), 0) % 730 - 365, i = new Date(n + r * xe);
131
+ return e instanceof Date ? i : i.toISOString();
132
+ }, Ce = (e, t) => {
133
+ if (t.value === null || t.value === void 0) return null;
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" ? Se(t.value, t.seed) : typeof e == "object" && "fake" in e ? ye(e.fake, t.value, t.seed) : typeof e == "object" && "custom" in e ? e.custom(t) : t.value;
136
+ }, N = (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 = he(a.name, e.name, t[a.name]?.[e.name], n);
140
+ s === "error" ? i.push(o) : r[o] = s;
141
+ }
142
+ return {
143
+ actions: r,
144
+ unclassified: i
145
+ };
146
+ }, we = [
147
+ {
148
+ name: "email",
149
+ re: /[\w.+-]+@[\w-]+\.[\w.-]+/
150
+ },
151
+ {
152
+ name: "phone",
153
+ re: /(?:\+?\d[\d\s().-]{8,}\d)/
154
+ },
155
+ {
156
+ name: "ipv4",
157
+ re: /\b(?:\d{1,3}\.){3}\d{1,3}\b/
158
+ },
159
+ {
160
+ name: "creditCard",
161
+ re: /\b(?:\d[ -]?){13,16}\b/
162
+ }
163
+ ], Te = (e, t, n) => {
164
+ let r = [], i = /* @__PURE__ */ new Set();
165
+ for (let [a, o] of Object.entries(n)) {
166
+ if (!a.startsWith(`${t}.`) || o !== "keep") continue;
167
+ let n = a.slice(t.length + 1);
168
+ for (let a of e) {
169
+ let e = a[n];
170
+ if (typeof e != "string" || e.length === 0) continue;
171
+ let o = we.find((t) => t.re.test(e));
172
+ if (o && !i.has(n)) {
173
+ i.add(n), r.push({
174
+ table: t,
175
+ column: n,
176
+ pattern: o.name,
177
+ sample: e.slice(0, 40)
178
+ });
179
+ break;
180
+ }
181
+ }
182
+ }
183
+ return r;
184
+ }, P = (e, t, n, r, i) => {
185
+ let a = {};
186
+ for (let [o, s] of Object.entries(e)) a[o] = Ce(n[`${t}.${o}`] ?? "keep", {
187
+ value: s,
188
+ table: t,
189
+ column: o,
190
+ seed: r,
191
+ ...i?.[o] ? { columnType: i[o] } : {}
192
+ });
193
+ return a;
194
+ }, F = class extends s.TaggedError()("BundleError", {
195
+ reason: s.String,
196
+ path: s.optional(s.String)
197
+ }) {}, Ee = class extends s.TaggedError()("CodecError", {
198
+ table: s.String,
199
+ reason: s.String
200
+ }) {}, I = class extends s.TaggedError()("IntegrityError", {
201
+ what: s.String,
202
+ expected: s.String,
203
+ actual: s.String
204
+ }) {}, De = class extends t.TaggedError("CompressionError") {}, Oe = class extends s.TaggedError()("ScopeError", { reason: s.String }) {}, ke = class extends s.TaggedError()("DanglingReferenceError", {
205
+ rows: s.Array(s.Struct({
206
+ table: s.String,
207
+ id: s.String,
208
+ reason: s.String
209
+ })),
210
+ totalCount: s.Number
211
+ }) {}, Ae = class extends s.TaggedError()("SchemaDriftError", {
212
+ bundleFingerprint: s.String,
213
+ targetFingerprint: s.String,
214
+ diff: s.Array(s.String)
215
+ }) {}, L = class extends t.TaggedError("NativeToolError") {}, je = class extends s.TaggedError()("MaskingError", { unclassified: s.Array(s.String) }) {}, Me = class extends s.TaggedError()("ImportModeError", {
216
+ mode: s.String,
217
+ reason: s.String
218
+ }) {}, Ne = class extends s.TaggedError()("CrossDialectError", {
219
+ sourceDialect: s.String,
220
+ targetDialect: s.String,
221
+ blocking: s.Array(s.String)
222
+ }) {}, R = (e, t) => e.tables.find((e) => e.name === t)?.columns.find((e) => e.type === "id")?.name ?? "id", Pe = (e, t) => (e.tables.find((e) => e.name === t)?.columns ?? []).filter((e) => e.references).map((e) => ({
223
+ col: e.name,
224
+ refTable: e.references.table
225
+ })), Fe = (e, t, r) => n.gen(function* () {
226
+ let i = r.maxDepth ?? 12, a = new Set(r.pinned ?? []), o = /* @__PURE__ */ new Map(), s = /* @__PURE__ */ new Map(), l = /* @__PURE__ */ new Map(), d = (e) => {
227
+ let t = s.get(e) ?? /* @__PURE__ */ new Set();
228
+ return s.set(e, t), t;
229
+ }, m = (e, t) => {
230
+ if (t == null || a.has(e) || s.get(e)?.has(t)) return;
231
+ let n = l.get(e) ?? /* @__PURE__ */ new Set();
232
+ n.add(t), l.set(e, n);
233
+ }, h = (e, t, n) => {
234
+ let r = d(e), i = a.has(e) ? void 0 : o.get(e) ?? (() => {
235
+ let t = /* @__PURE__ */ new Set();
236
+ return o.set(e, t), t;
237
+ })();
238
+ return (e) => {
239
+ r.add(e[t]), i?.add(e[t]);
240
+ for (let t of n) m(t.refTable, e[t.col]);
241
+ };
242
+ }, g = (r, i) => {
243
+ let a = h(r, R(t, r), Pe(t, r));
244
+ return c.runForEach(p(e, {
245
+ table: r,
246
+ pk: R(t, r),
247
+ ...i === void 0 ? {} : { where: i }
248
+ }), (e) => n.sync(() => a(e)));
249
+ }, _ = n.gen(function* () {
250
+ for (let e = 0; e < i && l.size > 0; e++) {
251
+ let e = [...l.entries()];
252
+ l.clear();
253
+ for (let [n, r] of e) {
254
+ let e = [...r].filter((e) => !s.get(n)?.has(e));
255
+ e.length !== 0 && (yield* g(n, u(R(t, n), e)));
256
+ }
257
+ }
258
+ });
259
+ for (let [e, t] of Object.entries(r.seeds)) yield* g(e, t);
260
+ if (yield* _, r.children) {
261
+ let e = new Set(r.children === !0 ? [...s.keys()] : r.children.roots.filter((e) => s.has(e)));
262
+ for (let n = 0; n < i; n++) {
263
+ let n = !1, r = [];
264
+ for (let i of t.tables) {
265
+ let t = i.name, a = i.columns.map((e) => ({
266
+ col: e.name,
267
+ refTable: e.references?.table
268
+ })).filter((t) => !!t.refTable && e.has(t.refTable) && (s.get(t.refTable)?.size ?? 0) > 0);
269
+ if (a.length === 0) continue;
270
+ let o = s.get(t)?.size ?? 0, c = a.map((e) => u(e.col, [...s.get(e.refTable)]));
271
+ 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);
272
+ }
273
+ for (let t of r) e.add(t);
274
+ if (yield* _, !n) break;
275
+ }
276
+ }
277
+ return o;
278
+ }), Ie = (e, t) => ({
279
+ tables: [...e.keys()],
280
+ predicateFor: (n) => {
281
+ let r = e.get(n);
282
+ return r ? u(R(t, n), [...r]) : void 0;
283
+ }
284
+ }), z = "tenantId", Le = (e, t, r) => n.gen(function* () {
285
+ let i = t.tables.map((e) => e.name), a = new Map(t.tables.map((e) => [e.name, e]));
286
+ if (e.kind === "all") return {
287
+ tables: i,
288
+ predicateFor: () => void 0
289
+ };
290
+ if (e.kind === "tables") {
291
+ let t = new Set(e.tables ?? []);
292
+ return {
293
+ tables: i.filter((e) => t.has(e)),
294
+ predicateFor: () => void 0
295
+ };
296
+ }
297
+ let o = e.tenantId;
298
+ if (o === void 0 || o === "") return yield* n.fail(new Oe({ reason: "scope { kind: 'tenant' } requires a tenantId — pass --tenant <id> (CLI) or scope.tenantId (API). Refusing to fall back to an unfiltered export." }));
299
+ let s = r.tenantTables ? r.tenantTables.filter((e) => a.has(e)) : i.filter((e) => a.get(e)?.columns.some((e) => e.name === z) ?? !1);
300
+ if (s.length === 0) return yield* n.fail(new Oe({ reason: r.tenantTables ? "tenant scope: none of the provided tenantTables exist in the schema — nothing to filter." : `tenant scope: no table carries a '${z}' column — nothing to filter. A tenant export of a schema without tenant-scoped tables would be the full database; refusing.` }));
301
+ let c = yield* Fe(r.store, t, {
302
+ seeds: Object.fromEntries(s.map((e) => [e, l(z, o)])),
303
+ pinned: s,
304
+ children: { roots: s }
305
+ }), d = [...c.entries()].filter(([, e]) => e.size > 0).map(([e]) => e), f = new Set(s);
306
+ return {
307
+ tables: [...s, ...d],
308
+ predicateFor: (e) => f.has(e) ? l(z, o) : c.has(e) ? u(R(t, e), [...c.get(e)]) : void 0
309
+ };
310
+ }), Re = (e, t) => ({
311
+ list: t,
312
+ open: (t) => C(e, t)
313
+ }), ze = (e) => ({
314
+ write: (t, n, r) => ee(e, t, n, r),
315
+ has: (t) => e.head(t).pipe(n.map((e) => e !== null))
316
+ }), Be = (e, t) => n.tryPromise({
317
+ try: async () => {
318
+ 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) {
319
+ u.update(e), d += e.length, n(null, e);
320
+ } });
321
+ await o(await te(e.stream), f, n(l));
322
+ let p = u.digest("hex"), m = c.join(t, p);
323
+ try {
324
+ await r.access(m), await r.rm(l, { force: !0 });
325
+ } catch {
326
+ await r.rename(l, m);
327
+ }
328
+ return {
329
+ sha256: p,
330
+ size: d,
331
+ contentType: e.contentType
332
+ };
333
+ },
334
+ catch: (e) => new F({
335
+ reason: `asset write failed: ${String(e?.message ?? e)}`,
336
+ path: t
337
+ })
338
+ }), Ve = (e, t, r) => n.gen(function* () {
339
+ 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))));
340
+ yield* e.write(r.key, u, {
341
+ contentType: r.contentType,
342
+ totalSize: r.size
343
+ });
344
+ let d = l.digest("hex");
345
+ if (d !== r.sha256) return yield* n.fail(new I({
346
+ what: `asset ${r.key}`,
347
+ expected: r.sha256,
348
+ actual: d
349
+ }));
350
+ }), He = () => typeof w.createZstdCompress == "function", Ue = (e) => e === "none" ? "none" : e === "gzip" ? "gzip" : He() ? "zstd" : "gzip", We = (e) => e === "zstd" ? ".zst" : e === "gzip" ? ".gz" : "", Ge = (e) => e === "zstd" ? w.createZstdCompress() : e === "gzip" ? w.createGzip() : new T(), Ke = (e) => e === "zstd" ? w.createZstdDecompress() : e === "gzip" ? w.createGunzip() : new T(), qe = 1, Je = s.Struct({
351
+ name: s.String,
352
+ file: s.String,
353
+ rowCount: s.Number,
354
+ checksum: s.String,
355
+ columnTypes: s.Record({
356
+ key: s.String,
357
+ value: s.String
358
+ }),
359
+ primaryKey: s.String
360
+ }), Ye = s.Struct({
361
+ kind: s.Literal("all", "tenant", "tables"),
362
+ tenantId: s.optional(s.String),
363
+ tables: s.optional(s.Array(s.String))
364
+ }), Xe = s.Struct({
365
+ count: s.Number,
366
+ totalBytes: s.Number,
367
+ index: s.optional(s.String)
368
+ });
369
+ s.Struct({
370
+ key: s.String,
371
+ sha256: s.String,
372
+ size: s.Number,
373
+ contentType: s.String
374
+ });
375
+ var Ze = s.Struct({
376
+ formatVersion: s.Number,
377
+ createdAt: s.String,
378
+ source: s.Struct({
379
+ dialect: s.String,
380
+ schemaFingerprint: s.String
381
+ }),
382
+ scope: Ye,
383
+ consistency: s.Literal("live", "snapshot"),
384
+ compression: s.Literal("zstd", "gzip", "none"),
385
+ tables: s.Array(Je),
386
+ assets: Xe,
387
+ masking: s.optional(s.Struct({
388
+ policyId: s.optional(s.String),
389
+ transformed: s.Array(s.String)
390
+ }))
391
+ }), Qe = s.encodeSync(s.parseJson(Ze)), $e = s.decodeUnknownSync(s.parseJson(Ze)), B = "manifest.json", et = "README.md", V = "data", H = "assets", U = "assets/index.ndjson", tt = ".ledger.json", nt = (e) => e.kind === "tenant" ? `tenant \`${e.tenantId}\`` : e.kind === "tables" ? `tables \`${(e.tables ?? []).join(", ")}\`` : "all tables", rt = (e, t) => {
392
+ 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");
393
+ return `# Voltro data export
394
+
395
+ The machine-readable manifest is \`manifest.json\`; this file is a human summary.
396
+
397
+ | | |
398
+ |---|---|
399
+ | **Generated** | ${e.createdAt} |
400
+ | **Exported from** | \`${t.hostname}\` |
401
+ | **Source dialect** | \`${e.source.dialect}\` |
402
+ | **Format version** | ${e.formatVersion} |
403
+ | **Consistency** | ${e.consistency} |
404
+ | **Compression** | ${e.compression} |
405
+ | **Scope** | ${nt(e.scope)} |
406
+ | **Tables** | ${e.tables.length} |
407
+ | **Rows (total)** | ${n} |
408
+ | **Assets** | ${a} |
409
+
410
+ ## Data sensitivity
411
+
412
+ ${r}${i}
413
+
414
+ ## Tables
415
+
416
+ | Table | Rows |
417
+ |---|---|
418
+ ${o}
419
+
420
+ ## Restore
421
+
422
+ \`\`\`bash
423
+ # into a stopped/replica DB directly:
424
+ voltro data import <this-directory>
425
+
426
+ # or into a running instance (needs the data-transfer secret):
427
+ voltro data import <this-directory> --target api --api-url <url> --token <secret>
428
+ \`\`\`
429
+ `;
430
+ }, it = i.counter("voltro_data_transfer_rows", { description: "Rows exported/imported by @voltro/data-transfer, tagged by phase + table." }), at = a.exponential({
431
+ start: .01,
432
+ factor: 2,
433
+ count: 16
434
+ }), ot = i.histogram("voltro_data_transfer_table_seconds", at, "Per-table export/import duration in seconds, tagged by phase."), W = (e, t) => {
435
+ if (e) try {
436
+ e(t);
437
+ } catch {}
438
+ }, st = (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(ot.pipe(i.tagged("phase", e), i.update((s - r) / 1e3)), it.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: {
439
+ table: t,
440
+ index: r,
441
+ tableCount: a,
442
+ phase: e
443
+ } })), ct = () => ({
444
+ tables: {},
445
+ assets: {}
446
+ }), G = (e) => n.tryPromise(async () => {
447
+ let t = await (await import("node:fs/promises")).readFile(e, "utf8");
448
+ return JSON.parse(t);
449
+ }).pipe(n.orElseSucceed(ct)), K = (e, t) => n.tryPromise({
450
+ try: async () => {
451
+ let n = await import("node:fs/promises"), { randomUUID: r } = await import("node:crypto"), i = `${e}.tmp-${r()}`;
452
+ await n.writeFile(i, JSON.stringify(t)), await n.rename(i, e);
453
+ },
454
+ catch: (t) => new F({
455
+ reason: `ledger write failed: ${String(t?.message ?? t)}`,
456
+ path: e
457
+ })
458
+ }), lt = (e, t) => t in e.tables, ut = (e, t) => t in e.assets, dt = /* @__PURE__ */ new Set([
459
+ "json",
460
+ "array",
461
+ "vector"
462
+ ]), ft = (e) => typeof e == "object" && !!e && !Array.isArray(e) && typeof e.$v == "string", pt = (e) => Buffer.from(e).toString("base64"), mt = (e) => new Uint8Array(Buffer.from(e, "base64")), ht = (e) => e instanceof Date ? e.toISOString() : typeof e == "number" ? new Date(e).toISOString() : String(e), gt = (e, t) => e == null ? null : t !== void 0 && dt.has(t) ? e : t === "bytes" ? pt(e) : t === "timestamp" || t === "date" ? ht(e) : typeof e == "bigint" ? {
463
+ $v: "bigint",
464
+ d: e.toString()
465
+ } : typeof e == "number" && !Number.isFinite(e) ? {
466
+ $v: "number",
467
+ d: String(e)
468
+ } : e instanceof Date ? {
469
+ $v: "date",
470
+ d: e.toISOString()
471
+ } : e instanceof Uint8Array ? {
472
+ $v: "bytes",
473
+ d: pt(e)
474
+ } : e, _t = (e) => {
475
+ switch (e.$v) {
476
+ case "bigint": return BigInt(e.d);
477
+ case "number": return Number(e.d);
478
+ case "date": return new Date(e.d);
479
+ case "bytes": return mt(e.d);
480
+ default: return e;
481
+ }
482
+ }, vt = (e, t) => e == null ? null : t !== void 0 && dt.has(t) ? e : ft(e) ? _t(e) : t === "bytes" ? mt(e) : t === "timestamp" || t === "date" ? new Date(e) : e, yt = (e, t) => {
483
+ let n = {};
484
+ for (let [r, i] of Object.entries(e)) n[r] = gt(i, t[r]);
485
+ return n;
486
+ }, bt = (e, t) => {
487
+ let n = {};
488
+ for (let [r, i] of Object.entries(e)) n[r] = vt(i, t[r]);
489
+ return n;
490
+ }, xt = new TextEncoder(), St = (e, t) => e.pipe(c.map((e) => xt.encode(`${JSON.stringify(yt(e, t))}\n`))), Ct = (e, t, r) => e.pipe(c.decodeText(), c.splitLines, c.filter((e) => e.trim().length > 0), c.mapEffect((e) => n.try({
491
+ try: () => bt(JSON.parse(e), r),
492
+ catch: (e) => new Ee({
493
+ table: t,
494
+ reason: String(e?.message ?? e)
495
+ })
496
+ }))), q = (e, t) => {
497
+ let n = new Set(e), r = /* @__PURE__ */ new Map();
498
+ for (let e of t.tables) {
499
+ if (!n.has(e.name)) continue;
500
+ let t = /* @__PURE__ */ new Set();
501
+ for (let r of e.columns) {
502
+ let i = r.references?.table;
503
+ i && i !== e.name && n.has(i) && t.add(i);
504
+ }
505
+ r.set(e.name, t);
506
+ }
507
+ let i = [], a = /* @__PURE__ */ new Set(), o = /* @__PURE__ */ new Set(), s = (e) => {
508
+ if (!(a.has(e) || o.has(e))) {
509
+ o.add(e);
510
+ for (let t of r.get(e) ?? []) s(t);
511
+ o.delete(e), a.add(e), i.push(e);
512
+ }
513
+ };
514
+ for (let t of e) n.has(t) && s(t);
515
+ return i;
516
+ }, wt = (e, t) => {
517
+ let n = e.tables.find((e) => e.name === t), r = {};
518
+ for (let e of n?.columns ?? []) r[e.name] = e.type;
519
+ return r;
520
+ }, Tt = (e, t) => e.tables.find((e) => e.name === t)?.columns.find((e) => e.type === "id")?.name ?? "id", Et = (e, t, r) => n.tryPromise({
521
+ try: async () => {
522
+ 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) {
523
+ d.update(e);
524
+ let r = e;
525
+ for (let e = 0; e < r.length; e++) r[e] === 10 && f++;
526
+ n(null, e);
527
+ } }), m = l.fromWeb(c.toReadableStream(e)), h = `${t}.tmp-${o()}`;
528
+ try {
529
+ await s(m, p, Ge(r), n(h)), await i.rename(h, t);
530
+ } catch (e) {
531
+ throw await i.rm(h, { force: !0 }).catch(() => {}), e;
532
+ }
533
+ return {
534
+ rowCount: f,
535
+ checksum: d.digest("hex")
536
+ };
537
+ },
538
+ catch: (e) => new F({
539
+ reason: `write table failed: ${String(e?.message ?? e)}`,
540
+ path: t
541
+ })
542
+ }), Dt = (e, t) => n.tryPromise({
543
+ try: async () => {
544
+ await (await import("node:fs/promises")).appendFile(e, `${t}\n`);
545
+ },
546
+ catch: (t) => new F({
547
+ reason: `append failed: ${String(t?.message ?? t)}`,
548
+ path: e
549
+ })
550
+ }), Ot = (e, t) => n.gen(function* () {
551
+ let n = [], r = t.ordered.length;
552
+ for (let i = 0; i < t.ordered.length; i++) {
553
+ let a = t.ordered[i], o = wt(t.snapshot, a), s = Tt(t.snapshot, a), l = `${V}/${a}.ndjson${We(t.compression)}`;
554
+ if (lt(t.ledger, a)) {
555
+ let e = t.ledger.tables[a];
556
+ W(t.onProgress, {
557
+ phase: "export",
558
+ table: a,
559
+ index: i,
560
+ tableCount: r,
561
+ event: "done",
562
+ rowsDone: e.rowCount,
563
+ total: e.rowCount
564
+ }), n.push({
565
+ name: a,
566
+ file: l,
567
+ rowCount: e.rowCount,
568
+ checksum: e.checksum,
569
+ columnTypes: o,
570
+ primaryKey: s
571
+ });
572
+ continue;
573
+ }
574
+ W(t.onProgress, {
575
+ phase: "export",
576
+ table: a,
577
+ index: i,
578
+ tableCount: r,
579
+ event: "start",
580
+ rowsDone: 0
581
+ });
582
+ let u = t.resolved.predicateFor(a), d = p(e, {
583
+ table: a,
584
+ pk: s,
585
+ chunkSize: t.chunkSize,
586
+ retry: t.retry,
587
+ ...u === void 0 ? {} : { where: u }
588
+ }), f = t.mask ? d.pipe(c.map((e) => P(e, a, t.mask.actions, t.mask.seed, o))) : d, { rowCount: m, checksum: h } = yield* st("export", a, i, r, (e) => e.rowCount, Et(St(f, o), t.bundleFile(l), t.compression));
589
+ t.ledger.tables[a] = {
590
+ rowCount: m,
591
+ checksum: h
592
+ }, yield* K(t.ledgerPath, t.ledger), W(t.onProgress, {
593
+ phase: "export",
594
+ table: a,
595
+ index: i,
596
+ tableCount: r,
597
+ event: "done",
598
+ rowsDone: m,
599
+ total: m
600
+ }), n.push({
601
+ name: a,
602
+ file: l,
603
+ rowCount: m,
604
+ checksum: h,
605
+ columnTypes: o,
606
+ primaryKey: s
607
+ });
608
+ }
609
+ return n;
610
+ }), kt = (e) => ({
611
+ _tag: "RawSqlFragment",
612
+ strings: [e],
613
+ values: []
614
+ }), At = (t, i, a) => n.tryPromise({
615
+ try: () => t.transactional(async (t) => {
616
+ if (t.raw) for (let e of pe(i)) await t.raw(kt(e));
617
+ let o = await n.runPromiseExit(a(t));
618
+ if (r.isFailure(o)) throw Error(e.pretty(o.cause));
619
+ return o.value;
620
+ }),
621
+ catch: (e) => e instanceof F ? e : new F({ reason: `snapshot export failed: ${String(e?.message ?? e)}` })
622
+ }), jt = (e) => n.gen(function* () {
623
+ let t = e.scope ?? { kind: "all" }, r = Ue(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);
624
+ yield* n.tryPromise({
625
+ try: async () => {
626
+ let t = await import("node:fs/promises");
627
+ await t.mkdir(u(V), { recursive: !0 }), e.assets && await t.mkdir(u(H), { recursive: !0 });
628
+ },
629
+ catch: (t) => new F({
630
+ reason: `mkdir failed: ${String(t?.message ?? t)}`,
631
+ path: e.outDir
632
+ })
633
+ });
634
+ let d = u(tt), f = yield* G(d), p = e.subset ? Ie(yield* Fe(e.store, e.snapshot, e.subset), e.snapshot) : yield* Le(t, e.snapshot, {
635
+ store: e.store,
636
+ ...e.tenantTables ? { tenantTables: e.tenantTables } : {}
637
+ }), h = q(p.tables, e.snapshot), g = e.consistency ?? "live", _, v;
638
+ if (e.masking) {
639
+ let t = e.classification ?? O(e.snapshot), r = N(h.map((t) => ({
640
+ name: t,
641
+ columns: (e.snapshot.tables.find((e) => e.name === t)?.columns ?? []).map((e) => ({
642
+ name: e.name,
643
+ type: e.type
644
+ }))
645
+ })), t, e.masking);
646
+ if (r.unclassified.length > 0) return yield* n.fail(new je({ unclassified: r.unclassified }));
647
+ v = {
648
+ actions: r.actions,
649
+ seed: e.masking.seed
650
+ };
651
+ let i = Object.entries(r.actions).filter(([, e]) => e !== "keep").map(([e]) => e);
652
+ _ = {
653
+ ...e.masking.id ? { policyId: e.masking.id } : {},
654
+ transformed: i
655
+ };
656
+ }
657
+ let y = {
658
+ snapshot: e.snapshot,
659
+ ordered: h,
660
+ resolved: p,
661
+ compression: r,
662
+ chunkSize: i,
663
+ retry: s,
664
+ ledger: f,
665
+ ledgerPath: d,
666
+ bundleFile: u,
667
+ ...v ? { mask: v } : {},
668
+ ...e.onProgress ? { onProgress: e.onProgress } : {}
669
+ }, b = g === "snapshot" ? yield* At(e.store, e.dialect, (e) => Ot(e, y)) : yield* Ot(e.store, y), x = 0, S = 0;
670
+ if (e.assets) {
671
+ let t = u(U);
672
+ yield* c.runForEach(e.assets.list(), (r) => r.key in f.assets ? n.void : e.assets.open(r.key).pipe(n.flatMap((e) => Be(e, u(H))), n.flatMap((e) => {
673
+ let i = {
674
+ key: r.key,
675
+ sha256: e.sha256,
676
+ size: e.size,
677
+ contentType: e.contentType
678
+ };
679
+ return x++, S += e.size, f.assets[r.key] = !0, Dt(t, JSON.stringify(i)).pipe(n.andThen(K(d, f)));
680
+ }))).pipe(n.mapError((e) => e instanceof F ? e : new F({ reason: `asset export failed: ${String(e)}` })));
681
+ }
682
+ let C = {
683
+ formatVersion: 1,
684
+ createdAt: e.createdAt ?? (/* @__PURE__ */ new Date()).toISOString(),
685
+ source: {
686
+ dialect: e.dialect,
687
+ schemaFingerprint: m(e.snapshot)
688
+ },
689
+ scope: t,
690
+ consistency: g,
691
+ compression: r,
692
+ tables: b,
693
+ assets: x > 0 ? {
694
+ count: x,
695
+ totalBytes: S,
696
+ index: U
697
+ } : {
698
+ count: 0,
699
+ totalBytes: 0
700
+ },
701
+ ..._ ? { masking: _ } : {}
702
+ };
703
+ return yield* n.tryPromise({
704
+ try: async () => {
705
+ await (await import("node:fs/promises")).writeFile(u(B), Qe(C));
706
+ },
707
+ catch: (e) => new F({
708
+ reason: `manifest write failed: ${String(e?.message ?? e)}`,
709
+ path: B
710
+ })
711
+ }), yield* n.tryPromise({
712
+ try: async () => {
713
+ let e = await import("node:fs/promises"), t = await import("node:os");
714
+ await e.writeFile(u(et), rt(C, { hostname: t.hostname() }));
715
+ },
716
+ catch: (e) => new F({
717
+ reason: `readme write failed: ${String(e?.message ?? e)}`,
718
+ path: et
719
+ })
720
+ }), C;
721
+ }), Mt = (e) => {
722
+ switch (e) {
723
+ case "id":
724
+ case "text":
725
+ case "enum": return e === "enum" ? "enum" : "string";
726
+ case "integer": return "integer";
727
+ case "real": return "float";
728
+ case "boolean": return "boolean";
729
+ case "timestamp": return "datetime";
730
+ case "date": return "date";
731
+ case "json": return "json";
732
+ case "bytes": return "binary";
733
+ case "reference": return "reference";
734
+ case "vector": return "vector";
735
+ case "array": return "array";
736
+ case "interval": return "interval";
737
+ case "raw": return "raw";
738
+ default: return "string";
739
+ }
740
+ }, Nt = {
741
+ vector: /* @__PURE__ */ new Set(["postgres"]),
742
+ array: /* @__PURE__ */ new Set(["postgres"]),
743
+ interval: /* @__PURE__ */ new Set(["postgres"])
744
+ }, Pt = (e, t, n, r) => {
745
+ let i = Mt(n);
746
+ if (i === "raw") return {
747
+ table: e,
748
+ column: t,
749
+ type: n,
750
+ severity: "block",
751
+ reason: `raw() is verbatim source-dialect SQL — it cannot be assumed valid on ${r}`
752
+ };
753
+ let a = Nt[i];
754
+ return !a || a.has(r) ? null : i === "array" || i === "interval" ? {
755
+ table: e,
756
+ column: t,
757
+ type: n,
758
+ severity: "warn",
759
+ reason: `${i} is native to postgres; ${r} will represent it as json/text — verify downstream reads`
760
+ } : {
761
+ table: e,
762
+ column: t,
763
+ type: n,
764
+ severity: "block",
765
+ reason: `${i} columns require a ${[...a].join("/")} target; ${r} has no compatible column type`
766
+ };
767
+ }, Ft = (e, t, n) => {
768
+ if (t === n) return [];
769
+ let r = [];
770
+ for (let t of e) for (let [e, i] of Object.entries(t.columnTypes)) {
771
+ let a = Pt(t.name, e, i, n);
772
+ a && r.push(a);
773
+ }
774
+ return r;
775
+ }, It = (e) => `[${e.severity}] ${e.table}.${e.column} (${e.type}): ${e.reason}`, Lt = (e, t) => new Map((e.tables.find((e) => e.name === t)?.columns ?? []).map((e) => [e.name, e.type])), Rt = (e, t) => {
776
+ let n = [], r = new Set(e.tables.map((e) => e.name)), i = new Set(t.tables.map((e) => e.name));
777
+ for (let e of [...r].filter((e) => !i.has(e)).sort()) n.push(`table '${e}' is in the bundle but MISSING from the target`);
778
+ 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)`);
779
+ for (let a of [...r].filter((e) => i.has(e)).sort()) {
780
+ let r = Lt(e, a), i = Lt(t, a);
781
+ for (let [e] of r) i.has(e) || n.push(`${a}.${e}: in the bundle, MISSING from the target`);
782
+ for (let [e] of i) r.has(e) || n.push(`${a}.${e}: in the target, not in the bundle`);
783
+ for (let [e, t] of r) {
784
+ let r = i.get(e);
785
+ r !== void 0 && r !== t && n.push(`${a}.${e}: type '${t}' (bundle) vs '${r}' (target)`);
786
+ }
787
+ }
788
+ 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"];
789
+ }, zt = (e, t, n) => {
790
+ let r = m(t);
791
+ return r === e ? {
792
+ drifted: !1,
793
+ bundleFingerprint: e,
794
+ targetFingerprint: r,
795
+ diff: []
796
+ } : {
797
+ drifted: !0,
798
+ bundleFingerprint: e,
799
+ targetFingerprint: r,
800
+ diff: n ? Rt(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)"]
801
+ };
802
+ }, Bt = (e) => n.tryPromise({
803
+ try: async () => {
804
+ let t = await import("node:fs/promises"), n = await import("node:path");
805
+ return $e(await t.readFile(n.join(e, B), "utf8"));
806
+ },
807
+ catch: (e) => new F({
808
+ reason: `manifest read/parse failed: ${String(e?.message ?? e)}`,
809
+ path: B
810
+ })
811
+ }), Vt = (t) => n.gen(function* () {
812
+ let i = yield* n.promise(() => import("node:path")), a = yield* Bt(t.bundleDir);
813
+ if (a.formatVersion !== 1) return yield* n.fail(new F({ reason: `unsupported bundle formatVersion ${a.formatVersion} (expected 1)` }));
814
+ if (t.targetSnapshot) {
815
+ let e = { tables: a.tables.map((e) => ({
816
+ name: e.name,
817
+ indexes: [],
818
+ columns: Object.entries(e.columnTypes).map(([e, t]) => ({
819
+ name: e,
820
+ type: t,
821
+ nullable: !0,
822
+ unique: !1,
823
+ hasDefault: !1
824
+ }))
825
+ })) }, r = zt(a.source.schemaFingerprint, t.targetSnapshot, e);
826
+ if (r.drifted) {
827
+ if (!t.force) return yield* n.fail(new Ae({
828
+ bundleFingerprint: r.bundleFingerprint,
829
+ targetFingerprint: r.targetFingerprint,
830
+ diff: r.diff
831
+ }));
832
+ 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("; ")}`);
833
+ }
834
+ }
835
+ if (t.targetDialect && t.targetDialect !== a.source.dialect) {
836
+ let e = Ft(a.tables, a.source.dialect, t.targetDialect).filter((e) => e.severity === "block");
837
+ if (e.length > 0 && !t.allowIncompatible) return yield* n.fail(new Ne({
838
+ sourceDialect: a.source.dialect,
839
+ targetDialect: t.targetDialect,
840
+ blocking: e.map(It)
841
+ }));
842
+ }
843
+ 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);
844
+ if (s === "replace" && a.scope.kind !== "all") return yield* n.fail(new Me({
845
+ mode: s,
846
+ 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.`
847
+ }));
848
+ let p = (e, t, n) => {
849
+ let r = t.name, i = t.primaryKey;
850
+ 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] });
851
+ }, m = (e, t) => n.tryPromise({
852
+ try: e,
853
+ catch: (e) => String(e?.message ?? e)
854
+ }).pipe(n.map(() => !0), n.catchAll((e) => n.sync(() => (t.reason = e, !1)))), h = (e) => {
855
+ let t = Object.entries(e.entry.columnTypes).filter(([t, n]) => n === "reference" && e.row[t] !== null && e.row[t] !== void 0).map(([e]) => e);
856
+ if (t.length !== 0) return {
857
+ ...e.row,
858
+ ...Object.fromEntries(t.map((e) => [e, null]))
859
+ };
860
+ }, g = (e, t) => n.gen(function* () {
861
+ let r = t, i = [], a = !0;
862
+ for (; r.length > 0 && a;) {
863
+ a = !1;
864
+ let t = [];
865
+ for (let n of r) (yield* m(() => p(e, n.entry, n.row), n)) ? a = !0 : t.push(n);
866
+ if (!a && t.length > 0) for (let n = t.length - 1; n >= 0; n--) {
867
+ let r = t[n], o = h(r);
868
+ o !== void 0 && (yield* m(() => p(e, r.entry, o), r)) && (i.push(r), t.splice(n, 1), a = !0);
869
+ }
870
+ r = t;
871
+ }
872
+ for (let t of i) (yield* m(() => e.upsert(t.entry.name, t.row, { conflictColumns: [t.entry.primaryKey] }), t)) || (r = [...r, t]);
873
+ if (r.length > 0) return yield* n.fail(new ke({
874
+ rows: r.slice(0, 20).map((e) => ({
875
+ table: e.entry.name,
876
+ id: String(e.row[e.entry.primaryKey]),
877
+ reason: e.reason
878
+ })),
879
+ totalCount: r.length
880
+ }));
881
+ }), _ = (e, r) => n.gen(function* () {
882
+ if (s === "replace" && !(r && f.truncated)) {
883
+ for (let t of [...a.tables].reverse()) yield* n.tryPromise({
884
+ try: () => e.deleteMany(t.name, { where: d(t.primaryKey) }),
885
+ catch: (e) => new F({ reason: `truncate ${t.name} failed: ${String(e?.message ?? e)}` })
886
+ });
887
+ r && (f.truncated = !0, yield* K(u, f));
888
+ }
889
+ let l = [], h = [], _ = a.tables.length;
890
+ for (let s = 0; s < a.tables.length; s++) {
891
+ let d = a.tables[s];
892
+ if (r && d.name in f.tables) {
893
+ W(t.onProgress, {
894
+ phase: "import",
895
+ table: d.name,
896
+ index: s,
897
+ tableCount: _,
898
+ event: "done",
899
+ rowsDone: f.tables[d.name].rowCount,
900
+ total: d.rowCount
901
+ });
902
+ continue;
903
+ }
904
+ let g = i.join(t.bundleDir, d.file);
905
+ W(t.onProgress, {
906
+ phase: "import",
907
+ table: d.name,
908
+ index: s,
909
+ tableCount: _,
910
+ event: "start",
911
+ rowsDone: 0,
912
+ total: d.rowCount
913
+ });
914
+ let v = l.length, y = n.gen(function* () {
915
+ let { createHash: t } = yield* n.promise(() => import("node:crypto")), r = t("sha256"), i = 0, o = S("bundle", () => E(g).pipe(Ke(a.compression))).pipe(c.tap((e) => n.sync(() => r.update(e))));
916
+ return yield* c.runForEach(Ct(o, d.name, d.columnTypes), (t) => {
917
+ i++;
918
+ let r = {
919
+ entry: d,
920
+ row: t,
921
+ reason: ""
922
+ };
923
+ return m(() => p(e, d, t), r).pipe(n.map((e) => {
924
+ e || l.push(r);
925
+ }));
926
+ }), {
927
+ rowCount: i,
928
+ checksum: r.digest("hex")
929
+ };
930
+ }), { rowCount: b, checksum: x } = yield* st("import", d.name, s, _, (e) => e.rowCount, y);
931
+ if (o) {
932
+ if (x !== d.checksum) return yield* n.fail(new I({
933
+ what: `table ${d.name} checksum`,
934
+ expected: d.checksum,
935
+ actual: x
936
+ }));
937
+ if (b !== d.rowCount) return yield* n.fail(new I({
938
+ what: `table ${d.name} rowCount`,
939
+ expected: String(d.rowCount),
940
+ actual: String(b)
941
+ }));
942
+ }
943
+ W(t.onProgress, {
944
+ phase: "import",
945
+ table: d.name,
946
+ index: s,
947
+ tableCount: _,
948
+ event: "done",
949
+ rowsDone: b,
950
+ total: d.rowCount
951
+ }), r && (l.length > v ? h.push({
952
+ name: d.name,
953
+ rowCount: b
954
+ }) : (f.tables[d.name] = {
955
+ rowCount: b,
956
+ checksum: d.checksum
957
+ }, yield* K(u, f)));
958
+ }
959
+ if (l.length > 0 && (yield* g(e, l)), r && h.length > 0) {
960
+ for (let e of h) {
961
+ let t = a.tables.find((t) => t.name === e.name);
962
+ f.tables[e.name] = {
963
+ rowCount: e.rowCount,
964
+ checksum: t.checksum
965
+ };
966
+ }
967
+ yield* K(u, f);
968
+ }
969
+ });
970
+ if (t.atomic ? yield* n.tryPromise({
971
+ try: () => t.store.transactional(async (t) => {
972
+ let i = await n.runPromiseExit(_(t, !1));
973
+ if (r.isFailure(i)) throw Error(e.pretty(i.cause));
974
+ }),
975
+ catch: (e) => new F({ reason: `atomic import failed (rolled back): ${String(e?.message ?? e)}` })
976
+ }) : yield* _(t.store, !0), t.assets && a.assets.index && !t.assetsAlreadyRestored) {
977
+ 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)));
978
+ yield* c.runForEach(s, (t) => t.key in f.assets ? n.void : Ve(e, r, t).pipe(n.andThen(n.sync(() => {
979
+ f.assets[t.key] = !0;
980
+ })), n.andThen(K(u, f))));
981
+ }
982
+ return a;
983
+ }), Ht = (e) => e, Ut = (e) => e.allowLive || e.liveInstance === null ? { refuse: !1 } : {
984
+ refuse: !0,
985
+ message: `refusing to write into a target with a LIVE instance (${e.liveInstance}). 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).`
986
+ }, J = Buffer.from("VBUNDLE2"), Wt = 0, Gt = 1, Kt = 2, qt = 32, Jt = async (e) => {
987
+ let t = [], n = async (r) => {
988
+ let i;
989
+ try {
990
+ i = await oe(D(e, r), { withFileTypes: !0 });
991
+ } catch {
992
+ return;
993
+ }
994
+ for (let e of i) {
995
+ let i = r ? `${r}/${e.name}` : e.name;
996
+ e.isDirectory() ? await n(i) : e.isFile() && t.push(i);
997
+ }
998
+ };
999
+ return await n(""), t.sort();
1000
+ }, Yt = (e, t) => {
1001
+ let n = Buffer.from(e, "utf8"), r = Buffer.alloc(5 + n.length + 8);
1002
+ return r.writeUInt8(Gt, 0), r.writeUInt32BE(n.length, 1), n.copy(r, 5), r.writeBigUInt64BE(BigInt(t), 5 + n.length), r;
1003
+ }, Xt = (e, t, n) => {
1004
+ let r = Buffer.from(e, "utf8"), i = Buffer.from(t, "utf8"), a = Buffer.alloc(5 + r.length + 2 + i.length + 8), o = 0;
1005
+ return a.writeUInt8(Kt, 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;
1006
+ };
1007
+ async function* Zt(e) {
1008
+ yield new Uint8Array(J);
1009
+ for (let t of await Jt(e.dir)) {
1010
+ let n = D(e.dir, t), r = await se(n);
1011
+ if (yield new Uint8Array(Yt(t, r.size)), r.size > 0) for await (let e of E(n)) yield new Uint8Array(e);
1012
+ }
1013
+ if (e.blobs) for await (let t of e.blobs.list()) {
1014
+ yield new Uint8Array(Xt(t.key, t.contentType, t.size));
1015
+ let n = _("sha256"), r = 0;
1016
+ for await (let i of e.blobs.open(t.key)) {
1017
+ let e = Buffer.from(i);
1018
+ n.update(e), r += e.length, yield new Uint8Array(e);
1019
+ }
1020
+ if (r !== t.size) throw Error(`blob '${t.key}' size mismatch: header ${t.size}, streamed ${r}`);
1021
+ yield new Uint8Array(n.digest());
1022
+ }
1023
+ yield new Uint8Array(Buffer.from([Wt]));
1024
+ }
1025
+ var Qt = (e, t) => new Promise((n, r) => e.write(t, (e) => e ? r(e) : n())), $t = (e) => new Promise((t) => e.end(t)), en = async (e, t) => {
1026
+ let n = le(t.dir);
1027
+ await ae(n, { recursive: !0 });
1028
+ let r = Buffer.alloc(0), i = e[Symbol.asyncIterator](), a = async () => {
1029
+ let { value: e, done: t } = await i.next();
1030
+ return t ? !1 : (r = r.length === 0 ? Buffer.from(e) : Buffer.concat([r, Buffer.from(e)]), !0);
1031
+ }, o = async (e) => {
1032
+ for (; r.length < e;) if (!await a()) throw Error("truncated bundle archive");
1033
+ }, s = (e) => {
1034
+ let t = r.subarray(0, e);
1035
+ return r = r.subarray(e), t;
1036
+ };
1037
+ if (await o(J.length), !s(J.length).equals(J)) throw Error("not a bundle archive (bad magic)");
1038
+ for (;;) {
1039
+ await o(1);
1040
+ let e = s(1).readUInt8(0);
1041
+ if (e === Wt) return;
1042
+ if (e === Gt) {
1043
+ await o(4);
1044
+ let e = s(4).readUInt32BE(0);
1045
+ await o(e);
1046
+ let t = s(e).toString("utf8");
1047
+ await o(8);
1048
+ let i = s(8).readBigUInt64BE(0), a = le(n, t);
1049
+ if (a !== n && !a.startsWith(n + ue)) throw Error(`archive path '${t}' escapes the destination`);
1050
+ await ae(ce(a), { recursive: !0 });
1051
+ let c = ie(a);
1052
+ for (; i > 0n;) {
1053
+ r.length === 0 && await o(1);
1054
+ let e = i < BigInt(r.length) ? Number(i) : r.length;
1055
+ await Qt(c, s(e)), i -= BigInt(e);
1056
+ }
1057
+ await $t(c);
1058
+ } else if (e === Kt) {
1059
+ await o(4);
1060
+ let e = s(4).readUInt32BE(0);
1061
+ await o(e);
1062
+ let n = s(e).toString("utf8");
1063
+ await o(2);
1064
+ let i = s(2).readUInt16BE(0);
1065
+ await o(i);
1066
+ let a = s(i).toString("utf8");
1067
+ await o(8);
1068
+ let c = s(8).readBigUInt64BE(0), l = await t.blobs.has(n), u = _("sha256"), d = new T(), f = l ? Promise.resolve() : t.blobs.write(n, d, {
1069
+ contentType: a,
1070
+ size: Number(c)
1071
+ }), p = c;
1072
+ for (; p > 0n;) {
1073
+ r.length === 0 && await o(1);
1074
+ let e = p < BigInt(r.length) ? Number(p) : r.length, t = s(e);
1075
+ u.update(t), l || await Qt(d, t), p -= BigInt(e);
1076
+ }
1077
+ l ? d.destroy() : await $t(d), await f, await o(qt);
1078
+ let m = s(qt);
1079
+ if (!u.digest().equals(m)) throw Error(`blob '${n}' failed integrity (sha mismatch)`);
1080
+ } else throw Error(`unknown bundle entry kind ${e}`);
1081
+ }
1082
+ }, tn = async (e, t) => {
1083
+ let n = new Set(t), r = /* @__PURE__ */ new Map(), i = Buffer.alloc(0), a = e[Symbol.asyncIterator](), o = async () => {
1084
+ let { value: e, done: t } = await a.next();
1085
+ return t ? !1 : (i = i.length === 0 ? Buffer.from(e) : Buffer.concat([i, Buffer.from(e)]), !0);
1086
+ }, s = async (e) => {
1087
+ for (; i.length < e;) if (!await o()) return !1;
1088
+ return !0;
1089
+ }, c = (e) => {
1090
+ let t = i.subarray(0, e);
1091
+ return i = i.subarray(e), t;
1092
+ }, l = async (e) => {
1093
+ let t = [], n = e;
1094
+ for (; n > 0n;) {
1095
+ if (i.length === 0 && !await s(1)) return null;
1096
+ let e = n < BigInt(i.length) ? Number(n) : i.length;
1097
+ t.push(c(e)), n -= BigInt(e);
1098
+ }
1099
+ return Buffer.concat(t);
1100
+ };
1101
+ if (!await s(J.length) || !c(J.length).equals(J)) throw Error("not a bundle archive (bad magic)");
1102
+ for (; await s(1);) {
1103
+ let e = c(1).readUInt8(0);
1104
+ if (e === Wt || e === Kt) break;
1105
+ if (e !== Gt) throw Error(`unknown bundle entry kind ${e}`);
1106
+ if (!await s(4)) break;
1107
+ let t = c(4).readUInt32BE(0);
1108
+ if (!await s(t)) break;
1109
+ let i = c(t).toString("utf8");
1110
+ if (!await s(8)) break;
1111
+ let a = await l(c(8).readBigUInt64BE(0));
1112
+ if (a === null || n.has(i) && (r.set(i, a), n.delete(i), n.size === 0)) break;
1113
+ }
1114
+ return r;
1115
+ }, nn = (e, t) => en(e, {
1116
+ dir: t,
1117
+ blobs: rn(t)
1118
+ }), rn = (e) => {
1119
+ let t = /* @__PURE__ */ new Set();
1120
+ return {
1121
+ has: async (e) => t.has(e),
1122
+ write: async (n, r, i) => {
1123
+ let a = await import("node:fs/promises"), { pipeline: o } = await import("node:stream/promises"), { Transform: s } = await import("node:stream"), c = D(e, "assets");
1124
+ await ae(c, { recursive: !0 });
1125
+ let l = _("sha256"), u = 0, d = new s({ transform(e, t, n) {
1126
+ l.update(e), u += e.length, n(null, e);
1127
+ } }), f = D(c, `.tmp-${Date.now()}-${t.size}`);
1128
+ await o(r, d, ie(f));
1129
+ let p = l.digest("hex");
1130
+ await a.rename(f, D(c, p)), await a.appendFile(D(c, "index.ndjson"), `${JSON.stringify({
1131
+ key: n,
1132
+ sha256: p,
1133
+ size: u,
1134
+ contentType: i.contentType
1135
+ })}\n`), t.add(n);
1136
+ }
1137
+ };
1138
+ }, an = de(b), on = Buffer.from("VENC1\0\0\0"), sn = 32, cn = 16, ln = 7, Y = 16, X = 256 * 1024, Z = {
1139
+ N: 32768,
1140
+ r: 8,
1141
+ p: 1
1142
+ }, un = 128 * 1024 * 1024, Q = 43, dn = (e, t, n) => {
1143
+ let r = Buffer.alloc(12);
1144
+ return e.copy(r, 0, 0, ln), r.writeUInt32BE(t >>> 0, ln), r.writeUInt8(+!!n, 11), r;
1145
+ };
1146
+ async function* fn(e, t) {
1147
+ if (!t) throw Error("encryptStream: a non-empty passphrase is required");
1148
+ let n = y(cn), r = y(ln), i = await an(t, n, sn, {
1149
+ ...Z,
1150
+ maxmem: un
1151
+ }), a = Buffer.alloc(Q);
1152
+ on.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);
1153
+ let o = 0, s = (e, t) => {
1154
+ let n = h("aes-256-gcm", i, dn(r, o, t));
1155
+ o === 0 && n.setAAD(a);
1156
+ let s = Buffer.concat([n.update(e), n.final()]), c = n.getAuthTag();
1157
+ o++;
1158
+ let l = Buffer.alloc(5 + s.length + Y);
1159
+ return l.writeUInt8(+!!t, 0), l.writeUInt32BE(s.length + Y, 1), s.copy(l, 5), c.copy(l, 5 + s.length), new Uint8Array(l);
1160
+ }, c = Buffer.alloc(0);
1161
+ for await (let t of e) for (c = c.length === 0 ? Buffer.from(t) : Buffer.concat([c, Buffer.from(t)]); c.length > X;) yield s(c.subarray(0, X), !1), c = c.subarray(X);
1162
+ yield s(c, !0);
1163
+ }
1164
+ async function* pn(e, t) {
1165
+ if (!t) throw Error("decryptStream: a non-empty passphrase is required");
1166
+ let n = e[Symbol.asyncIterator](), r = Buffer.alloc(0), i = !1, a = async () => {
1167
+ let { value: e, done: t } = await n.next();
1168
+ return t ? (i = !0, !1) : (r = r.length === 0 ? Buffer.from(e) : Buffer.concat([r, Buffer.from(e)]), !0);
1169
+ }, o = async (e) => {
1170
+ for (; r.length < e && !i && await a(););
1171
+ return r.length >= e;
1172
+ };
1173
+ if (!await o(Q)) throw Error("encrypted bundle truncated (no header)");
1174
+ let s = r.subarray(0, Q);
1175
+ if (!s.subarray(0, 8).equals(on)) throw Error("not an encrypted bundle (bad magic / wrong passphrase target)");
1176
+ 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 an(t, d, sn, {
1177
+ N: c,
1178
+ r: l,
1179
+ p: u,
1180
+ maxmem: un
1181
+ });
1182
+ r = r.subarray(Q);
1183
+ let m = 0, h = !1;
1184
+ for (;;) {
1185
+ if (!await o(5)) {
1186
+ if (r.length === 0 && h) return;
1187
+ throw Error("encrypted bundle truncated (no authenticated final frame)");
1188
+ }
1189
+ if (h) throw Error("encrypted bundle has trailing data after the final frame");
1190
+ let e = r.readUInt8(0) === 1, t = r.readUInt32BE(1);
1191
+ if (t < Y) throw Error("encrypted bundle corrupt (short frame)");
1192
+ if (!await o(5 + t)) throw Error("encrypted bundle truncated (frame body)");
1193
+ let n = r.subarray(5, 5 + t - Y), i = r.subarray(5 + t - Y, 5 + t);
1194
+ r = r.subarray(5 + t);
1195
+ let a = g("aes-256-gcm", p, dn(f, m, e));
1196
+ m === 0 && a.setAAD(s), a.setAuthTag(i);
1197
+ let c = Buffer.concat([a.update(n), a.final()]);
1198
+ m++, e && (h = !0), c.length > 0 && (yield new Uint8Array(c));
1199
+ }
1200
+ }
1201
+ //#endregion
1202
+ //#region src/blobStorage.ts
1203
+ var mn = (e, t) => ({
1204
+ list: () => {
1205
+ let e = t();
1206
+ return { async *[Symbol.asyncIterator]() {
1207
+ let t = await n.runPromise(c.runCollect(e));
1208
+ for (let e of t) yield {
1209
+ key: e.key,
1210
+ contentType: e.contentType,
1211
+ size: e.size
1212
+ };
1213
+ } };
1214
+ },
1215
+ open: (t) => ({ async *[Symbol.asyncIterator]() {
1216
+ let r = await te((await n.runPromise(C(e, t))).stream);
1217
+ for await (let e of r) yield e instanceof Uint8Array ? e : new Uint8Array(e);
1218
+ } })
1219
+ }), hn = (e, t) => mn(e, () => p(t, {
1220
+ table: x,
1221
+ chunkSize: 500
1222
+ }).pipe(c.map((e) => ({
1223
+ key: String(e.key),
1224
+ contentType: String(e.contentType ?? "application/octet-stream"),
1225
+ size: Number(e.size ?? 0)
1226
+ })))), gn = (e) => ({
1227
+ has: (t) => n.runPromise(e.head(t).pipe(n.map((e) => e !== null))),
1228
+ write: async (t, r, i) => {
1229
+ let a = S("storage", () => ne.from(r));
1230
+ await n.runPromise(ee(e, t, a, {
1231
+ contentType: i.contentType,
1232
+ totalSize: i.size
1233
+ }));
1234
+ }
1235
+ }), _n = (e) => {
1236
+ switch (e) {
1237
+ case "postgres": return "db.dump";
1238
+ case "mysql":
1239
+ case "mariadb": return "db.sql";
1240
+ case "sqlite":
1241
+ case "turso": return "db.sqlite";
1242
+ case "mssql": return "db.bacpac";
1243
+ default: return "db.dump";
1244
+ }
1245
+ }, vn = (e) => e.filename ?? e.database ?? ((e.url ?? "").replace(/^file:/, "") || "app.sqlite"), $ = (e) => {
1246
+ if (e.host || e.database) return {
1247
+ host: e.host ?? "localhost",
1248
+ port: e.port ?? 3306,
1249
+ username: e.username ?? "root",
1250
+ password: e.password ?? "",
1251
+ database: e.database ?? ""
1252
+ };
1253
+ let t = new URL(e.url ?? "");
1254
+ return {
1255
+ host: t.hostname || "localhost",
1256
+ port: t.port ? Number(t.port) : 3306,
1257
+ username: decodeURIComponent(t.username) || "root",
1258
+ password: decodeURIComponent(t.password) || "",
1259
+ database: t.pathname.replace(/^\//, "") || ""
1260
+ };
1261
+ }, yn = (e) => `Server=${e.host},${e.port};Database=${e.database};User ID=${e.username};Password=${e.password};TrustServerCertificate=True`, bn = (e, t, n) => {
1262
+ switch (e) {
1263
+ case "postgres": {
1264
+ if (t.url) return {
1265
+ kind: "spawn",
1266
+ tool: "pg_dump",
1267
+ args: [
1268
+ "--format=custom",
1269
+ "--no-owner",
1270
+ "--no-privileges",
1271
+ "--dbname",
1272
+ t.url,
1273
+ "--file",
1274
+ n
1275
+ ],
1276
+ env: {}
1277
+ };
1278
+ let e = $({
1279
+ ...t,
1280
+ port: t.port ?? 5432
1281
+ });
1282
+ return {
1283
+ kind: "spawn",
1284
+ tool: "pg_dump",
1285
+ args: [
1286
+ "--format=custom",
1287
+ "--no-owner",
1288
+ "--no-privileges",
1289
+ "-h",
1290
+ e.host,
1291
+ "-p",
1292
+ String(e.port),
1293
+ "-U",
1294
+ e.username,
1295
+ "-d",
1296
+ e.database,
1297
+ "--file",
1298
+ n
1299
+ ],
1300
+ env: { PGPASSWORD: e.password }
1301
+ };
1302
+ }
1303
+ case "mysql":
1304
+ case "mariadb": {
1305
+ let e = $(t);
1306
+ return {
1307
+ kind: "spawn",
1308
+ tool: "mysqldump",
1309
+ args: [
1310
+ "--single-transaction",
1311
+ "--routines",
1312
+ "--triggers",
1313
+ "--no-tablespaces",
1314
+ "-h",
1315
+ e.host,
1316
+ "-P",
1317
+ String(e.port),
1318
+ "-u",
1319
+ e.username,
1320
+ e.database
1321
+ ],
1322
+ env: { MYSQL_PWD: e.password },
1323
+ stdoutFile: n
1324
+ };
1325
+ }
1326
+ case "sqlite":
1327
+ case "turso": return {
1328
+ kind: "copy",
1329
+ from: vn(t),
1330
+ to: n
1331
+ };
1332
+ case "mssql": return {
1333
+ kind: "spawn",
1334
+ tool: "sqlpackage",
1335
+ args: [
1336
+ "/Action:Export",
1337
+ `/SourceConnectionString:${yn($({
1338
+ ...t,
1339
+ port: t.port ?? 1433
1340
+ }))}`,
1341
+ `/TargetFile:${n}`
1342
+ ],
1343
+ env: {}
1344
+ };
1345
+ default: throw new L({
1346
+ tool: "backup",
1347
+ reason: `no native backup for dialect '${e}'`
1348
+ });
1349
+ }
1350
+ }, xn = (e, t, n) => {
1351
+ switch (e) {
1352
+ case "postgres": {
1353
+ if (t.url) return {
1354
+ kind: "spawn",
1355
+ tool: "pg_restore",
1356
+ args: [
1357
+ "--clean",
1358
+ "--if-exists",
1359
+ "--no-owner",
1360
+ "--dbname",
1361
+ t.url,
1362
+ n
1363
+ ],
1364
+ env: {}
1365
+ };
1366
+ let e = $({
1367
+ ...t,
1368
+ port: t.port ?? 5432
1369
+ });
1370
+ return {
1371
+ kind: "spawn",
1372
+ tool: "pg_restore",
1373
+ args: [
1374
+ "--clean",
1375
+ "--if-exists",
1376
+ "--no-owner",
1377
+ "-h",
1378
+ e.host,
1379
+ "-p",
1380
+ String(e.port),
1381
+ "-U",
1382
+ e.username,
1383
+ "-d",
1384
+ e.database,
1385
+ n
1386
+ ],
1387
+ env: { PGPASSWORD: e.password }
1388
+ };
1389
+ }
1390
+ case "mysql":
1391
+ case "mariadb": {
1392
+ let e = $(t);
1393
+ return {
1394
+ kind: "spawn",
1395
+ tool: "mysql",
1396
+ args: [
1397
+ "-h",
1398
+ e.host,
1399
+ "-P",
1400
+ String(e.port),
1401
+ "-u",
1402
+ e.username,
1403
+ e.database
1404
+ ],
1405
+ env: { MYSQL_PWD: e.password },
1406
+ stdinFile: n
1407
+ };
1408
+ }
1409
+ case "sqlite":
1410
+ case "turso": return {
1411
+ kind: "copy",
1412
+ from: n,
1413
+ to: vn(t)
1414
+ };
1415
+ case "mssql": return {
1416
+ kind: "spawn",
1417
+ tool: "sqlpackage",
1418
+ args: [
1419
+ "/Action:Import",
1420
+ `/TargetConnectionString:${yn($({
1421
+ ...t,
1422
+ port: t.port ?? 1433
1423
+ }))}`,
1424
+ `/SourceFile:${n}`
1425
+ ],
1426
+ env: {}
1427
+ };
1428
+ default: throw new L({
1429
+ tool: "restore",
1430
+ reason: `no native restore for dialect '${e}'`
1431
+ });
1432
+ }
1433
+ }, Sn = (e) => e.kind === "copy" ? n.async((t) => {
1434
+ re(e.from, e.to, (r) => t(r ? n.fail(new L({
1435
+ tool: "copy",
1436
+ reason: `copy ${e.from} → ${e.to}: ${r.message}`
1437
+ })) : n.void));
1438
+ }) : n.async((t) => {
1439
+ let r = fe(e.tool, [...e.args], {
1440
+ env: {
1441
+ ...process.env,
1442
+ ...e.env
1443
+ },
1444
+ stdio: [
1445
+ "pipe",
1446
+ e.stdoutFile ? "pipe" : "inherit",
1447
+ "pipe"
1448
+ ]
1449
+ }), i = "";
1450
+ r.stderr?.on("data", (e) => {
1451
+ i += String(e);
1452
+ }), e.stdoutFile && r.stdout && r.stdout.pipe(ie(e.stdoutFile)), e.stdinFile && r.stdin && E(e.stdinFile).pipe(r.stdin), r.on("error", (r) => t(n.fail(new L({
1453
+ tool: e.tool,
1454
+ reason: `failed to launch (is '${e.tool}' installed + on PATH?): ${r.message}`
1455
+ })))), r.on("close", (r) => t(r === 0 ? n.void : n.fail(new L({
1456
+ tool: e.tool,
1457
+ reason: `exited with code ${r}`,
1458
+ stderr: i.slice(-2e3)
1459
+ }))));
1460
+ }), Cn = (e) => typeof e == "object" && e ? "fake" in e ? `fake:${e.fake}` : "custom" : String(e), wn = (e) => n.gen(function* () {
1461
+ let t = yield* Le(e.scope ?? { kind: "all" }, e.snapshot, {
1462
+ store: e.store,
1463
+ ...e.tenantTables ? { tenantTables: e.tenantTables } : {}
1464
+ }), r = q(t.tables, e.snapshot), i = e.classification ?? O(e.snapshot), a = e.sampleSize ?? 20, o = N(r.map((t) => ({
1465
+ name: t,
1466
+ columns: (e.snapshot.tables.find((e) => e.name === t)?.columns ?? []).map((e) => ({
1467
+ name: e.name,
1468
+ type: e.type
1469
+ }))
1470
+ })), i, e.masking), s = [], l = [];
1471
+ for (let i of r) {
1472
+ let r = t.predicateFor(i), u = yield* p(e.store, {
1473
+ table: i,
1474
+ chunkSize: a,
1475
+ ...r === void 0 ? {} : { where: r }
1476
+ }).pipe(c.take(a), c.runCollect, n.map((e) => [...e])), d = u.map((t) => P(t, i, o.actions, e.masking.seed));
1477
+ l.push(...Te(d, i, o.actions));
1478
+ let f = u[0], m = d[0], h = [];
1479
+ if (f && m) for (let [e, t] of Object.entries(o.actions)) {
1480
+ if (!e.startsWith(`${i}.`) || t === "keep") continue;
1481
+ let n = e.slice(i.length + 1);
1482
+ h.push({
1483
+ column: n,
1484
+ action: Cn(t),
1485
+ before: f[n],
1486
+ after: m[n]
1487
+ });
1488
+ }
1489
+ s.push({
1490
+ table: i,
1491
+ samples: h
1492
+ });
1493
+ }
1494
+ return {
1495
+ tables: s,
1496
+ leaks: l,
1497
+ unclassified: o.unclassified
1498
+ };
1499
+ });
1500
+ //#endregion
1501
+ export { H as ASSETS_DIR, U as ASSET_INDEX_FILE, F as BundleError, Ee as CodecError, De as CompressionError, Ne as CrossDialectError, V as DATA_DIR, me as DEFAULT_CLASS_ACTIONS, ke as DanglingReferenceError, qe as FORMAT_VERSION, Me as ImportModeError, I as IntegrityError, tt as LEDGER_FILE, B as MANIFEST_FILE, je as MaskingError, L as NativeToolError, Ae as SchemaDriftError, Oe as ScopeError, Ce as applyAction, Ut as assessLiveImport, ut as assetDone, _n as backupArtifactName, bn as backupCommand, Mt as canonicalType, Ft as checkPortability, zt as checkSchemaDrift, O as classificationFromSnapshot, We as compressionExt, Fe as computeSubsetIds, $e as decodeManifest, bt as decodeRow, vt as decodeValue, pn as decryptStream, Ht as defineDataProfile, Rt as diffSnapshots, rn as dirBlobSink, ct as emptyLedger, Qe as encodeManifest, yt as encodeRow, gt as encodeValue, fn as encryptStream, It as formatIssue, He as hasZstd, Ge as makeCompressor, Ke as makeDecompressor, P as maskRow, Ct as ndjsonToRows, Zt as packBundle, tn as peekBundle, Ue as pickCompression, N as planMasking, wn as previewMasking, G as readLedger, he as resolveAction, Le as resolveScope, Ve as restoreAssetFromCas, xn as restoreCommand, St as rowsToNdjson, jt as runExport, Vt as runImport, Sn as runNativeStep, Te as scanForLeaks, ze as storageAssetSink, Re as storageAssetSource, gn as storageBlobSink, mn as storageBlobSource, hn as storageRefsBlobSource, Ie as subsetToScope, lt as tableDone, q as topoSortTables, en as unpackBundle, nn as unpackBundleToDir, Be as writeAssetToCas, K as writeLedger };