@voltro/data-transfer 0.80.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 +1610 -6
- package/THIRD-PARTY-NOTICES.md +1 -1
- package/dist/index.d.ts +52 -4
- package/dist/index.js +616 -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,18 @@ 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"],
|
|
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"],
|
|
277
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"],
|
|
278
287
|
["_voltro_devices", "devices paired with THIS deployment — token hashes; a foreign row makes a device paired elsewhere authenticate here"],
|
|
279
288
|
["_voltro_seeds", "which seeds ran HERE — a foreign row suppresses seeding the target still needs"],
|
|
@@ -318,6 +327,7 @@ var Ce = (e) => {
|
|
|
318
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"],
|
|
319
328
|
["_voltro_workflow_control_requests", "cancel/resume traffic issued against executions HERE — a foreign row claims an operation nobody asked the target to perform"],
|
|
320
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"],
|
|
321
331
|
["_voltro_workflow_restart_requests", "restarts pending against this deployment's generations — a foreign row restarts a generation the target never entered"],
|
|
322
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"],
|
|
323
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"],
|
|
@@ -326,8 +336,13 @@ var Ce = (e) => {
|
|
|
326
336
|
["_voltro_notification_deliveries", "the notification attempts this deployment made — a foreign row claims a send the target never performed"],
|
|
327
337
|
["_voltro_notification_held", "notifications waiting to be SENT from here — a foreign row makes the target deliver something queued elsewhere"],
|
|
328
338
|
["_voltro_webhook_event_stats", "per-deployment delivery counters a backoff decision reads — foreign counts steer the target's retries"],
|
|
329
|
-
["_voltro_webhook_rate_windows", "the live rate-limit windows this deployment is inside — a foreign window throttles or releases wrongly"]
|
|
330
|
-
|
|
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([
|
|
331
346
|
["_voltro_agent_threads", "conversations the app's users had — app data"],
|
|
332
347
|
["_voltro_agent_messages", "the messages in those conversations — app data"],
|
|
333
348
|
["_voltro_prompts", "prompt definitions the app authored — app data"],
|
|
@@ -363,21 +378,21 @@ var Ce = (e) => {
|
|
|
363
378
|
["_voltro_comment_threads", "the threads those comments hang on — app data"],
|
|
364
379
|
["_voltro_comment_reactions", "the reactions the app's users left — app data"],
|
|
365
380
|
["_voltro_comment_reads", "which comments each user has read — app data, and losing it re-marks everything unread"]
|
|
366
|
-
]),
|
|
381
|
+
]), V = (e) => Ke.has(e), Je = (e) => Ke.get(e), Ye = (e, t) => {
|
|
367
382
|
if (e.length === 0) return;
|
|
368
|
-
let n = e.map((e) => ` ${e} — ${
|
|
383
|
+
let n = e.map((e) => ` ${e} — ${Je(e) ?? "describes this deployment"}`);
|
|
369
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.`;
|
|
370
|
-
},
|
|
385
|
+
}, H = class extends c.TaggedError()("BundleError", {
|
|
371
386
|
reason: c.String,
|
|
372
387
|
path: c.optional(c.String)
|
|
373
|
-
}) {},
|
|
388
|
+
}) {}, Xe = class extends c.TaggedError()("CodecError", {
|
|
374
389
|
table: c.String,
|
|
375
390
|
reason: c.String
|
|
376
|
-
}) {},
|
|
391
|
+
}) {}, Ze = class extends c.TaggedError()("IntegrityError", {
|
|
377
392
|
what: c.String,
|
|
378
393
|
expected: c.String,
|
|
379
394
|
actual: c.String
|
|
380
|
-
}) {},
|
|
395
|
+
}) {}, Qe = class extends t.TaggedError("CompressionError") {}, U = class extends c.TaggedError()("ScopeError", { reason: c.String }) {}, $e = class extends c.TaggedError()("RowsRefusedError", {
|
|
381
396
|
rows: c.Array(c.Struct({
|
|
382
397
|
table: c.String,
|
|
383
398
|
id: c.String,
|
|
@@ -391,29 +406,29 @@ var Ce = (e) => {
|
|
|
391
406
|
refused: c.Number,
|
|
392
407
|
primary: c.Number
|
|
393
408
|
}))
|
|
394
|
-
}) {},
|
|
409
|
+
}) {}, et = class extends c.TaggedError()("SchemaDriftError", {
|
|
395
410
|
bundleFingerprint: c.String,
|
|
396
411
|
targetFingerprint: c.String,
|
|
397
412
|
diff: c.Array(c.String)
|
|
398
|
-
}) {},
|
|
413
|
+
}) {}, W = class extends t.TaggedError("NativeToolError") {
|
|
399
414
|
get message() {
|
|
400
415
|
let e = this.stderr?.trim(), t = this.hint?.trim();
|
|
401
416
|
return `${this.tool}: ${this.reason}${e ? `\n${e}` : ""}${t ? `\n\nhint: ${t}` : ""}`;
|
|
402
417
|
}
|
|
403
|
-
},
|
|
418
|
+
}, tt = class extends c.TaggedError()("MaskingError", {
|
|
404
419
|
unclassified: c.Array(c.String),
|
|
405
420
|
invalidActions: c.optional(c.Array(c.String))
|
|
406
|
-
}) {},
|
|
421
|
+
}) {}, nt = class extends c.TaggedError()("ImportModeError", {
|
|
407
422
|
mode: c.String,
|
|
408
423
|
reason: c.String
|
|
409
|
-
}) {},
|
|
424
|
+
}) {}, rt = class extends c.TaggedError()("CrossDialectError", {
|
|
410
425
|
sourceDialect: c.String,
|
|
411
426
|
targetDialect: c.String,
|
|
412
427
|
blocking: c.Array(c.String)
|
|
413
|
-
}) {},
|
|
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) => ({
|
|
414
429
|
col: e.name,
|
|
415
430
|
refTable: e.references.table
|
|
416
|
-
})),
|
|
431
|
+
})), ot = (e, t, r) => n.gen(function* () {
|
|
417
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) => {
|
|
418
433
|
let t = s.get(e) ?? /* @__PURE__ */ new Set();
|
|
419
434
|
return s.set(e, t), t;
|
|
@@ -431,10 +446,10 @@ var Ce = (e) => {
|
|
|
431
446
|
for (let t of n) d(t.refTable, e[t.col]);
|
|
432
447
|
};
|
|
433
448
|
}, p = (r, i) => {
|
|
434
|
-
let a = f(r,
|
|
435
|
-
return l.runForEach(
|
|
449
|
+
let a = f(r, it(t, r), at(t, r));
|
|
450
|
+
return l.runForEach(C(e, {
|
|
436
451
|
table: r,
|
|
437
|
-
pk:
|
|
452
|
+
pk: it(t, r),
|
|
438
453
|
...i === void 0 ? {} : { where: i }
|
|
439
454
|
}), (e) => n.sync(() => a(e)));
|
|
440
455
|
}, m = n.gen(function* () {
|
|
@@ -443,7 +458,7 @@ var Ce = (e) => {
|
|
|
443
458
|
c.clear();
|
|
444
459
|
for (let [n, r] of e) {
|
|
445
460
|
let e = [...r].filter((e) => !s.get(n)?.has(e));
|
|
446
|
-
e.length !== 0 && (yield* p(n, b(
|
|
461
|
+
e.length !== 0 && (yield* p(n, b(it(t, n), e)));
|
|
447
462
|
}
|
|
448
463
|
}
|
|
449
464
|
});
|
|
@@ -466,24 +481,24 @@ var Ce = (e) => {
|
|
|
466
481
|
}
|
|
467
482
|
}
|
|
468
483
|
return o;
|
|
469
|
-
}),
|
|
484
|
+
}), st = (e, t) => ({
|
|
470
485
|
tables: [...e.keys()],
|
|
471
486
|
predicateFor: (n) => {
|
|
472
487
|
let r = e.get(n);
|
|
473
|
-
return r ? b(
|
|
488
|
+
return r ? b(it(t, n), [...r]) : void 0;
|
|
474
489
|
}
|
|
475
|
-
}),
|
|
490
|
+
}), ct = "tenantId", lt = (e, t, r) => n.gen(function* () {
|
|
476
491
|
let i = t.tables.map((e) => e.name), a = new Map(t.tables.map((e) => [e.name, e]));
|
|
477
492
|
if (e.kind === "all") {
|
|
478
493
|
let t = new Set(e.exclude ?? []);
|
|
479
494
|
return {
|
|
480
|
-
tables: i.filter((e) => !
|
|
495
|
+
tables: i.filter((e) => !V(e) && !t.has(e)),
|
|
481
496
|
predicateFor: () => void 0
|
|
482
497
|
};
|
|
483
498
|
}
|
|
484
499
|
if (e.kind === "tables") {
|
|
485
500
|
let t = e.tables ?? [], r = new Set(i), a = t.filter((e) => !r.has(e));
|
|
486
|
-
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}.` }));
|
|
487
502
|
let o = new Set(t);
|
|
488
503
|
return {
|
|
489
504
|
tables: i.filter((e) => o.has(e)),
|
|
@@ -491,30 +506,30 @@ var Ce = (e) => {
|
|
|
491
506
|
};
|
|
492
507
|
}
|
|
493
508
|
let o = e.tenantId;
|
|
494
|
-
if (o === void 0 || o === "") return yield* n.fail(new
|
|
495
|
-
let s = r.tenantTables ? r.tenantTables.filter((e) => a.has(e)) : i.filter((e) => a.get(e)?.columns.some((e) => e.name ===
|
|
496
|
-
if (s.length === 0) return yield* n.fail(new
|
|
497
|
-
let c = yield*
|
|
498
|
-
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)])),
|
|
499
514
|
pinned: s,
|
|
500
515
|
children: { roots: s }
|
|
501
516
|
}), l = [...c.entries()].filter(([, e]) => e.size > 0).map(([e]) => e), u = new Set(s);
|
|
502
517
|
return {
|
|
503
518
|
tables: [...s, ...l],
|
|
504
|
-
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
|
|
505
520
|
};
|
|
506
|
-
}),
|
|
521
|
+
}), ut = (e, t) => ({
|
|
507
522
|
list: t,
|
|
508
|
-
open: (t) =>
|
|
509
|
-
}),
|
|
510
|
-
write: (t, n, r) =>
|
|
523
|
+
open: (t) => _e(e, t)
|
|
524
|
+
}), dt = (e) => ({
|
|
525
|
+
write: (t, n, r) => k(e, t, n, r),
|
|
511
526
|
has: (t) => e.head(t).pipe(n.map((e) => e !== null))
|
|
512
|
-
}),
|
|
527
|
+
}), ft = (e, t) => n.tryPromise({
|
|
513
528
|
try: async () => {
|
|
514
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) {
|
|
515
530
|
u.update(e), d += e.length, n(null, e);
|
|
516
531
|
} });
|
|
517
|
-
await o(await
|
|
532
|
+
await o(await A(e.stream), f, n(l));
|
|
518
533
|
let p = u.digest("hex"), m = c.join(t, p);
|
|
519
534
|
try {
|
|
520
535
|
await r.access(m), await r.rm(l, { force: !0 });
|
|
@@ -527,30 +542,30 @@ var Ce = (e) => {
|
|
|
527
542
|
contentType: e.contentType
|
|
528
543
|
};
|
|
529
544
|
},
|
|
530
|
-
catch: (e) => new
|
|
545
|
+
catch: (e) => new H({
|
|
531
546
|
reason: `asset write failed: ${String(e?.message ?? e)}`,
|
|
532
547
|
path: t
|
|
533
548
|
})
|
|
534
|
-
}),
|
|
535
|
-
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))));
|
|
536
551
|
yield* e.write(r.key, u, {
|
|
537
552
|
contentType: r.contentType,
|
|
538
553
|
totalSize: r.size
|
|
539
554
|
});
|
|
540
555
|
let d = c.digest("hex");
|
|
541
|
-
if (d !== r.sha256) return yield* n.fail(new
|
|
556
|
+
if (d !== r.sha256) return yield* n.fail(new Ze({
|
|
542
557
|
what: `asset ${r.key}`,
|
|
543
558
|
expected: r.sha256,
|
|
544
559
|
actual: d
|
|
545
560
|
}));
|
|
546
|
-
}),
|
|
561
|
+
}), mt = {
|
|
547
562
|
done: () => !1,
|
|
548
563
|
mark: () => n.void
|
|
549
|
-
},
|
|
550
|
-
let t = e.progress ??
|
|
551
|
-
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(() => {
|
|
552
567
|
u.push(l.key);
|
|
553
|
-
})), 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) => {
|
|
554
569
|
let n = {
|
|
555
570
|
key: l.key,
|
|
556
571
|
sha256: e.sha256,
|
|
@@ -558,7 +573,7 @@ var Ce = (e) => {
|
|
|
558
573
|
contentType: e.contentType
|
|
559
574
|
};
|
|
560
575
|
return r++, i += e.size, s.has(e.sha256) || (s.add(e.sha256), o += e.size), t.mark(l.key, n);
|
|
561
|
-
}))))))).pipe(n.mapError((e) => e instanceof
|
|
576
|
+
}))))))).pipe(n.mapError((e) => e instanceof H ? e : new H({ reason: `asset export failed: ${String(e)}` }))), {
|
|
562
577
|
count: r,
|
|
563
578
|
totalBytes: i,
|
|
564
579
|
references: a,
|
|
@@ -566,18 +581,18 @@ var Ce = (e) => {
|
|
|
566
581
|
objectBytes: o,
|
|
567
582
|
missing: u
|
|
568
583
|
};
|
|
569
|
-
}),
|
|
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({
|
|
570
585
|
reason: `asset index unreadable: ${String(t)}`,
|
|
571
586
|
path: e
|
|
572
|
-
}))),
|
|
573
|
-
let t = e.progress ??
|
|
574
|
-
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(() => {
|
|
575
590
|
r++, i.add(o.sha256);
|
|
576
591
|
})), n.andThen(t.mark(o.key, o)))), {
|
|
577
592
|
count: r,
|
|
578
593
|
objects: i.size
|
|
579
594
|
};
|
|
580
|
-
}),
|
|
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({
|
|
581
596
|
name: c.String,
|
|
582
597
|
file: c.String,
|
|
583
598
|
rowCount: c.Number,
|
|
@@ -587,12 +602,12 @@ var Ce = (e) => {
|
|
|
587
602
|
value: c.String
|
|
588
603
|
}),
|
|
589
604
|
primaryKey: c.String
|
|
590
|
-
}),
|
|
605
|
+
}), Et = c.Struct({
|
|
591
606
|
kind: c.Literal("all", "tenant", "tables"),
|
|
592
607
|
tenantId: c.optional(c.String),
|
|
593
608
|
tables: c.optional(c.Array(c.String)),
|
|
594
609
|
exclude: c.optional(c.Array(c.String))
|
|
595
|
-
}),
|
|
610
|
+
}), Dt = c.Struct({
|
|
596
611
|
count: c.Number,
|
|
597
612
|
totalBytes: c.Number,
|
|
598
613
|
index: c.optional(c.String)
|
|
@@ -603,23 +618,23 @@ c.Struct({
|
|
|
603
618
|
size: c.Number,
|
|
604
619
|
contentType: c.String
|
|
605
620
|
});
|
|
606
|
-
var
|
|
621
|
+
var Ot = c.Struct({
|
|
607
622
|
formatVersion: c.Number,
|
|
608
623
|
createdAt: c.String,
|
|
609
624
|
source: c.Struct({
|
|
610
625
|
dialect: c.String,
|
|
611
626
|
schemaFingerprint: c.String
|
|
612
627
|
}),
|
|
613
|
-
scope:
|
|
628
|
+
scope: Et,
|
|
614
629
|
consistency: c.Literal("live", "snapshot"),
|
|
615
630
|
compression: c.Literal("zstd", "gzip", "none"),
|
|
616
|
-
tables: c.Array(
|
|
617
|
-
assets:
|
|
631
|
+
tables: c.Array(Tt),
|
|
632
|
+
assets: Dt,
|
|
618
633
|
masking: c.optional(c.Struct({
|
|
619
634
|
policyId: c.optional(c.String),
|
|
620
635
|
transformed: c.Array(c.String)
|
|
621
636
|
}))
|
|
622
|
-
}),
|
|
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) => {
|
|
623
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");
|
|
624
639
|
return `# Voltro data export
|
|
625
640
|
|
|
@@ -633,7 +648,7 @@ The machine-readable manifest is \`manifest.json\`; this file is a human summary
|
|
|
633
648
|
| **Format version** | ${e.formatVersion} |
|
|
634
649
|
| **Consistency** | ${e.consistency} |
|
|
635
650
|
| **Compression** | ${e.compression} |
|
|
636
|
-
| **Scope** | ${
|
|
651
|
+
| **Scope** | ${Lt(e.scope)} |
|
|
637
652
|
| **Tables** | ${e.tables.length} |
|
|
638
653
|
| **Rows (total)** | ${n} |
|
|
639
654
|
| **Assets** | ${a} |
|
|
@@ -658,39 +673,39 @@ voltro data import <this-directory>
|
|
|
658
673
|
voltro data import <this-directory> --target api --api-url <url> --token <secret>
|
|
659
674
|
\`\`\`
|
|
660
675
|
`;
|
|
661
|
-
},
|
|
676
|
+
}, zt = i.counter("voltro_data_transfer_rows", { description: "Rows exported/imported by @voltro/data-transfer, tagged by phase + table." }), Bt = a.exponential({
|
|
662
677
|
start: .01,
|
|
663
678
|
factor: 2,
|
|
664
679
|
count: 16
|
|
665
|
-
}),
|
|
680
|
+
}), Vt = i.histogram("voltro_data_transfer_table_seconds", Bt, "Per-table export/import duration in seconds, tagged by phase."), G = (e, t) => {
|
|
666
681
|
if (e) try {
|
|
667
682
|
e(t);
|
|
668
683
|
} catch {}
|
|
669
|
-
},
|
|
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: {
|
|
670
685
|
table: t,
|
|
671
686
|
index: r,
|
|
672
687
|
tableCount: a,
|
|
673
688
|
phase: e
|
|
674
|
-
} })),
|
|
689
|
+
} })), Ut = () => ({
|
|
675
690
|
tables: {},
|
|
676
691
|
assets: {}
|
|
677
|
-
}),
|
|
692
|
+
}), Wt = (e) => n.tryPromise(async () => {
|
|
678
693
|
let t = await (await import("node:fs/promises")).readFile(e, "utf8");
|
|
679
694
|
return JSON.parse(t);
|
|
680
|
-
}).pipe(n.orElseSucceed(
|
|
695
|
+
}).pipe(n.orElseSucceed(Ut)), K = (e, t) => n.tryPromise({
|
|
681
696
|
try: async () => {
|
|
682
697
|
let n = await import("node:fs/promises"), { randomUUID: r } = await import("node:crypto"), i = `${e}.tmp-${r()}`;
|
|
683
698
|
await n.writeFile(i, JSON.stringify(t)), await n.rename(i, e);
|
|
684
699
|
},
|
|
685
|
-
catch: (t) => new
|
|
700
|
+
catch: (t) => new H({
|
|
686
701
|
reason: `ledger write failed: ${String(t?.message ?? t)}`,
|
|
687
702
|
path: e
|
|
688
703
|
})
|
|
689
|
-
}),
|
|
704
|
+
}), Gt = (e, t) => t in e.tables, Kt = (e, t) => t in e.assets, qt = /* @__PURE__ */ new Set([
|
|
690
705
|
"json",
|
|
691
706
|
"array",
|
|
692
707
|
"vector"
|
|
693
|
-
]),
|
|
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" ? {
|
|
694
709
|
$v: "bigint",
|
|
695
710
|
d: e.toString()
|
|
696
711
|
} : typeof e == "number" && !Number.isFinite(e) ? {
|
|
@@ -701,30 +716,30 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
701
716
|
d: e.toISOString()
|
|
702
717
|
} : e instanceof Uint8Array ? {
|
|
703
718
|
$v: "bytes",
|
|
704
|
-
d:
|
|
705
|
-
} : e,
|
|
719
|
+
d: Yt(e)
|
|
720
|
+
} : e, $t = (e) => {
|
|
706
721
|
switch (e.$v) {
|
|
707
722
|
case "bigint": return BigInt(e.d);
|
|
708
723
|
case "number": return Number(e.d);
|
|
709
724
|
case "date": return new Date(e.d);
|
|
710
|
-
case "bytes": return
|
|
725
|
+
case "bytes": return Xt(e.d);
|
|
711
726
|
default: return e;
|
|
712
727
|
}
|
|
713
|
-
},
|
|
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) => {
|
|
714
729
|
let n = {};
|
|
715
|
-
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]);
|
|
716
731
|
return n;
|
|
717
|
-
},
|
|
732
|
+
}, nn = (e, t) => {
|
|
718
733
|
let n = {};
|
|
719
|
-
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]);
|
|
720
735
|
return n;
|
|
721
|
-
},
|
|
722
|
-
try: () =>
|
|
723
|
-
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({
|
|
724
739
|
table: t,
|
|
725
740
|
reason: String(e?.message ?? e)
|
|
726
741
|
})
|
|
727
|
-
}))),
|
|
742
|
+
}))), sn = (e, t) => {
|
|
728
743
|
let n = new Set(e), r = /* @__PURE__ */ new Map();
|
|
729
744
|
for (let e of t.tables) {
|
|
730
745
|
if (!n.has(e.name)) continue;
|
|
@@ -744,39 +759,39 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
744
759
|
};
|
|
745
760
|
for (let t of e) n.has(t) && s(t);
|
|
746
761
|
return i;
|
|
747
|
-
},
|
|
762
|
+
}, q = (e) => {
|
|
748
763
|
let t = e, n = [];
|
|
749
764
|
typeof t?._tag == "string" && t._tag !== "" && n.push(t._tag);
|
|
750
765
|
let r = typeof t?.message == "string" ? t.message.trim() : "";
|
|
751
|
-
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) {
|
|
752
767
|
let t = String(e ?? "").trim();
|
|
753
|
-
return t === "" || t === "[object Object]" ?
|
|
768
|
+
return t === "" || t === "[object Object]" ? cn(e) : t;
|
|
754
769
|
}
|
|
755
770
|
return n.join(": ");
|
|
756
|
-
},
|
|
771
|
+
}, cn = (e) => {
|
|
757
772
|
try {
|
|
758
773
|
let t = JSON.stringify(e);
|
|
759
774
|
return t === void 0 || t === "{}" ? "unknown error (no message, cause or tag)" : t;
|
|
760
775
|
} catch {
|
|
761
776
|
return "unknown error (not serialisable)";
|
|
762
777
|
}
|
|
763
|
-
},
|
|
778
|
+
}, ln = (e, t) => {
|
|
764
779
|
let n = e.tables.find((e) => e.name === t), r = {};
|
|
765
780
|
for (let e of n?.columns ?? []) e.generatedAs === void 0 && (r[e.name] = e.type);
|
|
766
781
|
return r;
|
|
767
|
-
},
|
|
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) => {
|
|
768
783
|
if (t.length === 0) return e;
|
|
769
784
|
let n = { ...e };
|
|
770
785
|
for (let e of t) delete n[e];
|
|
771
786
|
return n;
|
|
772
|
-
},
|
|
787
|
+
}, fn = (e, t) => {
|
|
773
788
|
let n = e.tables.find((e) => e.name === t);
|
|
774
789
|
if (n === void 0) return { refusal: `${t}: not in the schema snapshot, so its primary key is unknown.` };
|
|
775
790
|
let r = n.columns.find((e) => e.type === "id");
|
|
776
791
|
if (r !== void 0) return { column: r.name };
|
|
777
792
|
let i = n.indexes.find((e) => e.name === `${t}_pkey`)?.columns ?? n.primaryKey ?? [];
|
|
778
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.` };
|
|
779
|
-
},
|
|
794
|
+
}, pn = (e, t, r) => n.tryPromise({
|
|
780
795
|
try: async () => {
|
|
781
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) {
|
|
782
797
|
d.update(e);
|
|
@@ -785,7 +800,7 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
785
800
|
n(null, e);
|
|
786
801
|
} }), m = c.fromWeb(l.toReadableStream(e)), h = `${t}.tmp-${o()}`;
|
|
787
802
|
try {
|
|
788
|
-
await s(m, p,
|
|
803
|
+
await s(m, p, St(r), n(h)), await i.rename(h, t);
|
|
789
804
|
} catch (e) {
|
|
790
805
|
throw await i.rm(h, { force: !0 }).catch(() => {}), e;
|
|
791
806
|
}
|
|
@@ -794,27 +809,27 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
794
809
|
checksum: d.digest("hex")
|
|
795
810
|
};
|
|
796
811
|
},
|
|
797
|
-
catch: (e) => new
|
|
798
|
-
reason: `write table failed: ${
|
|
812
|
+
catch: (e) => new H({
|
|
813
|
+
reason: `write table failed: ${q(e)}`,
|
|
799
814
|
path: t
|
|
800
815
|
})
|
|
801
|
-
}),
|
|
816
|
+
}), mn = (e, t) => n.tryPromise({
|
|
802
817
|
try: async () => {
|
|
803
818
|
await (await import("node:fs/promises")).appendFile(e, `${t}\n`);
|
|
804
819
|
},
|
|
805
|
-
catch: (t) => new
|
|
806
|
-
reason: `append failed: ${
|
|
820
|
+
catch: (t) => new H({
|
|
821
|
+
reason: `append failed: ${q(t)}`,
|
|
807
822
|
path: e
|
|
808
823
|
})
|
|
809
|
-
}),
|
|
824
|
+
}), hn = (e, t) => n.gen(function* () {
|
|
810
825
|
let r = [], i = t.ordered.length;
|
|
811
826
|
for (let a = 0; a < t.ordered.length; a++) {
|
|
812
|
-
let o = t.ordered[a], s =
|
|
813
|
-
if ("refusal" in c) return yield* n.fail(new
|
|
814
|
-
let u = c.column, d = `${
|
|
815
|
-
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)) {
|
|
816
831
|
let e = t.ledger.tables[o];
|
|
817
|
-
|
|
832
|
+
G(t.onProgress, {
|
|
818
833
|
phase: "export",
|
|
819
834
|
table: o,
|
|
820
835
|
index: a,
|
|
@@ -832,7 +847,7 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
832
847
|
});
|
|
833
848
|
continue;
|
|
834
849
|
}
|
|
835
|
-
|
|
850
|
+
G(t.onProgress, {
|
|
836
851
|
phase: "export",
|
|
837
852
|
table: o,
|
|
838
853
|
index: a,
|
|
@@ -840,17 +855,17 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
840
855
|
event: "start",
|
|
841
856
|
rowsDone: 0
|
|
842
857
|
});
|
|
843
|
-
let f = t.resolved.predicateFor(o), p =
|
|
858
|
+
let f = t.resolved.predicateFor(o), p = C(e, {
|
|
844
859
|
table: o,
|
|
845
860
|
pk: u,
|
|
846
861
|
chunkSize: t.chunkSize,
|
|
847
862
|
retry: t.retry,
|
|
848
863
|
...f === void 0 ? {} : { where: f }
|
|
849
|
-
}), 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));
|
|
850
865
|
t.ledger.tables[o] = {
|
|
851
866
|
rowCount: _,
|
|
852
867
|
checksum: v
|
|
853
|
-
}, yield*
|
|
868
|
+
}, yield* K(t.ledgerPath, t.ledger), G(t.onProgress, {
|
|
854
869
|
phase: "export",
|
|
855
870
|
table: o,
|
|
856
871
|
index: a,
|
|
@@ -868,43 +883,43 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
868
883
|
});
|
|
869
884
|
}
|
|
870
885
|
return r;
|
|
871
|
-
}),
|
|
886
|
+
}), gn = (e) => ({
|
|
872
887
|
_tag: "RawSqlFragment",
|
|
873
888
|
strings: [e],
|
|
874
889
|
values: []
|
|
875
|
-
}),
|
|
890
|
+
}), _n = (t, i, a) => n.tryPromise({
|
|
876
891
|
try: () => t.transactional(async (t) => {
|
|
877
|
-
if (t.raw) for (let e of
|
|
892
|
+
if (t.raw) for (let e of Ee(i)) await t.raw(gn(e));
|
|
878
893
|
let o = await n.runPromiseExit(a(t));
|
|
879
894
|
if (r.isFailure(o)) throw Error(e.pretty(o.cause));
|
|
880
895
|
return o.value;
|
|
881
896
|
}),
|
|
882
|
-
catch: (e) => e instanceof
|
|
883
|
-
}),
|
|
884
|
-
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);
|
|
885
900
|
yield* n.tryPromise({
|
|
886
901
|
try: async () => {
|
|
887
902
|
let t = await import("node:fs/promises");
|
|
888
|
-
await t.mkdir(l(
|
|
903
|
+
await t.mkdir(l(Nt), { recursive: !0 }), e.assets && await t.mkdir(l(Pt), { recursive: !0 });
|
|
889
904
|
},
|
|
890
|
-
catch: (t) => new
|
|
891
|
-
reason: `mkdir failed: ${
|
|
905
|
+
catch: (t) => new H({
|
|
906
|
+
reason: `mkdir failed: ${q(t)}`,
|
|
892
907
|
path: e.outDir
|
|
893
908
|
})
|
|
894
909
|
});
|
|
895
|
-
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, {
|
|
896
911
|
store: e.store,
|
|
897
912
|
...e.tenantTables ? { tenantTables: e.tenantTables } : {}
|
|
898
|
-
}), p =
|
|
913
|
+
}), p = sn(f.tables, e.snapshot), m = e.consistency ?? "live", h, g;
|
|
899
914
|
if (e.masking) {
|
|
900
|
-
let t = e.classification ??
|
|
915
|
+
let t = e.classification ?? Oe(e.snapshot), r = He(p.map((t) => ({
|
|
901
916
|
name: t,
|
|
902
917
|
columns: (e.snapshot.tables.find((e) => e.name === t)?.columns ?? []).map((e) => ({
|
|
903
918
|
name: e.name,
|
|
904
919
|
type: e.type
|
|
905
920
|
}))
|
|
906
921
|
})), t, e.masking);
|
|
907
|
-
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({
|
|
908
923
|
unclassified: r.unclassified,
|
|
909
924
|
...r.invalid.length > 0 ? { invalidActions: r.invalid.map((e) => `${e.column}: ${JSON.stringify(e.action)}`) } : {}
|
|
910
925
|
}));
|
|
@@ -930,14 +945,14 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
930
945
|
bundleFile: l,
|
|
931
946
|
...g ? { mask: g } : {},
|
|
932
947
|
...e.onProgress ? { onProgress: e.onProgress } : {}
|
|
933
|
-
}, 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;
|
|
934
949
|
if (e.assets) {
|
|
935
|
-
let t = l(
|
|
950
|
+
let t = l(Ft), r = yield* gt({
|
|
936
951
|
source: e.assets,
|
|
937
|
-
assetsDir: l(
|
|
952
|
+
assetsDir: l(Pt),
|
|
938
953
|
progress: {
|
|
939
954
|
done: (e) => e in d.assets,
|
|
940
|
-
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))))
|
|
941
956
|
}
|
|
942
957
|
});
|
|
943
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` : "")));
|
|
@@ -947,7 +962,7 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
947
962
|
createdAt: e.createdAt ?? (/* @__PURE__ */ new Date()).toISOString(),
|
|
948
963
|
source: {
|
|
949
964
|
dialect: e.dialect,
|
|
950
|
-
schemaFingerprint:
|
|
965
|
+
schemaFingerprint: w(e.snapshot)
|
|
951
966
|
},
|
|
952
967
|
scope: t,
|
|
953
968
|
consistency: m,
|
|
@@ -956,7 +971,7 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
956
971
|
assets: y > 0 ? {
|
|
957
972
|
count: y,
|
|
958
973
|
totalBytes: b,
|
|
959
|
-
index:
|
|
974
|
+
index: Ft
|
|
960
975
|
} : {
|
|
961
976
|
count: 0,
|
|
962
977
|
totalBytes: 0
|
|
@@ -965,23 +980,23 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
965
980
|
};
|
|
966
981
|
return yield* n.tryPromise({
|
|
967
982
|
try: async () => {
|
|
968
|
-
await (await import("node:fs/promises")).writeFile(l(
|
|
983
|
+
await (await import("node:fs/promises")).writeFile(l(jt), kt(x));
|
|
969
984
|
},
|
|
970
|
-
catch: (e) => new
|
|
971
|
-
reason: `manifest write failed: ${
|
|
972
|
-
path:
|
|
985
|
+
catch: (e) => new H({
|
|
986
|
+
reason: `manifest write failed: ${q(e)}`,
|
|
987
|
+
path: jt
|
|
973
988
|
})
|
|
974
989
|
}), yield* n.tryPromise({
|
|
975
990
|
try: async () => {
|
|
976
991
|
let e = await import("node:fs/promises"), t = await import("node:os");
|
|
977
|
-
await e.writeFile(l(
|
|
992
|
+
await e.writeFile(l(Mt), Rt(x, { hostname: t.hostname() }));
|
|
978
993
|
},
|
|
979
|
-
catch: (e) => new
|
|
980
|
-
reason: `readme write failed: ${
|
|
981
|
-
path:
|
|
994
|
+
catch: (e) => new H({
|
|
995
|
+
reason: `readme write failed: ${q(e)}`,
|
|
996
|
+
path: Mt
|
|
982
997
|
})
|
|
983
998
|
}), x;
|
|
984
|
-
}),
|
|
999
|
+
}), yn = (e, t) => {
|
|
985
1000
|
let n = new Set(t), r = [];
|
|
986
1001
|
for (let t of e.tables) if (!n.has(t.name)) for (let e of t.columns) {
|
|
987
1002
|
let i = e.references?.table;
|
|
@@ -992,7 +1007,7 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
992
1007
|
});
|
|
993
1008
|
}
|
|
994
1009
|
return r;
|
|
995
|
-
},
|
|
1010
|
+
}, bn = (e) => {
|
|
996
1011
|
let t = /* @__PURE__ */ new Map();
|
|
997
1012
|
for (let n of e) t.set(n.from, [...t.get(n.from) ?? [], n]);
|
|
998
1013
|
let n = [...t.entries()].map(([e, t]) => {
|
|
@@ -1000,7 +1015,7 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
1000
1015
|
return ` ${e} (${n} row${n === 1 ? "" : "s"}): ${r}`;
|
|
1001
1016
|
});
|
|
1002
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.`;
|
|
1003
|
-
},
|
|
1018
|
+
}, xn = (e) => {
|
|
1004
1019
|
switch (e) {
|
|
1005
1020
|
case "id":
|
|
1006
1021
|
case "text":
|
|
@@ -1019,12 +1034,12 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
1019
1034
|
case "raw": return "raw";
|
|
1020
1035
|
default: return "string";
|
|
1021
1036
|
}
|
|
1022
|
-
},
|
|
1037
|
+
}, Sn = {
|
|
1023
1038
|
vector: /* @__PURE__ */ new Set(["postgres"]),
|
|
1024
1039
|
array: /* @__PURE__ */ new Set(["postgres"]),
|
|
1025
1040
|
interval: /* @__PURE__ */ new Set(["postgres"])
|
|
1026
|
-
},
|
|
1027
|
-
let i =
|
|
1041
|
+
}, Cn = (e, t, n, r) => {
|
|
1042
|
+
let i = xn(n);
|
|
1028
1043
|
if (i === "raw") return {
|
|
1029
1044
|
table: e,
|
|
1030
1045
|
column: t,
|
|
@@ -1032,7 +1047,7 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
1032
1047
|
severity: "block",
|
|
1033
1048
|
reason: `raw() is verbatim source-dialect SQL — it cannot be assumed valid on ${r}`
|
|
1034
1049
|
};
|
|
1035
|
-
let a =
|
|
1050
|
+
let a = Sn[i];
|
|
1036
1051
|
return !a || a.has(r) ? null : i === "array" || i === "interval" ? {
|
|
1037
1052
|
table: e,
|
|
1038
1053
|
column: t,
|
|
@@ -1046,15 +1061,15 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
1046
1061
|
severity: "block",
|
|
1047
1062
|
reason: `${i} columns require a ${[...a].join("/")} target; ${r} has no compatible column type`
|
|
1048
1063
|
};
|
|
1049
|
-
},
|
|
1064
|
+
}, wn = (e, t, n) => {
|
|
1050
1065
|
if (t === n) return [];
|
|
1051
1066
|
let r = [];
|
|
1052
1067
|
for (let t of e) for (let [e, i] of Object.entries(t.columnTypes)) {
|
|
1053
|
-
let a =
|
|
1068
|
+
let a = Cn(t.name, e, i, n);
|
|
1054
1069
|
a && r.push(a);
|
|
1055
1070
|
}
|
|
1056
1071
|
return r;
|
|
1057
|
-
},
|
|
1072
|
+
}, Tn = (e) => `[${e.severity}] ${e.table}.${e.column} (${e.type}): ${e.reason}`, En = (e) => {
|
|
1058
1073
|
let t = e.constraint ?? e.column, n = t === void 0 ? "" : ` ${t}`;
|
|
1059
1074
|
switch (e.kind) {
|
|
1060
1075
|
case "foreignKey": return `foreign key${n}: the referenced row does not exist (import it first, or check the bundle's table order)`;
|
|
@@ -1063,36 +1078,36 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
1063
1078
|
case "notNull": return `not-null constraint${n}: the column requires a value`;
|
|
1064
1079
|
case "check": return `check constraint${n}: the row does not satisfy it`;
|
|
1065
1080
|
}
|
|
1066
|
-
},
|
|
1081
|
+
}, Dn = (e) => {
|
|
1067
1082
|
let t = [e.dbCode, e.dbErrno ?? e.dbNumber].filter((e) => e !== void 0).map(String);
|
|
1068
1083
|
return t.length > 0 ? t.join("/") : void 0;
|
|
1069
|
-
},
|
|
1084
|
+
}, On = "Failed to execute statement", kn = (e) => {
|
|
1070
1085
|
let t = (e.split("\n", 1)[0] ?? "").trim();
|
|
1071
1086
|
for (; t.startsWith("(FiberFailure)");) t = t.slice(14).trim();
|
|
1072
|
-
return t === `SqlError: ${
|
|
1073
|
-
},
|
|
1087
|
+
return t === `SqlError: ${On}` ? On : t;
|
|
1088
|
+
}, An = (e) => {
|
|
1074
1089
|
let t = String(e?.stack ?? e), n = t.length <= 1200 ? t : `${t.slice(0, 1200)}…`, r = (e, t) => ({
|
|
1075
1090
|
reason: e.length <= 300 ? e : `${e.slice(0, 300)}…`,
|
|
1076
1091
|
unclassified: t,
|
|
1077
1092
|
raw: n
|
|
1078
|
-
}), i = v(e), a = m(i), o =
|
|
1079
|
-
if (a !== void 0) return r(`${
|
|
1080
|
-
let c = typeof i.dbMessage == "string" ? i.dbMessage : void 0, l = e?.message, u =
|
|
1081
|
-
return r(d ===
|
|
1082
|
-
},
|
|
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) => {
|
|
1083
1098
|
let t = v(e), n = m(t);
|
|
1084
1099
|
if (n?.kind === "foreignKeyInUse") {
|
|
1085
|
-
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);
|
|
1086
1101
|
return `foreign key${r}: rows elsewhere still reference this table${i === void 0 ? "" : ` [${i}]`}`;
|
|
1087
1102
|
}
|
|
1088
|
-
return
|
|
1089
|
-
},
|
|
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
|
|
1090
1105
|
process that dies mid-load depends on the database rolling it back. The rollback capture
|
|
1091
|
-
written before the first delete is what covers that case.`,
|
|
1092
|
-
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.`);
|
|
1093
1108
|
return t === "mysql" || t === "mariadb" ? `\`${e}\`` : t === "mssql" ? `[${e}]` : `"${e}"`;
|
|
1094
|
-
},
|
|
1095
|
-
let n =
|
|
1109
|
+
}, Ln = (e, t) => {
|
|
1110
|
+
let n = Y(e, t), r = Y(J(e), t);
|
|
1096
1111
|
switch (t) {
|
|
1097
1112
|
case "postgres": return `CREATE TABLE ${r} (LIKE ${n})`;
|
|
1098
1113
|
case "mysql":
|
|
@@ -1100,20 +1115,20 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
1100
1115
|
case "sqlite": return `CREATE TABLE ${r} AS SELECT * FROM ${n} WHERE 0`;
|
|
1101
1116
|
case "mssql": return `SELECT * INTO ${r} FROM ${n} WHERE 1 = 0`;
|
|
1102
1117
|
}
|
|
1103
|
-
},
|
|
1104
|
-
let n =
|
|
1105
|
-
return t === "mssql" ? `IF OBJECT_ID('${
|
|
1106
|
-
},
|
|
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) => {
|
|
1107
1122
|
let n = t === "mysql" || t === "mariadb", r = [];
|
|
1108
1123
|
n && r.push("SET FOREIGN_KEY_CHECKS = 0");
|
|
1109
|
-
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)}`);
|
|
1110
1125
|
for (let n of e) {
|
|
1111
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.`);
|
|
1112
|
-
let e = n.columns.map((e) =>
|
|
1113
|
-
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)}`);
|
|
1114
1129
|
}
|
|
1115
1130
|
return n && r.push("SET FOREIGN_KEY_CHECKS = 1"), r;
|
|
1116
|
-
},
|
|
1131
|
+
}, Bn = (e, t) => {
|
|
1117
1132
|
let n = [], r = () => {
|
|
1118
1133
|
for (let e of n) t.unregisterTable(e);
|
|
1119
1134
|
};
|
|
@@ -1121,7 +1136,7 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
1121
1136
|
for (let r of e) {
|
|
1122
1137
|
let e = t.getTable(r);
|
|
1123
1138
|
if (e === void 0) continue;
|
|
1124
|
-
let i =
|
|
1139
|
+
let i = J(r);
|
|
1125
1140
|
t.registerTable({
|
|
1126
1141
|
...e,
|
|
1127
1142
|
tableName: i,
|
|
@@ -1135,7 +1150,7 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
1135
1150
|
staged: n,
|
|
1136
1151
|
undo: r
|
|
1137
1152
|
};
|
|
1138
|
-
},
|
|
1153
|
+
}, Vn = (e, t) => {
|
|
1139
1154
|
let n = new Set(t), r = [];
|
|
1140
1155
|
for (let t of e.tables) {
|
|
1141
1156
|
if (!n.has(t.name)) continue;
|
|
@@ -1152,22 +1167,22 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
1152
1167
|
}
|
|
1153
1168
|
}
|
|
1154
1169
|
return r;
|
|
1155
|
-
},
|
|
1156
|
-
let n =
|
|
1157
|
-
return `SELECT ${
|
|
1158
|
-
},
|
|
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) => {
|
|
1159
1174
|
if (e.length === 0) return;
|
|
1160
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}`);
|
|
1161
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.";
|
|
1162
|
-
},
|
|
1163
|
-
t.length !== 0 && await e.run(
|
|
1164
|
-
},
|
|
1165
|
-
let i =
|
|
1166
|
-
i.length !== 0 && await e.run(
|
|
1167
|
-
},
|
|
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) => {
|
|
1168
1183
|
let i = [];
|
|
1169
1184
|
for (let a of t) {
|
|
1170
|
-
let t = await e.run(
|
|
1185
|
+
let t = await e.run(N.SqlClient.pipe(n.flatMap((e) => e.unsafe(Hn(a, r)))));
|
|
1171
1186
|
for (let e of t) i.push({
|
|
1172
1187
|
table: a.from,
|
|
1173
1188
|
primaryKey: String(e.pk ?? ""),
|
|
@@ -1177,14 +1192,14 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
1177
1192
|
});
|
|
1178
1193
|
}
|
|
1179
1194
|
return i;
|
|
1180
|
-
},
|
|
1195
|
+
}, qn = (e, t) => {
|
|
1181
1196
|
let n = new Map(t.map((e, t) => [e, t]));
|
|
1182
1197
|
return e.filter((e) => {
|
|
1183
1198
|
if (e.from === e.to) return !1;
|
|
1184
1199
|
let t = n.get(e.from), r = n.get(e.to);
|
|
1185
1200
|
return t === void 0 || r === void 0 ? !1 : r > t;
|
|
1186
1201
|
});
|
|
1187
|
-
},
|
|
1202
|
+
}, Jn = (e) => e === "mysql" || e === "mariadb", Yn = (e) => {
|
|
1188
1203
|
if (e.mode !== "replace") return {
|
|
1189
1204
|
active: !1,
|
|
1190
1205
|
tables: [],
|
|
@@ -1234,7 +1249,7 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
1234
1249
|
tables: [],
|
|
1235
1250
|
blocker: "every table in the bundle is one that describes a deployment, so there is nothing for a staged swap to move."
|
|
1236
1251
|
};
|
|
1237
|
-
let s = o.map((e) => e.name), c =
|
|
1252
|
+
let s = o.map((e) => e.name), c = Jn(t) ? [] : qn(Vn(n, s), s);
|
|
1238
1253
|
return c.length > 0 ? {
|
|
1239
1254
|
active: !1,
|
|
1240
1255
|
tables: [],
|
|
@@ -1243,9 +1258,9 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
1243
1258
|
active: !0,
|
|
1244
1259
|
tables: o
|
|
1245
1260
|
};
|
|
1246
|
-
},
|
|
1261
|
+
}, Xn = (e) => n.gen(function* () {
|
|
1247
1262
|
if (e.mode !== "replace" || e.dir === void 0 || e.tables.length === 0) return;
|
|
1248
|
-
if (e.snapshot === void 0) return yield* n.fail(new
|
|
1263
|
+
if (e.snapshot === void 0) return yield* n.fail(new H({
|
|
1249
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.",
|
|
1250
1265
|
path: e.dir
|
|
1251
1266
|
}));
|
|
@@ -1256,14 +1271,14 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
1256
1271
|
if (t.tables.length === 0) return;
|
|
1257
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,
|
|
1258
1273
|
so it survives a run whose process does not.`);
|
|
1259
|
-
let r = yield*
|
|
1274
|
+
let r = yield* vn({
|
|
1260
1275
|
store: e.store,
|
|
1261
1276
|
snapshot: t,
|
|
1262
1277
|
dialect: e.dialect ?? "unknown",
|
|
1263
1278
|
outDir: e.dir,
|
|
1264
1279
|
scope: { kind: "all" },
|
|
1265
1280
|
compression: "none"
|
|
1266
|
-
}).pipe(n.mapError((t) => new
|
|
1281
|
+
}).pipe(n.mapError((t) => new H({
|
|
1267
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.`,
|
|
1268
1283
|
path: e.dir
|
|
1269
1284
|
})));
|
|
@@ -1272,18 +1287,18 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
1272
1287
|
rows: r.tables.reduce((e, t) => e + t.rowCount, 0),
|
|
1273
1288
|
tables: r.tables.length
|
|
1274
1289
|
};
|
|
1275
|
-
}),
|
|
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) => {
|
|
1276
1291
|
let n = [];
|
|
1277
1292
|
for (let r of [...e.tables].sort((e, t) => e.name.localeCompare(t.name))) {
|
|
1278
|
-
if (
|
|
1293
|
+
if (Qn(t, r.name) === void 0) {
|
|
1279
1294
|
n.push(`table '${r.name}' is in the bundle but MISSING from the target — its rows have nowhere to go`);
|
|
1280
1295
|
continue;
|
|
1281
1296
|
}
|
|
1282
|
-
let e =
|
|
1297
|
+
let e = $n(t, r.name), i = new Map(r.columns.map((e) => [e.name, e]));
|
|
1283
1298
|
for (let [t, a] of i) {
|
|
1284
1299
|
let i = e.get(t);
|
|
1285
1300
|
if (i === void 0) {
|
|
1286
|
-
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`);
|
|
1287
1302
|
continue;
|
|
1288
1303
|
}
|
|
1289
1304
|
i.type !== a.type && n.push(`${r.name}.${t}: type '${a.type}' (bundle) vs '${i.type}' (target)`);
|
|
@@ -1291,22 +1306,22 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
1291
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`);
|
|
1292
1307
|
}
|
|
1293
1308
|
return n.length > 30 ? [...n.slice(0, 30), `… and ${n.length - 30} more difference(s)`] : n;
|
|
1294
|
-
},
|
|
1295
|
-
let r =
|
|
1309
|
+
}, nr = (e, t, n) => {
|
|
1310
|
+
let r = w(t);
|
|
1296
1311
|
if (r === e || n === void 0) return {
|
|
1297
1312
|
drifted: !1,
|
|
1298
1313
|
bundleFingerprint: e,
|
|
1299
1314
|
targetFingerprint: r,
|
|
1300
1315
|
diff: []
|
|
1301
1316
|
};
|
|
1302
|
-
let i =
|
|
1317
|
+
let i = tr(n, t);
|
|
1303
1318
|
return {
|
|
1304
1319
|
drifted: i.length > 0,
|
|
1305
1320
|
bundleFingerprint: e,
|
|
1306
1321
|
targetFingerprint: r,
|
|
1307
1322
|
diff: i
|
|
1308
1323
|
};
|
|
1309
|
-
},
|
|
1324
|
+
}, rr = 2e3, ir = 2e3, ar = 200, or = /* @__PURE__ */ new Set([
|
|
1310
1325
|
"BundleError",
|
|
1311
1326
|
"CodecError",
|
|
1312
1327
|
"IntegrityError",
|
|
@@ -1315,33 +1330,33 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
1315
1330
|
"RowsRefusedError",
|
|
1316
1331
|
"SchemaDriftError",
|
|
1317
1332
|
"StorageError"
|
|
1318
|
-
]),
|
|
1333
|
+
]), sr = (t) => {
|
|
1319
1334
|
let n = o.isFiberFailure(t) ? [...e.failures(t[o.FiberFailureCauseId]), ...e.defects(t[o.FiberFailureCauseId])] : [t];
|
|
1320
1335
|
for (let e of n) {
|
|
1321
1336
|
let t = e?._tag;
|
|
1322
|
-
if (typeof t == "string" &&
|
|
1337
|
+
if (typeof t == "string" && or.has(t)) return e;
|
|
1323
1338
|
if (o.isFiberFailure(e)) {
|
|
1324
|
-
let t =
|
|
1339
|
+
let t = sr(e);
|
|
1325
1340
|
if (t) return t;
|
|
1326
1341
|
}
|
|
1327
1342
|
}
|
|
1328
|
-
},
|
|
1343
|
+
}, cr = (t) => [...e.failures(t)][0] ?? Error(e.pretty(t)), lr = (e) => n.tryPromise({
|
|
1329
1344
|
try: async () => {
|
|
1330
1345
|
let t = await import("node:fs/promises"), n = await import("node:path");
|
|
1331
|
-
return
|
|
1346
|
+
return At(await t.readFile(n.join(e, jt), "utf8"));
|
|
1332
1347
|
},
|
|
1333
|
-
catch: (e) => new
|
|
1348
|
+
catch: (e) => new H({
|
|
1334
1349
|
reason: `manifest read/parse failed: ${String(e?.message ?? e)}`,
|
|
1335
|
-
path:
|
|
1350
|
+
path: jt
|
|
1336
1351
|
})
|
|
1337
|
-
}),
|
|
1352
|
+
}), ur = (e) => {
|
|
1338
1353
|
let t;
|
|
1339
1354
|
return n.gen(function* () {
|
|
1340
|
-
let i = yield* n.promise(() => import("node:path")), a = yield*
|
|
1341
|
-
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)` }));
|
|
1342
1357
|
if (e.tables !== void 0) {
|
|
1343
1358
|
let t = new Set(a.tables.map((e) => e.name)), r = e.tables.filter((e) => !t.has(e));
|
|
1344
|
-
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(", ")}.` }));
|
|
1345
1360
|
}
|
|
1346
1361
|
let o = e.tables === void 0 ? void 0 : new Set(e.tables), s = o === void 0 ? a : {
|
|
1347
1362
|
...a,
|
|
@@ -1358,9 +1373,9 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
1358
1373
|
unique: !1,
|
|
1359
1374
|
hasDefault: !1
|
|
1360
1375
|
}))
|
|
1361
|
-
})) }, r =
|
|
1376
|
+
})) }, r = nr(s.source.schemaFingerprint, e.targetSnapshot, t);
|
|
1362
1377
|
if (r.drifted) {
|
|
1363
|
-
if (!e.force) return yield* n.fail(new
|
|
1378
|
+
if (!e.force) return yield* n.fail(new et({
|
|
1364
1379
|
bundleFingerprint: r.bundleFingerprint,
|
|
1365
1380
|
targetFingerprint: r.targetFingerprint,
|
|
1366
1381
|
diff: r.diff
|
|
@@ -1369,15 +1384,15 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
1369
1384
|
}
|
|
1370
1385
|
}
|
|
1371
1386
|
if (e.targetDialect && e.targetDialect !== s.source.dialect) {
|
|
1372
|
-
let t =
|
|
1373
|
-
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({
|
|
1374
1389
|
sourceDialect: s.source.dialect,
|
|
1375
1390
|
targetDialect: e.targetDialect,
|
|
1376
|
-
blocking: t.map(
|
|
1391
|
+
blocking: t.map(Tn)
|
|
1377
1392
|
}));
|
|
1378
1393
|
}
|
|
1379
|
-
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*
|
|
1380
|
-
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({
|
|
1381
1396
|
mode: f,
|
|
1382
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.`
|
|
1383
1398
|
}));
|
|
@@ -1389,8 +1404,8 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
1389
1404
|
if (f === "replace") {
|
|
1390
1405
|
let t = s.tables.map((e) => e.name), r = e.store.incomingForeignKeys ? yield* n.tryPromise({
|
|
1391
1406
|
try: () => e.store.incomingForeignKeys(t),
|
|
1392
|
-
catch: (e) => new
|
|
1393
|
-
}) : 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();
|
|
1394
1409
|
for (let t of r) {
|
|
1395
1410
|
if (!a.has(t.from)) {
|
|
1396
1411
|
let r = yield* n.tryPromise({
|
|
@@ -1402,7 +1417,7 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
1402
1417
|
skip: void 0,
|
|
1403
1418
|
projection: []
|
|
1404
1419
|
}),
|
|
1405
|
-
catch: () => new
|
|
1420
|
+
catch: () => new H({ reason: `unreadable: ${t.from}` })
|
|
1406
1421
|
}).pipe(n.map((e) => e.length), n.orElseSucceed(() => 0));
|
|
1407
1422
|
a.set(t.from, r);
|
|
1408
1423
|
}
|
|
@@ -1412,9 +1427,9 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
1412
1427
|
rowCount: r
|
|
1413
1428
|
});
|
|
1414
1429
|
}
|
|
1415
|
-
if (i.length > 0) return yield* n.fail(new
|
|
1430
|
+
if (i.length > 0) return yield* n.fail(new nt({
|
|
1416
1431
|
mode: f,
|
|
1417
|
-
reason:
|
|
1432
|
+
reason: bn(i)
|
|
1418
1433
|
}));
|
|
1419
1434
|
}
|
|
1420
1435
|
if (e.dryRun === !0) return e.traceId !== void 0 && (yield* n.promise(() => e.store.update(u, e.traceId, {
|
|
@@ -1435,27 +1450,35 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
1435
1450
|
let e = t.columns.filter((e) => e.generatedAs !== void 0).map((e) => e.name);
|
|
1436
1451
|
e.length > 0 && S.set(t.name, e);
|
|
1437
1452
|
}
|
|
1438
|
-
let
|
|
1453
|
+
let C = (e, t) => {
|
|
1439
1454
|
let n = S.get(e);
|
|
1440
1455
|
if (n === void 0) return t;
|
|
1441
1456
|
let r;
|
|
1442
1457
|
for (let e of n) e in t && (r ??= { ...t }, delete r[e]);
|
|
1443
1458
|
return r ?? t;
|
|
1444
|
-
},
|
|
1445
|
-
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);
|
|
1446
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] });
|
|
1447
|
-
},
|
|
1448
|
-
|
|
1449
|
-
|
|
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({
|
|
1450
1473
|
try: e,
|
|
1451
|
-
catch: (e) =>
|
|
1452
|
-
}).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) => {
|
|
1453
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);
|
|
1454
1477
|
if (t.length !== 0) return {
|
|
1455
1478
|
...e.row,
|
|
1456
1479
|
...Object.fromEntries(t.map((e) => [e, null]))
|
|
1457
1480
|
};
|
|
1458
|
-
},
|
|
1481
|
+
}, de = (e) => {
|
|
1459
1482
|
let t = new Set(e.map((e) => String(e.row[e.entry.primaryKey]))), n = (e) => Object.entries(e.entry.columnTypes).some(([n, r]) => {
|
|
1460
1483
|
if (r !== "reference") return !1;
|
|
1461
1484
|
let i = e.row[n];
|
|
@@ -1473,7 +1496,7 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
1473
1496
|
};
|
|
1474
1497
|
t.refused++, e.derived || t.primary++, a.set(e.table, t);
|
|
1475
1498
|
}
|
|
1476
|
-
return new
|
|
1499
|
+
return new $e({
|
|
1477
1500
|
rows: i.slice(0, 20),
|
|
1478
1501
|
primaryCount: r.filter((e) => !e.derived).length,
|
|
1479
1502
|
totalCount: e.length,
|
|
@@ -1483,62 +1506,62 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
1483
1506
|
primary: t.primary
|
|
1484
1507
|
})).sort((e, t) => t.refused - e.refused || e.table.localeCompare(t.table)).slice(0, 100)
|
|
1485
1508
|
});
|
|
1486
|
-
},
|
|
1509
|
+
}, pe = (e, t) => n.gen(function* () {
|
|
1487
1510
|
let r = t, i = [], a = !0;
|
|
1488
1511
|
for (; r.length > 0 && a;) {
|
|
1489
1512
|
a = !1;
|
|
1490
1513
|
let t = [];
|
|
1491
|
-
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);
|
|
1492
1515
|
if (!a && t.length > 0) for (let n = t.length - 1; n >= 0; n--) {
|
|
1493
|
-
let r = t[n], o =
|
|
1494
|
-
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);
|
|
1495
1518
|
}
|
|
1496
1519
|
r = t;
|
|
1497
1520
|
}
|
|
1498
|
-
for (let t of i) (yield*
|
|
1499
|
-
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));
|
|
1500
1523
|
}), E = (() => {
|
|
1501
1524
|
let t = e.targetDialect;
|
|
1502
1525
|
return t === "postgres" || t === "mysql" || t === "mariadb" || t === "sqlite" || t === "mssql" ? t : void 0;
|
|
1503
|
-
})(), D =
|
|
1526
|
+
})(), D = Yn({
|
|
1504
1527
|
mode: f,
|
|
1505
1528
|
...e.targetDialect === void 0 ? {} : { targetDialect: e.targetDialect },
|
|
1506
1529
|
...e.targetSnapshot === void 0 ? {} : { targetSnapshot: e.targetSnapshot },
|
|
1507
1530
|
bundleTables: s.tables.map((e) => e.name),
|
|
1508
|
-
isSkipped:
|
|
1509
|
-
canRunSql:
|
|
1510
|
-
}),
|
|
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* () {
|
|
1511
1534
|
if (f === "replace" && !O && !(r && b.truncated)) {
|
|
1512
1535
|
e.recordInterruption === !0 && (yield* n.tryPromise({
|
|
1513
1536
|
try: () => t.insert(d, {
|
|
1514
|
-
id: h("repl",
|
|
1515
|
-
startedAt:
|
|
1537
|
+
id: h("repl", ye),
|
|
1538
|
+
startedAt: be,
|
|
1516
1539
|
tables: String(s.tables.length),
|
|
1517
|
-
capture:
|
|
1540
|
+
capture: F?.dir ?? null,
|
|
1518
1541
|
via: e.via ?? "direct"
|
|
1519
1542
|
}),
|
|
1520
|
-
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
|
|
1521
1544
|
not proceed without it.` })
|
|
1522
1545
|
}));
|
|
1523
|
-
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 () => {
|
|
1524
1547
|
for (let e of [...s.tables].reverse()) await t.deleteMany(e.name, { where: x(e.primaryKey) });
|
|
1525
1548
|
} : () => t.transactional(async (e) => {
|
|
1526
1549
|
for (let t of [...s.tables].reverse()) await e.deleteMany(t.name, { where: x(t.primaryKey) });
|
|
1527
1550
|
});
|
|
1528
1551
|
yield* n.tryPromise({
|
|
1529
1552
|
try: o,
|
|
1530
|
-
catch: (e) => new
|
|
1531
|
-
}), 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));
|
|
1532
1555
|
}
|
|
1533
1556
|
let a = [], o = [], u = [], p = [], g = s.tables.length;
|
|
1534
1557
|
for (let d = 0; d < s.tables.length; d++) {
|
|
1535
1558
|
let h = s.tables[d];
|
|
1536
|
-
if (
|
|
1559
|
+
if (V(h.name)) {
|
|
1537
1560
|
p.push(h.name);
|
|
1538
1561
|
continue;
|
|
1539
1562
|
}
|
|
1540
1563
|
if (r && h.name in b.tables) {
|
|
1541
|
-
u.push(h.name),
|
|
1564
|
+
u.push(h.name), N++, ve += b.tables[h.name].rowCount, G(e.onProgress, {
|
|
1542
1565
|
phase: "import",
|
|
1543
1566
|
table: h.name,
|
|
1544
1567
|
index: d,
|
|
@@ -1550,7 +1573,7 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
1550
1573
|
continue;
|
|
1551
1574
|
}
|
|
1552
1575
|
let _ = i.join(e.bundleDir, h.file);
|
|
1553
|
-
|
|
1576
|
+
G(e.onProgress, {
|
|
1554
1577
|
phase: "import",
|
|
1555
1578
|
table: h.name,
|
|
1556
1579
|
index: d,
|
|
@@ -1560,22 +1583,22 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
1560
1583
|
total: h.rowCount
|
|
1561
1584
|
});
|
|
1562
1585
|
let y = a.length, x = n.gen(function* () {
|
|
1563
|
-
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) => {
|
|
1564
1587
|
let n = {
|
|
1565
1588
|
entry: h,
|
|
1566
1589
|
row: e,
|
|
1567
1590
|
reason: ""
|
|
1568
1591
|
};
|
|
1569
1592
|
try {
|
|
1570
|
-
await
|
|
1593
|
+
await T(t, () => w(t, h, e));
|
|
1571
1594
|
} catch (t) {
|
|
1572
|
-
let r =
|
|
1573
|
-
n.reason = r.reason,
|
|
1595
|
+
let r = An(t);
|
|
1596
|
+
n.reason = r.reason, ce(h, e, r), a.push(n);
|
|
1574
1597
|
}
|
|
1575
1598
|
}, d = yield* n.promise(async () => {
|
|
1576
1599
|
let n = e.copyLoader;
|
|
1577
1600
|
if (!n || n.dialect !== "postgres") return !1;
|
|
1578
|
-
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;
|
|
1579
1602
|
if (f === "replace") return !0;
|
|
1580
1603
|
if (f !== "upsert") return !1;
|
|
1581
1604
|
try {
|
|
@@ -1605,46 +1628,46 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
1605
1628
|
d = !1, e.onWarn?.(`bulk COPY into ${h.name} failed (${String(n?.message ?? n)}); falling back to per-row writes for this table`);
|
|
1606
1629
|
for (let e of t) await u(e);
|
|
1607
1630
|
}
|
|
1608
|
-
}, 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 () => {
|
|
1609
1632
|
if (S.length === 0) return;
|
|
1610
1633
|
let e = S;
|
|
1611
1634
|
S = [];
|
|
1612
1635
|
try {
|
|
1613
1636
|
await t.savepoint(async () => {
|
|
1614
|
-
for (let n of e) await
|
|
1637
|
+
for (let n of e) await w(t, h, n);
|
|
1615
1638
|
});
|
|
1616
1639
|
} catch {
|
|
1617
1640
|
for (let t of e) await u(t);
|
|
1618
1641
|
}
|
|
1619
1642
|
};
|
|
1620
|
-
return yield* l.runForEach(
|
|
1643
|
+
return yield* l.runForEach(on(c, h.name, h.columnTypes), (e) => n.promise(async () => {
|
|
1621
1644
|
if (o++, M?.(), d) {
|
|
1622
1645
|
v.push(e), v.length >= g && await y();
|
|
1623
1646
|
return;
|
|
1624
1647
|
}
|
|
1625
1648
|
if (x) {
|
|
1626
|
-
S.push(e), S.length >= b && await
|
|
1649
|
+
S.push(e), S.length >= b && await ee();
|
|
1627
1650
|
return;
|
|
1628
1651
|
}
|
|
1629
1652
|
await u(e);
|
|
1630
|
-
})), yield* n.promise(
|
|
1653
|
+
})), yield* n.promise(ee), yield* n.promise(y), {
|
|
1631
1654
|
rowCount: o,
|
|
1632
1655
|
checksum: i.digest("hex")
|
|
1633
1656
|
};
|
|
1634
|
-
}), { rowCount: S, checksum:
|
|
1657
|
+
}), { rowCount: S, checksum: ee } = yield* Ht("import", h.name, d, g, (e) => e.rowCount, x);
|
|
1635
1658
|
if (c) {
|
|
1636
|
-
if (
|
|
1659
|
+
if (ee !== h.checksum) return yield* n.fail(new Ze({
|
|
1637
1660
|
what: `table ${h.name} checksum`,
|
|
1638
1661
|
expected: h.checksum,
|
|
1639
|
-
actual:
|
|
1662
|
+
actual: ee
|
|
1640
1663
|
}));
|
|
1641
|
-
if (S !== h.rowCount) return yield* n.fail(new
|
|
1664
|
+
if (S !== h.rowCount) return yield* n.fail(new Ze({
|
|
1642
1665
|
what: `table ${h.name} rowCount`,
|
|
1643
1666
|
expected: String(h.rowCount),
|
|
1644
1667
|
actual: String(S)
|
|
1645
1668
|
}));
|
|
1646
1669
|
}
|
|
1647
|
-
|
|
1670
|
+
G(e.onProgress, {
|
|
1648
1671
|
phase: "import",
|
|
1649
1672
|
table: h.name,
|
|
1650
1673
|
index: d,
|
|
@@ -1652,18 +1675,18 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
1652
1675
|
event: "done",
|
|
1653
1676
|
rowsDone: S,
|
|
1654
1677
|
total: h.rowCount
|
|
1655
|
-
}),
|
|
1678
|
+
}), A++, k += S, j?.(), M?.(), r && (a.length > y ? o.push({
|
|
1656
1679
|
name: h.name,
|
|
1657
1680
|
rowCount: S
|
|
1658
1681
|
}) : (b.tables[h.name] = {
|
|
1659
1682
|
rowCount: S,
|
|
1660
1683
|
checksum: h.checksum
|
|
1661
|
-
}, yield*
|
|
1684
|
+
}, yield* K(v, b)));
|
|
1662
1685
|
}
|
|
1663
|
-
if (a.length > 0 && (yield*
|
|
1686
|
+
if (a.length > 0 && (yield* pe(t, a)), f === "replace" && (yield* n.promise(() => t.deleteMany(d, { where: {
|
|
1664
1687
|
column: "startedAt",
|
|
1665
1688
|
op: "lte",
|
|
1666
|
-
value:
|
|
1689
|
+
value: be
|
|
1667
1690
|
} }).then(() => void 0, () => void 0))), r && o.length > 0) {
|
|
1668
1691
|
for (let e of o) {
|
|
1669
1692
|
let t = s.tables.find((t) => t.name === e.name);
|
|
@@ -1672,35 +1695,35 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
1672
1695
|
checksum: t.checksum
|
|
1673
1696
|
};
|
|
1674
1697
|
}
|
|
1675
|
-
yield*
|
|
1698
|
+
yield* K(v, b);
|
|
1676
1699
|
}
|
|
1677
1700
|
{
|
|
1678
|
-
let t =
|
|
1701
|
+
let t = Ye(p, "skipped");
|
|
1679
1702
|
t !== void 0 && e.onWarn?.(t);
|
|
1680
1703
|
}
|
|
1681
1704
|
if (u.length > 0) {
|
|
1682
1705
|
let t = u.length === s.tables.length;
|
|
1683
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.`);
|
|
1684
1707
|
}
|
|
1685
|
-
}),
|
|
1708
|
+
}), ye = `${Date.now().toString(36)}${Math.random().toString(36).slice(2, 8)}`, be = /* @__PURE__ */ new Date(), F = yield* Xn({
|
|
1686
1709
|
store: e.store,
|
|
1687
1710
|
mode: f,
|
|
1688
1711
|
dir: e.rollbackDir,
|
|
1689
1712
|
snapshot: e.targetSnapshot,
|
|
1690
1713
|
dialect: e.targetDialect,
|
|
1691
|
-
tables: s.tables.map((e) => e.name).filter((e) => !
|
|
1714
|
+
tables: s.tables.map((e) => e.name).filter((e) => !V(e)),
|
|
1692
1715
|
onWarn: e.onWarn
|
|
1693
1716
|
});
|
|
1694
|
-
|
|
1695
|
-
try: () => e.onRollbackCaptured(
|
|
1696
|
-
catch: (e) => new
|
|
1717
|
+
F !== void 0 && (e.onRollbackCaptured !== void 0 && (yield* n.tryPromise({
|
|
1718
|
+
try: () => e.onRollbackCaptured(F),
|
|
1719
|
+
catch: (e) => new H({
|
|
1697
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.`,
|
|
1698
|
-
path:
|
|
1721
|
+
path: F.dir
|
|
1699
1722
|
})
|
|
1700
|
-
})), e.onWarn?.(
|
|
1701
|
-
let
|
|
1702
|
-
|
|
1703
|
-
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,
|
|
1704
1727
|
mode: f,
|
|
1705
1728
|
via: e.via ?? "direct",
|
|
1706
1729
|
direction: "import",
|
|
@@ -1710,45 +1733,45 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
1710
1733
|
rowsWritten: 0,
|
|
1711
1734
|
staged: f === "replace" ? O : null
|
|
1712
1735
|
}).then(() => {
|
|
1713
|
-
|
|
1736
|
+
L = !0;
|
|
1714
1737
|
}, (t) => {
|
|
1715
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
|
|
1716
1739
|
\`voltro db apply\` so the next one is recorded.`);
|
|
1717
|
-
}))), e.traceId !== void 0 &&
|
|
1740
|
+
}))), e.traceId !== void 0 && Ce && (yield* n.promise(() => e.store.update(u, I, {
|
|
1718
1741
|
staged: f === "replace" ? O : null,
|
|
1719
1742
|
sourceFingerprint: s.source.schemaFingerprint ?? null
|
|
1720
1743
|
}).then(() => void 0, () => void 0)));
|
|
1721
|
-
let
|
|
1722
|
-
|
|
1723
|
-
if (!
|
|
1744
|
+
let we = 0, Te = !1;
|
|
1745
|
+
j = () => {
|
|
1746
|
+
if (!L || Te) return;
|
|
1724
1747
|
let t = Date.now();
|
|
1725
|
-
t -
|
|
1726
|
-
tablesWritten:
|
|
1727
|
-
rowsWritten:
|
|
1748
|
+
t - we < rr || (we = t, e.store.update(u, I, {
|
|
1749
|
+
tablesWritten: A,
|
|
1750
|
+
rowsWritten: k
|
|
1728
1751
|
}).then(() => void 0, () => {
|
|
1729
|
-
|
|
1752
|
+
Te = !0;
|
|
1730
1753
|
}));
|
|
1731
1754
|
};
|
|
1732
|
-
let
|
|
1755
|
+
let Ee = (t) => L ? e.store.update(u, I, {
|
|
1733
1756
|
finishedAt: t === null ? /* @__PURE__ */ new Date() : null,
|
|
1734
|
-
tablesWritten:
|
|
1735
|
-
rowsWritten:
|
|
1757
|
+
tablesWritten: A,
|
|
1758
|
+
rowsWritten: k,
|
|
1736
1759
|
failure: t
|
|
1737
1760
|
}).then(() => void 0, () => void 0) : Promise.resolve();
|
|
1738
|
-
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
|
|
1739
1762
|
something that did not happen — and this path already writes through the raw store, without
|
|
1740
1763
|
tenant scoping or \`audit()\` stamping, for the same reason.`), O) {
|
|
1741
|
-
e.onWarn?.(`staging ${
|
|
1742
|
-
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;
|
|
1743
1766
|
if (e.recordInterruption === !0) {
|
|
1744
1767
|
yield* n.promise(() => e.store.insert(d, {
|
|
1745
1768
|
id: i,
|
|
1746
|
-
startedAt:
|
|
1769
|
+
startedAt: be,
|
|
1747
1770
|
kind: "staging",
|
|
1748
|
-
tables: String(
|
|
1749
|
-
capture:
|
|
1771
|
+
tables: String(me.length),
|
|
1772
|
+
capture: F?.dir ?? null,
|
|
1750
1773
|
via: e.via ?? "direct",
|
|
1751
|
-
staging: r.map(
|
|
1774
|
+
staging: r.map(J).join(","),
|
|
1752
1775
|
heartbeatAt: /* @__PURE__ */ new Date(),
|
|
1753
1776
|
resumable: !m
|
|
1754
1777
|
}).then(() => {
|
|
@@ -1762,76 +1785,76 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
1762
1785
|
M = () => {
|
|
1763
1786
|
if (!a) return;
|
|
1764
1787
|
let n = Date.now();
|
|
1765
|
-
n - t <
|
|
1788
|
+
n - t < ir || (t = n, e.store.update(d, i, { heartbeatAt: /* @__PURE__ */ new Date() }).then(() => void 0, () => void 0));
|
|
1766
1789
|
};
|
|
1767
1790
|
}
|
|
1768
|
-
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, {
|
|
1769
1792
|
getTable: (e) => y(e),
|
|
1770
1793
|
registerTable: (e) => {
|
|
1771
|
-
|
|
1794
|
+
te(e);
|
|
1772
1795
|
},
|
|
1773
|
-
unregisterTable:
|
|
1796
|
+
unregisterTable: ie
|
|
1774
1797
|
}), c = !1;
|
|
1775
1798
|
try {
|
|
1776
|
-
let i = m ? r : r.filter((e) => !
|
|
1799
|
+
let i = m ? r : r.filter((e) => !Gt(b, e));
|
|
1777
1800
|
yield* n.tryPromise({
|
|
1778
1801
|
try: async () => {
|
|
1779
|
-
await
|
|
1802
|
+
await Wn(t, i.map((e) => Rn(e, E))), await Wn(t, i.map((e) => Ln(e, E)));
|
|
1780
1803
|
},
|
|
1781
|
-
catch: (e) => new
|
|
1782
|
-
}), yield*
|
|
1783
|
-
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(() => {
|
|
1784
1807
|
c = !0;
|
|
1785
1808
|
}),
|
|
1786
|
-
catch: (e) => new
|
|
1809
|
+
catch: (e) => new H({ reason: String(e?.message ?? e) })
|
|
1787
1810
|
}).pipe(n.catchAll((i) => n.gen(function* () {
|
|
1788
|
-
let a =
|
|
1789
|
-
return yield* n.fail(new
|
|
1790
|
-
}))), !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));
|
|
1791
1814
|
} finally {
|
|
1792
|
-
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");
|
|
1793
1816
|
}
|
|
1794
1817
|
} else m ? yield* n.tryPromise({
|
|
1795
1818
|
try: () => e.store.transactional(async (e) => {
|
|
1796
|
-
let t = await
|
|
1797
|
-
if (r.isFailure(t)) throw
|
|
1819
|
+
let t = await xe(() => n.runPromiseExit(P(e, !1)));
|
|
1820
|
+
if (r.isFailure(t)) throw cr(t.cause);
|
|
1798
1821
|
}),
|
|
1799
|
-
catch: (e) =>
|
|
1800
|
-
}) : 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));
|
|
1801
1824
|
if (e.assets && s.assets.index && !e.assetsAlreadyRestored) {
|
|
1802
1825
|
let t = e.assets;
|
|
1803
|
-
yield*
|
|
1826
|
+
yield* vt({
|
|
1804
1827
|
sink: t,
|
|
1805
|
-
assetsDir: i.join(e.bundleDir,
|
|
1828
|
+
assetsDir: i.join(e.bundleDir, Pt),
|
|
1806
1829
|
indexPath: i.join(e.bundleDir, s.assets.index ?? "assets/index.ndjson"),
|
|
1807
1830
|
progress: {
|
|
1808
1831
|
done: (e) => e in b.assets,
|
|
1809
|
-
mark: (e) => (b.assets[e] = !0,
|
|
1832
|
+
mark: (e) => (b.assets[e] = !0, K(v, b))
|
|
1810
1833
|
}
|
|
1811
1834
|
});
|
|
1812
1835
|
}
|
|
1813
|
-
return yield* n.promise(() =>
|
|
1836
|
+
return yield* n.promise(() => Ee(null)), {
|
|
1814
1837
|
manifest: s,
|
|
1815
|
-
tablesWritten:
|
|
1816
|
-
rowsWritten:
|
|
1817
|
-
tablesSkipped:
|
|
1818
|
-
rowsSkipped:
|
|
1819
|
-
fullyResumed:
|
|
1820
|
-
...
|
|
1838
|
+
tablesWritten: A,
|
|
1839
|
+
rowsWritten: k,
|
|
1840
|
+
tablesSkipped: N,
|
|
1841
|
+
rowsSkipped: ve,
|
|
1842
|
+
fullyResumed: A === 0 && N > 0,
|
|
1843
|
+
...F === void 0 ? {} : { rollback: F }
|
|
1821
1844
|
};
|
|
1822
1845
|
}).pipe(n.tapError((e) => n.promise(() => t?.(e?.reason ?? e?._tag ?? "the import did not finish") ?? Promise.resolve())));
|
|
1823
|
-
},
|
|
1846
|
+
}, dr = (e) => e, fr = (e) => {
|
|
1824
1847
|
if (e.allowLive || e.liveInstance === null || e.sameTarget === "different") return { refuse: !1 };
|
|
1825
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.";
|
|
1826
1849
|
return {
|
|
1827
1850
|
refuse: !0,
|
|
1828
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).`
|
|
1829
1852
|
};
|
|
1830
|
-
},
|
|
1853
|
+
}, X = Buffer.from("VBUNDLE2"), pr = 0, mr = 1, hr = 2, gr = 32, _r = async (e) => {
|
|
1831
1854
|
let t = [], n = async (r) => {
|
|
1832
1855
|
let i;
|
|
1833
1856
|
try {
|
|
1834
|
-
i = await
|
|
1857
|
+
i = await ye(I(e, r), { withFileTypes: !0 });
|
|
1835
1858
|
} catch {
|
|
1836
1859
|
return;
|
|
1837
1860
|
}
|
|
@@ -1841,22 +1864,22 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
1841
1864
|
}
|
|
1842
1865
|
};
|
|
1843
1866
|
return await n(""), t.sort();
|
|
1844
|
-
},
|
|
1867
|
+
}, vr = (e, t) => {
|
|
1845
1868
|
let n = Buffer.from(e, "utf8"), r = Buffer.alloc(5 + n.length + 8);
|
|
1846
|
-
return r.writeUInt8(
|
|
1847
|
-
},
|
|
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) => {
|
|
1848
1871
|
let r = Buffer.from(e, "utf8"), i = Buffer.from(t, "utf8"), a = Buffer.alloc(5 + r.length + 2 + i.length + 8), o = 0;
|
|
1849
|
-
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;
|
|
1850
1873
|
};
|
|
1851
|
-
async function*
|
|
1852
|
-
yield new Uint8Array(
|
|
1853
|
-
for (let t of await
|
|
1854
|
-
let n =
|
|
1855
|
-
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);
|
|
1856
1879
|
}
|
|
1857
1880
|
if (e.blobs) for await (let t of e.blobs.list()) {
|
|
1858
|
-
yield new Uint8Array(
|
|
1859
|
-
let n =
|
|
1881
|
+
yield new Uint8Array(yr(t.key, t.contentType, t.size));
|
|
1882
|
+
let n = T("sha256"), r = 0;
|
|
1860
1883
|
for await (let i of e.blobs.open(t.key)) {
|
|
1861
1884
|
let e = Buffer.from(i);
|
|
1862
1885
|
n.update(e), r += e.length, yield new Uint8Array(e);
|
|
@@ -1864,11 +1887,11 @@ async function* vr(e) {
|
|
|
1864
1887
|
if (r !== t.size) throw Error(`blob '${t.key}' size mismatch: header ${t.size}, streamed ${r}`);
|
|
1865
1888
|
yield new Uint8Array(n.digest());
|
|
1866
1889
|
}
|
|
1867
|
-
yield new Uint8Array(Buffer.from([
|
|
1890
|
+
yield new Uint8Array(Buffer.from([pr]));
|
|
1868
1891
|
}
|
|
1869
|
-
var
|
|
1870
|
-
let n =
|
|
1871
|
-
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 });
|
|
1872
1895
|
let r = Buffer.alloc(0), i = e[Symbol.asyncIterator](), a = !1, o = async () => {
|
|
1873
1896
|
let { value: e, done: t } = await i.next();
|
|
1874
1897
|
return t ? (a = !0, !1) : (r = r.length === 0 ? Buffer.from(e) : Buffer.concat([r, Buffer.from(e)]), !0);
|
|
@@ -1879,28 +1902,28 @@ var yr = (e, t) => new Promise((n, r) => e.write(t, (e) => e ? r(e) : n())), br
|
|
|
1879
1902
|
return r = r.subarray(e), t;
|
|
1880
1903
|
};
|
|
1881
1904
|
try {
|
|
1882
|
-
if (await s(
|
|
1905
|
+
if (await s(X.length), !c(X.length).equals(X)) throw Error("not a bundle archive (bad magic)");
|
|
1883
1906
|
for (;;) {
|
|
1884
1907
|
await s(1);
|
|
1885
1908
|
let e = c(1).readUInt8(0);
|
|
1886
|
-
if (e ===
|
|
1887
|
-
if (e ===
|
|
1909
|
+
if (e === pr) return;
|
|
1910
|
+
if (e === mr) {
|
|
1888
1911
|
await s(4);
|
|
1889
1912
|
let e = c(4).readUInt32BE(0);
|
|
1890
1913
|
await s(e);
|
|
1891
1914
|
let t = c(e).toString("utf8");
|
|
1892
1915
|
await s(8);
|
|
1893
|
-
let i = c(8).readBigUInt64BE(0), a =
|
|
1894
|
-
if (a !== n && !a.startsWith(n +
|
|
1895
|
-
await
|
|
1896
|
-
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);
|
|
1897
1920
|
for (; i > 0n;) {
|
|
1898
1921
|
r.length === 0 && await s(1);
|
|
1899
1922
|
let e = i < BigInt(r.length) ? Number(i) : r.length;
|
|
1900
|
-
await
|
|
1923
|
+
await xr(o, c(e)), i -= BigInt(e);
|
|
1901
1924
|
}
|
|
1902
|
-
await
|
|
1903
|
-
} else if (e ===
|
|
1925
|
+
await Sr(o);
|
|
1926
|
+
} else if (e === hr) {
|
|
1904
1927
|
await s(4);
|
|
1905
1928
|
let e = c(4).readUInt32BE(0);
|
|
1906
1929
|
await s(e);
|
|
@@ -1910,24 +1933,24 @@ var yr = (e, t) => new Promise((n, r) => e.write(t, (e) => e ? r(e) : n())), br
|
|
|
1910
1933
|
await s(i);
|
|
1911
1934
|
let a = c(i).toString("utf8");
|
|
1912
1935
|
await s(8);
|
|
1913
|
-
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, {
|
|
1914
1937
|
contentType: a,
|
|
1915
1938
|
size: Number(o)
|
|
1916
1939
|
}), p = o;
|
|
1917
1940
|
for (; p > 0n;) {
|
|
1918
1941
|
r.length === 0 && await s(1);
|
|
1919
1942
|
let e = p < BigInt(r.length) ? Number(p) : r.length, t = c(e);
|
|
1920
|
-
u.update(t), l || await
|
|
1943
|
+
u.update(t), l || await xr(d, t), p -= BigInt(e);
|
|
1921
1944
|
}
|
|
1922
|
-
l ? d.destroy() : await
|
|
1923
|
-
let m = c(
|
|
1945
|
+
l ? d.destroy() : await Sr(d), await f, await s(gr);
|
|
1946
|
+
let m = c(gr);
|
|
1924
1947
|
if (!u.digest().equals(m)) throw Error(`blob '${n}' failed integrity (sha mismatch)`);
|
|
1925
1948
|
} else throw Error(`unknown bundle entry kind ${e}`);
|
|
1926
1949
|
}
|
|
1927
1950
|
} finally {
|
|
1928
1951
|
a || await Promise.resolve(i.return?.()).catch(() => void 0);
|
|
1929
1952
|
}
|
|
1930
|
-
},
|
|
1953
|
+
}, wr = async (e, t) => {
|
|
1931
1954
|
let n = new Set(t), r = /* @__PURE__ */ new Map(), i = Buffer.alloc(0), a = e[Symbol.asyncIterator](), o = async () => {
|
|
1932
1955
|
let { value: e, done: t } = await a.next();
|
|
1933
1956
|
return !t && (i = i.length === 0 ? Buffer.from(e) : Buffer.concat([i, Buffer.from(e)]), !0);
|
|
@@ -1946,11 +1969,11 @@ var yr = (e, t) => new Promise((n, r) => e.write(t, (e) => e ? r(e) : n())), br
|
|
|
1946
1969
|
}
|
|
1947
1970
|
return Buffer.concat(t);
|
|
1948
1971
|
};
|
|
1949
|
-
if (!await s(
|
|
1972
|
+
if (!await s(X.length) || !c(X.length).equals(X)) throw Error("not a bundle archive (bad magic)");
|
|
1950
1973
|
for (; await s(1);) {
|
|
1951
1974
|
let e = c(1).readUInt8(0);
|
|
1952
|
-
if (e ===
|
|
1953
|
-
if (e !==
|
|
1975
|
+
if (e === pr || e === hr) break;
|
|
1976
|
+
if (e !== mr) throw Error(`unknown bundle entry kind ${e}`);
|
|
1954
1977
|
if (!await s(4)) break;
|
|
1955
1978
|
let t = c(4).readUInt32BE(0);
|
|
1956
1979
|
if (!await s(t)) break;
|
|
@@ -1960,22 +1983,22 @@ var yr = (e, t) => new Promise((n, r) => e.write(t, (e) => e ? r(e) : n())), br
|
|
|
1960
1983
|
if (a === null || n.has(i) && (r.set(i, a), n.delete(i), n.size === 0)) break;
|
|
1961
1984
|
}
|
|
1962
1985
|
return r;
|
|
1963
|
-
},
|
|
1986
|
+
}, Tr = (e, t) => Cr(e, {
|
|
1964
1987
|
dir: t,
|
|
1965
|
-
blobs:
|
|
1966
|
-
}),
|
|
1988
|
+
blobs: Er(t)
|
|
1989
|
+
}), Er = (e) => {
|
|
1967
1990
|
let t = /* @__PURE__ */ new Set();
|
|
1968
1991
|
return {
|
|
1969
1992
|
has: async (e) => t.has(e),
|
|
1970
1993
|
write: async (n, r, i) => {
|
|
1971
|
-
let a = await import("node:fs/promises"), { pipeline: o } = await import("node:stream/promises"), { Transform: s } = await import("node:stream"), c =
|
|
1972
|
-
await
|
|
1973
|
-
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) {
|
|
1974
1997
|
l.update(e), u += e.length, n(null, e);
|
|
1975
|
-
} }), f =
|
|
1976
|
-
await o(r, d,
|
|
1998
|
+
} }), f = I(c, `.tmp-${Date.now()}-${t.size}`);
|
|
1999
|
+
await o(r, d, pe(f));
|
|
1977
2000
|
let p = l.digest("hex");
|
|
1978
|
-
await a.rename(f,
|
|
2001
|
+
await a.rename(f, I(c, p)), await a.appendFile(I(c, "index.ndjson"), `${JSON.stringify({
|
|
1979
2002
|
key: n,
|
|
1980
2003
|
sha256: p,
|
|
1981
2004
|
size: u,
|
|
@@ -1983,33 +2006,33 @@ var yr = (e, t) => new Promise((n, r) => e.write(t, (e) => e ? r(e) : n())), br
|
|
|
1983
2006
|
})}\n`), t.add(n);
|
|
1984
2007
|
}
|
|
1985
2008
|
};
|
|
1986
|
-
},
|
|
2009
|
+
}, Dr = we(ue), Or = Buffer.from("VENC1\0\0\0"), kr = 32, Ar = 16, jr = 7, Mr = 16, Nr = 262144, Pr = {
|
|
1987
2010
|
N: 32768,
|
|
1988
2011
|
r: 8,
|
|
1989
2012
|
p: 1
|
|
1990
|
-
},
|
|
2013
|
+
}, Fr = 134217728, Ir = 43, Lr = (e, t, n) => {
|
|
1991
2014
|
let r = Buffer.alloc(12);
|
|
1992
|
-
return e.copy(r, 0, 0,
|
|
2015
|
+
return e.copy(r, 0, 0, jr), r.writeUInt32BE(t >>> 0, jr), r.writeUInt8(+!!n, 11), r;
|
|
1993
2016
|
};
|
|
1994
|
-
async function*
|
|
2017
|
+
async function* Rr(e, t) {
|
|
1995
2018
|
if (!t) throw Error("encryptStream: a non-empty passphrase is required");
|
|
1996
|
-
let n = ce(
|
|
1997
|
-
...
|
|
1998
|
-
maxmem:
|
|
1999
|
-
}), a = Buffer.alloc(
|
|
2000
|
-
|
|
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);
|
|
2001
2024
|
let o = 0, s = (e, t) => {
|
|
2002
|
-
let n =
|
|
2025
|
+
let n = ae("aes-256-gcm", i, Lr(r, o, t));
|
|
2003
2026
|
o === 0 && n.setAAD(a);
|
|
2004
2027
|
let s = Buffer.concat([n.update(e), n.final()]), c = n.getAuthTag();
|
|
2005
2028
|
o++;
|
|
2006
|
-
let l = Buffer.alloc(5 + s.length +
|
|
2007
|
-
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);
|
|
2008
2031
|
}, c = Buffer.alloc(0);
|
|
2009
|
-
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);
|
|
2010
2033
|
yield s(c, !0);
|
|
2011
2034
|
}
|
|
2012
|
-
async function*
|
|
2035
|
+
async function* zr(e, t) {
|
|
2013
2036
|
if (!t) throw Error("decryptStream: a non-empty passphrase is required");
|
|
2014
2037
|
let n = e[Symbol.asyncIterator](), r = Buffer.alloc(0), i = !1, a = async () => {
|
|
2015
2038
|
let { value: e, done: t } = await n.next();
|
|
@@ -2018,16 +2041,16 @@ async function* Lr(e, t) {
|
|
|
2018
2041
|
for (; r.length < e && !i && await a(););
|
|
2019
2042
|
return r.length >= e;
|
|
2020
2043
|
};
|
|
2021
|
-
if (!await o(
|
|
2022
|
-
let s = r.subarray(0,
|
|
2023
|
-
if (!s.subarray(0, 8).equals(
|
|
2024
|
-
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, {
|
|
2025
2048
|
N: c,
|
|
2026
2049
|
r: l,
|
|
2027
2050
|
p: u,
|
|
2028
|
-
maxmem:
|
|
2051
|
+
maxmem: Fr
|
|
2029
2052
|
});
|
|
2030
|
-
r = r.subarray(
|
|
2053
|
+
r = r.subarray(Ir);
|
|
2031
2054
|
let m = 0, h = !1;
|
|
2032
2055
|
for (;;) {
|
|
2033
2056
|
if (!await o(5)) {
|
|
@@ -2036,11 +2059,11 @@ async function* Lr(e, t) {
|
|
|
2036
2059
|
}
|
|
2037
2060
|
if (h) throw Error("encrypted bundle has trailing data after the final frame");
|
|
2038
2061
|
let e = r.readUInt8(0) === 1, t = r.readUInt32BE(1);
|
|
2039
|
-
if (t <
|
|
2062
|
+
if (t < Mr) throw Error("encrypted bundle corrupt (short frame)");
|
|
2040
2063
|
if (!await o(5 + t)) throw Error("encrypted bundle truncated (frame body)");
|
|
2041
|
-
let n = r.subarray(5, 5 + t -
|
|
2064
|
+
let n = r.subarray(5, 5 + t - Mr), i = r.subarray(5 + t - Mr, 5 + t);
|
|
2042
2065
|
r = r.subarray(5 + t);
|
|
2043
|
-
let a =
|
|
2066
|
+
let a = oe("aes-256-gcm", p, Lr(f, m, e));
|
|
2044
2067
|
m === 0 && a.setAAD(s), a.setAuthTag(i);
|
|
2045
2068
|
let c = Buffer.concat([a.update(n), a.final()]);
|
|
2046
2069
|
m++, e && (h = !0), c.length > 0 && (yield new Uint8Array(c));
|
|
@@ -2048,7 +2071,7 @@ async function* Lr(e, t) {
|
|
|
2048
2071
|
}
|
|
2049
2072
|
//#endregion
|
|
2050
2073
|
//#region src/blobStorage.ts
|
|
2051
|
-
var
|
|
2074
|
+
var Br = (e, t) => ({
|
|
2052
2075
|
list: () => {
|
|
2053
2076
|
let e = t();
|
|
2054
2077
|
return { async *[Symbol.asyncIterator]() {
|
|
@@ -2061,32 +2084,32 @@ var Rr = (e, t) => ({
|
|
|
2061
2084
|
} };
|
|
2062
2085
|
},
|
|
2063
2086
|
open: (t) => ({ async *[Symbol.asyncIterator]() {
|
|
2064
|
-
let r = await n.runPromise(
|
|
2087
|
+
let r = await n.runPromise(_e(e, t)), i = await A(r.stream);
|
|
2065
2088
|
for await (let e of i) yield e instanceof Uint8Array ? e : new Uint8Array(e);
|
|
2066
2089
|
} })
|
|
2067
|
-
}),
|
|
2068
|
-
table:
|
|
2090
|
+
}), Vr = (e, t) => Br(e, () => C(t, {
|
|
2091
|
+
table: O,
|
|
2069
2092
|
chunkSize: 500
|
|
2070
2093
|
}).pipe(l.map((e) => ({
|
|
2071
2094
|
key: String(e.key),
|
|
2072
2095
|
contentType: String(e.contentType ?? "application/octet-stream"),
|
|
2073
2096
|
size: Number(e.size ?? 0)
|
|
2074
|
-
})))),
|
|
2097
|
+
})))), Hr = (e) => ({
|
|
2075
2098
|
has: (t) => n.runPromise(e.head(t).pipe(n.map((e) => e !== null))),
|
|
2076
2099
|
write: async (t, r, i) => {
|
|
2077
|
-
let a =
|
|
2078
|
-
await n.runPromise(
|
|
2100
|
+
let a = ge("storage", () => ve.from(r));
|
|
2101
|
+
await n.runPromise(k(e, t, a, {
|
|
2079
2102
|
contentType: i.contentType,
|
|
2080
2103
|
totalSize: i.size
|
|
2081
2104
|
}));
|
|
2082
2105
|
}
|
|
2083
|
-
}),
|
|
2106
|
+
}), Ur = (e, t) => {
|
|
2084
2107
|
let n = t === "dump" ? "mariadb-dump" : "mariadb", r = t === "dump" ? "mysqldump" : "mysql";
|
|
2085
|
-
return e === "mariadb" ?
|
|
2108
|
+
return e === "mariadb" ? Wr(n) ? { tool: n } : {
|
|
2086
2109
|
tool: r,
|
|
2087
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.`
|
|
2088
2111
|
} : { tool: r };
|
|
2089
|
-
},
|
|
2112
|
+
}, Wr = (e) => (process.env.PATH ?? "").split(xe).filter((e) => e !== "").some((t) => E(I(t, e))), Gr = (e) => {
|
|
2090
2113
|
switch (e) {
|
|
2091
2114
|
case "postgres": return "db.dump";
|
|
2092
2115
|
case "mysql":
|
|
@@ -2096,23 +2119,23 @@ var Rr = (e, t) => ({
|
|
|
2096
2119
|
case "mssql": return "db.bacpac";
|
|
2097
2120
|
default: return "db.dump";
|
|
2098
2121
|
}
|
|
2099
|
-
},
|
|
2122
|
+
}, Kr = (e) => e.filename ?? e.database ?? ((e.url ?? "").replace(/^file:/, "") || "app.sqlite"), Z = (e, t = 3306) => {
|
|
2100
2123
|
if (e.host || e.database) return {
|
|
2101
2124
|
host: e.host ?? "localhost",
|
|
2102
|
-
port: e.port ??
|
|
2125
|
+
port: e.port ?? t,
|
|
2103
2126
|
username: e.username ?? "root",
|
|
2104
2127
|
password: e.password ?? "",
|
|
2105
2128
|
database: e.database ?? ""
|
|
2106
2129
|
};
|
|
2107
|
-
let
|
|
2130
|
+
let n = new URL(e.url ?? "");
|
|
2108
2131
|
return {
|
|
2109
|
-
host:
|
|
2110
|
-
port:
|
|
2111
|
-
username: decodeURIComponent(
|
|
2112
|
-
password: decodeURIComponent(
|
|
2113
|
-
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(/^\//, "") || ""
|
|
2114
2137
|
};
|
|
2115
|
-
},
|
|
2138
|
+
}, qr = (e) => `Server=${e.host},${e.port};Database=${e.database};User ID=${e.username};Password=${e.password};TrustServerCertificate=True`, Jr = (e, t, n) => {
|
|
2116
2139
|
switch (e) {
|
|
2117
2140
|
case "postgres": {
|
|
2118
2141
|
if (t.url) return {
|
|
@@ -2122,7 +2145,7 @@ var Rr = (e, t) => ({
|
|
|
2122
2145
|
"--format=custom",
|
|
2123
2146
|
"--no-owner",
|
|
2124
2147
|
"--no-privileges",
|
|
2125
|
-
...
|
|
2148
|
+
...Xr,
|
|
2126
2149
|
"--dbname",
|
|
2127
2150
|
t.url,
|
|
2128
2151
|
"--file",
|
|
@@ -2130,10 +2153,7 @@ var Rr = (e, t) => ({
|
|
|
2130
2153
|
],
|
|
2131
2154
|
env: {}
|
|
2132
2155
|
};
|
|
2133
|
-
let e =
|
|
2134
|
-
...t,
|
|
2135
|
-
port: t.port ?? 5432
|
|
2136
|
-
});
|
|
2156
|
+
let e = Z(t, 5432);
|
|
2137
2157
|
return {
|
|
2138
2158
|
kind: "spawn",
|
|
2139
2159
|
tool: "pg_dump",
|
|
@@ -2141,7 +2161,7 @@ var Rr = (e, t) => ({
|
|
|
2141
2161
|
"--format=custom",
|
|
2142
2162
|
"--no-owner",
|
|
2143
2163
|
"--no-privileges",
|
|
2144
|
-
...
|
|
2164
|
+
...Xr,
|
|
2145
2165
|
"-h",
|
|
2146
2166
|
e.host,
|
|
2147
2167
|
"-p",
|
|
@@ -2158,17 +2178,17 @@ var Rr = (e, t) => ({
|
|
|
2158
2178
|
}
|
|
2159
2179
|
case "mysql":
|
|
2160
2180
|
case "mariadb": {
|
|
2161
|
-
let r =
|
|
2181
|
+
let r = Z(t);
|
|
2162
2182
|
return {
|
|
2163
2183
|
kind: "spawn",
|
|
2164
|
-
...
|
|
2184
|
+
...Ur(e, "dump"),
|
|
2165
2185
|
args: [
|
|
2166
2186
|
"--single-transaction",
|
|
2167
2187
|
"--routines",
|
|
2168
2188
|
"--triggers",
|
|
2169
2189
|
"--no-tablespaces",
|
|
2170
2190
|
"--protocol=TCP",
|
|
2171
|
-
...
|
|
2191
|
+
...Yr.map((e) => `--ignore-table=${r.database}.${e}`),
|
|
2172
2192
|
"-h",
|
|
2173
2193
|
r.host,
|
|
2174
2194
|
"-P",
|
|
@@ -2184,7 +2204,7 @@ var Rr = (e, t) => ({
|
|
|
2184
2204
|
case "sqlite":
|
|
2185
2205
|
case "turso": return {
|
|
2186
2206
|
kind: "copy",
|
|
2187
|
-
from:
|
|
2207
|
+
from: Kr(t),
|
|
2188
2208
|
to: n
|
|
2189
2209
|
};
|
|
2190
2210
|
case "mssql": return {
|
|
@@ -2192,20 +2212,17 @@ var Rr = (e, t) => ({
|
|
|
2192
2212
|
tool: "sqlpackage",
|
|
2193
2213
|
args: [
|
|
2194
2214
|
"/Action:Export",
|
|
2195
|
-
`/SourceConnectionString:${
|
|
2196
|
-
...t,
|
|
2197
|
-
port: t.port ?? 1433
|
|
2198
|
-
}))}`,
|
|
2215
|
+
`/SourceConnectionString:${qr(Z(t, 1433))}`,
|
|
2199
2216
|
`/TargetFile:${n}`
|
|
2200
2217
|
],
|
|
2201
2218
|
env: {}
|
|
2202
2219
|
};
|
|
2203
|
-
default: throw new
|
|
2220
|
+
default: throw new W({
|
|
2204
2221
|
tool: "backup",
|
|
2205
2222
|
reason: `no native backup for dialect '${e}'`
|
|
2206
2223
|
});
|
|
2207
2224
|
}
|
|
2208
|
-
},
|
|
2225
|
+
}, Yr = [d, u], Xr = Yr.flatMap((e) => ["--exclude-table", e]), Zr = (e) => e === "postgres" || e === "mysql" || e === "mariadb" ? Yr : [], Qr = (e, t, n) => {
|
|
2209
2226
|
switch (e) {
|
|
2210
2227
|
case "postgres": {
|
|
2211
2228
|
if (t.url) return {
|
|
@@ -2221,10 +2238,7 @@ var Rr = (e, t) => ({
|
|
|
2221
2238
|
],
|
|
2222
2239
|
env: {}
|
|
2223
2240
|
};
|
|
2224
|
-
let e =
|
|
2225
|
-
...t,
|
|
2226
|
-
port: t.port ?? 5432
|
|
2227
|
-
});
|
|
2241
|
+
let e = Z(t, 5432);
|
|
2228
2242
|
return {
|
|
2229
2243
|
kind: "spawn",
|
|
2230
2244
|
tool: "pg_restore",
|
|
@@ -2247,10 +2261,10 @@ var Rr = (e, t) => ({
|
|
|
2247
2261
|
}
|
|
2248
2262
|
case "mysql":
|
|
2249
2263
|
case "mariadb": {
|
|
2250
|
-
let r =
|
|
2264
|
+
let r = Z(t);
|
|
2251
2265
|
return {
|
|
2252
2266
|
kind: "spawn",
|
|
2253
|
-
...
|
|
2267
|
+
...Ur(e, "client"),
|
|
2254
2268
|
args: [
|
|
2255
2269
|
"--protocol=TCP",
|
|
2256
2270
|
"-h",
|
|
@@ -2269,37 +2283,104 @@ var Rr = (e, t) => ({
|
|
|
2269
2283
|
case "turso": return {
|
|
2270
2284
|
kind: "copy",
|
|
2271
2285
|
from: n,
|
|
2272
|
-
to:
|
|
2273
|
-
};
|
|
2274
|
-
case "mssql": return {
|
|
2275
|
-
kind: "spawn",
|
|
2276
|
-
tool: "sqlpackage",
|
|
2277
|
-
args: [
|
|
2278
|
-
"/Action:Import",
|
|
2279
|
-
`/TargetConnectionString:${Gr($({
|
|
2280
|
-
...t,
|
|
2281
|
-
port: t.port ?? 1433
|
|
2282
|
-
}))}`,
|
|
2283
|
-
`/SourceFile:${n}`
|
|
2284
|
-
],
|
|
2285
|
-
env: {}
|
|
2286
|
+
to: Kr(t)
|
|
2286
2287
|
};
|
|
2287
|
-
|
|
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({
|
|
2288
2318
|
tool: "restore",
|
|
2289
2319
|
reason: `no native restore for dialect '${e}'`
|
|
2290
2320
|
});
|
|
2291
2321
|
}
|
|
2292
|
-
},
|
|
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) => {
|
|
2293
2374
|
let r = `${e.to}.restoring-${le()}`, i = (e) => {
|
|
2294
2375
|
try {
|
|
2295
|
-
|
|
2376
|
+
he(r);
|
|
2296
2377
|
} catch {}
|
|
2297
|
-
t(n.fail(new
|
|
2378
|
+
t(n.fail(new W({
|
|
2298
2379
|
tool: "copy",
|
|
2299
2380
|
reason: e
|
|
2300
2381
|
})));
|
|
2301
2382
|
};
|
|
2302
|
-
|
|
2383
|
+
de(e.from, r, (a) => {
|
|
2303
2384
|
if (a) {
|
|
2304
2385
|
i(`copy ${e.from} → ${e.to}: ${a.message}`);
|
|
2305
2386
|
return;
|
|
@@ -2309,9 +2390,9 @@ var Rr = (e, t) => ({
|
|
|
2309
2390
|
`${e.to}-shm`,
|
|
2310
2391
|
`${e.to}-journal`
|
|
2311
2392
|
]) try {
|
|
2312
|
-
|
|
2393
|
+
he(t);
|
|
2313
2394
|
} catch {}
|
|
2314
|
-
|
|
2395
|
+
D(r, e.to, (r) => {
|
|
2315
2396
|
if (r) {
|
|
2316
2397
|
i(`copy ${e.from} → ${e.to}: ${r.message}`);
|
|
2317
2398
|
return;
|
|
@@ -2320,7 +2401,7 @@ var Rr = (e, t) => ({
|
|
|
2320
2401
|
});
|
|
2321
2402
|
});
|
|
2322
2403
|
}) : n.async((t) => {
|
|
2323
|
-
let r =
|
|
2404
|
+
let r = Te(e.tool, [...e.args], {
|
|
2324
2405
|
env: {
|
|
2325
2406
|
...process.env,
|
|
2326
2407
|
...e.env
|
|
@@ -2340,27 +2421,27 @@ var Rr = (e, t) => ({
|
|
|
2340
2421
|
s ??= e;
|
|
2341
2422
|
};
|
|
2342
2423
|
if (e.stdoutFile && r.stdout) {
|
|
2343
|
-
let t =
|
|
2344
|
-
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);
|
|
2345
2426
|
}
|
|
2346
2427
|
let l = 0;
|
|
2347
2428
|
if (e.stdinFile && r.stdin) {
|
|
2348
|
-
let t =
|
|
2429
|
+
let t = fe(e.stdinFile);
|
|
2349
2430
|
t.on("data", (e) => {
|
|
2350
2431
|
l += e.length;
|
|
2351
2432
|
}), t.on("error", (t) => {
|
|
2352
|
-
c(`reading ${
|
|
2433
|
+
c(`reading ${F(e.stdinFile)}: ${t.message}`), r.stdin?.end();
|
|
2353
2434
|
}), r.stdin.on("error", (t) => {
|
|
2354
|
-
t.code !== "EPIPE" && c(`feeding ${
|
|
2435
|
+
t.code !== "EPIPE" && c(`feeding ${F(e.stdinFile)} to ${e.tool}: ${t.message}`);
|
|
2355
2436
|
}), t.pipe(r.stdin);
|
|
2356
2437
|
}
|
|
2357
2438
|
let u = () => {
|
|
2358
2439
|
if (e.stdoutFile !== void 0) try {
|
|
2359
|
-
|
|
2440
|
+
he(e.stdoutFile);
|
|
2360
2441
|
} catch {}
|
|
2361
2442
|
};
|
|
2362
2443
|
r.on("error", (t) => {
|
|
2363
|
-
u(), o(n.fail(new
|
|
2444
|
+
u(), o(n.fail(new W({
|
|
2364
2445
|
tool: e.tool,
|
|
2365
2446
|
reason: `failed to launch (is '${e.tool}' installed + on PATH?): ${t.message}`,
|
|
2366
2447
|
...e.hint === void 0 ? {} : { hint: e.hint }
|
|
@@ -2371,25 +2452,25 @@ var Rr = (e, t) => ({
|
|
|
2371
2452
|
return;
|
|
2372
2453
|
}
|
|
2373
2454
|
u();
|
|
2374
|
-
let r = e.stdinFile === void 0 ? "" : ` — ${l} of ${
|
|
2375
|
-
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({
|
|
2376
2457
|
tool: e.tool,
|
|
2377
|
-
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`),
|
|
2378
2459
|
stderr: i.trim() === "" ? `(${e.tool} printed nothing to stderr)` : i.slice(-2e3),
|
|
2379
2460
|
...e.hint === void 0 ? {} : { hint: e.hint }
|
|
2380
2461
|
})));
|
|
2381
2462
|
});
|
|
2382
|
-
}),
|
|
2463
|
+
}), ci = (e) => {
|
|
2383
2464
|
try {
|
|
2384
|
-
return String(
|
|
2465
|
+
return String(me(e).size);
|
|
2385
2466
|
} catch {
|
|
2386
2467
|
return "?";
|
|
2387
2468
|
}
|
|
2388
|
-
},
|
|
2389
|
-
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, {
|
|
2390
2471
|
store: e.store,
|
|
2391
2472
|
...e.tenantTables ? { tenantTables: e.tenantTables } : {}
|
|
2392
|
-
}), r =
|
|
2473
|
+
}), r = sn(t.tables, e.snapshot), i = e.classification ?? Oe(e.snapshot), a = e.sampleSize ?? 20, o = He(r.map((t) => ({
|
|
2393
2474
|
name: t,
|
|
2394
2475
|
columns: (e.snapshot.tables.find((e) => e.name === t)?.columns ?? []).map((e) => ({
|
|
2395
2476
|
name: e.name,
|
|
@@ -2397,19 +2478,19 @@ var Rr = (e, t) => ({
|
|
|
2397
2478
|
}))
|
|
2398
2479
|
})), i, e.masking), s = [], c = [];
|
|
2399
2480
|
for (let i of r) {
|
|
2400
|
-
let r = t.predicateFor(i), u = yield*
|
|
2481
|
+
let r = t.predicateFor(i), u = yield* C(e.store, {
|
|
2401
2482
|
table: i,
|
|
2402
2483
|
chunkSize: a,
|
|
2403
2484
|
...r === void 0 ? {} : { where: r }
|
|
2404
|
-
}).pipe(l.take(a), l.runCollect, n.map((e) => [...e])), d = u.map((t) =>
|
|
2405
|
-
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));
|
|
2406
2487
|
let f = u[0], p = d[0], m = [];
|
|
2407
2488
|
if (f && p) for (let [e, t] of Object.entries(o.actions)) {
|
|
2408
2489
|
if (!e.startsWith(`${i}.`) || t === "keep") continue;
|
|
2409
2490
|
let n = e.slice(i.length + 1);
|
|
2410
2491
|
m.push({
|
|
2411
2492
|
column: n,
|
|
2412
|
-
action:
|
|
2493
|
+
action: li(t),
|
|
2413
2494
|
before: f[n],
|
|
2414
2495
|
after: p[n]
|
|
2415
2496
|
});
|
|
@@ -2424,7 +2505,7 @@ var Rr = (e, t) => ({
|
|
|
2424
2505
|
leaks: c,
|
|
2425
2506
|
unclassified: o.unclassified
|
|
2426
2507
|
};
|
|
2427
|
-
}),
|
|
2508
|
+
}), di = (e, t) => {
|
|
2428
2509
|
let n = new Map(t.map((e) => [e.name, e])), r = [], i = {};
|
|
2429
2510
|
for (let t of e) {
|
|
2430
2511
|
let e = n.get(t.name);
|
|
@@ -2479,7 +2560,7 @@ var Rr = (e, t) => ({
|
|
|
2479
2560
|
skipColumns: i,
|
|
2480
2561
|
refuse: r.some((e) => e.verdict === "refuse")
|
|
2481
2562
|
};
|
|
2482
|
-
},
|
|
2563
|
+
}, fi = (e) => {
|
|
2483
2564
|
if (e.findings.length === 0) return [" schema matches the bundle"];
|
|
2484
2565
|
let t = {
|
|
2485
2566
|
safe: "✓",
|
|
@@ -2490,4 +2571,4 @@ var Rr = (e, t) => ({
|
|
|
2490
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;
|
|
2491
2572
|
};
|
|
2492
2573
|
//#endregion
|
|
2493
|
-
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 };
|