@voltro/data-transfer 0.81.0 → 0.82.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +1520 -6
- package/THIRD-PARTY-NOTICES.md +1 -1
- package/dist/index.d.ts +52 -4
- package/dist/index.js +615 -535
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
import { Cause as e, Data as t, Effect as n, Exit as r, Metric as i, MetricBoundaries as a, Runtime as o, Schedule as s, Schema as c, Stream as l } from "effect";
|
|
2
|
-
import { DATA_TRANSFERS_TABLE as u, REPLACE_IN_PROGRESS_TABLE as d, STAGING_TABLE_PREFIX as f, _voltroDataTransfersTable as p, classifyConstraintViolation as m, derivedRowId as h, ensureTableRegistered as g, eq as _, extractDbCause as v, getTable as y, inSet as b, isNotNull as x, or as S, recordsTable as
|
|
3
|
-
import { fingerprintSchema as
|
|
4
|
-
import { createCipheriv as
|
|
5
|
-
import { copyFile as
|
|
6
|
-
import { STORAGE_REFS_TABLE as
|
|
7
|
-
import * as
|
|
8
|
-
import { PassThrough as
|
|
9
|
-
import { SqlClient as
|
|
10
|
-
import { mkdir as
|
|
11
|
-
import { basename as
|
|
12
|
-
import { promisify as
|
|
13
|
-
import { spawn as
|
|
2
|
+
import { DATA_TRANSFERS_TABLE as u, REPLACE_IN_PROGRESS_TABLE as d, STAGING_TABLE_PREFIX as f, _voltroDataTransfersTable as p, classifyConstraintViolation as m, derivedRowId as h, ensureTableRegistered as g, eq as _, extractDbCause as v, getTable as y, inSet as b, isNotNull as x, or as S, recordsTable as ee, registerTable as te, streamTable as C, suspendWriteRecorders as ne, suspendWriteRecordersEffect as re, unregisterTable as ie } from "@voltro/database";
|
|
3
|
+
import { fingerprintSchema as w } from "@voltro/database/sql";
|
|
4
|
+
import { createCipheriv as ae, createDecipheriv as oe, createHash as T, createHmac as se, randomBytes as ce, randomUUID as le, scrypt as ue } from "node:crypto";
|
|
5
|
+
import { copyFile as de, createReadStream as fe, createWriteStream as pe, existsSync as E, rename as D, statSync as me, unlinkSync as he } from "node:fs";
|
|
6
|
+
import { STORAGE_REFS_TABLE as O, fromNodeReadable as ge, getObjectStream as _e, putObjectStream as k, toNodeReadable as A } from "@voltro/plugin-storage";
|
|
7
|
+
import * as j from "node:zlib";
|
|
8
|
+
import { PassThrough as M, Readable as ve } from "node:stream";
|
|
9
|
+
import { SqlClient as N } from "@effect/sql";
|
|
10
|
+
import { mkdir as P, readdir as ye, stat as be } from "node:fs/promises";
|
|
11
|
+
import { basename as F, delimiter as xe, dirname as Se, join as I, resolve as L, sep as Ce } from "node:path";
|
|
12
|
+
import { promisify as we } from "node:util";
|
|
13
|
+
import { spawn as Te } from "node:child_process";
|
|
14
14
|
//#region src/consistency.ts
|
|
15
|
-
var
|
|
15
|
+
var Ee = (e) => {
|
|
16
16
|
switch (e) {
|
|
17
17
|
case "postgres": return ["SET TRANSACTION ISOLATION LEVEL REPEATABLE READ"];
|
|
18
18
|
case "mysql":
|
|
@@ -22,7 +22,7 @@ var Ce = (e) => {
|
|
|
22
22
|
case "turso": return [];
|
|
23
23
|
default: return [];
|
|
24
24
|
}
|
|
25
|
-
},
|
|
25
|
+
}, De = {
|
|
26
26
|
email: { fake: "email" },
|
|
27
27
|
fullName: { fake: "fullName" },
|
|
28
28
|
firstName: { fake: "firstName" },
|
|
@@ -37,7 +37,7 @@ var Ce = (e) => {
|
|
|
37
37
|
date: "dateShift",
|
|
38
38
|
secret: "null",
|
|
39
39
|
freeText: "redact"
|
|
40
|
-
},
|
|
40
|
+
}, Oe = (e) => {
|
|
41
41
|
let t = {};
|
|
42
42
|
for (let n of e.tables) {
|
|
43
43
|
let e = {};
|
|
@@ -49,15 +49,15 @@ var Ce = (e) => {
|
|
|
49
49
|
t[n.name] = e;
|
|
50
50
|
}
|
|
51
51
|
return t;
|
|
52
|
-
},
|
|
52
|
+
}, ke = (e, t, n, r) => {
|
|
53
53
|
let i = r.columns?.[`${e}.${t}`];
|
|
54
54
|
if (i) return i;
|
|
55
55
|
if (n?.sensitive) {
|
|
56
56
|
let e = n.sensitive.class;
|
|
57
|
-
return r.classes?.[e] ??
|
|
57
|
+
return r.classes?.[e] ?? De[e] ?? "redact";
|
|
58
58
|
}
|
|
59
59
|
return n?.safe ? r.onSafe ?? "keep" : n?.columnType === "id" || n?.columnType === "reference" ? "keep" : r.onUnclassified ?? "error";
|
|
60
|
-
},
|
|
60
|
+
}, Ae = (e, t) => se("sha256", e).update(t == null ? "∅" : String(t)).digest(), R = (e, t) => e.readUInt32BE(t * 4 % (e.length - 4)), je = [
|
|
61
61
|
"Ada",
|
|
62
62
|
"Alan",
|
|
63
63
|
"Grace",
|
|
@@ -70,7 +70,7 @@ var Ce = (e) => {
|
|
|
70
70
|
"Guido",
|
|
71
71
|
"Margaret",
|
|
72
72
|
"Bjarne"
|
|
73
|
-
],
|
|
73
|
+
], Me = [
|
|
74
74
|
"Lovelace",
|
|
75
75
|
"Turing",
|
|
76
76
|
"Hopper",
|
|
@@ -83,7 +83,7 @@ var Ce = (e) => {
|
|
|
83
83
|
"Rossum",
|
|
84
84
|
"Hamilton",
|
|
85
85
|
"Stroustrup"
|
|
86
|
-
],
|
|
86
|
+
], Ne = [
|
|
87
87
|
"Maple",
|
|
88
88
|
"Oak",
|
|
89
89
|
"Cedar",
|
|
@@ -92,7 +92,7 @@ var Ce = (e) => {
|
|
|
92
92
|
"Birch",
|
|
93
93
|
"Willow",
|
|
94
94
|
"Ash"
|
|
95
|
-
],
|
|
95
|
+
], Pe = [
|
|
96
96
|
"Initech",
|
|
97
97
|
"Hooli",
|
|
98
98
|
"Umbrella",
|
|
@@ -101,23 +101,23 @@ var Ce = (e) => {
|
|
|
101
101
|
"Soylent",
|
|
102
102
|
"Stark",
|
|
103
103
|
"Wayne"
|
|
104
|
-
],
|
|
105
|
-
let r =
|
|
104
|
+
], z = (e, t, n) => e[R(t, n) % e.length], Fe = (e, t, n) => {
|
|
105
|
+
let r = Ae(n, `${e}:${String(t)}`), i = R(r, 1) % 1e4;
|
|
106
106
|
switch (e) {
|
|
107
|
-
case "email": return `${
|
|
108
|
-
case "fullName": return `${
|
|
109
|
-
case "firstName": return
|
|
110
|
-
case "lastName": return
|
|
111
|
-
case "username": return `${
|
|
112
|
-
case "phone": return `+1${String(
|
|
113
|
-
case "address": return `${
|
|
114
|
-
case "company": return
|
|
107
|
+
case "email": return `${z(je, r, 0).toLowerCase()}.${z(Me, r, 2).toLowerCase()}${i}@example.com`;
|
|
108
|
+
case "fullName": return `${z(je, r, 0)} ${z(Me, r, 1)}`;
|
|
109
|
+
case "firstName": return z(je, r, 0);
|
|
110
|
+
case "lastName": return z(Me, r, 1);
|
|
111
|
+
case "username": return `${z(je, r, 0).toLowerCase()}${i}`;
|
|
112
|
+
case "phone": return `+1${String(R(r, 0) % 1e10).padStart(10, "0")}`;
|
|
113
|
+
case "address": return `${R(r, 0) % 9899 + 100} ${z(Ne, r, 1)} St`;
|
|
114
|
+
case "company": return z(Pe, r, 0);
|
|
115
115
|
case "url": return `https://example.com/${r.toString("hex").slice(0, 12)}`;
|
|
116
|
-
case "ip": return `${
|
|
117
|
-
case "creditCard": return
|
|
116
|
+
case "ip": return `${R(r, 0) % 256}.${R(r, 1) % 256}.${R(r, 2) % 256}.${R(r, 3) % 254 + 1}`;
|
|
117
|
+
case "creditCard": return Ie(`4${r.toString("hex").replace(/\D/g, "").padEnd(14, "0").slice(0, 14)}`);
|
|
118
118
|
default: return `${e}_${r.toString("hex").slice(0, 8)}`;
|
|
119
119
|
}
|
|
120
|
-
},
|
|
120
|
+
}, Ie = (e) => {
|
|
121
121
|
let t = e.slice(0, 15).split("").map(Number), n = 0;
|
|
122
122
|
t.forEach((e, t) => {
|
|
123
123
|
let r = e;
|
|
@@ -125,29 +125,29 @@ var Ce = (e) => {
|
|
|
125
125
|
});
|
|
126
126
|
let r = (10 - n % 10) % 10;
|
|
127
127
|
return e.slice(0, 15) + String(r);
|
|
128
|
-
},
|
|
128
|
+
}, Le = 864e5, Re = (e, t) => {
|
|
129
129
|
let n = e instanceof Date ? e.getTime() : Date.parse(String(e));
|
|
130
130
|
if (Number.isNaN(n)) return e;
|
|
131
|
-
let r =
|
|
131
|
+
let r = R(Ae(t, "date-shift-offset"), 0) % 730 - 365, i = new Date(n + r * Le);
|
|
132
132
|
return e instanceof Date ? i : i.toISOString();
|
|
133
|
-
},
|
|
133
|
+
}, B = (e, t) => {
|
|
134
134
|
if (t.value === null || t.value === void 0) return null;
|
|
135
135
|
if (e === "error") throw Error(`masking: unresolved 'error' action for ${t.table}.${t.column}`);
|
|
136
136
|
if (e === "keep") return t.value;
|
|
137
137
|
if (e === "null") return null;
|
|
138
138
|
if (e === "redact") return t.columnType === "text" || typeof t.value == "string" ? "[redacted]" : null;
|
|
139
|
-
if (e === "hash") return
|
|
140
|
-
if (e === "dateShift") return
|
|
141
|
-
if (typeof e == "object" && "fake" in e) return
|
|
139
|
+
if (e === "hash") return Ae(t.seed, t.value).toString("hex").slice(0, 16);
|
|
140
|
+
if (e === "dateShift") return Re(t.value, t.seed);
|
|
141
|
+
if (typeof e == "object" && "fake" in e) return Fe(e.fake, t.value, t.seed);
|
|
142
142
|
if (typeof e == "object" && "custom" in e) return e.custom(t);
|
|
143
|
-
if (typeof e == "object" && "json" in e) return
|
|
143
|
+
if (typeof e == "object" && "json" in e) return ze(e, t);
|
|
144
144
|
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 } | { json: { fields, rest? } }.`);
|
|
145
|
-
},
|
|
146
|
-
let { fields: n, rest: r = "redact" } = e.json, i = typeof t.value == "string" ?
|
|
145
|
+
}, ze = (e, t) => {
|
|
146
|
+
let { fields: n, rest: r = "redact" } = e.json, i = typeof t.value == "string" ? Be(t.value) : {
|
|
147
147
|
ok: !0,
|
|
148
148
|
value: t.value
|
|
149
149
|
};
|
|
150
|
-
if (!i.ok) return
|
|
150
|
+
if (!i.ok) return B(r, {
|
|
151
151
|
...t,
|
|
152
152
|
columnType: "text"
|
|
153
153
|
});
|
|
@@ -158,12 +158,12 @@ var Ce = (e) => {
|
|
|
158
158
|
let a = {};
|
|
159
159
|
for (let [o, s] of Object.entries(e)) {
|
|
160
160
|
let e = n[o] ?? r, c = `${i}.${o}`;
|
|
161
|
-
a[o] = typeof e == "object" && "json" in e ?
|
|
161
|
+
a[o] = typeof e == "object" && "json" in e ? ze(e, {
|
|
162
162
|
...t,
|
|
163
163
|
value: s,
|
|
164
164
|
column: c,
|
|
165
165
|
columnType: "json"
|
|
166
|
-
}) :
|
|
166
|
+
}) : B(e, {
|
|
167
167
|
...t,
|
|
168
168
|
value: s,
|
|
169
169
|
column: c,
|
|
@@ -172,7 +172,7 @@ var Ce = (e) => {
|
|
|
172
172
|
}
|
|
173
173
|
return a;
|
|
174
174
|
}
|
|
175
|
-
return
|
|
175
|
+
return B(r, {
|
|
176
176
|
...t,
|
|
177
177
|
value: e,
|
|
178
178
|
column: i,
|
|
@@ -180,7 +180,7 @@ var Ce = (e) => {
|
|
|
180
180
|
});
|
|
181
181
|
}, o = a(i.value, t.column);
|
|
182
182
|
return typeof t.value == "string" ? JSON.stringify(o) : o;
|
|
183
|
-
},
|
|
183
|
+
}, Be = (e) => {
|
|
184
184
|
try {
|
|
185
185
|
return {
|
|
186
186
|
ok: !0,
|
|
@@ -189,7 +189,7 @@ var Ce = (e) => {
|
|
|
189
189
|
} catch {
|
|
190
190
|
return { ok: !1 };
|
|
191
191
|
}
|
|
192
|
-
},
|
|
192
|
+
}, Ve = (e) => {
|
|
193
193
|
if (typeof e == "string") return e === "keep" || e === "null" || e === "redact" || e === "hash" || e === "dateShift" || e === "error";
|
|
194
194
|
if (typeof e != "object" || !e) return !1;
|
|
195
195
|
if ("fake" in e) return typeof e.fake == "string";
|
|
@@ -198,18 +198,18 @@ var Ce = (e) => {
|
|
|
198
198
|
let t = e.json;
|
|
199
199
|
if (typeof t != "object" || !t) return !1;
|
|
200
200
|
let { fields: n, rest: r } = t;
|
|
201
|
-
return typeof n != "object" || !n ? !1 : Object.values(n).every(
|
|
201
|
+
return typeof n != "object" || !n ? !1 : Object.values(n).every(Ve) && (r === void 0 || Ve(r));
|
|
202
202
|
}
|
|
203
203
|
return !1;
|
|
204
|
-
},
|
|
204
|
+
}, He = (e, t, n) => {
|
|
205
205
|
let r = {}, i = [], a = [];
|
|
206
206
|
for (let o of e) for (let e of o.columns) {
|
|
207
|
-
let s = `${o.name}.${e.name}`, c =
|
|
207
|
+
let s = `${o.name}.${e.name}`, c = ke(o.name, e.name, t[o.name]?.[e.name], n);
|
|
208
208
|
if (c === "error") {
|
|
209
209
|
i.push(s);
|
|
210
210
|
continue;
|
|
211
211
|
}
|
|
212
|
-
if (!
|
|
212
|
+
if (!Ve(c)) {
|
|
213
213
|
a.push({
|
|
214
214
|
column: s,
|
|
215
215
|
action: c
|
|
@@ -223,7 +223,7 @@ var Ce = (e) => {
|
|
|
223
223
|
unclassified: i,
|
|
224
224
|
invalid: a
|
|
225
225
|
};
|
|
226
|
-
},
|
|
226
|
+
}, Ue = [
|
|
227
227
|
{
|
|
228
228
|
name: "email",
|
|
229
229
|
re: /[\w.+-]+@[\w-]+\.[\w.-]+/
|
|
@@ -240,7 +240,7 @@ var Ce = (e) => {
|
|
|
240
240
|
name: "creditCard",
|
|
241
241
|
re: /\b(?:\d[ -]?){13,16}\b/
|
|
242
242
|
}
|
|
243
|
-
],
|
|
243
|
+
], We = (e, t, n) => {
|
|
244
244
|
let r = [], i = /* @__PURE__ */ new Set();
|
|
245
245
|
for (let [a, o] of Object.entries(n)) {
|
|
246
246
|
if (!a.startsWith(`${t}.`) || o !== "keep") continue;
|
|
@@ -248,7 +248,7 @@ var Ce = (e) => {
|
|
|
248
248
|
for (let a of e) {
|
|
249
249
|
let e = a[n];
|
|
250
250
|
if (typeof e != "string" || e.length === 0) continue;
|
|
251
|
-
let o =
|
|
251
|
+
let o = Ue.find((t) => t.re.test(e));
|
|
252
252
|
if (o && !i.has(n)) {
|
|
253
253
|
i.add(n), r.push({
|
|
254
254
|
table: t,
|
|
@@ -261,9 +261,9 @@ var Ce = (e) => {
|
|
|
261
261
|
}
|
|
262
262
|
}
|
|
263
263
|
return r;
|
|
264
|
-
},
|
|
264
|
+
}, Ge = (e, t, n, r, i) => {
|
|
265
265
|
let a = {};
|
|
266
|
-
for (let [o, s] of Object.entries(e)) a[o] =
|
|
266
|
+
for (let [o, s] of Object.entries(e)) a[o] = B(n[`${t}.${o}`] ?? "keep", {
|
|
267
267
|
value: s,
|
|
268
268
|
table: t,
|
|
269
269
|
column: o,
|
|
@@ -271,9 +271,17 @@ var Ce = (e) => {
|
|
|
271
271
|
...i?.[o] ? { columnType: i[o] } : {}
|
|
272
272
|
});
|
|
273
273
|
return a;
|
|
274
|
-
},
|
|
274
|
+
}, Ke = /* @__PURE__ */ new Map([
|
|
275
|
+
["_voltro_aggregate_meta", "materialized refresh generations computed HERE — a foreign row would claim that the target refreshed its own source data"],
|
|
276
|
+
["_voltro_aggregate_rows", "materialized rows tied to this deployment’s refresh generation — the target recomputes them from its own data"],
|
|
277
|
+
["_voltro_timeline", "captured source mutations from this deployment — foreign rows invent local timeline history"],
|
|
278
|
+
["_voltro_timeline_meta", "capture epoch and source cursor of this database — foreign metadata claims continuity with another database"],
|
|
279
|
+
["_voltro_timeline_leases", "active capture readers of this database — foreign leases claim readers that do not exist here"],
|
|
280
|
+
["_voltro_timeline_slots", "bounded capture slots belonging to this source epoch — foreign slots invent local mutation history"],
|
|
281
|
+
["_voltro_plugin_migrations", "plugin migration steps applied to this database — a foreign ledger would skip steps that the target has not run"],
|
|
275
282
|
["_voltro_migration_plans", "the schema fingerprint THIS deployment applied — a foreign row makes the next boot refuse"],
|
|
276
283
|
["_voltro_migrations", "which file-based migrations ran HERE — a foreign row marks unrun migrations as done"],
|
|
284
|
+
["_voltro_plugin_migrations", "which plugin migration steps ran HERE — a foreign row marks a plugin's unrun steps as done"],
|
|
277
285
|
["_voltro_schema_owner", "which app owns THIS database — a foreign row hands the target's schema to the source app, so the target's own app refuses to boot on it"],
|
|
278
286
|
["_voltro_deploys", "the deploy THIS database is in the middle of, with the baseline to undo it from — a foreign row makes the next apply undo a deploy the target never started"],
|
|
279
287
|
["_voltro_devices", "devices paired with THIS deployment — token hashes; a foreign row makes a device paired elsewhere authenticate here"],
|
|
@@ -319,6 +327,7 @@ var Ce = (e) => {
|
|
|
319
327
|
["_voltro_workflow_start_receipts", "the caller-facing identity of a start placed HERE, resolved through this deployment's placements — a foreign receipt names a run the target never accepted"],
|
|
320
328
|
["_voltro_workflow_control_requests", "cancel/resume traffic issued against executions HERE — a foreign row claims an operation nobody asked the target to perform"],
|
|
321
329
|
["_voltro_workflow_queued_cancellations", "cancellations waiting on a run that is queued HERE — a foreign row cancels something the target has not queued"],
|
|
330
|
+
["_voltro_workflow_restart_withdrawals", "withdrawal fences for restart requests issued HERE — a foreign row would block a target restart that its operator never withdrew"],
|
|
322
331
|
["_voltro_workflow_restart_requests", "restarts pending against this deployment's generations — a foreign row restarts a generation the target never entered"],
|
|
323
332
|
["_voltro_workflow_retry_requests", "retry intents an operator raised against runs HERE, keyed by their own request id — a foreign row binds the target to an intent nobody raised against it, and lets a later observation read somebody else's execution"],
|
|
324
333
|
["_voltro_workflow_parent_closures", "which parents are still waiting on children in flight HERE — a foreign row holds a parent open against a child the target is not running"],
|
|
@@ -327,8 +336,13 @@ var Ce = (e) => {
|
|
|
327
336
|
["_voltro_notification_deliveries", "the notification attempts this deployment made — a foreign row claims a send the target never performed"],
|
|
328
337
|
["_voltro_notification_held", "notifications waiting to be SENT from here — a foreign row makes the target deliver something queued elsewhere"],
|
|
329
338
|
["_voltro_webhook_event_stats", "per-deployment delivery counters a backoff decision reads — foreign counts steer the target's retries"],
|
|
330
|
-
["_voltro_webhook_rate_windows", "the live rate-limit windows this deployment is inside — a foreign window throttles or releases wrongly"]
|
|
331
|
-
|
|
339
|
+
["_voltro_webhook_rate_windows", "the live rate-limit windows this deployment is inside — a foreign window throttles or releases wrongly"],
|
|
340
|
+
["cluster_runners", "the workflow runners of THIS deployment and their addresses — a foreign row routes shards to a runner that does not exist here"],
|
|
341
|
+
["cluster_locks", "the shard leases THIS deployment's runners hold — a foreign row holds a shard for nobody, and its work stalls"],
|
|
342
|
+
["cluster_messages", "workflow messages in flight HERE — a foreign row makes the target run work that was started, and may be running, elsewhere"],
|
|
343
|
+
["cluster_replies", "replies to those messages — a foreign row answers a request the target never sent"],
|
|
344
|
+
["cluster_migrations", "which engine migrations ran HERE — a foreign row marks the target's engine tables migrated when they are not"]
|
|
345
|
+
]), qe = /* @__PURE__ */ new Map([
|
|
332
346
|
["_voltro_agent_threads", "conversations the app's users had — app data"],
|
|
333
347
|
["_voltro_agent_messages", "the messages in those conversations — app data"],
|
|
334
348
|
["_voltro_prompts", "prompt definitions the app authored — app data"],
|
|
@@ -364,21 +378,21 @@ var Ce = (e) => {
|
|
|
364
378
|
["_voltro_comment_threads", "the threads those comments hang on — app data"],
|
|
365
379
|
["_voltro_comment_reactions", "the reactions the app's users left — app data"],
|
|
366
380
|
["_voltro_comment_reads", "which comments each user has read — app data, and losing it re-marks everything unread"]
|
|
367
|
-
]),
|
|
381
|
+
]), V = (e) => Ke.has(e), Je = (e) => Ke.get(e), Ye = (e, t) => {
|
|
368
382
|
if (e.length === 0) return;
|
|
369
|
-
let n = e.map((e) => ` ${e} — ${
|
|
383
|
+
let n = e.map((e) => ` ${e} — ${Je(e) ?? "describes this deployment"}`);
|
|
370
384
|
return `${t} ${e.length} table(s) that describe a deployment rather than its data:\n${n.join("\n")}\n A row from another environment is not stale there, it is a false statement about this one.`;
|
|
371
|
-
},
|
|
385
|
+
}, H = class extends c.TaggedError()("BundleError", {
|
|
372
386
|
reason: c.String,
|
|
373
387
|
path: c.optional(c.String)
|
|
374
|
-
}) {},
|
|
388
|
+
}) {}, Xe = class extends c.TaggedError()("CodecError", {
|
|
375
389
|
table: c.String,
|
|
376
390
|
reason: c.String
|
|
377
|
-
}) {},
|
|
391
|
+
}) {}, Ze = class extends c.TaggedError()("IntegrityError", {
|
|
378
392
|
what: c.String,
|
|
379
393
|
expected: c.String,
|
|
380
394
|
actual: c.String
|
|
381
|
-
}) {},
|
|
395
|
+
}) {}, Qe = class extends t.TaggedError("CompressionError") {}, U = class extends c.TaggedError()("ScopeError", { reason: c.String }) {}, $e = class extends c.TaggedError()("RowsRefusedError", {
|
|
382
396
|
rows: c.Array(c.Struct({
|
|
383
397
|
table: c.String,
|
|
384
398
|
id: c.String,
|
|
@@ -392,29 +406,29 @@ var Ce = (e) => {
|
|
|
392
406
|
refused: c.Number,
|
|
393
407
|
primary: c.Number
|
|
394
408
|
}))
|
|
395
|
-
}) {},
|
|
409
|
+
}) {}, et = class extends c.TaggedError()("SchemaDriftError", {
|
|
396
410
|
bundleFingerprint: c.String,
|
|
397
411
|
targetFingerprint: c.String,
|
|
398
412
|
diff: c.Array(c.String)
|
|
399
|
-
}) {},
|
|
413
|
+
}) {}, W = class extends t.TaggedError("NativeToolError") {
|
|
400
414
|
get message() {
|
|
401
415
|
let e = this.stderr?.trim(), t = this.hint?.trim();
|
|
402
416
|
return `${this.tool}: ${this.reason}${e ? `\n${e}` : ""}${t ? `\n\nhint: ${t}` : ""}`;
|
|
403
417
|
}
|
|
404
|
-
},
|
|
418
|
+
}, tt = class extends c.TaggedError()("MaskingError", {
|
|
405
419
|
unclassified: c.Array(c.String),
|
|
406
420
|
invalidActions: c.optional(c.Array(c.String))
|
|
407
|
-
}) {},
|
|
421
|
+
}) {}, nt = class extends c.TaggedError()("ImportModeError", {
|
|
408
422
|
mode: c.String,
|
|
409
423
|
reason: c.String
|
|
410
|
-
}) {},
|
|
424
|
+
}) {}, rt = class extends c.TaggedError()("CrossDialectError", {
|
|
411
425
|
sourceDialect: c.String,
|
|
412
426
|
targetDialect: c.String,
|
|
413
427
|
blocking: c.Array(c.String)
|
|
414
|
-
}) {},
|
|
428
|
+
}) {}, it = (e, t) => e.tables.find((e) => e.name === t)?.columns.find((e) => e.type === "id")?.name ?? "id", at = (e, t) => (e.tables.find((e) => e.name === t)?.columns ?? []).filter((e) => e.references).map((e) => ({
|
|
415
429
|
col: e.name,
|
|
416
430
|
refTable: e.references.table
|
|
417
|
-
})),
|
|
431
|
+
})), ot = (e, t, r) => n.gen(function* () {
|
|
418
432
|
let i = r.maxDepth ?? 12, a = new Set(r.pinned ?? []), o = /* @__PURE__ */ new Map(), s = /* @__PURE__ */ new Map(), c = /* @__PURE__ */ new Map(), u = (e) => {
|
|
419
433
|
let t = s.get(e) ?? /* @__PURE__ */ new Set();
|
|
420
434
|
return s.set(e, t), t;
|
|
@@ -432,10 +446,10 @@ var Ce = (e) => {
|
|
|
432
446
|
for (let t of n) d(t.refTable, e[t.col]);
|
|
433
447
|
};
|
|
434
448
|
}, p = (r, i) => {
|
|
435
|
-
let a = f(r,
|
|
436
|
-
return l.runForEach(
|
|
449
|
+
let a = f(r, it(t, r), at(t, r));
|
|
450
|
+
return l.runForEach(C(e, {
|
|
437
451
|
table: r,
|
|
438
|
-
pk:
|
|
452
|
+
pk: it(t, r),
|
|
439
453
|
...i === void 0 ? {} : { where: i }
|
|
440
454
|
}), (e) => n.sync(() => a(e)));
|
|
441
455
|
}, m = n.gen(function* () {
|
|
@@ -444,7 +458,7 @@ var Ce = (e) => {
|
|
|
444
458
|
c.clear();
|
|
445
459
|
for (let [n, r] of e) {
|
|
446
460
|
let e = [...r].filter((e) => !s.get(n)?.has(e));
|
|
447
|
-
e.length !== 0 && (yield* p(n, b(
|
|
461
|
+
e.length !== 0 && (yield* p(n, b(it(t, n), e)));
|
|
448
462
|
}
|
|
449
463
|
}
|
|
450
464
|
});
|
|
@@ -467,24 +481,24 @@ var Ce = (e) => {
|
|
|
467
481
|
}
|
|
468
482
|
}
|
|
469
483
|
return o;
|
|
470
|
-
}),
|
|
484
|
+
}), st = (e, t) => ({
|
|
471
485
|
tables: [...e.keys()],
|
|
472
486
|
predicateFor: (n) => {
|
|
473
487
|
let r = e.get(n);
|
|
474
|
-
return r ? b(
|
|
488
|
+
return r ? b(it(t, n), [...r]) : void 0;
|
|
475
489
|
}
|
|
476
|
-
}),
|
|
490
|
+
}), ct = "tenantId", lt = (e, t, r) => n.gen(function* () {
|
|
477
491
|
let i = t.tables.map((e) => e.name), a = new Map(t.tables.map((e) => [e.name, e]));
|
|
478
492
|
if (e.kind === "all") {
|
|
479
493
|
let t = new Set(e.exclude ?? []);
|
|
480
494
|
return {
|
|
481
|
-
tables: i.filter((e) => !
|
|
495
|
+
tables: i.filter((e) => !V(e) && !t.has(e)),
|
|
482
496
|
predicateFor: () => void 0
|
|
483
497
|
};
|
|
484
498
|
}
|
|
485
499
|
if (e.kind === "tables") {
|
|
486
500
|
let t = e.tables ?? [], r = new Set(i), a = t.filter((e) => !r.has(e));
|
|
487
|
-
if (a.length > 0) return yield* n.fail(new
|
|
501
|
+
if (a.length > 0) return yield* n.fail(new U({ 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}.` }));
|
|
488
502
|
let o = new Set(t);
|
|
489
503
|
return {
|
|
490
504
|
tables: i.filter((e) => o.has(e)),
|
|
@@ -492,30 +506,30 @@ var Ce = (e) => {
|
|
|
492
506
|
};
|
|
493
507
|
}
|
|
494
508
|
let o = e.tenantId;
|
|
495
|
-
if (o === void 0 || o === "") return yield* n.fail(new
|
|
496
|
-
let s = r.tenantTables ? r.tenantTables.filter((e) => a.has(e)) : i.filter((e) => a.get(e)?.columns.some((e) => e.name ===
|
|
497
|
-
if (s.length === 0) return yield* n.fail(new
|
|
498
|
-
let c = yield*
|
|
499
|
-
seeds: Object.fromEntries(s.map((e) => [e, _(
|
|
509
|
+
if (o === void 0 || o === "") return yield* n.fail(new U({ reason: "scope { kind: 'tenant' } requires a tenantId — pass --tenant <id> (CLI) or scope.tenantId (API). Refusing to fall back to an unfiltered export." }));
|
|
510
|
+
let s = r.tenantTables ? r.tenantTables.filter((e) => a.has(e)) : i.filter((e) => a.get(e)?.columns.some((e) => e.name === ct) ?? !1);
|
|
511
|
+
if (s.length === 0) return yield* n.fail(new U({ reason: r.tenantTables ? "tenant scope: none of the provided tenantTables exist in the schema — nothing to filter." : `tenant scope: no table carries a '${ct}' column — nothing to filter. A tenant export of a schema without tenant-scoped tables would be the full database; refusing.` }));
|
|
512
|
+
let c = yield* ot(r.store, t, {
|
|
513
|
+
seeds: Object.fromEntries(s.map((e) => [e, _(ct, o)])),
|
|
500
514
|
pinned: s,
|
|
501
515
|
children: { roots: s }
|
|
502
516
|
}), l = [...c.entries()].filter(([, e]) => e.size > 0).map(([e]) => e), u = new Set(s);
|
|
503
517
|
return {
|
|
504
518
|
tables: [...s, ...l],
|
|
505
|
-
predicateFor: (e) => u.has(e) ? _(
|
|
519
|
+
predicateFor: (e) => u.has(e) ? _(ct, o) : c.has(e) ? b(it(t, e), [...c.get(e)]) : void 0
|
|
506
520
|
};
|
|
507
|
-
}),
|
|
521
|
+
}), ut = (e, t) => ({
|
|
508
522
|
list: t,
|
|
509
|
-
open: (t) =>
|
|
510
|
-
}),
|
|
511
|
-
write: (t, n, r) =>
|
|
523
|
+
open: (t) => _e(e, t)
|
|
524
|
+
}), dt = (e) => ({
|
|
525
|
+
write: (t, n, r) => k(e, t, n, r),
|
|
512
526
|
has: (t) => e.head(t).pipe(n.map((e) => e !== null))
|
|
513
|
-
}),
|
|
527
|
+
}), ft = (e, t) => n.tryPromise({
|
|
514
528
|
try: async () => {
|
|
515
529
|
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) {
|
|
516
530
|
u.update(e), d += e.length, n(null, e);
|
|
517
531
|
} });
|
|
518
|
-
await o(await
|
|
532
|
+
await o(await A(e.stream), f, n(l));
|
|
519
533
|
let p = u.digest("hex"), m = c.join(t, p);
|
|
520
534
|
try {
|
|
521
535
|
await r.access(m), await r.rm(l, { force: !0 });
|
|
@@ -528,30 +542,30 @@ var Ce = (e) => {
|
|
|
528
542
|
contentType: e.contentType
|
|
529
543
|
};
|
|
530
544
|
},
|
|
531
|
-
catch: (e) => new
|
|
545
|
+
catch: (e) => new H({
|
|
532
546
|
reason: `asset write failed: ${String(e?.message ?? e)}`,
|
|
533
547
|
path: t
|
|
534
548
|
})
|
|
535
|
-
}),
|
|
536
|
-
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), c = o("sha256"), u =
|
|
549
|
+
}), pt = (e, t, r) => n.gen(function* () {
|
|
550
|
+
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), c = o("sha256"), u = ge("bundle", () => a(s)).pipe(l.tap((e) => n.sync(() => c.update(e))));
|
|
537
551
|
yield* e.write(r.key, u, {
|
|
538
552
|
contentType: r.contentType,
|
|
539
553
|
totalSize: r.size
|
|
540
554
|
});
|
|
541
555
|
let d = c.digest("hex");
|
|
542
|
-
if (d !== r.sha256) return yield* n.fail(new
|
|
556
|
+
if (d !== r.sha256) return yield* n.fail(new Ze({
|
|
543
557
|
what: `asset ${r.key}`,
|
|
544
558
|
expected: r.sha256,
|
|
545
559
|
actual: d
|
|
546
560
|
}));
|
|
547
|
-
}),
|
|
561
|
+
}), mt = {
|
|
548
562
|
done: () => !1,
|
|
549
563
|
mark: () => n.void
|
|
550
|
-
},
|
|
551
|
-
let t = e.progress ??
|
|
552
|
-
return yield* l.runForEach(e.source.list(), (l) => (a++, t.done(l.key) || c.has(l.key) ? n.void : (c.add(l.key), e.source.open(l.key).pipe(n.map((e) => e), n.catchIf(
|
|
564
|
+
}, ht = (e) => typeof e == "object" && !!e && e.status === 404, gt = (e) => n.gen(function* () {
|
|
565
|
+
let t = e.progress ?? mt, r = 0, i = 0, a = 0, o = 0, s = /* @__PURE__ */ new Set(), c = /* @__PURE__ */ new Set(), u = [];
|
|
566
|
+
return yield* l.runForEach(e.source.list(), (l) => (a++, t.done(l.key) || c.has(l.key) ? n.void : (c.add(l.key), e.source.open(l.key).pipe(n.map((e) => e), n.catchIf(ht, () => n.sync(() => {
|
|
553
567
|
u.push(l.key);
|
|
554
|
-
})), n.flatMap((a) => a === void 0 ? n.void :
|
|
568
|
+
})), n.flatMap((a) => a === void 0 ? n.void : ft(a, e.assetsDir).pipe(n.flatMap((e) => {
|
|
555
569
|
let n = {
|
|
556
570
|
key: l.key,
|
|
557
571
|
sha256: e.sha256,
|
|
@@ -559,7 +573,7 @@ var Ce = (e) => {
|
|
|
559
573
|
contentType: e.contentType
|
|
560
574
|
};
|
|
561
575
|
return r++, i += e.size, s.has(e.sha256) || (s.add(e.sha256), o += e.size), t.mark(l.key, n);
|
|
562
|
-
}))))))).pipe(n.mapError((e) => e instanceof
|
|
576
|
+
}))))))).pipe(n.mapError((e) => e instanceof H ? e : new H({ reason: `asset export failed: ${String(e)}` }))), {
|
|
563
577
|
count: r,
|
|
564
578
|
totalBytes: i,
|
|
565
579
|
references: a,
|
|
@@ -567,18 +581,18 @@ var Ce = (e) => {
|
|
|
567
581
|
objectBytes: o,
|
|
568
582
|
missing: u
|
|
569
583
|
};
|
|
570
|
-
}),
|
|
584
|
+
}), _t = (e) => ge("bundle", () => fe(e)).pipe(l.decodeText(), l.splitLines, l.filter((e) => e.trim().length > 0), l.map((e) => JSON.parse(e)), l.mapError((t) => t instanceof H ? t : new H({
|
|
571
585
|
reason: `asset index unreadable: ${String(t)}`,
|
|
572
586
|
path: e
|
|
573
|
-
}))),
|
|
574
|
-
let t = e.progress ??
|
|
575
|
-
return yield* l.runForEach(
|
|
587
|
+
}))), vt = (e) => n.gen(function* () {
|
|
588
|
+
let t = e.progress ?? mt, r = 0, i = /* @__PURE__ */ new Set(), a = /* @__PURE__ */ new Set();
|
|
589
|
+
return yield* l.runForEach(_t(e.indexPath), (o) => t.done(o.key) || a.has(o.key) ? n.void : (a.add(o.key), pt(e.sink, e.assetsDir, o)).pipe(n.andThen(n.sync(() => {
|
|
576
590
|
r++, i.add(o.sha256);
|
|
577
591
|
})), n.andThen(t.mark(o.key, o)))), {
|
|
578
592
|
count: r,
|
|
579
593
|
objects: i.size
|
|
580
594
|
};
|
|
581
|
-
}),
|
|
595
|
+
}), yt = () => typeof j.createZstdCompress == "function", bt = (e) => e === "none" ? "none" : e === "gzip" ? "gzip" : yt() ? "zstd" : "gzip", xt = (e) => e === "zstd" ? ".zst" : e === "gzip" ? ".gz" : "", St = (e) => e === "zstd" ? j.createZstdCompress() : e === "gzip" ? j.createGzip() : new M(), Ct = (e) => e === "zstd" ? j.createZstdDecompress() : e === "gzip" ? j.createGunzip() : new M(), wt = 1, Tt = c.Struct({
|
|
582
596
|
name: c.String,
|
|
583
597
|
file: c.String,
|
|
584
598
|
rowCount: c.Number,
|
|
@@ -588,12 +602,12 @@ var Ce = (e) => {
|
|
|
588
602
|
value: c.String
|
|
589
603
|
}),
|
|
590
604
|
primaryKey: c.String
|
|
591
|
-
}),
|
|
605
|
+
}), Et = c.Struct({
|
|
592
606
|
kind: c.Literal("all", "tenant", "tables"),
|
|
593
607
|
tenantId: c.optional(c.String),
|
|
594
608
|
tables: c.optional(c.Array(c.String)),
|
|
595
609
|
exclude: c.optional(c.Array(c.String))
|
|
596
|
-
}),
|
|
610
|
+
}), Dt = c.Struct({
|
|
597
611
|
count: c.Number,
|
|
598
612
|
totalBytes: c.Number,
|
|
599
613
|
index: c.optional(c.String)
|
|
@@ -604,23 +618,23 @@ c.Struct({
|
|
|
604
618
|
size: c.Number,
|
|
605
619
|
contentType: c.String
|
|
606
620
|
});
|
|
607
|
-
var
|
|
621
|
+
var Ot = c.Struct({
|
|
608
622
|
formatVersion: c.Number,
|
|
609
623
|
createdAt: c.String,
|
|
610
624
|
source: c.Struct({
|
|
611
625
|
dialect: c.String,
|
|
612
626
|
schemaFingerprint: c.String
|
|
613
627
|
}),
|
|
614
|
-
scope:
|
|
628
|
+
scope: Et,
|
|
615
629
|
consistency: c.Literal("live", "snapshot"),
|
|
616
630
|
compression: c.Literal("zstd", "gzip", "none"),
|
|
617
|
-
tables: c.Array(
|
|
618
|
-
assets:
|
|
631
|
+
tables: c.Array(Tt),
|
|
632
|
+
assets: Dt,
|
|
619
633
|
masking: c.optional(c.Struct({
|
|
620
634
|
policyId: c.optional(c.String),
|
|
621
635
|
transformed: c.Array(c.String)
|
|
622
636
|
}))
|
|
623
|
-
}),
|
|
637
|
+
}), kt = c.encodeSync(c.parseJson(Ot)), At = c.decodeUnknownSync(c.parseJson(Ot)), jt = "manifest.json", Mt = "README.md", Nt = "data", Pt = "assets", Ft = "assets/index.ndjson", It = ".ledger.json", Lt = (e) => e.kind === "tenant" ? `tenant \`${e.tenantId}\`` : e.kind === "tables" ? `tables \`${(e.tables ?? []).join(", ")}\`` : "all tables", Rt = (e, t) => {
|
|
624
638
|
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");
|
|
625
639
|
return `# Voltro data export
|
|
626
640
|
|
|
@@ -634,7 +648,7 @@ The machine-readable manifest is \`manifest.json\`; this file is a human summary
|
|
|
634
648
|
| **Format version** | ${e.formatVersion} |
|
|
635
649
|
| **Consistency** | ${e.consistency} |
|
|
636
650
|
| **Compression** | ${e.compression} |
|
|
637
|
-
| **Scope** | ${
|
|
651
|
+
| **Scope** | ${Lt(e.scope)} |
|
|
638
652
|
| **Tables** | ${e.tables.length} |
|
|
639
653
|
| **Rows (total)** | ${n} |
|
|
640
654
|
| **Assets** | ${a} |
|
|
@@ -659,39 +673,39 @@ voltro data import <this-directory>
|
|
|
659
673
|
voltro data import <this-directory> --target api --api-url <url> --token <secret>
|
|
660
674
|
\`\`\`
|
|
661
675
|
`;
|
|
662
|
-
},
|
|
676
|
+
}, zt = i.counter("voltro_data_transfer_rows", { description: "Rows exported/imported by @voltro/data-transfer, tagged by phase + table." }), Bt = a.exponential({
|
|
663
677
|
start: .01,
|
|
664
678
|
factor: 2,
|
|
665
679
|
count: 16
|
|
666
|
-
}),
|
|
680
|
+
}), Vt = i.histogram("voltro_data_transfer_table_seconds", Bt, "Per-table export/import duration in seconds, tagged by phase."), G = (e, t) => {
|
|
667
681
|
if (e) try {
|
|
668
682
|
e(t);
|
|
669
683
|
} catch {}
|
|
670
|
-
},
|
|
684
|
+
}, Ht = (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(Vt.pipe(i.tagged("phase", e), i.update((s - r) / 1e3)), zt.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: {
|
|
671
685
|
table: t,
|
|
672
686
|
index: r,
|
|
673
687
|
tableCount: a,
|
|
674
688
|
phase: e
|
|
675
|
-
} })),
|
|
689
|
+
} })), Ut = () => ({
|
|
676
690
|
tables: {},
|
|
677
691
|
assets: {}
|
|
678
|
-
}),
|
|
692
|
+
}), Wt = (e) => n.tryPromise(async () => {
|
|
679
693
|
let t = await (await import("node:fs/promises")).readFile(e, "utf8");
|
|
680
694
|
return JSON.parse(t);
|
|
681
|
-
}).pipe(n.orElseSucceed(
|
|
695
|
+
}).pipe(n.orElseSucceed(Ut)), K = (e, t) => n.tryPromise({
|
|
682
696
|
try: async () => {
|
|
683
697
|
let n = await import("node:fs/promises"), { randomUUID: r } = await import("node:crypto"), i = `${e}.tmp-${r()}`;
|
|
684
698
|
await n.writeFile(i, JSON.stringify(t)), await n.rename(i, e);
|
|
685
699
|
},
|
|
686
|
-
catch: (t) => new
|
|
700
|
+
catch: (t) => new H({
|
|
687
701
|
reason: `ledger write failed: ${String(t?.message ?? t)}`,
|
|
688
702
|
path: e
|
|
689
703
|
})
|
|
690
|
-
}),
|
|
704
|
+
}), Gt = (e, t) => t in e.tables, Kt = (e, t) => t in e.assets, qt = /* @__PURE__ */ new Set([
|
|
691
705
|
"json",
|
|
692
706
|
"array",
|
|
693
707
|
"vector"
|
|
694
|
-
]),
|
|
708
|
+
]), Jt = (e) => typeof e == "object" && !!e && !Array.isArray(e) && typeof e.$v == "string", Yt = (e) => Buffer.from(e).toString("base64"), Xt = (e) => new Uint8Array(Buffer.from(e, "base64")), Zt = (e) => e instanceof Date ? e.toISOString() : typeof e == "number" ? new Date(e).toISOString() : String(e), Qt = (e, t) => e == null ? null : t !== void 0 && qt.has(t) ? e : t === "bytes" ? Yt(e) : t === "timestamp" || t === "date" ? Zt(e) : typeof e == "bigint" ? {
|
|
695
709
|
$v: "bigint",
|
|
696
710
|
d: e.toString()
|
|
697
711
|
} : typeof e == "number" && !Number.isFinite(e) ? {
|
|
@@ -702,30 +716,30 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
702
716
|
d: e.toISOString()
|
|
703
717
|
} : e instanceof Uint8Array ? {
|
|
704
718
|
$v: "bytes",
|
|
705
|
-
d:
|
|
706
|
-
} : e,
|
|
719
|
+
d: Yt(e)
|
|
720
|
+
} : e, $t = (e) => {
|
|
707
721
|
switch (e.$v) {
|
|
708
722
|
case "bigint": return BigInt(e.d);
|
|
709
723
|
case "number": return Number(e.d);
|
|
710
724
|
case "date": return new Date(e.d);
|
|
711
|
-
case "bytes": return
|
|
725
|
+
case "bytes": return Xt(e.d);
|
|
712
726
|
default: return e;
|
|
713
727
|
}
|
|
714
|
-
},
|
|
728
|
+
}, en = (e, t) => e == null ? null : t !== void 0 && qt.has(t) ? e : Jt(e) ? $t(e) : t === "bytes" ? Xt(e) : t === "timestamp" || t === "date" ? new Date(e) : e, tn = (e, t) => {
|
|
715
729
|
let n = {};
|
|
716
|
-
for (let [r, i] of Object.entries(e)) n[r] =
|
|
730
|
+
for (let [r, i] of Object.entries(e)) n[r] = Qt(i, t[r]);
|
|
717
731
|
return n;
|
|
718
|
-
},
|
|
732
|
+
}, nn = (e, t) => {
|
|
719
733
|
let n = {};
|
|
720
|
-
for (let [r, i] of Object.entries(e)) n[r] =
|
|
734
|
+
for (let [r, i] of Object.entries(e)) n[r] = en(i, t[r]);
|
|
721
735
|
return n;
|
|
722
|
-
},
|
|
723
|
-
try: () =>
|
|
724
|
-
catch: (e) => new
|
|
736
|
+
}, rn = new TextEncoder(), an = (e, t) => e.pipe(l.map((e) => rn.encode(`${JSON.stringify(tn(e, t))}\n`))), on = (e, t, r) => e.pipe(l.decodeText(), l.splitLines, l.filter((e) => e.trim().length > 0), l.mapEffect((e) => n.try({
|
|
737
|
+
try: () => nn(JSON.parse(e), r),
|
|
738
|
+
catch: (e) => new Xe({
|
|
725
739
|
table: t,
|
|
726
740
|
reason: String(e?.message ?? e)
|
|
727
741
|
})
|
|
728
|
-
}))),
|
|
742
|
+
}))), sn = (e, t) => {
|
|
729
743
|
let n = new Set(e), r = /* @__PURE__ */ new Map();
|
|
730
744
|
for (let e of t.tables) {
|
|
731
745
|
if (!n.has(e.name)) continue;
|
|
@@ -745,39 +759,39 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
745
759
|
};
|
|
746
760
|
for (let t of e) n.has(t) && s(t);
|
|
747
761
|
return i;
|
|
748
|
-
},
|
|
762
|
+
}, q = (e) => {
|
|
749
763
|
let t = e, n = [];
|
|
750
764
|
typeof t?._tag == "string" && t._tag !== "" && n.push(t._tag);
|
|
751
765
|
let r = typeof t?.message == "string" ? t.message.trim() : "";
|
|
752
|
-
if (r === "" ? t?.cause !== void 0 && t.cause !== null && n.push(
|
|
766
|
+
if (r === "" ? t?.cause !== void 0 && t.cause !== null && n.push(q(t.cause)) : n.push(r), n.length === 0) {
|
|
753
767
|
let t = String(e ?? "").trim();
|
|
754
|
-
return t === "" || t === "[object Object]" ?
|
|
768
|
+
return t === "" || t === "[object Object]" ? cn(e) : t;
|
|
755
769
|
}
|
|
756
770
|
return n.join(": ");
|
|
757
|
-
},
|
|
771
|
+
}, cn = (e) => {
|
|
758
772
|
try {
|
|
759
773
|
let t = JSON.stringify(e);
|
|
760
774
|
return t === void 0 || t === "{}" ? "unknown error (no message, cause or tag)" : t;
|
|
761
775
|
} catch {
|
|
762
776
|
return "unknown error (not serialisable)";
|
|
763
777
|
}
|
|
764
|
-
},
|
|
778
|
+
}, ln = (e, t) => {
|
|
765
779
|
let n = e.tables.find((e) => e.name === t), r = {};
|
|
766
780
|
for (let e of n?.columns ?? []) e.generatedAs === void 0 && (r[e.name] = e.type);
|
|
767
781
|
return r;
|
|
768
|
-
},
|
|
782
|
+
}, un = (e, t) => (e.tables.find((e) => e.name === t)?.columns ?? []).filter((e) => e.generatedAs !== void 0).map((e) => e.name), dn = (e, t) => {
|
|
769
783
|
if (t.length === 0) return e;
|
|
770
784
|
let n = { ...e };
|
|
771
785
|
for (let e of t) delete n[e];
|
|
772
786
|
return n;
|
|
773
|
-
},
|
|
787
|
+
}, fn = (e, t) => {
|
|
774
788
|
let n = e.tables.find((e) => e.name === t);
|
|
775
789
|
if (n === void 0) return { refusal: `${t}: not in the schema snapshot, so its primary key is unknown.` };
|
|
776
790
|
let r = n.columns.find((e) => e.type === "id");
|
|
777
791
|
if (r !== void 0) return { column: r.name };
|
|
778
792
|
let i = n.indexes.find((e) => e.name === `${t}_pkey`)?.columns ?? n.primaryKey ?? [];
|
|
779
793
|
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.` };
|
|
780
|
-
},
|
|
794
|
+
}, pn = (e, t, r) => n.tryPromise({
|
|
781
795
|
try: async () => {
|
|
782
796
|
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: c, Transform: u } = await import("node:stream"), d = a("sha256"), f = 0, p = new u({ transform(e, t, n) {
|
|
783
797
|
d.update(e);
|
|
@@ -786,7 +800,7 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
786
800
|
n(null, e);
|
|
787
801
|
} }), m = c.fromWeb(l.toReadableStream(e)), h = `${t}.tmp-${o()}`;
|
|
788
802
|
try {
|
|
789
|
-
await s(m, p,
|
|
803
|
+
await s(m, p, St(r), n(h)), await i.rename(h, t);
|
|
790
804
|
} catch (e) {
|
|
791
805
|
throw await i.rm(h, { force: !0 }).catch(() => {}), e;
|
|
792
806
|
}
|
|
@@ -795,27 +809,27 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
795
809
|
checksum: d.digest("hex")
|
|
796
810
|
};
|
|
797
811
|
},
|
|
798
|
-
catch: (e) => new
|
|
799
|
-
reason: `write table failed: ${
|
|
812
|
+
catch: (e) => new H({
|
|
813
|
+
reason: `write table failed: ${q(e)}`,
|
|
800
814
|
path: t
|
|
801
815
|
})
|
|
802
|
-
}),
|
|
816
|
+
}), mn = (e, t) => n.tryPromise({
|
|
803
817
|
try: async () => {
|
|
804
818
|
await (await import("node:fs/promises")).appendFile(e, `${t}\n`);
|
|
805
819
|
},
|
|
806
|
-
catch: (t) => new
|
|
807
|
-
reason: `append failed: ${
|
|
820
|
+
catch: (t) => new H({
|
|
821
|
+
reason: `append failed: ${q(t)}`,
|
|
808
822
|
path: e
|
|
809
823
|
})
|
|
810
|
-
}),
|
|
824
|
+
}), hn = (e, t) => n.gen(function* () {
|
|
811
825
|
let r = [], i = t.ordered.length;
|
|
812
826
|
for (let a = 0; a < t.ordered.length; a++) {
|
|
813
|
-
let o = t.ordered[a], s =
|
|
814
|
-
if ("refusal" in c) return yield* n.fail(new
|
|
815
|
-
let u = c.column, d = `${
|
|
816
|
-
if (
|
|
827
|
+
let o = t.ordered[a], s = ln(t.snapshot, o), c = fn(t.snapshot, o);
|
|
828
|
+
if ("refusal" in c) return yield* n.fail(new U({ reason: `export: ${c.refusal}` }));
|
|
829
|
+
let u = c.column, d = `${Nt}/${o}.ndjson${xt(t.compression)}`;
|
|
830
|
+
if (Gt(t.ledger, o)) {
|
|
817
831
|
let e = t.ledger.tables[o];
|
|
818
|
-
|
|
832
|
+
G(t.onProgress, {
|
|
819
833
|
phase: "export",
|
|
820
834
|
table: o,
|
|
821
835
|
index: a,
|
|
@@ -833,7 +847,7 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
833
847
|
});
|
|
834
848
|
continue;
|
|
835
849
|
}
|
|
836
|
-
|
|
850
|
+
G(t.onProgress, {
|
|
837
851
|
phase: "export",
|
|
838
852
|
table: o,
|
|
839
853
|
index: a,
|
|
@@ -841,17 +855,17 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
841
855
|
event: "start",
|
|
842
856
|
rowsDone: 0
|
|
843
857
|
});
|
|
844
|
-
let f = t.resolved.predicateFor(o), p =
|
|
858
|
+
let f = t.resolved.predicateFor(o), p = C(e, {
|
|
845
859
|
table: o,
|
|
846
860
|
pk: u,
|
|
847
861
|
chunkSize: t.chunkSize,
|
|
848
862
|
retry: t.retry,
|
|
849
863
|
...f === void 0 ? {} : { where: f }
|
|
850
|
-
}), m =
|
|
864
|
+
}), m = un(t.snapshot, o), h = m.length === 0 ? p : p.pipe(l.map((e) => dn(e, m))), g = t.mask ? h.pipe(l.map((e) => Ge(e, o, t.mask.actions, t.mask.seed, s))) : h, { rowCount: _, checksum: v } = yield* Ht("export", o, a, i, (e) => e.rowCount, pn(an(g, s), t.bundleFile(d), t.compression));
|
|
851
865
|
t.ledger.tables[o] = {
|
|
852
866
|
rowCount: _,
|
|
853
867
|
checksum: v
|
|
854
|
-
}, yield*
|
|
868
|
+
}, yield* K(t.ledgerPath, t.ledger), G(t.onProgress, {
|
|
855
869
|
phase: "export",
|
|
856
870
|
table: o,
|
|
857
871
|
index: a,
|
|
@@ -869,43 +883,43 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
869
883
|
});
|
|
870
884
|
}
|
|
871
885
|
return r;
|
|
872
|
-
}),
|
|
886
|
+
}), gn = (e) => ({
|
|
873
887
|
_tag: "RawSqlFragment",
|
|
874
888
|
strings: [e],
|
|
875
889
|
values: []
|
|
876
|
-
}),
|
|
890
|
+
}), _n = (t, i, a) => n.tryPromise({
|
|
877
891
|
try: () => t.transactional(async (t) => {
|
|
878
|
-
if (t.raw) for (let e of
|
|
892
|
+
if (t.raw) for (let e of Ee(i)) await t.raw(gn(e));
|
|
879
893
|
let o = await n.runPromiseExit(a(t));
|
|
880
894
|
if (r.isFailure(o)) throw Error(e.pretty(o.cause));
|
|
881
895
|
return o.value;
|
|
882
896
|
}),
|
|
883
|
-
catch: (e) => e instanceof
|
|
884
|
-
}),
|
|
885
|
-
let t = e.scope ?? { kind: "all" }, r =
|
|
897
|
+
catch: (e) => e instanceof H ? e : new H({ reason: `snapshot export failed: ${q(e)}` })
|
|
898
|
+
}), vn = (e) => n.gen(function* () {
|
|
899
|
+
let t = e.scope ?? { kind: "all" }, r = bt(e.compression), i = e.chunkSize ?? 1e3, a = e.retryTimes ?? 5, o = s.exponential("50 millis").pipe(s.jittered, s.intersect(s.recurs(a))), c = yield* n.promise(() => import("node:path")), l = (t) => c.join(e.outDir, t);
|
|
886
900
|
yield* n.tryPromise({
|
|
887
901
|
try: async () => {
|
|
888
902
|
let t = await import("node:fs/promises");
|
|
889
|
-
await t.mkdir(l(
|
|
903
|
+
await t.mkdir(l(Nt), { recursive: !0 }), e.assets && await t.mkdir(l(Pt), { recursive: !0 });
|
|
890
904
|
},
|
|
891
|
-
catch: (t) => new
|
|
892
|
-
reason: `mkdir failed: ${
|
|
905
|
+
catch: (t) => new H({
|
|
906
|
+
reason: `mkdir failed: ${q(t)}`,
|
|
893
907
|
path: e.outDir
|
|
894
908
|
})
|
|
895
909
|
});
|
|
896
|
-
let u = l(
|
|
910
|
+
let u = l(It), d = yield* Wt(u), f = e.subset ? st(yield* ot(e.store, e.snapshot, e.subset), e.snapshot) : yield* lt(t, e.snapshot, {
|
|
897
911
|
store: e.store,
|
|
898
912
|
...e.tenantTables ? { tenantTables: e.tenantTables } : {}
|
|
899
|
-
}), p =
|
|
913
|
+
}), p = sn(f.tables, e.snapshot), m = e.consistency ?? "live", h, g;
|
|
900
914
|
if (e.masking) {
|
|
901
|
-
let t = e.classification ??
|
|
915
|
+
let t = e.classification ?? Oe(e.snapshot), r = He(p.map((t) => ({
|
|
902
916
|
name: t,
|
|
903
917
|
columns: (e.snapshot.tables.find((e) => e.name === t)?.columns ?? []).map((e) => ({
|
|
904
918
|
name: e.name,
|
|
905
919
|
type: e.type
|
|
906
920
|
}))
|
|
907
921
|
})), t, e.masking);
|
|
908
|
-
if (r.unclassified.length > 0 || r.invalid.length > 0) return yield* n.fail(new
|
|
922
|
+
if (r.unclassified.length > 0 || r.invalid.length > 0) return yield* n.fail(new tt({
|
|
909
923
|
unclassified: r.unclassified,
|
|
910
924
|
...r.invalid.length > 0 ? { invalidActions: r.invalid.map((e) => `${e.column}: ${JSON.stringify(e.action)}`) } : {}
|
|
911
925
|
}));
|
|
@@ -931,14 +945,14 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
931
945
|
bundleFile: l,
|
|
932
946
|
...g ? { mask: g } : {},
|
|
933
947
|
...e.onProgress ? { onProgress: e.onProgress } : {}
|
|
934
|
-
}, v = m === "snapshot" ? yield*
|
|
948
|
+
}, v = m === "snapshot" ? yield* _n(e.store, e.dialect, (e) => hn(e, _)) : yield* hn(e.store, _), y = 0, b = 0;
|
|
935
949
|
if (e.assets) {
|
|
936
|
-
let t = l(
|
|
950
|
+
let t = l(Ft), r = yield* gt({
|
|
937
951
|
source: e.assets,
|
|
938
|
-
assetsDir: l(
|
|
952
|
+
assetsDir: l(Pt),
|
|
939
953
|
progress: {
|
|
940
954
|
done: (e) => e in d.assets,
|
|
941
|
-
mark: (e, r) => (d.assets[e] = !0,
|
|
955
|
+
mark: (e, r) => (d.assets[e] = !0, mn(t, JSON.stringify(r)).pipe(n.andThen(K(u, d))))
|
|
942
956
|
}
|
|
943
957
|
});
|
|
944
958
|
y = r.count, b = r.totalBytes, r.missing.length > 0 && (yield* n.logWarning(`${r.missing.length} of ${r.missing.length + r.count} blob reference(s) point at objects the storage provider does not have; they are NOT in this bundle and no import can bring them back. e.g. ${r.missing.slice(0, 3).map((e) => `'${e}'`).join(", ")}` + (r.missing.length > 3 ? `, and ${r.missing.length - 3} more` : "")));
|
|
@@ -948,7 +962,7 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
948
962
|
createdAt: e.createdAt ?? (/* @__PURE__ */ new Date()).toISOString(),
|
|
949
963
|
source: {
|
|
950
964
|
dialect: e.dialect,
|
|
951
|
-
schemaFingerprint:
|
|
965
|
+
schemaFingerprint: w(e.snapshot)
|
|
952
966
|
},
|
|
953
967
|
scope: t,
|
|
954
968
|
consistency: m,
|
|
@@ -957,7 +971,7 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
957
971
|
assets: y > 0 ? {
|
|
958
972
|
count: y,
|
|
959
973
|
totalBytes: b,
|
|
960
|
-
index:
|
|
974
|
+
index: Ft
|
|
961
975
|
} : {
|
|
962
976
|
count: 0,
|
|
963
977
|
totalBytes: 0
|
|
@@ -966,23 +980,23 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
966
980
|
};
|
|
967
981
|
return yield* n.tryPromise({
|
|
968
982
|
try: async () => {
|
|
969
|
-
await (await import("node:fs/promises")).writeFile(l(
|
|
983
|
+
await (await import("node:fs/promises")).writeFile(l(jt), kt(x));
|
|
970
984
|
},
|
|
971
|
-
catch: (e) => new
|
|
972
|
-
reason: `manifest write failed: ${
|
|
973
|
-
path:
|
|
985
|
+
catch: (e) => new H({
|
|
986
|
+
reason: `manifest write failed: ${q(e)}`,
|
|
987
|
+
path: jt
|
|
974
988
|
})
|
|
975
989
|
}), yield* n.tryPromise({
|
|
976
990
|
try: async () => {
|
|
977
991
|
let e = await import("node:fs/promises"), t = await import("node:os");
|
|
978
|
-
await e.writeFile(l(
|
|
992
|
+
await e.writeFile(l(Mt), Rt(x, { hostname: t.hostname() }));
|
|
979
993
|
},
|
|
980
|
-
catch: (e) => new
|
|
981
|
-
reason: `readme write failed: ${
|
|
982
|
-
path:
|
|
994
|
+
catch: (e) => new H({
|
|
995
|
+
reason: `readme write failed: ${q(e)}`,
|
|
996
|
+
path: Mt
|
|
983
997
|
})
|
|
984
998
|
}), x;
|
|
985
|
-
}),
|
|
999
|
+
}), yn = (e, t) => {
|
|
986
1000
|
let n = new Set(t), r = [];
|
|
987
1001
|
for (let t of e.tables) if (!n.has(t.name)) for (let e of t.columns) {
|
|
988
1002
|
let i = e.references?.table;
|
|
@@ -993,7 +1007,7 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
993
1007
|
});
|
|
994
1008
|
}
|
|
995
1009
|
return r;
|
|
996
|
-
},
|
|
1010
|
+
}, bn = (e) => {
|
|
997
1011
|
let t = /* @__PURE__ */ new Map();
|
|
998
1012
|
for (let n of e) t.set(n.from, [...t.get(n.from) ?? [], n]);
|
|
999
1013
|
let n = [...t.entries()].map(([e, t]) => {
|
|
@@ -1001,7 +1015,7 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
1001
1015
|
return ` ${e} (${n} row${n === 1 ? "" : "s"}): ${r}`;
|
|
1002
1016
|
});
|
|
1003
1017
|
return `replace cannot empty this target: ${t.size} table(s) OUTSIDE the bundle hold rows that reference tables INSIDE it. Emptying the bundle's tables would leave those rows pointing at nothing, and the bundle cannot restore them.\n${n.join("\n")}\nNothing has been deleted. Either re-export with a scope that includes those tables, or use --mode upsert if those rows are meant to survive.`;
|
|
1004
|
-
},
|
|
1018
|
+
}, xn = (e) => {
|
|
1005
1019
|
switch (e) {
|
|
1006
1020
|
case "id":
|
|
1007
1021
|
case "text":
|
|
@@ -1020,12 +1034,12 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
1020
1034
|
case "raw": return "raw";
|
|
1021
1035
|
default: return "string";
|
|
1022
1036
|
}
|
|
1023
|
-
},
|
|
1037
|
+
}, Sn = {
|
|
1024
1038
|
vector: /* @__PURE__ */ new Set(["postgres"]),
|
|
1025
1039
|
array: /* @__PURE__ */ new Set(["postgres"]),
|
|
1026
1040
|
interval: /* @__PURE__ */ new Set(["postgres"])
|
|
1027
|
-
},
|
|
1028
|
-
let i =
|
|
1041
|
+
}, Cn = (e, t, n, r) => {
|
|
1042
|
+
let i = xn(n);
|
|
1029
1043
|
if (i === "raw") return {
|
|
1030
1044
|
table: e,
|
|
1031
1045
|
column: t,
|
|
@@ -1033,7 +1047,7 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
1033
1047
|
severity: "block",
|
|
1034
1048
|
reason: `raw() is verbatim source-dialect SQL — it cannot be assumed valid on ${r}`
|
|
1035
1049
|
};
|
|
1036
|
-
let a =
|
|
1050
|
+
let a = Sn[i];
|
|
1037
1051
|
return !a || a.has(r) ? null : i === "array" || i === "interval" ? {
|
|
1038
1052
|
table: e,
|
|
1039
1053
|
column: t,
|
|
@@ -1047,15 +1061,15 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
1047
1061
|
severity: "block",
|
|
1048
1062
|
reason: `${i} columns require a ${[...a].join("/")} target; ${r} has no compatible column type`
|
|
1049
1063
|
};
|
|
1050
|
-
},
|
|
1064
|
+
}, wn = (e, t, n) => {
|
|
1051
1065
|
if (t === n) return [];
|
|
1052
1066
|
let r = [];
|
|
1053
1067
|
for (let t of e) for (let [e, i] of Object.entries(t.columnTypes)) {
|
|
1054
|
-
let a =
|
|
1068
|
+
let a = Cn(t.name, e, i, n);
|
|
1055
1069
|
a && r.push(a);
|
|
1056
1070
|
}
|
|
1057
1071
|
return r;
|
|
1058
|
-
},
|
|
1072
|
+
}, Tn = (e) => `[${e.severity}] ${e.table}.${e.column} (${e.type}): ${e.reason}`, En = (e) => {
|
|
1059
1073
|
let t = e.constraint ?? e.column, n = t === void 0 ? "" : ` ${t}`;
|
|
1060
1074
|
switch (e.kind) {
|
|
1061
1075
|
case "foreignKey": return `foreign key${n}: the referenced row does not exist (import it first, or check the bundle's table order)`;
|
|
@@ -1064,36 +1078,36 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
1064
1078
|
case "notNull": return `not-null constraint${n}: the column requires a value`;
|
|
1065
1079
|
case "check": return `check constraint${n}: the row does not satisfy it`;
|
|
1066
1080
|
}
|
|
1067
|
-
},
|
|
1081
|
+
}, Dn = (e) => {
|
|
1068
1082
|
let t = [e.dbCode, e.dbErrno ?? e.dbNumber].filter((e) => e !== void 0).map(String);
|
|
1069
1083
|
return t.length > 0 ? t.join("/") : void 0;
|
|
1070
|
-
},
|
|
1084
|
+
}, On = "Failed to execute statement", kn = (e) => {
|
|
1071
1085
|
let t = (e.split("\n", 1)[0] ?? "").trim();
|
|
1072
1086
|
for (; t.startsWith("(FiberFailure)");) t = t.slice(14).trim();
|
|
1073
|
-
return t === `SqlError: ${
|
|
1074
|
-
},
|
|
1087
|
+
return t === `SqlError: ${On}` ? On : t;
|
|
1088
|
+
}, An = (e) => {
|
|
1075
1089
|
let t = String(e?.stack ?? e), n = t.length <= 1200 ? t : `${t.slice(0, 1200)}…`, r = (e, t) => ({
|
|
1076
1090
|
reason: e.length <= 300 ? e : `${e.slice(0, 300)}…`,
|
|
1077
1091
|
unclassified: t,
|
|
1078
1092
|
raw: n
|
|
1079
|
-
}), i = v(e), a = m(i), o =
|
|
1080
|
-
if (a !== void 0) return r(`${
|
|
1081
|
-
let c = typeof i.dbMessage == "string" ? i.dbMessage : void 0, l = e?.message, u =
|
|
1082
|
-
return r(d ===
|
|
1083
|
-
},
|
|
1093
|
+
}), i = v(e), a = m(i), o = Dn(i), s = o === void 0 ? "" : ` [${o}]`;
|
|
1094
|
+
if (a !== void 0) return r(`${En(a)}${s}`, !1);
|
|
1095
|
+
let c = typeof i.dbMessage == "string" ? i.dbMessage : void 0, l = e?.message, u = kn(typeof l == "string" && l.length > 0 ? l : String(e)), d = c !== void 0 && c !== u && !c.startsWith("SqlError:") ? c : u, f = typeof i.dbCauseChain == "string" ? i.dbCauseChain : void 0, p = f !== void 0 && /[←‖]/.test(f) ? ` (via ${f})` : "";
|
|
1096
|
+
return r(d === On || d.length === 0 ? `the database refused the write and the driver gave no detail${s}${p}` : `${d}${s}`, d === On || d.length === 0);
|
|
1097
|
+
}, jn = (e) => An(e).reason, Mn = (e) => {
|
|
1084
1098
|
let t = v(e), n = m(t);
|
|
1085
1099
|
if (n?.kind === "foreignKeyInUse") {
|
|
1086
|
-
let e = n.constraint ?? n.column, r = e === void 0 ? "" : ` ${e}`, i =
|
|
1100
|
+
let e = n.constraint ?? n.column, r = e === void 0 ? "" : ` ${e}`, i = Dn(t);
|
|
1087
1101
|
return `foreign key${r}: rows elsewhere still reference this table${i === void 0 ? "" : ` [${i}]`}`;
|
|
1088
1102
|
}
|
|
1089
|
-
return
|
|
1090
|
-
},
|
|
1103
|
+
return jn(e);
|
|
1104
|
+
}, Nn = f, J = (e) => `${Nn}${e}`, Pn = (e) => typeof e.run == "function", Fn = (e) => `staging is not available for this run — loading directly into the target instead: ${e}\n The load therefore holds the destructive transaction open for its whole duration, so a
|
|
1091
1105
|
process that dies mid-load depends on the database rolling it back. The rollback capture
|
|
1092
|
-
written before the first delete is what covers that case.`,
|
|
1093
|
-
if (!
|
|
1106
|
+
written before the first delete is what covers that case.`, In = /^[a-zA-Z_][a-zA-Z0-9_]*$/, Y = (e, t) => {
|
|
1107
|
+
if (!In.test(e)) throw Error(`refusing to build SQL for the table name ${JSON.stringify(e)}: it is outside the identifier class the framework allows. A name from a bundle manifest reaches this concatenation, so it is checked here rather than assumed to still be what the declaration validated.`);
|
|
1094
1108
|
return t === "mysql" || t === "mariadb" ? `\`${e}\`` : t === "mssql" ? `[${e}]` : `"${e}"`;
|
|
1095
|
-
},
|
|
1096
|
-
let n =
|
|
1109
|
+
}, Ln = (e, t) => {
|
|
1110
|
+
let n = Y(e, t), r = Y(J(e), t);
|
|
1097
1111
|
switch (t) {
|
|
1098
1112
|
case "postgres": return `CREATE TABLE ${r} (LIKE ${n})`;
|
|
1099
1113
|
case "mysql":
|
|
@@ -1101,20 +1115,20 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
1101
1115
|
case "sqlite": return `CREATE TABLE ${r} AS SELECT * FROM ${n} WHERE 0`;
|
|
1102
1116
|
case "mssql": return `SELECT * INTO ${r} FROM ${n} WHERE 1 = 0`;
|
|
1103
1117
|
}
|
|
1104
|
-
},
|
|
1105
|
-
let n =
|
|
1106
|
-
return t === "mssql" ? `IF OBJECT_ID('${
|
|
1107
|
-
},
|
|
1118
|
+
}, Rn = (e, t) => {
|
|
1119
|
+
let n = Y(J(e), t);
|
|
1120
|
+
return t === "mssql" ? `IF OBJECT_ID('${J(e)}', 'U') IS NOT NULL DROP TABLE ${n}` : `DROP TABLE IF EXISTS ${n}`;
|
|
1121
|
+
}, zn = (e, t) => {
|
|
1108
1122
|
let n = t === "mysql" || t === "mariadb", r = [];
|
|
1109
1123
|
n && r.push("SET FOREIGN_KEY_CHECKS = 0");
|
|
1110
|
-
for (let n of [...e].reverse()) r.push(`DELETE FROM ${
|
|
1124
|
+
for (let n of [...e].reverse()) r.push(`DELETE FROM ${Y(n.name, t)}`);
|
|
1111
1125
|
for (let n of e) {
|
|
1112
1126
|
if (n.columns.length === 0) throw Error(`refusing to build a swap for '${n.name}' with no columns: an empty list would have to mean \`SELECT *\`, which is the shape that fails on a generated column.`);
|
|
1113
|
-
let e = n.columns.map((e) =>
|
|
1114
|
-
r.push(`INSERT INTO ${
|
|
1127
|
+
let e = n.columns.map((e) => Y(e, t)).join(", ");
|
|
1128
|
+
r.push(`INSERT INTO ${Y(n.name, t)} (${e}) SELECT ${e} FROM ${Y(J(n.name), t)}`);
|
|
1115
1129
|
}
|
|
1116
1130
|
return n && r.push("SET FOREIGN_KEY_CHECKS = 1"), r;
|
|
1117
|
-
},
|
|
1131
|
+
}, Bn = (e, t) => {
|
|
1118
1132
|
let n = [], r = () => {
|
|
1119
1133
|
for (let e of n) t.unregisterTable(e);
|
|
1120
1134
|
};
|
|
@@ -1122,7 +1136,7 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
1122
1136
|
for (let r of e) {
|
|
1123
1137
|
let e = t.getTable(r);
|
|
1124
1138
|
if (e === void 0) continue;
|
|
1125
|
-
let i =
|
|
1139
|
+
let i = J(r);
|
|
1126
1140
|
t.registerTable({
|
|
1127
1141
|
...e,
|
|
1128
1142
|
tableName: i,
|
|
@@ -1136,7 +1150,7 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
1136
1150
|
staged: n,
|
|
1137
1151
|
undo: r
|
|
1138
1152
|
};
|
|
1139
|
-
},
|
|
1153
|
+
}, Vn = (e, t) => {
|
|
1140
1154
|
let n = new Set(t), r = [];
|
|
1141
1155
|
for (let t of e.tables) {
|
|
1142
1156
|
if (!n.has(t.name)) continue;
|
|
@@ -1153,22 +1167,22 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
1153
1167
|
}
|
|
1154
1168
|
}
|
|
1155
1169
|
return r;
|
|
1156
|
-
},
|
|
1157
|
-
let n =
|
|
1158
|
-
return `SELECT ${
|
|
1159
|
-
},
|
|
1170
|
+
}, Hn = (e, t) => {
|
|
1171
|
+
let n = Y(J(e.from), t), r = Y(J(e.to), t), i = Y(e.column, t), a = Y(e.toColumn, t);
|
|
1172
|
+
return `SELECT ${Y(e.primaryKey, t)} AS pk, ${i} AS value FROM ${n} c WHERE ${i} IS NOT NULL AND NOT EXISTS (SELECT 1 FROM ${r} p WHERE p.${a} = c.${i})`;
|
|
1173
|
+
}, Un = (e) => {
|
|
1160
1174
|
if (e.length === 0) return;
|
|
1161
1175
|
let t = e.slice(0, 20), n = t.map((e) => ` ${e.table}.${e.primaryKey}: ${e.column} = ${JSON.stringify(e.value)} — no such row in ${e.references}`);
|
|
1162
1176
|
return `the swap could not run: ${e.length} row(s) in the bundle reference a row the bundle does not carry.\n${n.join("\n")}\n` + (e.length > t.length ? ` … and ${e.length - t.length} more\n` : "") + " The target is UNCHANGED — the swap runs in one transaction and none of it committed.\n Every offending row is listed above rather than only the first, so this can be fixed in one pass.";
|
|
1163
|
-
},
|
|
1164
|
-
t.length !== 0 && await e.run(
|
|
1165
|
-
},
|
|
1166
|
-
let i =
|
|
1167
|
-
i.length !== 0 && await e.run(
|
|
1168
|
-
},
|
|
1177
|
+
}, Wn = async (e, t) => {
|
|
1178
|
+
t.length !== 0 && await e.run(N.SqlClient.pipe(n.flatMap((e) => n.forEach(t, (t) => e.unsafe(t), { discard: !0 }))));
|
|
1179
|
+
}, Gn = async (e, t, r) => {
|
|
1180
|
+
let i = zn(t, r);
|
|
1181
|
+
i.length !== 0 && await e.run(N.SqlClient.pipe(n.flatMap((e) => e.withTransaction(n.forEach(i, (t) => e.unsafe(t), { discard: !0 })))));
|
|
1182
|
+
}, Kn = async (e, t, r) => {
|
|
1169
1183
|
let i = [];
|
|
1170
1184
|
for (let a of t) {
|
|
1171
|
-
let t = await e.run(
|
|
1185
|
+
let t = await e.run(N.SqlClient.pipe(n.flatMap((e) => e.unsafe(Hn(a, r)))));
|
|
1172
1186
|
for (let e of t) i.push({
|
|
1173
1187
|
table: a.from,
|
|
1174
1188
|
primaryKey: String(e.pk ?? ""),
|
|
@@ -1178,14 +1192,14 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
1178
1192
|
});
|
|
1179
1193
|
}
|
|
1180
1194
|
return i;
|
|
1181
|
-
},
|
|
1195
|
+
}, qn = (e, t) => {
|
|
1182
1196
|
let n = new Map(t.map((e, t) => [e, t]));
|
|
1183
1197
|
return e.filter((e) => {
|
|
1184
1198
|
if (e.from === e.to) return !1;
|
|
1185
1199
|
let t = n.get(e.from), r = n.get(e.to);
|
|
1186
1200
|
return t === void 0 || r === void 0 ? !1 : r > t;
|
|
1187
1201
|
});
|
|
1188
|
-
},
|
|
1202
|
+
}, Jn = (e) => e === "mysql" || e === "mariadb", Yn = (e) => {
|
|
1189
1203
|
if (e.mode !== "replace") return {
|
|
1190
1204
|
active: !1,
|
|
1191
1205
|
tables: [],
|
|
@@ -1235,7 +1249,7 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
1235
1249
|
tables: [],
|
|
1236
1250
|
blocker: "every table in the bundle is one that describes a deployment, so there is nothing for a staged swap to move."
|
|
1237
1251
|
};
|
|
1238
|
-
let s = o.map((e) => e.name), c =
|
|
1252
|
+
let s = o.map((e) => e.name), c = Jn(t) ? [] : qn(Vn(n, s), s);
|
|
1239
1253
|
return c.length > 0 ? {
|
|
1240
1254
|
active: !1,
|
|
1241
1255
|
tables: [],
|
|
@@ -1244,9 +1258,9 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
1244
1258
|
active: !0,
|
|
1245
1259
|
tables: o
|
|
1246
1260
|
};
|
|
1247
|
-
},
|
|
1261
|
+
}, Xn = (e) => n.gen(function* () {
|
|
1248
1262
|
if (e.mode !== "replace" || e.dir === void 0 || e.tables.length === 0) return;
|
|
1249
|
-
if (e.snapshot === void 0) return yield* n.fail(new
|
|
1263
|
+
if (e.snapshot === void 0) return yield* n.fail(new H({
|
|
1250
1264
|
reason: "rollback capture needs the TARGET's schema, and this run has none.\n `--mode replace` empties the target first, so a run without a capture can leave it\n emptied and unfilled if the process does not survive to roll back. Pass the target\n snapshot, or `--no-rollback` to accept that risk deliberately.",
|
|
1251
1265
|
path: e.dir
|
|
1252
1266
|
}));
|
|
@@ -1257,14 +1271,14 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
1257
1271
|
if (t.tables.length === 0) return;
|
|
1258
1272
|
e.onWarn?.(`capturing the target's current rows before emptying it → ${e.dir}\n This is what a failed replace is restored FROM. It is written before the first delete,
|
|
1259
1273
|
so it survives a run whose process does not.`);
|
|
1260
|
-
let r = yield*
|
|
1274
|
+
let r = yield* vn({
|
|
1261
1275
|
store: e.store,
|
|
1262
1276
|
snapshot: t,
|
|
1263
1277
|
dialect: e.dialect ?? "unknown",
|
|
1264
1278
|
outDir: e.dir,
|
|
1265
1279
|
scope: { kind: "all" },
|
|
1266
1280
|
compression: "none"
|
|
1267
|
-
}).pipe(n.mapError((t) => new
|
|
1281
|
+
}).pipe(n.mapError((t) => new H({
|
|
1268
1282
|
reason: `rollback capture failed, so the import did not start and the target is untouched: ${t.reason ?? String(t)}\n Fix the capture, or re-run with \`--no-rollback\` to proceed without one.`,
|
|
1269
1283
|
path: e.dir
|
|
1270
1284
|
})));
|
|
@@ -1273,18 +1287,18 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
1273
1287
|
rows: r.tables.reduce((e, t) => e + t.rowCount, 0),
|
|
1274
1288
|
tables: r.tables.length
|
|
1275
1289
|
};
|
|
1276
|
-
}),
|
|
1290
|
+
}), Zn = (e) => `rollback capture: ${e.rows} row(s) across ${e.tables} table(s) → ${e.dir}\n If this run does not finish, restore with: voltro data import ${e.dir} --mode replace`, Qn = (e, t) => e.tables.find((e) => e.name === t), $n = (e, t) => new Map((Qn(e, t)?.columns ?? []).map((e) => [e.name, e])), er = /__dropped_\d+$/, tr = (e, t) => {
|
|
1277
1291
|
let n = [];
|
|
1278
1292
|
for (let r of [...e.tables].sort((e, t) => e.name.localeCompare(t.name))) {
|
|
1279
|
-
if (
|
|
1293
|
+
if (Qn(t, r.name) === void 0) {
|
|
1280
1294
|
n.push(`table '${r.name}' is in the bundle but MISSING from the target — its rows have nowhere to go`);
|
|
1281
1295
|
continue;
|
|
1282
1296
|
}
|
|
1283
|
-
let e =
|
|
1297
|
+
let e = $n(t, r.name), i = new Map(r.columns.map((e) => [e.name, e]));
|
|
1284
1298
|
for (let [t, a] of i) {
|
|
1285
1299
|
let i = e.get(t);
|
|
1286
1300
|
if (i === void 0) {
|
|
1287
|
-
n.push(
|
|
1301
|
+
n.push(er.test(t) ? `${r.name}.${t}: a soft-dropped column, present only in the SOURCE — reclaim it there (voltro db gc-snapshots --before <date>) or re-export without it; the target is not missing anything` : `${r.name}.${t}: in the bundle, MISSING from the target — the value has nowhere to go`);
|
|
1288
1302
|
continue;
|
|
1289
1303
|
}
|
|
1290
1304
|
i.type !== a.type && n.push(`${r.name}.${t}: type '${a.type}' (bundle) vs '${i.type}' (target)`);
|
|
@@ -1292,22 +1306,22 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
1292
1306
|
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`);
|
|
1293
1307
|
}
|
|
1294
1308
|
return n.length > 30 ? [...n.slice(0, 30), `… and ${n.length - 30} more difference(s)`] : n;
|
|
1295
|
-
},
|
|
1296
|
-
let r =
|
|
1309
|
+
}, nr = (e, t, n) => {
|
|
1310
|
+
let r = w(t);
|
|
1297
1311
|
if (r === e || n === void 0) return {
|
|
1298
1312
|
drifted: !1,
|
|
1299
1313
|
bundleFingerprint: e,
|
|
1300
1314
|
targetFingerprint: r,
|
|
1301
1315
|
diff: []
|
|
1302
1316
|
};
|
|
1303
|
-
let i =
|
|
1317
|
+
let i = tr(n, t);
|
|
1304
1318
|
return {
|
|
1305
1319
|
drifted: i.length > 0,
|
|
1306
1320
|
bundleFingerprint: e,
|
|
1307
1321
|
targetFingerprint: r,
|
|
1308
1322
|
diff: i
|
|
1309
1323
|
};
|
|
1310
|
-
},
|
|
1324
|
+
}, rr = 2e3, ir = 2e3, ar = 200, or = /* @__PURE__ */ new Set([
|
|
1311
1325
|
"BundleError",
|
|
1312
1326
|
"CodecError",
|
|
1313
1327
|
"IntegrityError",
|
|
@@ -1316,33 +1330,33 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
1316
1330
|
"RowsRefusedError",
|
|
1317
1331
|
"SchemaDriftError",
|
|
1318
1332
|
"StorageError"
|
|
1319
|
-
]),
|
|
1333
|
+
]), sr = (t) => {
|
|
1320
1334
|
let n = o.isFiberFailure(t) ? [...e.failures(t[o.FiberFailureCauseId]), ...e.defects(t[o.FiberFailureCauseId])] : [t];
|
|
1321
1335
|
for (let e of n) {
|
|
1322
1336
|
let t = e?._tag;
|
|
1323
|
-
if (typeof t == "string" &&
|
|
1337
|
+
if (typeof t == "string" && or.has(t)) return e;
|
|
1324
1338
|
if (o.isFiberFailure(e)) {
|
|
1325
|
-
let t =
|
|
1339
|
+
let t = sr(e);
|
|
1326
1340
|
if (t) return t;
|
|
1327
1341
|
}
|
|
1328
1342
|
}
|
|
1329
|
-
},
|
|
1343
|
+
}, cr = (t) => [...e.failures(t)][0] ?? Error(e.pretty(t)), lr = (e) => n.tryPromise({
|
|
1330
1344
|
try: async () => {
|
|
1331
1345
|
let t = await import("node:fs/promises"), n = await import("node:path");
|
|
1332
|
-
return
|
|
1346
|
+
return At(await t.readFile(n.join(e, jt), "utf8"));
|
|
1333
1347
|
},
|
|
1334
|
-
catch: (e) => new
|
|
1348
|
+
catch: (e) => new H({
|
|
1335
1349
|
reason: `manifest read/parse failed: ${String(e?.message ?? e)}`,
|
|
1336
|
-
path:
|
|
1350
|
+
path: jt
|
|
1337
1351
|
})
|
|
1338
|
-
}),
|
|
1352
|
+
}), ur = (e) => {
|
|
1339
1353
|
let t;
|
|
1340
1354
|
return n.gen(function* () {
|
|
1341
|
-
let i = yield* n.promise(() => import("node:path")), a = yield*
|
|
1342
|
-
if (a.formatVersion !== 1) return yield* n.fail(new
|
|
1355
|
+
let i = yield* n.promise(() => import("node:path")), a = yield* lr(e.bundleDir);
|
|
1356
|
+
if (a.formatVersion !== 1) return yield* n.fail(new H({ reason: `unsupported bundle formatVersion ${a.formatVersion} (expected 1)` }));
|
|
1343
1357
|
if (e.tables !== void 0) {
|
|
1344
1358
|
let t = new Set(a.tables.map((e) => e.name)), r = e.tables.filter((e) => !t.has(e));
|
|
1345
|
-
if (r.length > 0) return yield* n.fail(new
|
|
1359
|
+
if (r.length > 0) return yield* n.fail(new H({ reason: `--tables names ${r.length} table(s) this bundle does not carry: ${r.join(", ")}. The bundle carries: ${[...t].sort().join(", ")}.` }));
|
|
1346
1360
|
}
|
|
1347
1361
|
let o = e.tables === void 0 ? void 0 : new Set(e.tables), s = o === void 0 ? a : {
|
|
1348
1362
|
...a,
|
|
@@ -1359,9 +1373,9 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
1359
1373
|
unique: !1,
|
|
1360
1374
|
hasDefault: !1
|
|
1361
1375
|
}))
|
|
1362
|
-
})) }, r =
|
|
1376
|
+
})) }, r = nr(s.source.schemaFingerprint, e.targetSnapshot, t);
|
|
1363
1377
|
if (r.drifted) {
|
|
1364
|
-
if (!e.force) return yield* n.fail(new
|
|
1378
|
+
if (!e.force) return yield* n.fail(new et({
|
|
1365
1379
|
bundleFingerprint: r.bundleFingerprint,
|
|
1366
1380
|
targetFingerprint: r.targetFingerprint,
|
|
1367
1381
|
diff: r.diff
|
|
@@ -1370,15 +1384,15 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
1370
1384
|
}
|
|
1371
1385
|
}
|
|
1372
1386
|
if (e.targetDialect && e.targetDialect !== s.source.dialect) {
|
|
1373
|
-
let t =
|
|
1374
|
-
if (t.length > 0 && !e.allowIncompatible) return yield* n.fail(new
|
|
1387
|
+
let t = wn(s.tables, s.source.dialect, e.targetDialect).filter((e) => e.severity === "block");
|
|
1388
|
+
if (t.length > 0 && !e.allowIncompatible) return yield* n.fail(new rt({
|
|
1375
1389
|
sourceDialect: s.source.dialect,
|
|
1376
1390
|
targetDialect: e.targetDialect,
|
|
1377
|
-
blocking: t.map(
|
|
1391
|
+
blocking: t.map(Tn)
|
|
1378
1392
|
}));
|
|
1379
1393
|
}
|
|
1380
|
-
let c = e.verify ?? !0, f = e.mode ?? "upsert", m = e.atomic ?? f === "replace", _ = e.onConflict ?? "skip", v = e.ledgerPath ?? i.join(e.bundleDir, ".import..ledger.json"), b = yield*
|
|
1381
|
-
if (f === "replace" && s.scope.kind !== "all") return yield* n.fail(new
|
|
1394
|
+
let c = e.verify ?? !0, f = e.mode ?? "upsert", m = e.atomic ?? f === "replace", _ = e.onConflict ?? "skip", v = e.ledgerPath ?? i.join(e.bundleDir, ".import..ledger.json"), b = yield* Wt(v);
|
|
1395
|
+
if (f === "replace" && s.scope.kind !== "all") return yield* n.fail(new nt({
|
|
1382
1396
|
mode: f,
|
|
1383
1397
|
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. To leave specific tables out of a FULL export, use \`--exclude a,b\`: it keeps the scope \`all\` and records what it left out.`
|
|
1384
1398
|
}));
|
|
@@ -1390,8 +1404,8 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
1390
1404
|
if (f === "replace") {
|
|
1391
1405
|
let t = s.tables.map((e) => e.name), r = e.store.incomingForeignKeys ? yield* n.tryPromise({
|
|
1392
1406
|
try: () => e.store.incomingForeignKeys(t),
|
|
1393
|
-
catch: (e) => new
|
|
1394
|
-
}) : e.targetSnapshot === void 0 ? [] :
|
|
1407
|
+
catch: (e) => new H({ reason: `foreign-key pre-flight failed: ${Mn(e)}` })
|
|
1408
|
+
}) : e.targetSnapshot === void 0 ? [] : yn(e.targetSnapshot, t), i = [], a = /* @__PURE__ */ new Map();
|
|
1395
1409
|
for (let t of r) {
|
|
1396
1410
|
if (!a.has(t.from)) {
|
|
1397
1411
|
let r = yield* n.tryPromise({
|
|
@@ -1403,7 +1417,7 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
1403
1417
|
skip: void 0,
|
|
1404
1418
|
projection: []
|
|
1405
1419
|
}),
|
|
1406
|
-
catch: () => new
|
|
1420
|
+
catch: () => new H({ reason: `unreadable: ${t.from}` })
|
|
1407
1421
|
}).pipe(n.map((e) => e.length), n.orElseSucceed(() => 0));
|
|
1408
1422
|
a.set(t.from, r);
|
|
1409
1423
|
}
|
|
@@ -1413,9 +1427,9 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
1413
1427
|
rowCount: r
|
|
1414
1428
|
});
|
|
1415
1429
|
}
|
|
1416
|
-
if (i.length > 0) return yield* n.fail(new
|
|
1430
|
+
if (i.length > 0) return yield* n.fail(new nt({
|
|
1417
1431
|
mode: f,
|
|
1418
|
-
reason:
|
|
1432
|
+
reason: bn(i)
|
|
1419
1433
|
}));
|
|
1420
1434
|
}
|
|
1421
1435
|
if (e.dryRun === !0) return e.traceId !== void 0 && (yield* n.promise(() => e.store.update(u, e.traceId, {
|
|
@@ -1436,27 +1450,35 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
1436
1450
|
let e = t.columns.filter((e) => e.generatedAs !== void 0).map((e) => e.name);
|
|
1437
1451
|
e.length > 0 && S.set(t.name, e);
|
|
1438
1452
|
}
|
|
1439
|
-
let
|
|
1453
|
+
let C = (e, t) => {
|
|
1440
1454
|
let n = S.get(e);
|
|
1441
1455
|
if (n === void 0) return t;
|
|
1442
1456
|
let r;
|
|
1443
1457
|
for (let e of n) e in t && (r ??= { ...t }, delete r[e]);
|
|
1444
1458
|
return r ?? t;
|
|
1445
|
-
},
|
|
1446
|
-
let i = O ?
|
|
1459
|
+
}, w = (e, t, n, r = !1) => {
|
|
1460
|
+
let i = O ? J(t.name) : t.name, a = t.primaryKey, o = oe(t.name, C(t.name, n), t.columnTypes);
|
|
1447
1461
|
return f === "append" ? _ === "fail" ? e.insert(i, o) : e.insertIgnore(i, o, { conflictColumns: [a] }) : f === "replace" ? r ? e.upsert(i, o, { conflictColumns: [a] }) : e.insert(i, o) : e.upsert(i, o, { conflictColumns: [a] });
|
|
1448
|
-
},
|
|
1449
|
-
|
|
1450
|
-
|
|
1462
|
+
}, ae = e.targetDialect !== void 0 && e.targetDialect !== "memory", oe = (e, t, n) => {
|
|
1463
|
+
if (!ae || n === void 0 || y(e) !== void 0) return t;
|
|
1464
|
+
let r = null;
|
|
1465
|
+
for (let [e, i] of Object.entries(n)) {
|
|
1466
|
+
let n = t[e];
|
|
1467
|
+
i === "json" && n != null && (r === null && (r = { ...t }), r[e] = JSON.stringify(n));
|
|
1468
|
+
}
|
|
1469
|
+
return r ?? t;
|
|
1470
|
+
}, T = (e, t) => e.savepoint ? e.savepoint(t) : t(), se = 0, ce = (t, n, r) => {
|
|
1471
|
+
r.unclassified && (se++, !(se > 3) && e.onWarn?.(`row refused with no driver detail — table '${t.name}', row '${String(n.id ?? "?")}'. The full rendering follows so the LAYER that refused is on the record; it is logged, never returned. ${r.raw}` + (se === 3 ? " (further unclassified refusals are counted, not logged)" : "")));
|
|
1472
|
+
}, le = (e, t, r = !0) => n.tryPromise({
|
|
1451
1473
|
try: e,
|
|
1452
|
-
catch: (e) =>
|
|
1453
|
-
}).pipe(n.map(() => !0), n.catchAll((e) => n.sync(() => (r && (t.reason = e.reason,
|
|
1474
|
+
catch: (e) => An(e)
|
|
1475
|
+
}).pipe(n.map(() => !0), n.catchAll((e) => n.sync(() => (r && (t.reason = e.reason, ce(t.entry, t.row, e)), !1)))), ue = (e) => {
|
|
1454
1476
|
let t = Object.entries(e.entry.columnTypes).filter(([t, n]) => n === "reference" && e.row[t] !== null && e.row[t] !== void 0).map(([e]) => e);
|
|
1455
1477
|
if (t.length !== 0) return {
|
|
1456
1478
|
...e.row,
|
|
1457
1479
|
...Object.fromEntries(t.map((e) => [e, null]))
|
|
1458
1480
|
};
|
|
1459
|
-
},
|
|
1481
|
+
}, de = (e) => {
|
|
1460
1482
|
let t = new Set(e.map((e) => String(e.row[e.entry.primaryKey]))), n = (e) => Object.entries(e.entry.columnTypes).some(([n, r]) => {
|
|
1461
1483
|
if (r !== "reference") return !1;
|
|
1462
1484
|
let i = e.row[n];
|
|
@@ -1474,7 +1496,7 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
1474
1496
|
};
|
|
1475
1497
|
t.refused++, e.derived || t.primary++, a.set(e.table, t);
|
|
1476
1498
|
}
|
|
1477
|
-
return new
|
|
1499
|
+
return new $e({
|
|
1478
1500
|
rows: i.slice(0, 20),
|
|
1479
1501
|
primaryCount: r.filter((e) => !e.derived).length,
|
|
1480
1502
|
totalCount: e.length,
|
|
@@ -1484,62 +1506,62 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
1484
1506
|
primary: t.primary
|
|
1485
1507
|
})).sort((e, t) => t.refused - e.refused || e.table.localeCompare(t.table)).slice(0, 100)
|
|
1486
1508
|
});
|
|
1487
|
-
},
|
|
1509
|
+
}, pe = (e, t) => n.gen(function* () {
|
|
1488
1510
|
let r = t, i = [], a = !0;
|
|
1489
1511
|
for (; r.length > 0 && a;) {
|
|
1490
1512
|
a = !1;
|
|
1491
1513
|
let t = [];
|
|
1492
|
-
for (let n of r) (yield*
|
|
1514
|
+
for (let n of r) (yield* le(() => T(e, () => w(e, n.entry, n.row, !0)), n)) ? a = !0 : t.push(n);
|
|
1493
1515
|
if (!a && t.length > 0) for (let n = t.length - 1; n >= 0; n--) {
|
|
1494
|
-
let r = t[n], o =
|
|
1495
|
-
o !== void 0 && (yield*
|
|
1516
|
+
let r = t[n], o = ue(r);
|
|
1517
|
+
o !== void 0 && (yield* le(() => T(e, () => w(e, r.entry, o, !0)), r, !1)) && (i.push(r), t.splice(n, 1), a = !0);
|
|
1496
1518
|
}
|
|
1497
1519
|
r = t;
|
|
1498
1520
|
}
|
|
1499
|
-
for (let t of i) (yield*
|
|
1500
|
-
if (r.length > 0) return yield* n.fail(
|
|
1521
|
+
for (let t of i) (yield* le(() => T(e, () => e.upsert(t.entry.name, oe(t.entry.name, t.row, t.entry.columnTypes), { conflictColumns: [t.entry.primaryKey] })), t)) || (r = [...r, t]);
|
|
1522
|
+
if (r.length > 0) return yield* n.fail(de(r));
|
|
1501
1523
|
}), E = (() => {
|
|
1502
1524
|
let t = e.targetDialect;
|
|
1503
1525
|
return t === "postgres" || t === "mysql" || t === "mariadb" || t === "sqlite" || t === "mssql" ? t : void 0;
|
|
1504
|
-
})(), D =
|
|
1526
|
+
})(), D = Yn({
|
|
1505
1527
|
mode: f,
|
|
1506
1528
|
...e.targetDialect === void 0 ? {} : { targetDialect: e.targetDialect },
|
|
1507
1529
|
...e.targetSnapshot === void 0 ? {} : { targetSnapshot: e.targetSnapshot },
|
|
1508
1530
|
bundleTables: s.tables.map((e) => e.name),
|
|
1509
|
-
isSkipped:
|
|
1510
|
-
canRunSql:
|
|
1511
|
-
}),
|
|
1531
|
+
isSkipped: V,
|
|
1532
|
+
canRunSql: Pn(e.store)
|
|
1533
|
+
}), me = D.tables, he = s.tables.filter((e) => !V(e.name) && ee(e.name)).map((e) => e.name), O = D.active, _e = !1, k = 0, A = 0, j, M, ve = 0, N = 0, P = (t, r) => n.gen(function* () {
|
|
1512
1534
|
if (f === "replace" && !O && !(r && b.truncated)) {
|
|
1513
1535
|
e.recordInterruption === !0 && (yield* n.tryPromise({
|
|
1514
1536
|
try: () => t.insert(d, {
|
|
1515
|
-
id: h("repl",
|
|
1516
|
-
startedAt:
|
|
1537
|
+
id: h("repl", ye),
|
|
1538
|
+
startedAt: be,
|
|
1517
1539
|
tables: String(s.tables.length),
|
|
1518
|
-
capture:
|
|
1540
|
+
capture: F?.dir ?? null,
|
|
1519
1541
|
via: e.via ?? "direct"
|
|
1520
1542
|
}),
|
|
1521
|
-
catch: (e) => new
|
|
1543
|
+
catch: (e) => new H({ reason: `could not record that this replace started: ${String(e?.message ?? e)}\n The marker is what makes an interrupted run visible instead of silent, so the run does
|
|
1522
1544
|
not proceed without it.` })
|
|
1523
1545
|
}));
|
|
1524
|
-
let i = [...s.tables].reverse().map((e) => e.name).filter((e) => !
|
|
1546
|
+
let i = [...s.tables].reverse().map((e) => e.name).filter((e) => !V(e)), a = !r, o = t.emptyTables ? () => t.emptyTables(i) : a ? async () => {
|
|
1525
1547
|
for (let e of [...s.tables].reverse()) await t.deleteMany(e.name, { where: x(e.primaryKey) });
|
|
1526
1548
|
} : () => t.transactional(async (e) => {
|
|
1527
1549
|
for (let t of [...s.tables].reverse()) await e.deleteMany(t.name, { where: x(t.primaryKey) });
|
|
1528
1550
|
});
|
|
1529
1551
|
yield* n.tryPromise({
|
|
1530
1552
|
try: o,
|
|
1531
|
-
catch: (e) => new
|
|
1532
|
-
}), r && (b.truncated = !0, yield*
|
|
1553
|
+
catch: (e) => new H({ reason: `emptying the target for --mode replace failed (nothing was deleted): ${Mn(e)}` })
|
|
1554
|
+
}), r && (b.truncated = !0, yield* K(v, b));
|
|
1533
1555
|
}
|
|
1534
1556
|
let a = [], o = [], u = [], p = [], g = s.tables.length;
|
|
1535
1557
|
for (let d = 0; d < s.tables.length; d++) {
|
|
1536
1558
|
let h = s.tables[d];
|
|
1537
|
-
if (
|
|
1559
|
+
if (V(h.name)) {
|
|
1538
1560
|
p.push(h.name);
|
|
1539
1561
|
continue;
|
|
1540
1562
|
}
|
|
1541
1563
|
if (r && h.name in b.tables) {
|
|
1542
|
-
u.push(h.name),
|
|
1564
|
+
u.push(h.name), N++, ve += b.tables[h.name].rowCount, G(e.onProgress, {
|
|
1543
1565
|
phase: "import",
|
|
1544
1566
|
table: h.name,
|
|
1545
1567
|
index: d,
|
|
@@ -1551,7 +1573,7 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
1551
1573
|
continue;
|
|
1552
1574
|
}
|
|
1553
1575
|
let _ = i.join(e.bundleDir, h.file);
|
|
1554
|
-
|
|
1576
|
+
G(e.onProgress, {
|
|
1555
1577
|
phase: "import",
|
|
1556
1578
|
table: h.name,
|
|
1557
1579
|
index: d,
|
|
@@ -1561,22 +1583,22 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
1561
1583
|
total: h.rowCount
|
|
1562
1584
|
});
|
|
1563
1585
|
let y = a.length, x = n.gen(function* () {
|
|
1564
|
-
let { createHash: r } = yield* n.promise(() => import("node:crypto")), i = r("sha256"), o = 0, c =
|
|
1586
|
+
let { createHash: r } = yield* n.promise(() => import("node:crypto")), i = r("sha256"), o = 0, c = ge("bundle", () => fe(_).pipe(Ct(s.compression))).pipe(l.tap((e) => n.sync(() => i.update(e)))), u = async (e) => {
|
|
1565
1587
|
let n = {
|
|
1566
1588
|
entry: h,
|
|
1567
1589
|
row: e,
|
|
1568
1590
|
reason: ""
|
|
1569
1591
|
};
|
|
1570
1592
|
try {
|
|
1571
|
-
await
|
|
1593
|
+
await T(t, () => w(t, h, e));
|
|
1572
1594
|
} catch (t) {
|
|
1573
|
-
let r =
|
|
1574
|
-
n.reason = r.reason,
|
|
1595
|
+
let r = An(t);
|
|
1596
|
+
n.reason = r.reason, ce(h, e, r), a.push(n);
|
|
1575
1597
|
}
|
|
1576
1598
|
}, d = yield* n.promise(async () => {
|
|
1577
1599
|
let n = e.copyLoader;
|
|
1578
1600
|
if (!n || n.dialect !== "postgres") return !1;
|
|
1579
|
-
if (m) return
|
|
1601
|
+
if (m) return _e || (_e = !0, e.onWarn?.("bulk COPY is off for this run: it needs its own connection and this import runs in ONE transaction (the default for --mode replace, so a failure mid-load cannot leave the target emptied and unfilled). Pass --no-atomic to trade that guarantee back for COPY.")), !1;
|
|
1580
1602
|
if (f === "replace") return !0;
|
|
1581
1603
|
if (f !== "upsert") return !1;
|
|
1582
1604
|
try {
|
|
@@ -1606,46 +1628,46 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
1606
1628
|
d = !1, e.onWarn?.(`bulk COPY into ${h.name} failed (${String(n?.message ?? n)}); falling back to per-row writes for this table`);
|
|
1607
1629
|
for (let e of t) await u(e);
|
|
1608
1630
|
}
|
|
1609
|
-
}, b = Math.max(1, e.savepointBatchSize ?? 200), x = typeof t.savepoint == "function", S = [],
|
|
1631
|
+
}, b = Math.max(1, e.savepointBatchSize ?? 200), x = typeof t.savepoint == "function", S = [], ee = async () => {
|
|
1610
1632
|
if (S.length === 0) return;
|
|
1611
1633
|
let e = S;
|
|
1612
1634
|
S = [];
|
|
1613
1635
|
try {
|
|
1614
1636
|
await t.savepoint(async () => {
|
|
1615
|
-
for (let n of e) await
|
|
1637
|
+
for (let n of e) await w(t, h, n);
|
|
1616
1638
|
});
|
|
1617
1639
|
} catch {
|
|
1618
1640
|
for (let t of e) await u(t);
|
|
1619
1641
|
}
|
|
1620
1642
|
};
|
|
1621
|
-
return yield* l.runForEach(
|
|
1643
|
+
return yield* l.runForEach(on(c, h.name, h.columnTypes), (e) => n.promise(async () => {
|
|
1622
1644
|
if (o++, M?.(), d) {
|
|
1623
1645
|
v.push(e), v.length >= g && await y();
|
|
1624
1646
|
return;
|
|
1625
1647
|
}
|
|
1626
1648
|
if (x) {
|
|
1627
|
-
S.push(e), S.length >= b && await
|
|
1649
|
+
S.push(e), S.length >= b && await ee();
|
|
1628
1650
|
return;
|
|
1629
1651
|
}
|
|
1630
1652
|
await u(e);
|
|
1631
|
-
})), yield* n.promise(
|
|
1653
|
+
})), yield* n.promise(ee), yield* n.promise(y), {
|
|
1632
1654
|
rowCount: o,
|
|
1633
1655
|
checksum: i.digest("hex")
|
|
1634
1656
|
};
|
|
1635
|
-
}), { rowCount: S, checksum:
|
|
1657
|
+
}), { rowCount: S, checksum: ee } = yield* Ht("import", h.name, d, g, (e) => e.rowCount, x);
|
|
1636
1658
|
if (c) {
|
|
1637
|
-
if (
|
|
1659
|
+
if (ee !== h.checksum) return yield* n.fail(new Ze({
|
|
1638
1660
|
what: `table ${h.name} checksum`,
|
|
1639
1661
|
expected: h.checksum,
|
|
1640
|
-
actual:
|
|
1662
|
+
actual: ee
|
|
1641
1663
|
}));
|
|
1642
|
-
if (S !== h.rowCount) return yield* n.fail(new
|
|
1664
|
+
if (S !== h.rowCount) return yield* n.fail(new Ze({
|
|
1643
1665
|
what: `table ${h.name} rowCount`,
|
|
1644
1666
|
expected: String(h.rowCount),
|
|
1645
1667
|
actual: String(S)
|
|
1646
1668
|
}));
|
|
1647
1669
|
}
|
|
1648
|
-
|
|
1670
|
+
G(e.onProgress, {
|
|
1649
1671
|
phase: "import",
|
|
1650
1672
|
table: h.name,
|
|
1651
1673
|
index: d,
|
|
@@ -1653,18 +1675,18 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
1653
1675
|
event: "done",
|
|
1654
1676
|
rowsDone: S,
|
|
1655
1677
|
total: h.rowCount
|
|
1656
|
-
}),
|
|
1678
|
+
}), A++, k += S, j?.(), M?.(), r && (a.length > y ? o.push({
|
|
1657
1679
|
name: h.name,
|
|
1658
1680
|
rowCount: S
|
|
1659
1681
|
}) : (b.tables[h.name] = {
|
|
1660
1682
|
rowCount: S,
|
|
1661
1683
|
checksum: h.checksum
|
|
1662
|
-
}, yield*
|
|
1684
|
+
}, yield* K(v, b)));
|
|
1663
1685
|
}
|
|
1664
|
-
if (a.length > 0 && (yield*
|
|
1686
|
+
if (a.length > 0 && (yield* pe(t, a)), f === "replace" && (yield* n.promise(() => t.deleteMany(d, { where: {
|
|
1665
1687
|
column: "startedAt",
|
|
1666
1688
|
op: "lte",
|
|
1667
|
-
value:
|
|
1689
|
+
value: be
|
|
1668
1690
|
} }).then(() => void 0, () => void 0))), r && o.length > 0) {
|
|
1669
1691
|
for (let e of o) {
|
|
1670
1692
|
let t = s.tables.find((t) => t.name === e.name);
|
|
@@ -1673,35 +1695,35 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
1673
1695
|
checksum: t.checksum
|
|
1674
1696
|
};
|
|
1675
1697
|
}
|
|
1676
|
-
yield*
|
|
1698
|
+
yield* K(v, b);
|
|
1677
1699
|
}
|
|
1678
1700
|
{
|
|
1679
|
-
let t =
|
|
1701
|
+
let t = Ye(p, "skipped");
|
|
1680
1702
|
t !== void 0 && e.onWarn?.(t);
|
|
1681
1703
|
}
|
|
1682
1704
|
if (u.length > 0) {
|
|
1683
1705
|
let t = u.length === s.tables.length;
|
|
1684
1706
|
e.onWarn?.(`resume: ${u.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${t ? " — that is every table in the bundle, so nothing was written at all" : ""}. Tables: ${u.join(", ")}. Delete ${v} to force a full re-import.`);
|
|
1685
1707
|
}
|
|
1686
|
-
}),
|
|
1708
|
+
}), ye = `${Date.now().toString(36)}${Math.random().toString(36).slice(2, 8)}`, be = /* @__PURE__ */ new Date(), F = yield* Xn({
|
|
1687
1709
|
store: e.store,
|
|
1688
1710
|
mode: f,
|
|
1689
1711
|
dir: e.rollbackDir,
|
|
1690
1712
|
snapshot: e.targetSnapshot,
|
|
1691
1713
|
dialect: e.targetDialect,
|
|
1692
|
-
tables: s.tables.map((e) => e.name).filter((e) => !
|
|
1714
|
+
tables: s.tables.map((e) => e.name).filter((e) => !V(e)),
|
|
1693
1715
|
onWarn: e.onWarn
|
|
1694
1716
|
});
|
|
1695
|
-
|
|
1696
|
-
try: () => e.onRollbackCaptured(
|
|
1697
|
-
catch: (e) => new
|
|
1717
|
+
F !== void 0 && (e.onRollbackCaptured !== void 0 && (yield* n.tryPromise({
|
|
1718
|
+
try: () => e.onRollbackCaptured(F),
|
|
1719
|
+
catch: (e) => new H({
|
|
1698
1720
|
reason: `the rollback capture could not be stored durably, so the import did not start and the target is untouched: ${String(e?.message ?? e)}\n The capture only helps if it outlives this process — that is the failure it exists for.`,
|
|
1699
|
-
path:
|
|
1721
|
+
path: F.dir
|
|
1700
1722
|
})
|
|
1701
|
-
})), e.onWarn?.(
|
|
1702
|
-
let
|
|
1703
|
-
|
|
1704
|
-
id:
|
|
1723
|
+
})), e.onWarn?.(Zn(F)));
|
|
1724
|
+
let xe = (e) => f === "replace" ? ne(e) : e(), Se = (e) => f === "replace" ? re(e) : e, I = e.traceId ?? h("dimp", `${Date.now()}-${s.source.schemaFingerprint ?? ""}`), L = e.traceId !== void 0, Ce = (e.targetSnapshot?.tables.some((e) => e.name === u) ?? !1) || y(u) !== void 0;
|
|
1725
|
+
Ce && g(p), Ce && e.traceId === void 0 && (yield* n.promise(() => e.store.insert(u, {
|
|
1726
|
+
id: I,
|
|
1705
1727
|
mode: f,
|
|
1706
1728
|
via: e.via ?? "direct",
|
|
1707
1729
|
direction: "import",
|
|
@@ -1711,45 +1733,45 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
1711
1733
|
rowsWritten: 0,
|
|
1712
1734
|
staged: f === "replace" ? O : null
|
|
1713
1735
|
}).then(() => {
|
|
1714
|
-
|
|
1736
|
+
L = !0;
|
|
1715
1737
|
}, (t) => {
|
|
1716
1738
|
e.onWarn?.(`the import trace could not be written (${String(t?.message ?? t)}).\n The import continues — this is a record of what happened, not a safety check. Run
|
|
1717
1739
|
\`voltro db apply\` so the next one is recorded.`);
|
|
1718
|
-
}))), e.traceId !== void 0 &&
|
|
1740
|
+
}))), e.traceId !== void 0 && Ce && (yield* n.promise(() => e.store.update(u, I, {
|
|
1719
1741
|
staged: f === "replace" ? O : null,
|
|
1720
1742
|
sourceFingerprint: s.source.schemaFingerprint ?? null
|
|
1721
1743
|
}).then(() => void 0, () => void 0)));
|
|
1722
|
-
let
|
|
1723
|
-
|
|
1724
|
-
if (!
|
|
1744
|
+
let we = 0, Te = !1;
|
|
1745
|
+
j = () => {
|
|
1746
|
+
if (!L || Te) return;
|
|
1725
1747
|
let t = Date.now();
|
|
1726
|
-
t -
|
|
1727
|
-
tablesWritten:
|
|
1728
|
-
rowsWritten:
|
|
1748
|
+
t - we < rr || (we = t, e.store.update(u, I, {
|
|
1749
|
+
tablesWritten: A,
|
|
1750
|
+
rowsWritten: k
|
|
1729
1751
|
}).then(() => void 0, () => {
|
|
1730
|
-
|
|
1752
|
+
Te = !0;
|
|
1731
1753
|
}));
|
|
1732
1754
|
};
|
|
1733
|
-
let
|
|
1755
|
+
let Ee = (t) => L ? e.store.update(u, I, {
|
|
1734
1756
|
finishedAt: t === null ? /* @__PURE__ */ new Date() : null,
|
|
1735
|
-
tablesWritten:
|
|
1736
|
-
rowsWritten:
|
|
1757
|
+
tablesWritten: A,
|
|
1758
|
+
rowsWritten: k,
|
|
1737
1759
|
failure: t
|
|
1738
1760
|
}).then(() => void 0, () => void 0) : Promise.resolve();
|
|
1739
|
-
if (t = (e) =>
|
|
1761
|
+
if (t = (e) => Ee(e), f === "replace" && !O && D.blocker !== void 0 && e.onWarn?.(Fn(D.blocker)), f === "replace" && he.length > 0 && e.onWarn?.(`write recorders are SUSPENDED for this replace (${he.length} table(s) have one).\n A replace sets a state rather than changing rows, so a per-row history entry would describe
|
|
1740
1762
|
something that did not happen — and this path already writes through the raw store, without
|
|
1741
1763
|
tenant scoping or \`audit()\` stamping, for the same reason.`), O) {
|
|
1742
|
-
e.onWarn?.(`staging ${
|
|
1743
|
-
let t = e.store, r =
|
|
1764
|
+
e.onWarn?.(`staging ${me.length} table(s) before the swap — the target keeps its rows until the load stands.\n The destructive step is one server-side transaction at the end, not the whole load.`);
|
|
1765
|
+
let t = e.store, r = me.map((e) => e.name), i = h("repl", `staging-${ye}`), a = !1;
|
|
1744
1766
|
if (e.recordInterruption === !0) {
|
|
1745
1767
|
yield* n.promise(() => e.store.insert(d, {
|
|
1746
1768
|
id: i,
|
|
1747
|
-
startedAt:
|
|
1769
|
+
startedAt: be,
|
|
1748
1770
|
kind: "staging",
|
|
1749
|
-
tables: String(
|
|
1750
|
-
capture:
|
|
1771
|
+
tables: String(me.length),
|
|
1772
|
+
capture: F?.dir ?? null,
|
|
1751
1773
|
via: e.via ?? "direct",
|
|
1752
|
-
staging: r.map(
|
|
1774
|
+
staging: r.map(J).join(","),
|
|
1753
1775
|
heartbeatAt: /* @__PURE__ */ new Date(),
|
|
1754
1776
|
resumable: !m
|
|
1755
1777
|
}).then(() => {
|
|
@@ -1763,76 +1785,76 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
1763
1785
|
M = () => {
|
|
1764
1786
|
if (!a) return;
|
|
1765
1787
|
let n = Date.now();
|
|
1766
|
-
n - t <
|
|
1788
|
+
n - t < ir || (t = n, e.store.update(d, i, { heartbeatAt: /* @__PURE__ */ new Date() }).then(() => void 0, () => void 0));
|
|
1767
1789
|
};
|
|
1768
1790
|
}
|
|
1769
|
-
let o = () => a ? e.store.delete(d, i).then(() => void 0, () => void 0) : Promise.resolve(), s =
|
|
1791
|
+
let o = () => a ? e.store.delete(d, i).then(() => void 0, () => void 0) : Promise.resolve(), s = Bn(r, {
|
|
1770
1792
|
getTable: (e) => y(e),
|
|
1771
1793
|
registerTable: (e) => {
|
|
1772
|
-
|
|
1794
|
+
te(e);
|
|
1773
1795
|
},
|
|
1774
|
-
unregisterTable:
|
|
1796
|
+
unregisterTable: ie
|
|
1775
1797
|
}), c = !1;
|
|
1776
1798
|
try {
|
|
1777
|
-
let i = m ? r : r.filter((e) => !
|
|
1799
|
+
let i = m ? r : r.filter((e) => !Gt(b, e));
|
|
1778
1800
|
yield* n.tryPromise({
|
|
1779
1801
|
try: async () => {
|
|
1780
|
-
await
|
|
1802
|
+
await Wn(t, i.map((e) => Rn(e, E))), await Wn(t, i.map((e) => Ln(e, E)));
|
|
1781
1803
|
},
|
|
1782
|
-
catch: (e) => new
|
|
1783
|
-
}), yield*
|
|
1784
|
-
try: () =>
|
|
1804
|
+
catch: (e) => new H({ reason: `could not prepare the staging tables, so the import did not start and the target is untouched: ${String(e?.message ?? e)}` })
|
|
1805
|
+
}), yield* Se(P(e.store, !m)), !m && b.truncated === !0 ? c = !0 : yield* n.tryPromise({
|
|
1806
|
+
try: () => Gn(t, me, E).then(() => {
|
|
1785
1807
|
c = !0;
|
|
1786
1808
|
}),
|
|
1787
|
-
catch: (e) => new
|
|
1809
|
+
catch: (e) => new H({ reason: String(e?.message ?? e) })
|
|
1788
1810
|
}).pipe(n.catchAll((i) => n.gen(function* () {
|
|
1789
|
-
let a =
|
|
1790
|
-
return yield* n.fail(new
|
|
1791
|
-
}))), !m && c && b.truncated !== !0 && (b.truncated = !0, yield*
|
|
1811
|
+
let a = Un(yield* n.promise(() => Kn(t, Vn(e.targetSnapshot, r), E).then((e) => e, () => [])));
|
|
1812
|
+
return yield* n.fail(new H({ reason: a ?? `the swap failed and the target is UNCHANGED: ${i.reason}` }));
|
|
1813
|
+
}))), !m && c && b.truncated !== !0 && (b.truncated = !0, yield* K(v, b));
|
|
1792
1814
|
} finally {
|
|
1793
|
-
s.undo(), c || m ? (M = void 0, yield* n.promise(() =>
|
|
1815
|
+
s.undo(), c || m ? (M = void 0, yield* n.promise(() => Wn(t, r.map((e) => Rn(e, E))).then(() => void 0, () => void 0)), yield* n.promise(o)) : e.onWarn?.("the staged rows are KEPT so a re-run can continue from them rather than reload.\n If you are not going to re-run this bundle, drop them: voltro data clear-staging --yes");
|
|
1794
1816
|
}
|
|
1795
1817
|
} else m ? yield* n.tryPromise({
|
|
1796
1818
|
try: () => e.store.transactional(async (e) => {
|
|
1797
|
-
let t = await
|
|
1798
|
-
if (r.isFailure(t)) throw
|
|
1819
|
+
let t = await xe(() => n.runPromiseExit(P(e, !1)));
|
|
1820
|
+
if (r.isFailure(t)) throw cr(t.cause);
|
|
1799
1821
|
}),
|
|
1800
|
-
catch: (e) =>
|
|
1801
|
-
}) : yield*
|
|
1822
|
+
catch: (e) => sr(e) ?? new H({ reason: `atomic import failed (rolled back): ${String(e?.message ?? e)}` })
|
|
1823
|
+
}) : yield* Se(P(e.store, !0));
|
|
1802
1824
|
if (e.assets && s.assets.index && !e.assetsAlreadyRestored) {
|
|
1803
1825
|
let t = e.assets;
|
|
1804
|
-
yield*
|
|
1826
|
+
yield* vt({
|
|
1805
1827
|
sink: t,
|
|
1806
|
-
assetsDir: i.join(e.bundleDir,
|
|
1828
|
+
assetsDir: i.join(e.bundleDir, Pt),
|
|
1807
1829
|
indexPath: i.join(e.bundleDir, s.assets.index ?? "assets/index.ndjson"),
|
|
1808
1830
|
progress: {
|
|
1809
1831
|
done: (e) => e in b.assets,
|
|
1810
|
-
mark: (e) => (b.assets[e] = !0,
|
|
1832
|
+
mark: (e) => (b.assets[e] = !0, K(v, b))
|
|
1811
1833
|
}
|
|
1812
1834
|
});
|
|
1813
1835
|
}
|
|
1814
|
-
return yield* n.promise(() =>
|
|
1836
|
+
return yield* n.promise(() => Ee(null)), {
|
|
1815
1837
|
manifest: s,
|
|
1816
|
-
tablesWritten:
|
|
1817
|
-
rowsWritten:
|
|
1818
|
-
tablesSkipped:
|
|
1819
|
-
rowsSkipped:
|
|
1820
|
-
fullyResumed:
|
|
1821
|
-
...
|
|
1838
|
+
tablesWritten: A,
|
|
1839
|
+
rowsWritten: k,
|
|
1840
|
+
tablesSkipped: N,
|
|
1841
|
+
rowsSkipped: ve,
|
|
1842
|
+
fullyResumed: A === 0 && N > 0,
|
|
1843
|
+
...F === void 0 ? {} : { rollback: F }
|
|
1822
1844
|
};
|
|
1823
1845
|
}).pipe(n.tapError((e) => n.promise(() => t?.(e?.reason ?? e?._tag ?? "the import did not finish") ?? Promise.resolve())));
|
|
1824
|
-
},
|
|
1846
|
+
}, dr = (e) => e, fr = (e) => {
|
|
1825
1847
|
if (e.allowLive || e.liveInstance === null || e.sameTarget === "different") return { refuse: !1 };
|
|
1826
1848
|
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.";
|
|
1827
1849
|
return {
|
|
1828
1850
|
refuse: !0,
|
|
1829
1851
|
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).`
|
|
1830
1852
|
};
|
|
1831
|
-
},
|
|
1853
|
+
}, X = Buffer.from("VBUNDLE2"), pr = 0, mr = 1, hr = 2, gr = 32, _r = async (e) => {
|
|
1832
1854
|
let t = [], n = async (r) => {
|
|
1833
1855
|
let i;
|
|
1834
1856
|
try {
|
|
1835
|
-
i = await
|
|
1857
|
+
i = await ye(I(e, r), { withFileTypes: !0 });
|
|
1836
1858
|
} catch {
|
|
1837
1859
|
return;
|
|
1838
1860
|
}
|
|
@@ -1842,22 +1864,22 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
1842
1864
|
}
|
|
1843
1865
|
};
|
|
1844
1866
|
return await n(""), t.sort();
|
|
1845
|
-
},
|
|
1867
|
+
}, vr = (e, t) => {
|
|
1846
1868
|
let n = Buffer.from(e, "utf8"), r = Buffer.alloc(5 + n.length + 8);
|
|
1847
|
-
return r.writeUInt8(
|
|
1848
|
-
},
|
|
1869
|
+
return r.writeUInt8(mr, 0), r.writeUInt32BE(n.length, 1), n.copy(r, 5), r.writeBigUInt64BE(BigInt(t), 5 + n.length), r;
|
|
1870
|
+
}, yr = (e, t, n) => {
|
|
1849
1871
|
let r = Buffer.from(e, "utf8"), i = Buffer.from(t, "utf8"), a = Buffer.alloc(5 + r.length + 2 + i.length + 8), o = 0;
|
|
1850
|
-
return a.writeUInt8(
|
|
1872
|
+
return a.writeUInt8(hr, 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;
|
|
1851
1873
|
};
|
|
1852
|
-
async function*
|
|
1853
|
-
yield new Uint8Array(
|
|
1854
|
-
for (let t of await
|
|
1855
|
-
let n =
|
|
1856
|
-
if (yield new Uint8Array(
|
|
1874
|
+
async function* br(e) {
|
|
1875
|
+
yield new Uint8Array(X);
|
|
1876
|
+
for (let t of await _r(e.dir)) {
|
|
1877
|
+
let n = I(e.dir, t), r = await be(n);
|
|
1878
|
+
if (yield new Uint8Array(vr(t, r.size)), r.size > 0) for await (let e of fe(n)) yield new Uint8Array(e);
|
|
1857
1879
|
}
|
|
1858
1880
|
if (e.blobs) for await (let t of e.blobs.list()) {
|
|
1859
|
-
yield new Uint8Array(
|
|
1860
|
-
let n =
|
|
1881
|
+
yield new Uint8Array(yr(t.key, t.contentType, t.size));
|
|
1882
|
+
let n = T("sha256"), r = 0;
|
|
1861
1883
|
for await (let i of e.blobs.open(t.key)) {
|
|
1862
1884
|
let e = Buffer.from(i);
|
|
1863
1885
|
n.update(e), r += e.length, yield new Uint8Array(e);
|
|
@@ -1865,11 +1887,11 @@ async function* vr(e) {
|
|
|
1865
1887
|
if (r !== t.size) throw Error(`blob '${t.key}' size mismatch: header ${t.size}, streamed ${r}`);
|
|
1866
1888
|
yield new Uint8Array(n.digest());
|
|
1867
1889
|
}
|
|
1868
|
-
yield new Uint8Array(Buffer.from([
|
|
1890
|
+
yield new Uint8Array(Buffer.from([pr]));
|
|
1869
1891
|
}
|
|
1870
|
-
var
|
|
1871
|
-
let n =
|
|
1872
|
-
await
|
|
1892
|
+
var xr = (e, t) => new Promise((n, r) => e.write(t, (e) => e ? r(e) : n())), Sr = (e) => new Promise((t) => e.end(t)), Cr = async (e, t) => {
|
|
1893
|
+
let n = L(t.dir);
|
|
1894
|
+
await P(n, { recursive: !0 });
|
|
1873
1895
|
let r = Buffer.alloc(0), i = e[Symbol.asyncIterator](), a = !1, o = async () => {
|
|
1874
1896
|
let { value: e, done: t } = await i.next();
|
|
1875
1897
|
return t ? (a = !0, !1) : (r = r.length === 0 ? Buffer.from(e) : Buffer.concat([r, Buffer.from(e)]), !0);
|
|
@@ -1880,28 +1902,28 @@ var yr = (e, t) => new Promise((n, r) => e.write(t, (e) => e ? r(e) : n())), br
|
|
|
1880
1902
|
return r = r.subarray(e), t;
|
|
1881
1903
|
};
|
|
1882
1904
|
try {
|
|
1883
|
-
if (await s(
|
|
1905
|
+
if (await s(X.length), !c(X.length).equals(X)) throw Error("not a bundle archive (bad magic)");
|
|
1884
1906
|
for (;;) {
|
|
1885
1907
|
await s(1);
|
|
1886
1908
|
let e = c(1).readUInt8(0);
|
|
1887
|
-
if (e ===
|
|
1888
|
-
if (e ===
|
|
1909
|
+
if (e === pr) return;
|
|
1910
|
+
if (e === mr) {
|
|
1889
1911
|
await s(4);
|
|
1890
1912
|
let e = c(4).readUInt32BE(0);
|
|
1891
1913
|
await s(e);
|
|
1892
1914
|
let t = c(e).toString("utf8");
|
|
1893
1915
|
await s(8);
|
|
1894
|
-
let i = c(8).readBigUInt64BE(0), a =
|
|
1895
|
-
if (a !== n && !a.startsWith(n +
|
|
1896
|
-
await
|
|
1897
|
-
let o =
|
|
1916
|
+
let i = c(8).readBigUInt64BE(0), a = L(n, t);
|
|
1917
|
+
if (a !== n && !a.startsWith(n + Ce)) throw Error(`archive path '${t}' escapes the destination`);
|
|
1918
|
+
await P(Se(a), { recursive: !0 });
|
|
1919
|
+
let o = pe(a);
|
|
1898
1920
|
for (; i > 0n;) {
|
|
1899
1921
|
r.length === 0 && await s(1);
|
|
1900
1922
|
let e = i < BigInt(r.length) ? Number(i) : r.length;
|
|
1901
|
-
await
|
|
1923
|
+
await xr(o, c(e)), i -= BigInt(e);
|
|
1902
1924
|
}
|
|
1903
|
-
await
|
|
1904
|
-
} else if (e ===
|
|
1925
|
+
await Sr(o);
|
|
1926
|
+
} else if (e === hr) {
|
|
1905
1927
|
await s(4);
|
|
1906
1928
|
let e = c(4).readUInt32BE(0);
|
|
1907
1929
|
await s(e);
|
|
@@ -1911,24 +1933,24 @@ var yr = (e, t) => new Promise((n, r) => e.write(t, (e) => e ? r(e) : n())), br
|
|
|
1911
1933
|
await s(i);
|
|
1912
1934
|
let a = c(i).toString("utf8");
|
|
1913
1935
|
await s(8);
|
|
1914
|
-
let o = c(8).readBigUInt64BE(0), l = await t.blobs.has(n), u =
|
|
1936
|
+
let o = c(8).readBigUInt64BE(0), l = await t.blobs.has(n), u = T("sha256"), d = new M(), f = l ? Promise.resolve() : t.blobs.write(n, d, {
|
|
1915
1937
|
contentType: a,
|
|
1916
1938
|
size: Number(o)
|
|
1917
1939
|
}), p = o;
|
|
1918
1940
|
for (; p > 0n;) {
|
|
1919
1941
|
r.length === 0 && await s(1);
|
|
1920
1942
|
let e = p < BigInt(r.length) ? Number(p) : r.length, t = c(e);
|
|
1921
|
-
u.update(t), l || await
|
|
1943
|
+
u.update(t), l || await xr(d, t), p -= BigInt(e);
|
|
1922
1944
|
}
|
|
1923
|
-
l ? d.destroy() : await
|
|
1924
|
-
let m = c(
|
|
1945
|
+
l ? d.destroy() : await Sr(d), await f, await s(gr);
|
|
1946
|
+
let m = c(gr);
|
|
1925
1947
|
if (!u.digest().equals(m)) throw Error(`blob '${n}' failed integrity (sha mismatch)`);
|
|
1926
1948
|
} else throw Error(`unknown bundle entry kind ${e}`);
|
|
1927
1949
|
}
|
|
1928
1950
|
} finally {
|
|
1929
1951
|
a || await Promise.resolve(i.return?.()).catch(() => void 0);
|
|
1930
1952
|
}
|
|
1931
|
-
},
|
|
1953
|
+
}, wr = async (e, t) => {
|
|
1932
1954
|
let n = new Set(t), r = /* @__PURE__ */ new Map(), i = Buffer.alloc(0), a = e[Symbol.asyncIterator](), o = async () => {
|
|
1933
1955
|
let { value: e, done: t } = await a.next();
|
|
1934
1956
|
return !t && (i = i.length === 0 ? Buffer.from(e) : Buffer.concat([i, Buffer.from(e)]), !0);
|
|
@@ -1947,11 +1969,11 @@ var yr = (e, t) => new Promise((n, r) => e.write(t, (e) => e ? r(e) : n())), br
|
|
|
1947
1969
|
}
|
|
1948
1970
|
return Buffer.concat(t);
|
|
1949
1971
|
};
|
|
1950
|
-
if (!await s(
|
|
1972
|
+
if (!await s(X.length) || !c(X.length).equals(X)) throw Error("not a bundle archive (bad magic)");
|
|
1951
1973
|
for (; await s(1);) {
|
|
1952
1974
|
let e = c(1).readUInt8(0);
|
|
1953
|
-
if (e ===
|
|
1954
|
-
if (e !==
|
|
1975
|
+
if (e === pr || e === hr) break;
|
|
1976
|
+
if (e !== mr) throw Error(`unknown bundle entry kind ${e}`);
|
|
1955
1977
|
if (!await s(4)) break;
|
|
1956
1978
|
let t = c(4).readUInt32BE(0);
|
|
1957
1979
|
if (!await s(t)) break;
|
|
@@ -1961,22 +1983,22 @@ var yr = (e, t) => new Promise((n, r) => e.write(t, (e) => e ? r(e) : n())), br
|
|
|
1961
1983
|
if (a === null || n.has(i) && (r.set(i, a), n.delete(i), n.size === 0)) break;
|
|
1962
1984
|
}
|
|
1963
1985
|
return r;
|
|
1964
|
-
},
|
|
1986
|
+
}, Tr = (e, t) => Cr(e, {
|
|
1965
1987
|
dir: t,
|
|
1966
|
-
blobs:
|
|
1967
|
-
}),
|
|
1988
|
+
blobs: Er(t)
|
|
1989
|
+
}), Er = (e) => {
|
|
1968
1990
|
let t = /* @__PURE__ */ new Set();
|
|
1969
1991
|
return {
|
|
1970
1992
|
has: async (e) => t.has(e),
|
|
1971
1993
|
write: async (n, r, i) => {
|
|
1972
|
-
let a = await import("node:fs/promises"), { pipeline: o } = await import("node:stream/promises"), { Transform: s } = await import("node:stream"), c =
|
|
1973
|
-
await
|
|
1974
|
-
let l =
|
|
1994
|
+
let a = await import("node:fs/promises"), { pipeline: o } = await import("node:stream/promises"), { Transform: s } = await import("node:stream"), c = I(e, "assets");
|
|
1995
|
+
await P(c, { recursive: !0 });
|
|
1996
|
+
let l = T("sha256"), u = 0, d = new s({ transform(e, t, n) {
|
|
1975
1997
|
l.update(e), u += e.length, n(null, e);
|
|
1976
|
-
} }), f =
|
|
1977
|
-
await o(r, d,
|
|
1998
|
+
} }), f = I(c, `.tmp-${Date.now()}-${t.size}`);
|
|
1999
|
+
await o(r, d, pe(f));
|
|
1978
2000
|
let p = l.digest("hex");
|
|
1979
|
-
await a.rename(f,
|
|
2001
|
+
await a.rename(f, I(c, p)), await a.appendFile(I(c, "index.ndjson"), `${JSON.stringify({
|
|
1980
2002
|
key: n,
|
|
1981
2003
|
sha256: p,
|
|
1982
2004
|
size: u,
|
|
@@ -1984,33 +2006,33 @@ var yr = (e, t) => new Promise((n, r) => e.write(t, (e) => e ? r(e) : n())), br
|
|
|
1984
2006
|
})}\n`), t.add(n);
|
|
1985
2007
|
}
|
|
1986
2008
|
};
|
|
1987
|
-
},
|
|
2009
|
+
}, Dr = we(ue), Or = Buffer.from("VENC1\0\0\0"), kr = 32, Ar = 16, jr = 7, Mr = 16, Nr = 262144, Pr = {
|
|
1988
2010
|
N: 32768,
|
|
1989
2011
|
r: 8,
|
|
1990
2012
|
p: 1
|
|
1991
|
-
},
|
|
2013
|
+
}, Fr = 134217728, Ir = 43, Lr = (e, t, n) => {
|
|
1992
2014
|
let r = Buffer.alloc(12);
|
|
1993
|
-
return e.copy(r, 0, 0,
|
|
2015
|
+
return e.copy(r, 0, 0, jr), r.writeUInt32BE(t >>> 0, jr), r.writeUInt8(+!!n, 11), r;
|
|
1994
2016
|
};
|
|
1995
|
-
async function*
|
|
2017
|
+
async function* Rr(e, t) {
|
|
1996
2018
|
if (!t) throw Error("encryptStream: a non-empty passphrase is required");
|
|
1997
|
-
let n = ce(
|
|
1998
|
-
...
|
|
1999
|
-
maxmem:
|
|
2000
|
-
}), a = Buffer.alloc(
|
|
2001
|
-
|
|
2019
|
+
let n = ce(Ar), r = ce(jr), i = await Dr(t, n, kr, {
|
|
2020
|
+
...Pr,
|
|
2021
|
+
maxmem: Fr
|
|
2022
|
+
}), a = Buffer.alloc(Ir);
|
|
2023
|
+
Or.copy(a, 0), a.writeUInt32BE(Pr.N, 8), a.writeUInt32BE(Pr.r, 12), a.writeUInt32BE(Pr.p, 16), n.copy(a, 20), r.copy(a, 36), yield new Uint8Array(a);
|
|
2002
2024
|
let o = 0, s = (e, t) => {
|
|
2003
|
-
let n =
|
|
2025
|
+
let n = ae("aes-256-gcm", i, Lr(r, o, t));
|
|
2004
2026
|
o === 0 && n.setAAD(a);
|
|
2005
2027
|
let s = Buffer.concat([n.update(e), n.final()]), c = n.getAuthTag();
|
|
2006
2028
|
o++;
|
|
2007
|
-
let l = Buffer.alloc(5 + s.length +
|
|
2008
|
-
return l.writeUInt8(+!!t, 0), l.writeUInt32BE(s.length +
|
|
2029
|
+
let l = Buffer.alloc(5 + s.length + Mr);
|
|
2030
|
+
return l.writeUInt8(+!!t, 0), l.writeUInt32BE(s.length + Mr, 1), s.copy(l, 5), c.copy(l, 5 + s.length), new Uint8Array(l);
|
|
2009
2031
|
}, c = Buffer.alloc(0);
|
|
2010
|
-
for await (let t of e) for (c = c.length === 0 ? Buffer.from(t) : Buffer.concat([c, Buffer.from(t)]); c.length >
|
|
2032
|
+
for await (let t of e) for (c = c.length === 0 ? Buffer.from(t) : Buffer.concat([c, Buffer.from(t)]); c.length > Nr;) yield s(c.subarray(0, Nr), !1), c = c.subarray(Nr);
|
|
2011
2033
|
yield s(c, !0);
|
|
2012
2034
|
}
|
|
2013
|
-
async function*
|
|
2035
|
+
async function* zr(e, t) {
|
|
2014
2036
|
if (!t) throw Error("decryptStream: a non-empty passphrase is required");
|
|
2015
2037
|
let n = e[Symbol.asyncIterator](), r = Buffer.alloc(0), i = !1, a = async () => {
|
|
2016
2038
|
let { value: e, done: t } = await n.next();
|
|
@@ -2019,16 +2041,16 @@ async function* Lr(e, t) {
|
|
|
2019
2041
|
for (; r.length < e && !i && await a(););
|
|
2020
2042
|
return r.length >= e;
|
|
2021
2043
|
};
|
|
2022
|
-
if (!await o(
|
|
2023
|
-
let s = r.subarray(0,
|
|
2024
|
-
if (!s.subarray(0, 8).equals(
|
|
2025
|
-
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,
|
|
2044
|
+
if (!await o(Ir)) throw Error("encrypted bundle truncated (no header)");
|
|
2045
|
+
let s = r.subarray(0, Ir);
|
|
2046
|
+
if (!s.subarray(0, 8).equals(Or)) throw Error("not an encrypted bundle (bad magic / wrong passphrase target)");
|
|
2047
|
+
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, Ir)), p = await Dr(t, d, kr, {
|
|
2026
2048
|
N: c,
|
|
2027
2049
|
r: l,
|
|
2028
2050
|
p: u,
|
|
2029
|
-
maxmem:
|
|
2051
|
+
maxmem: Fr
|
|
2030
2052
|
});
|
|
2031
|
-
r = r.subarray(
|
|
2053
|
+
r = r.subarray(Ir);
|
|
2032
2054
|
let m = 0, h = !1;
|
|
2033
2055
|
for (;;) {
|
|
2034
2056
|
if (!await o(5)) {
|
|
@@ -2037,11 +2059,11 @@ async function* Lr(e, t) {
|
|
|
2037
2059
|
}
|
|
2038
2060
|
if (h) throw Error("encrypted bundle has trailing data after the final frame");
|
|
2039
2061
|
let e = r.readUInt8(0) === 1, t = r.readUInt32BE(1);
|
|
2040
|
-
if (t <
|
|
2062
|
+
if (t < Mr) throw Error("encrypted bundle corrupt (short frame)");
|
|
2041
2063
|
if (!await o(5 + t)) throw Error("encrypted bundle truncated (frame body)");
|
|
2042
|
-
let n = r.subarray(5, 5 + t -
|
|
2064
|
+
let n = r.subarray(5, 5 + t - Mr), i = r.subarray(5 + t - Mr, 5 + t);
|
|
2043
2065
|
r = r.subarray(5 + t);
|
|
2044
|
-
let a =
|
|
2066
|
+
let a = oe("aes-256-gcm", p, Lr(f, m, e));
|
|
2045
2067
|
m === 0 && a.setAAD(s), a.setAuthTag(i);
|
|
2046
2068
|
let c = Buffer.concat([a.update(n), a.final()]);
|
|
2047
2069
|
m++, e && (h = !0), c.length > 0 && (yield new Uint8Array(c));
|
|
@@ -2049,7 +2071,7 @@ async function* Lr(e, t) {
|
|
|
2049
2071
|
}
|
|
2050
2072
|
//#endregion
|
|
2051
2073
|
//#region src/blobStorage.ts
|
|
2052
|
-
var
|
|
2074
|
+
var Br = (e, t) => ({
|
|
2053
2075
|
list: () => {
|
|
2054
2076
|
let e = t();
|
|
2055
2077
|
return { async *[Symbol.asyncIterator]() {
|
|
@@ -2062,32 +2084,32 @@ var Rr = (e, t) => ({
|
|
|
2062
2084
|
} };
|
|
2063
2085
|
},
|
|
2064
2086
|
open: (t) => ({ async *[Symbol.asyncIterator]() {
|
|
2065
|
-
let r = await n.runPromise(
|
|
2087
|
+
let r = await n.runPromise(_e(e, t)), i = await A(r.stream);
|
|
2066
2088
|
for await (let e of i) yield e instanceof Uint8Array ? e : new Uint8Array(e);
|
|
2067
2089
|
} })
|
|
2068
|
-
}),
|
|
2069
|
-
table:
|
|
2090
|
+
}), Vr = (e, t) => Br(e, () => C(t, {
|
|
2091
|
+
table: O,
|
|
2070
2092
|
chunkSize: 500
|
|
2071
2093
|
}).pipe(l.map((e) => ({
|
|
2072
2094
|
key: String(e.key),
|
|
2073
2095
|
contentType: String(e.contentType ?? "application/octet-stream"),
|
|
2074
2096
|
size: Number(e.size ?? 0)
|
|
2075
|
-
})))),
|
|
2097
|
+
})))), Hr = (e) => ({
|
|
2076
2098
|
has: (t) => n.runPromise(e.head(t).pipe(n.map((e) => e !== null))),
|
|
2077
2099
|
write: async (t, r, i) => {
|
|
2078
|
-
let a =
|
|
2079
|
-
await n.runPromise(
|
|
2100
|
+
let a = ge("storage", () => ve.from(r));
|
|
2101
|
+
await n.runPromise(k(e, t, a, {
|
|
2080
2102
|
contentType: i.contentType,
|
|
2081
2103
|
totalSize: i.size
|
|
2082
2104
|
}));
|
|
2083
2105
|
}
|
|
2084
|
-
}),
|
|
2106
|
+
}), Ur = (e, t) => {
|
|
2085
2107
|
let n = t === "dump" ? "mariadb-dump" : "mariadb", r = t === "dump" ? "mysqldump" : "mysql";
|
|
2086
|
-
return e === "mariadb" ?
|
|
2108
|
+
return e === "mariadb" ? Wr(n) ? { tool: n } : {
|
|
2087
2109
|
tool: r,
|
|
2088
2110
|
hint: `'${n}' is not on PATH, so this ran '${r}' instead. If that binary came from Oracle's MySQL client it queries information_schema.COLUMN_STATISTICS, which MariaDB does not have, and the run dies with error 1109 after the first table. Install the MariaDB client package (which ships '${n}') and re-run. Do NOT reach for --column-statistics=0: that flag does not exist on '${n}', so it fixes the wrong client and breaks the right one. Note: a MariaDB 12.x client requires TLS by default, so running '${n}' BY HAND against a server without it fails with "TLS/SSL error: SSL is required" (2026) and needs --skip-ssl. This command is not affected.`
|
|
2089
2111
|
} : { tool: r };
|
|
2090
|
-
},
|
|
2112
|
+
}, Wr = (e) => (process.env.PATH ?? "").split(xe).filter((e) => e !== "").some((t) => E(I(t, e))), Gr = (e) => {
|
|
2091
2113
|
switch (e) {
|
|
2092
2114
|
case "postgres": return "db.dump";
|
|
2093
2115
|
case "mysql":
|
|
@@ -2097,23 +2119,23 @@ var Rr = (e, t) => ({
|
|
|
2097
2119
|
case "mssql": return "db.bacpac";
|
|
2098
2120
|
default: return "db.dump";
|
|
2099
2121
|
}
|
|
2100
|
-
},
|
|
2122
|
+
}, Kr = (e) => e.filename ?? e.database ?? ((e.url ?? "").replace(/^file:/, "") || "app.sqlite"), Z = (e, t = 3306) => {
|
|
2101
2123
|
if (e.host || e.database) return {
|
|
2102
2124
|
host: e.host ?? "localhost",
|
|
2103
|
-
port: e.port ??
|
|
2125
|
+
port: e.port ?? t,
|
|
2104
2126
|
username: e.username ?? "root",
|
|
2105
2127
|
password: e.password ?? "",
|
|
2106
2128
|
database: e.database ?? ""
|
|
2107
2129
|
};
|
|
2108
|
-
let
|
|
2130
|
+
let n = new URL(e.url ?? "");
|
|
2109
2131
|
return {
|
|
2110
|
-
host:
|
|
2111
|
-
port:
|
|
2112
|
-
username: decodeURIComponent(
|
|
2113
|
-
password: decodeURIComponent(
|
|
2114
|
-
database:
|
|
2132
|
+
host: n.hostname || "localhost",
|
|
2133
|
+
port: e.port ?? (n.port ? Number(n.port) : t),
|
|
2134
|
+
username: decodeURIComponent(n.username) || "root",
|
|
2135
|
+
password: decodeURIComponent(n.password) || "",
|
|
2136
|
+
database: n.pathname.replace(/^\//, "") || ""
|
|
2115
2137
|
};
|
|
2116
|
-
},
|
|
2138
|
+
}, qr = (e) => `Server=${e.host},${e.port};Database=${e.database};User ID=${e.username};Password=${e.password};TrustServerCertificate=True`, Jr = (e, t, n) => {
|
|
2117
2139
|
switch (e) {
|
|
2118
2140
|
case "postgres": {
|
|
2119
2141
|
if (t.url) return {
|
|
@@ -2123,7 +2145,7 @@ var Rr = (e, t) => ({
|
|
|
2123
2145
|
"--format=custom",
|
|
2124
2146
|
"--no-owner",
|
|
2125
2147
|
"--no-privileges",
|
|
2126
|
-
...
|
|
2148
|
+
...Xr,
|
|
2127
2149
|
"--dbname",
|
|
2128
2150
|
t.url,
|
|
2129
2151
|
"--file",
|
|
@@ -2131,10 +2153,7 @@ var Rr = (e, t) => ({
|
|
|
2131
2153
|
],
|
|
2132
2154
|
env: {}
|
|
2133
2155
|
};
|
|
2134
|
-
let e =
|
|
2135
|
-
...t,
|
|
2136
|
-
port: t.port ?? 5432
|
|
2137
|
-
});
|
|
2156
|
+
let e = Z(t, 5432);
|
|
2138
2157
|
return {
|
|
2139
2158
|
kind: "spawn",
|
|
2140
2159
|
tool: "pg_dump",
|
|
@@ -2142,7 +2161,7 @@ var Rr = (e, t) => ({
|
|
|
2142
2161
|
"--format=custom",
|
|
2143
2162
|
"--no-owner",
|
|
2144
2163
|
"--no-privileges",
|
|
2145
|
-
...
|
|
2164
|
+
...Xr,
|
|
2146
2165
|
"-h",
|
|
2147
2166
|
e.host,
|
|
2148
2167
|
"-p",
|
|
@@ -2159,17 +2178,17 @@ var Rr = (e, t) => ({
|
|
|
2159
2178
|
}
|
|
2160
2179
|
case "mysql":
|
|
2161
2180
|
case "mariadb": {
|
|
2162
|
-
let r =
|
|
2181
|
+
let r = Z(t);
|
|
2163
2182
|
return {
|
|
2164
2183
|
kind: "spawn",
|
|
2165
|
-
...
|
|
2184
|
+
...Ur(e, "dump"),
|
|
2166
2185
|
args: [
|
|
2167
2186
|
"--single-transaction",
|
|
2168
2187
|
"--routines",
|
|
2169
2188
|
"--triggers",
|
|
2170
2189
|
"--no-tablespaces",
|
|
2171
2190
|
"--protocol=TCP",
|
|
2172
|
-
...
|
|
2191
|
+
...Yr.map((e) => `--ignore-table=${r.database}.${e}`),
|
|
2173
2192
|
"-h",
|
|
2174
2193
|
r.host,
|
|
2175
2194
|
"-P",
|
|
@@ -2185,7 +2204,7 @@ var Rr = (e, t) => ({
|
|
|
2185
2204
|
case "sqlite":
|
|
2186
2205
|
case "turso": return {
|
|
2187
2206
|
kind: "copy",
|
|
2188
|
-
from:
|
|
2207
|
+
from: Kr(t),
|
|
2189
2208
|
to: n
|
|
2190
2209
|
};
|
|
2191
2210
|
case "mssql": return {
|
|
@@ -2193,20 +2212,17 @@ var Rr = (e, t) => ({
|
|
|
2193
2212
|
tool: "sqlpackage",
|
|
2194
2213
|
args: [
|
|
2195
2214
|
"/Action:Export",
|
|
2196
|
-
`/SourceConnectionString:${
|
|
2197
|
-
...t,
|
|
2198
|
-
port: t.port ?? 1433
|
|
2199
|
-
}))}`,
|
|
2215
|
+
`/SourceConnectionString:${qr(Z(t, 1433))}`,
|
|
2200
2216
|
`/TargetFile:${n}`
|
|
2201
2217
|
],
|
|
2202
2218
|
env: {}
|
|
2203
2219
|
};
|
|
2204
|
-
default: throw new
|
|
2220
|
+
default: throw new W({
|
|
2205
2221
|
tool: "backup",
|
|
2206
2222
|
reason: `no native backup for dialect '${e}'`
|
|
2207
2223
|
});
|
|
2208
2224
|
}
|
|
2209
|
-
},
|
|
2225
|
+
}, Yr = [d, u], Xr = Yr.flatMap((e) => ["--exclude-table", e]), Zr = (e) => e === "postgres" || e === "mysql" || e === "mariadb" ? Yr : [], Qr = (e, t, n) => {
|
|
2210
2226
|
switch (e) {
|
|
2211
2227
|
case "postgres": {
|
|
2212
2228
|
if (t.url) return {
|
|
@@ -2222,10 +2238,7 @@ var Rr = (e, t) => ({
|
|
|
2222
2238
|
],
|
|
2223
2239
|
env: {}
|
|
2224
2240
|
};
|
|
2225
|
-
let e =
|
|
2226
|
-
...t,
|
|
2227
|
-
port: t.port ?? 5432
|
|
2228
|
-
});
|
|
2241
|
+
let e = Z(t, 5432);
|
|
2229
2242
|
return {
|
|
2230
2243
|
kind: "spawn",
|
|
2231
2244
|
tool: "pg_restore",
|
|
@@ -2248,10 +2261,10 @@ var Rr = (e, t) => ({
|
|
|
2248
2261
|
}
|
|
2249
2262
|
case "mysql":
|
|
2250
2263
|
case "mariadb": {
|
|
2251
|
-
let r =
|
|
2264
|
+
let r = Z(t);
|
|
2252
2265
|
return {
|
|
2253
2266
|
kind: "spawn",
|
|
2254
|
-
...
|
|
2267
|
+
...Ur(e, "client"),
|
|
2255
2268
|
args: [
|
|
2256
2269
|
"--protocol=TCP",
|
|
2257
2270
|
"-h",
|
|
@@ -2270,37 +2283,104 @@ var Rr = (e, t) => ({
|
|
|
2270
2283
|
case "turso": return {
|
|
2271
2284
|
kind: "copy",
|
|
2272
2285
|
from: n,
|
|
2273
|
-
to:
|
|
2274
|
-
};
|
|
2275
|
-
case "mssql": return {
|
|
2276
|
-
kind: "spawn",
|
|
2277
|
-
tool: "sqlpackage",
|
|
2278
|
-
args: [
|
|
2279
|
-
"/Action:Import",
|
|
2280
|
-
`/TargetConnectionString:${Gr($({
|
|
2281
|
-
...t,
|
|
2282
|
-
port: t.port ?? 1433
|
|
2283
|
-
}))}`,
|
|
2284
|
-
`/SourceFile:${n}`
|
|
2285
|
-
],
|
|
2286
|
-
env: {}
|
|
2286
|
+
to: Kr(t)
|
|
2287
2287
|
};
|
|
2288
|
-
|
|
2288
|
+
case "mssql": {
|
|
2289
|
+
let e = Z(t, 1433), r = ei(e.database);
|
|
2290
|
+
return {
|
|
2291
|
+
kind: "mssql-replace",
|
|
2292
|
+
load: {
|
|
2293
|
+
kind: "spawn",
|
|
2294
|
+
tool: "sqlpackage",
|
|
2295
|
+
args: [
|
|
2296
|
+
"/Action:Import",
|
|
2297
|
+
`/TargetConnectionString:${qr({
|
|
2298
|
+
...e,
|
|
2299
|
+
database: r
|
|
2300
|
+
})}`,
|
|
2301
|
+
`/SourceFile:${n}`
|
|
2302
|
+
],
|
|
2303
|
+
env: {}
|
|
2304
|
+
},
|
|
2305
|
+
server: {
|
|
2306
|
+
host: e.host,
|
|
2307
|
+
port: e.port,
|
|
2308
|
+
username: e.username,
|
|
2309
|
+
password: e.password,
|
|
2310
|
+
database: "master"
|
|
2311
|
+
},
|
|
2312
|
+
live: e.database,
|
|
2313
|
+
scratch: r,
|
|
2314
|
+
carry: Yr
|
|
2315
|
+
};
|
|
2316
|
+
}
|
|
2317
|
+
default: throw new W({
|
|
2289
2318
|
tool: "restore",
|
|
2290
2319
|
reason: `no native restore for dialect '${e}'`
|
|
2291
2320
|
});
|
|
2292
2321
|
}
|
|
2293
|
-
},
|
|
2322
|
+
}, Q = (e) => `[${e.replaceAll("]", "]]")}]`, $ = (e) => `N'${e.replaceAll("'", "''")}'`, $r = "__voltro_restore_", ei = (e, t = le().slice(0, 8)) => `${e}${$r}${t}`, ti = (e) => e.replace($r, "__voltro_replaced_"), ni = (e) => `IF DB_ID(${$(e)}) IS NOT NULL BEGIN ALTER DATABASE ${Q(e)} SET SINGLE_USER WITH ROLLBACK IMMEDIATE; DROP DATABASE ${Q(e)} END`, ri = (e) => `DECLARE @leftover sysname, @drop nvarchar(max);
|
|
2323
|
+
DECLARE leftovers CURSOR LOCAL FAST_FORWARD FOR SELECT name FROM sys.databases WHERE name LIKE ${$(`${`${e}${$r}`.replace(/[\\%_[]/g, (e) => `\\${e}`)}%`)} ESCAPE N'\\';
|
|
2324
|
+
OPEN leftovers; FETCH NEXT FROM leftovers INTO @leftover;
|
|
2325
|
+
WHILE @@FETCH_STATUS = 0 BEGIN
|
|
2326
|
+
SET @drop = N'ALTER DATABASE ' + QUOTENAME(@leftover) + N' SET SINGLE_USER WITH ROLLBACK IMMEDIATE; DROP DATABASE ' + QUOTENAME(@leftover);
|
|
2327
|
+
EXEC(@drop);
|
|
2328
|
+
FETCH NEXT FROM leftovers INTO @leftover;
|
|
2329
|
+
END`, ii = (e) => {
|
|
2330
|
+
let t = Q(e.live), n = Q(e.scratch), r = ti(e.scratch);
|
|
2331
|
+
return {
|
|
2332
|
+
prepare: [ri(e.live)],
|
|
2333
|
+
carry: e.carry.map((e) => {
|
|
2334
|
+
let r = $(`${n}.dbo.${Q(e)}`), i = $(`${t}.dbo.${Q(e)}`);
|
|
2335
|
+
return `IF OBJECT_ID(${r}) IS NOT NULL BEGIN
|
|
2336
|
+
DELETE FROM ${n}.dbo.${Q(e)};
|
|
2337
|
+
IF OBJECT_ID(${i}) IS NOT NULL BEGIN
|
|
2338
|
+
DECLARE @columns nvarchar(max) = (SELECT STRING_AGG(QUOTENAME(s.name), ',') FROM ${n}.sys.columns s
|
|
2339
|
+
JOIN ${t}.sys.columns l ON l.name = s.name AND l.object_id = OBJECT_ID(${i})
|
|
2340
|
+
WHERE s.object_id = OBJECT_ID(${r}) AND s.is_computed = 0);
|
|
2341
|
+
EXEC(N'INSERT INTO ${n.replaceAll("'", "''")}.dbo.${Q(e).replaceAll("'", "''")} (' + @columns + N') SELECT ' + @columns + N' FROM ${t.replaceAll("'", "''")}.dbo.${Q(e).replaceAll("'", "''")}');
|
|
2342
|
+
END
|
|
2343
|
+
END`;
|
|
2344
|
+
}),
|
|
2345
|
+
swap: [
|
|
2346
|
+
`ALTER DATABASE ${t} SET SINGLE_USER WITH ROLLBACK IMMEDIATE`,
|
|
2347
|
+
`ALTER DATABASE ${t} MODIFY NAME = ${Q(r)}`,
|
|
2348
|
+
`ALTER DATABASE ${n} MODIFY NAME = ${t}`,
|
|
2349
|
+
ni(r)
|
|
2350
|
+
],
|
|
2351
|
+
undoSwap: [`IF DB_ID(${$(e.live)}) IS NULL AND DB_ID(${$(r)}) IS NOT NULL ALTER DATABASE ${Q(r)} MODIFY NAME = ${t}`, `IF DB_ID(${$(e.live)}) IS NOT NULL ALTER DATABASE ${t} SET MULTI_USER`],
|
|
2352
|
+
cleanup: [ni(e.scratch)]
|
|
2353
|
+
};
|
|
2354
|
+
}, ai = (e) => {
|
|
2355
|
+
let t = [];
|
|
2356
|
+
for (let n = e, r = 0; n != null && r < 4; r++) {
|
|
2357
|
+
let e = n instanceof Error ? n.message : typeof n == "object" && "message" in n ? String(n.message) : String(n);
|
|
2358
|
+
e && !t.includes(e) && t.push(e), n = typeof n == "object" && "cause" in n ? n.cause : void 0;
|
|
2359
|
+
}
|
|
2360
|
+
return t.join(": ");
|
|
2361
|
+
}, oi = (e, t) => {
|
|
2362
|
+
if (t === void 0) return n.fail(new W({
|
|
2363
|
+
tool: "sqlpackage",
|
|
2364
|
+
reason: "an mssql restore swaps databases and needs a SQL connection to the server; none was provided"
|
|
2365
|
+
}));
|
|
2366
|
+
let r = ii(e), i = (r, i) => t(e.server, i).pipe(n.mapError((e) => new W({
|
|
2367
|
+
tool: "sqlpackage",
|
|
2368
|
+
reason: `${r}: ${ai(e)}`
|
|
2369
|
+
}))), a = i("dropping the scratch database", r.cleanup).pipe(n.ignore);
|
|
2370
|
+
return n.gen(function* () {
|
|
2371
|
+
yield* i(`preparing ${e.scratch}`, r.prepare), yield* si(e.load).pipe(n.tapError(() => a)), yield* i(`carrying ${e.carry.join(", ")} into the imported copy`, r.carry).pipe(n.tapError(() => a)), yield* i(`swapping ${e.scratch} in as ${e.live}`, r.swap).pipe(n.tapError(() => i("putting the original database back", r.undoSwap).pipe(n.ignore)));
|
|
2372
|
+
});
|
|
2373
|
+
}, si = (e, t) => e.kind === "mssql-replace" ? oi(e, t) : e.kind === "copy" ? n.async((t) => {
|
|
2294
2374
|
let r = `${e.to}.restoring-${le()}`, i = (e) => {
|
|
2295
2375
|
try {
|
|
2296
|
-
|
|
2376
|
+
he(r);
|
|
2297
2377
|
} catch {}
|
|
2298
|
-
t(n.fail(new
|
|
2378
|
+
t(n.fail(new W({
|
|
2299
2379
|
tool: "copy",
|
|
2300
2380
|
reason: e
|
|
2301
2381
|
})));
|
|
2302
2382
|
};
|
|
2303
|
-
|
|
2383
|
+
de(e.from, r, (a) => {
|
|
2304
2384
|
if (a) {
|
|
2305
2385
|
i(`copy ${e.from} → ${e.to}: ${a.message}`);
|
|
2306
2386
|
return;
|
|
@@ -2310,9 +2390,9 @@ var Rr = (e, t) => ({
|
|
|
2310
2390
|
`${e.to}-shm`,
|
|
2311
2391
|
`${e.to}-journal`
|
|
2312
2392
|
]) try {
|
|
2313
|
-
|
|
2393
|
+
he(t);
|
|
2314
2394
|
} catch {}
|
|
2315
|
-
|
|
2395
|
+
D(r, e.to, (r) => {
|
|
2316
2396
|
if (r) {
|
|
2317
2397
|
i(`copy ${e.from} → ${e.to}: ${r.message}`);
|
|
2318
2398
|
return;
|
|
@@ -2321,7 +2401,7 @@ var Rr = (e, t) => ({
|
|
|
2321
2401
|
});
|
|
2322
2402
|
});
|
|
2323
2403
|
}) : n.async((t) => {
|
|
2324
|
-
let r =
|
|
2404
|
+
let r = Te(e.tool, [...e.args], {
|
|
2325
2405
|
env: {
|
|
2326
2406
|
...process.env,
|
|
2327
2407
|
...e.env
|
|
@@ -2341,27 +2421,27 @@ var Rr = (e, t) => ({
|
|
|
2341
2421
|
s ??= e;
|
|
2342
2422
|
};
|
|
2343
2423
|
if (e.stdoutFile && r.stdout) {
|
|
2344
|
-
let t =
|
|
2345
|
-
t.on("error", (t) => c(`writing ${
|
|
2424
|
+
let t = pe(e.stdoutFile);
|
|
2425
|
+
t.on("error", (t) => c(`writing ${F(e.stdoutFile)}: ${t.message}`)), r.stdout.on("error", (e) => c(`reading the tool's output: ${e.message}`)), r.stdout.pipe(t);
|
|
2346
2426
|
}
|
|
2347
2427
|
let l = 0;
|
|
2348
2428
|
if (e.stdinFile && r.stdin) {
|
|
2349
|
-
let t =
|
|
2429
|
+
let t = fe(e.stdinFile);
|
|
2350
2430
|
t.on("data", (e) => {
|
|
2351
2431
|
l += e.length;
|
|
2352
2432
|
}), t.on("error", (t) => {
|
|
2353
|
-
c(`reading ${
|
|
2433
|
+
c(`reading ${F(e.stdinFile)}: ${t.message}`), r.stdin?.end();
|
|
2354
2434
|
}), r.stdin.on("error", (t) => {
|
|
2355
|
-
t.code !== "EPIPE" && c(`feeding ${
|
|
2435
|
+
t.code !== "EPIPE" && c(`feeding ${F(e.stdinFile)} to ${e.tool}: ${t.message}`);
|
|
2356
2436
|
}), t.pipe(r.stdin);
|
|
2357
2437
|
}
|
|
2358
2438
|
let u = () => {
|
|
2359
2439
|
if (e.stdoutFile !== void 0) try {
|
|
2360
|
-
|
|
2440
|
+
he(e.stdoutFile);
|
|
2361
2441
|
} catch {}
|
|
2362
2442
|
};
|
|
2363
2443
|
r.on("error", (t) => {
|
|
2364
|
-
u(), o(n.fail(new
|
|
2444
|
+
u(), o(n.fail(new W({
|
|
2365
2445
|
tool: e.tool,
|
|
2366
2446
|
reason: `failed to launch (is '${e.tool}' installed + on PATH?): ${t.message}`,
|
|
2367
2447
|
...e.hint === void 0 ? {} : { hint: e.hint }
|
|
@@ -2372,25 +2452,25 @@ var Rr = (e, t) => ({
|
|
|
2372
2452
|
return;
|
|
2373
2453
|
}
|
|
2374
2454
|
u();
|
|
2375
|
-
let r = e.stdinFile === void 0 ? "" : ` — ${l} of ${
|
|
2376
|
-
o(n.fail(new
|
|
2455
|
+
let r = e.stdinFile === void 0 ? "" : ` — ${l} of ${ci(e.stdinFile)} byte(s) of ${F(e.stdinFile)} had been fed to it`;
|
|
2456
|
+
o(n.fail(new W({
|
|
2377
2457
|
tool: e.tool,
|
|
2378
|
-
reason: (t === 0 ? `exited cleanly, but ${s}` : `exited with code ${t}${s === void 0 ? "" : ` (${s})`}`) + r + (e.stdoutFile === void 0 ? "" : ` — the partial ${
|
|
2458
|
+
reason: (t === 0 ? `exited cleanly, but ${s}` : `exited with code ${t}${s === void 0 ? "" : ` (${s})`}`) + r + (e.stdoutFile === void 0 ? "" : ` — the partial ${F(e.stdoutFile)} was removed, so it cannot be mistaken for a backup`),
|
|
2379
2459
|
stderr: i.trim() === "" ? `(${e.tool} printed nothing to stderr)` : i.slice(-2e3),
|
|
2380
2460
|
...e.hint === void 0 ? {} : { hint: e.hint }
|
|
2381
2461
|
})));
|
|
2382
2462
|
});
|
|
2383
|
-
}),
|
|
2463
|
+
}), ci = (e) => {
|
|
2384
2464
|
try {
|
|
2385
|
-
return String(
|
|
2465
|
+
return String(me(e).size);
|
|
2386
2466
|
} catch {
|
|
2387
2467
|
return "?";
|
|
2388
2468
|
}
|
|
2389
|
-
},
|
|
2390
|
-
let t = yield*
|
|
2469
|
+
}, li = (e) => typeof e == "object" && e ? "fake" in e ? `fake:${e.fake}` : "custom" : String(e), ui = (e) => n.gen(function* () {
|
|
2470
|
+
let t = yield* lt(e.scope ?? { kind: "all" }, e.snapshot, {
|
|
2391
2471
|
store: e.store,
|
|
2392
2472
|
...e.tenantTables ? { tenantTables: e.tenantTables } : {}
|
|
2393
|
-
}), r =
|
|
2473
|
+
}), r = sn(t.tables, e.snapshot), i = e.classification ?? Oe(e.snapshot), a = e.sampleSize ?? 20, o = He(r.map((t) => ({
|
|
2394
2474
|
name: t,
|
|
2395
2475
|
columns: (e.snapshot.tables.find((e) => e.name === t)?.columns ?? []).map((e) => ({
|
|
2396
2476
|
name: e.name,
|
|
@@ -2398,19 +2478,19 @@ var Rr = (e, t) => ({
|
|
|
2398
2478
|
}))
|
|
2399
2479
|
})), i, e.masking), s = [], c = [];
|
|
2400
2480
|
for (let i of r) {
|
|
2401
|
-
let r = t.predicateFor(i), u = yield*
|
|
2481
|
+
let r = t.predicateFor(i), u = yield* C(e.store, {
|
|
2402
2482
|
table: i,
|
|
2403
2483
|
chunkSize: a,
|
|
2404
2484
|
...r === void 0 ? {} : { where: r }
|
|
2405
|
-
}).pipe(l.take(a), l.runCollect, n.map((e) => [...e])), d = u.map((t) =>
|
|
2406
|
-
c.push(...
|
|
2485
|
+
}).pipe(l.take(a), l.runCollect, n.map((e) => [...e])), d = u.map((t) => Ge(t, i, o.actions, e.masking.seed));
|
|
2486
|
+
c.push(...We(d, i, o.actions));
|
|
2407
2487
|
let f = u[0], p = d[0], m = [];
|
|
2408
2488
|
if (f && p) for (let [e, t] of Object.entries(o.actions)) {
|
|
2409
2489
|
if (!e.startsWith(`${i}.`) || t === "keep") continue;
|
|
2410
2490
|
let n = e.slice(i.length + 1);
|
|
2411
2491
|
m.push({
|
|
2412
2492
|
column: n,
|
|
2413
|
-
action:
|
|
2493
|
+
action: li(t),
|
|
2414
2494
|
before: f[n],
|
|
2415
2495
|
after: p[n]
|
|
2416
2496
|
});
|
|
@@ -2425,7 +2505,7 @@ var Rr = (e, t) => ({
|
|
|
2425
2505
|
leaks: c,
|
|
2426
2506
|
unclassified: o.unclassified
|
|
2427
2507
|
};
|
|
2428
|
-
}),
|
|
2508
|
+
}), di = (e, t) => {
|
|
2429
2509
|
let n = new Map(t.map((e) => [e.name, e])), r = [], i = {};
|
|
2430
2510
|
for (let t of e) {
|
|
2431
2511
|
let e = n.get(t.name);
|
|
@@ -2480,7 +2560,7 @@ var Rr = (e, t) => ({
|
|
|
2480
2560
|
skipColumns: i,
|
|
2481
2561
|
refuse: r.some((e) => e.verdict === "refuse")
|
|
2482
2562
|
};
|
|
2483
|
-
},
|
|
2563
|
+
}, fi = (e) => {
|
|
2484
2564
|
if (e.findings.length === 0) return [" schema matches the bundle"];
|
|
2485
2565
|
let t = {
|
|
2486
2566
|
safe: "✓",
|
|
@@ -2491,4 +2571,4 @@ var Rr = (e, t) => ({
|
|
|
2491
2571
|
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;
|
|
2492
2572
|
};
|
|
2493
2573
|
//#endregion
|
|
2494
|
-
export {
|
|
2574
|
+
export { Pt as ASSETS_DIR, Ft as ASSET_INDEX_FILE, H as BundleError, Xe as CodecError, Qe as CompressionError, rt as CrossDialectError, Nt as DATA_DIR, De as DEFAULT_CLASS_ACTIONS, Ke as ENVIRONMENT_LOCAL_TABLES, qe as ENVIRONMENT_PORTABLE_TABLES, Yr as EXCLUDED_FROM_DUMP, wt as FORMAT_VERSION, nt as ImportModeError, Ze as IntegrityError, It as LEDGER_FILE, jt as MANIFEST_FILE, tt as MaskingError, W as NativeToolError, $e as RowsRefusedError, ar as SAVEPOINT_BATCH_SIZE, Nn as STAGING_PREFIX, et as SchemaDriftError, U as ScopeError, B as applyAction, sr as asImportError, fr as assessLiveImport, Kt as assetDone, Gr as backupArtifactName, Jr as backupCommand, Pn as canStage, xn as canonicalType, gt as captureAssetsToCas, wn as checkPortability, nr as checkSchemaDrift, Oe as classificationFromSnapshot, di as classifyImportDrift, xt as compressionExt, ot as computeSubsetIds, Yn as decideStaging, At as decodeManifest, nn as decodeRow, en as decodeValue, zr as decryptStream, dr as defineDataProfile, tr as diffSnapshots, Er as dirBlobSink, Rn as dropStagingSql, Zr as dumpExcludedTables, Ut as emptyLedger, kt as encodeManifest, tn as encodeRow, Qt as encodeValue, Rr as encryptStream, Ye as environmentLocalNotice, Je as environmentLocalReason, Wn as execStatements, fi as formatImportDrift, Tn as formatIssue, yt as hasZstd, V as isEnvironmentLocal, St as makeCompressor, Ct as makeDecompressor, Ge as maskRow, ii as mssqlReplaceStatements, ei as mssqlScratchName, on as ndjsonToRows, mt as noAssetProgress, bn as outsideReferenceRefusal, yn as outsideReferencesInto, br as packBundle, wr as peekBundle, bt as pickCompression, He as planMasking, ui as previewMasking, _t as readAssetIndex, Wt as readLedger, ke as resolveAction, lt as resolveScope, pt as restoreAssetFromCas, vt as restoreAssetsFromCas, Qr as restoreCommand, an as rowsToNdjson, vn as runExport, ur as runImport, si as runNativeStep, We as scanForLeaks, J as stagingNameFor, dt as storageAssetSink, ut as storageAssetSource, Hr as storageBlobSink, Br as storageBlobSource, Vr as storageRefsBlobSource, st as subsetToScope, Gt as tableDone, sn as topoSortTables, Cr as unpackBundle, Tr as unpackBundleToDir, ft as writeAssetToCas, K as writeLedger };
|