@voltro/data-transfer 0.48.0 → 0.49.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 +67 -0
- package/dist/index.d.ts +13 -9
- package/dist/index.js +138 -128
- package/package.json +3 -3
package/CHANGELOG.md
CHANGED
|
@@ -39,6 +39,73 @@ _Changes staged for the next release accumulate here (rolled up from
|
|
|
39
39
|
|
|
40
40
|
---
|
|
41
41
|
|
|
42
|
+
## [0.49.0] — 2026-08-23
|
|
43
|
+
|
|
44
|
+
### ⚠ BREAKING
|
|
45
|
+
|
|
46
|
+
- **@voltro/cli, @voltro/data-transfer, @voltro/database, @voltro/sql-sqlite, @voltro/voltro** — A data transfer is a series of short requests now — no single one may outlive a caller's budget.
|
|
47
|
+
|
|
48
|
+
**The rule:** *a request that carries bytes never runs a transfer; a request that starts a transfer never carries bytes.* It was broken in the worst available place. The upload was already chunked and resumable — many short requests, each abandonable — and then the FINAL chunk fell through and ran the whole import. So the longest request of the flow arrived AFTER the entire upload had succeeded, and a caller under a policy that caps a single request (a job runner that kills a client at ten minutes; a 30 s ingress ceiling) lost the most expensive thing they had already paid for. A single-request upload had the same shape without the excuse, and the export had no protocol at all: one request that read the whole database and streamed it back.
|
|
49
|
+
|
|
50
|
+
**Import.** `POST /_voltro/admin/import` accumulates and answers `202`. `POST /_voltro/admin/import/start` begins the run and answers `202 { runId }` as soon as the run's first row exists. `start` is idempotent per upload — it is a short request and therefore a retryable one, and without a claim a retry would begin a second destructive run from the same bytes. A claim whose run has ENDED is taken over rather than honoured forever, so a process that dies holding one cannot poison a bundle.
|
|
51
|
+
|
|
52
|
+
**Export.** `POST /_voltro/admin/export` answers `202 { runId }` and produces in the background; the bytes come back from `GET /_voltro/admin/export/download?runId=&offset=&length=` in ranges, resumable, with the total in a header. Object storage (`--bundle-key`) remains for a bundle you want to KEEP — it is no longer the only way to get one out, because requiring it would leave an instance without storage unable to export at all.
|
|
53
|
+
|
|
54
|
+
**The client.** `--max-request-seconds` (or `VOLTRO_MAX_REQUEST_SECONDS`) declares the budget — declared rather than probed, because the thing that kills a request is a policy on the caller's side and only they know it. `--detach` returns once the run has started and says the outcome is NOT known. Attached, the CLI polls the record and prints per-table progress; Ctrl-C then loses the watching and never the run.
|
|
55
|
+
|
|
56
|
+
**The trap, stated because it is the one way to get this wrong:** a failure used to arrive in the response (409 on drift, 409 on a refused mode, 500 otherwise). After the split the response is a `202`, so **a client deriving its exit code from the status line reports a failed import as a success.** The exit code comes from the polled record, in one shared function, and the drift check moved into `start` where it can still be a refusal that leaves no history.
|
|
57
|
+
|
|
58
|
+
**Two knobs that were constants.** `VOLTRO_IMPORT_UPLOAD_DIR` and `VOLTRO_EXPORT_ARTIFACT_DIR` move the staging areas off the default temp filesystem — which on a container is frequently a small tmpfs, so an instance simply could not accept a bundle the size a grown database produces, and the failure arrived as a write error halfway through an upload somebody had been waiting on.
|
|
59
|
+
|
|
60
|
+
**Renamed:** `voltro data imports` → `voltro data transfers`, and `_voltro_data_imports` → `_voltro_data_transfers` with a `direction` column. The command showed one direction and now shows both; the table rename carries its rows via the declarative differ on every dialect and needs nothing from you. The CLI rename ships a `manual` codemod — the command lives in scripts, CI jobs and runbooks, which `voltro update` cannot see or rewrite. The four PUBLIC exports that named the same record were renamed with it (`ImportRun`, `describeImportRun`, `IMPORT_RUNS_TABLE`, `_voltroImportRunsTable`); those are application source, they ship their own `transform` codemod, and they have their own entry.
|
|
61
|
+
- **@voltro/database, @voltro/voltro** — The run-history exports say `transfer`, not `import`.
|
|
62
|
+
|
|
63
|
+
`@voltro/database` (and `voltro/database`) renamed four public exports along with the table behind them:
|
|
64
|
+
|
|
65
|
+
| was | is | |---|---| | `ImportRun` | `DataTransferRun` | | `describeImportRun` | `describeTransferRun` | | `IMPORT_RUNS_TABLE` | `DATA_TRANSFERS_TABLE` | | `_voltroImportRunsTable` | `_voltroDataTransfersTable` |
|
|
66
|
+
|
|
67
|
+
An EXPORT writes to this record now — the row carries a `direction` — so every one of those names described half of what it holds.
|
|
68
|
+
|
|
69
|
+
A `transform` codemod rewrites all four, alias-aware, from either module spelling. It also rewrites a hand-spelled `_voltro_data_imports` in a string, template or raw-SQL fragment, and that is the half worth stating: the four identifiers announce themselves as compile errors, while a query that addresses the table by name has nothing to fail on. The table itself moves with its rows via the declarative differ on every dialect.
|
|
70
|
+
|
|
71
|
+
This is filed apart from the transfer-protocol entry beside it deliberately. That one's codemod is `manual` and is about a CLI invocation living in scripts and CI jobs; this one is application source and is rewritten for you. Reading the first as covering both is what would leave a build broken with a note saying nothing in your source was affected.
|
|
72
|
+
|
|
73
|
+
### Added
|
|
74
|
+
|
|
75
|
+
- **@voltro/database, @voltro/data-transfer, @voltro/cli** — An import records WHETHER it staged, and a soft-dropped column says so in a drift refusal.
|
|
76
|
+
|
|
77
|
+
**`_voltro_data_imports.staged`.** The pre-upload preflight says what the instance WILL do; the run's own line says what it did — and that line is printed inside the instance, which is exactly where an operator using `--target api` cannot read it. So "we were told it would stage" and "it staged" were two claims with no way to close the gap between them from outside. The column is `null` for a mode where the question does not arise; `voltro data imports` and `GET /_voltro/admin/imports` both carry it.
|
|
78
|
+
|
|
79
|
+
**A soft-dropped column is named as one.** `<original>__dropped_<stamp>` is what the differ leaves behind when an app stops declaring a column — only the database that did the drop has it, so it drifts against every target. The refusal reported it as an ordinary missing column ("the value has nowhere to go"), which points at the TARGET's schema: the one place the fix does not lie. It now says where the column lives and how to reclaim it.
|
|
80
|
+
|
|
81
|
+
### Fixed
|
|
82
|
+
|
|
83
|
+
- **@voltro/data-transfer, @voltro/sql-sqlite, @voltro/database** — A successful `--mode replace --no-atomic` left a marker that refused the next boot.
|
|
84
|
+
|
|
85
|
+
Two defects, one visible symptom, and both were silent by construction.
|
|
86
|
+
|
|
87
|
+
**The clear was gated on the WRITE's condition.** `!(useLedger && ledger.truncated)` means "an earlier attempt already recorded this destructive run, do not write a second row" — correct on the write. Copied down to the clear its meaning inverts: `ledger.truncated` is set by the emptying step of THIS run, so on `--no-atomic` (the only mode where `useLedger` is true) the clear was skipped by the very run that wrote the marker.
|
|
88
|
+
|
|
89
|
+
**And a `Date` in a predicate is not bindable on sqlite.** `better-sqlite3` binds numbers, strings, bigints, buffers and null; the row path has coerced Dates since that store was written, and the eager-join compiler carried its own private copy of the fix, but `query` / `updateMany` / `deleteMany` bound the raw value. So every comparison of a timestamp column against a `Date` failed with `Failed to execute statement` — including the marker's clear, which swallows its errors ON PURPOSE (a store with no marker table must not fail an import over a bookkeeping row) and therefore said nothing. The retention sweep compares `lt(column, cutoff)` the same way.
|
|
90
|
+
|
|
91
|
+
Together: a fully successful replace left the marker standing, and the next boot REFUSED with "a destructive import did not finish" over a database that was completely fine. The one recovery is a command the operator has no reason to think they need. It stayed invisible because `atomic` defaults to true for `replace`, and because a staged replace writes no marker at all — two defaults hiding the one mode that exists for large, interruptible loads.
|
|
92
|
+
|
|
93
|
+
The coercion is shared now and applied at all three predicate sites, with a guard that fails on a fourth that forgets. A dry run also closes its trace row: a preview that finished instantly used to leave the record open, so a polling caller waited out its whole budget over a run that was long done.
|
|
94
|
+
- **@voltro/cli** — `voltro codegen` declared twenty framework tables fewer than a boot.
|
|
95
|
+
|
|
96
|
+
The app half of this was fixed last release and looked like the whole thing. It was not: `codegen` derived the FEATURE MIX from the file list it had just walked, and that list is the entity/relations set — which contains no `*.workflow.tsx`, no `*.agent.ts`, no `*.cron.tsx`. So every feature flag came back false, and the dialect was never passed at all, taking `_voltro_cdc_offsets` with it. Measured on an app with two workflow files: 18 framework tables where the shared assembly produces 33.
|
|
97
|
+
|
|
98
|
+
It calls `assembleFrameworkTables({ root })` now — the same entry `voltro db plan/apply` uses, which detects the mix from the root rather than being handed one.
|
|
99
|
+
|
|
100
|
+
The parity guard moved with it. Comparing the two WALKS could not see this: both walks were right about files, and the divergence was introduced one layer past them. It compares the assembled SETS now, and runs codegen's own table function on a tree whose only feature signals are a workflow file and an agent file — a source assertion that the right function is CALLED cannot see a wrong argument handed to it, and a wrong argument is what this was.
|
|
101
|
+
- **@voltro/cli** — `voltro data --help` advertised four subcommands out of nine.
|
|
102
|
+
|
|
103
|
+
It printed `<export|import|backup|restore>` while the command dispatched those four plus `imports`, `inspect`, `unpack`, `clear-replace-marker` and `clear-staging`. A quoted enumeration is read as exhaustive — the same failure `subcommandNames.ts` was written for after a `db` list cost two wrong conclusions — and the missing entry here is the one that answers "what is my import doing right now" for somebody who cannot reach the pod.
|
|
104
|
+
|
|
105
|
+
`subcommandHelpParity.test.ts` had listed `data` among the commands it could not check, loudly and correctly: there was no name list to check against. There is one now (`DATA_SUBCOMMANDS`), the dispatch is a keyed `Record`, so a subcommand with no name and a name with no handler are both compile errors, and the usage line is generated from the same array. `data` is out of the unchecked list.
|
|
106
|
+
|
|
107
|
+
---
|
|
108
|
+
|
|
42
109
|
## [0.48.0] — 2026-08-22
|
|
43
110
|
|
|
44
111
|
### Added
|
package/dist/index.d.ts
CHANGED
|
@@ -366,15 +366,6 @@ export declare const DEFAULT_CLASS_ACTIONS: Readonly<Record<string, MaskAction>>
|
|
|
366
366
|
/** Identity helper for authoring a profile with full type-checking + inference. */
|
|
367
367
|
export declare const defineDataProfile: (profile: DataTransferProfile) => DataTransferProfile;
|
|
368
368
|
|
|
369
|
-
/**
|
|
370
|
-
* Differences that would actually break THIS import, in a stable order.
|
|
371
|
-
*
|
|
372
|
-
* `bundle` is the shape reconstructed from the manifest, so only its table
|
|
373
|
-
* names, column names and column TYPES are meaningful — its `nullable` /
|
|
374
|
-
* `hasDefault` are placeholders and are never read here. Every judgement about
|
|
375
|
-
* required-ness is therefore made from the TARGET side, which is introspected
|
|
376
|
-
* and real.
|
|
377
|
-
*/
|
|
378
369
|
export declare const diffSnapshots: (bundle: SchemaSnapshot, target: SchemaSnapshot) => ReadonlyArray<string>;
|
|
379
370
|
|
|
380
371
|
/** A {@link BlobSink} that writes blobs to the LOCAL dir as `assets/<sha>` files
|
|
@@ -710,6 +701,19 @@ export declare interface ImportOptions {
|
|
|
710
701
|
/** Which transport is running this — named in the refusal a later boot prints,
|
|
711
702
|
* so the reader knows where to look for logs. */
|
|
712
703
|
readonly via?: string;
|
|
704
|
+
/**
|
|
705
|
+
* The id of a trace row the CALLER has already written.
|
|
706
|
+
*
|
|
707
|
+
* The admin-import `start` endpoint answers `202` with a run id before the
|
|
708
|
+
* import has done anything, and a caller who polls immediately must find a
|
|
709
|
+
* row rather than an absence — "not started" and "no record" are the two
|
|
710
|
+
* states a poll loop cannot be allowed to confuse. So `start` opens the row
|
|
711
|
+
* itself and hands the id here; this run then ADVANCES and CLOSES that row
|
|
712
|
+
* instead of opening a second one.
|
|
713
|
+
*
|
|
714
|
+
* Absent, the run opens its own row exactly as before.
|
|
715
|
+
*/
|
|
716
|
+
readonly traceId?: string;
|
|
713
717
|
/**
|
|
714
718
|
* Record that this run emptied the target, so a later boot can refuse over a
|
|
715
719
|
* database it left half-replaced.
|
package/dist/index.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
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 {
|
|
2
|
+
import { DATA_TRANSFERS_TABLE as u, REPLACE_IN_PROGRESS_TABLE as d, _voltroDataTransfersTable as f, classifyConstraintViolation as p, derivedRowId as m, ensureTableRegistered as h, eq as g, extractDbCause as _, getTable as v, inSet as y, isNotNull as b, or as x, recordsTable as S, registerTable as C, streamTable as w, suspendWriteRecorders as ee, suspendWriteRecordersEffect as te, unregisterTable as ne } from "@voltro/database";
|
|
3
3
|
import { fingerprintSchema as re } from "@voltro/database/sql";
|
|
4
|
-
import { createCipheriv as T, createDecipheriv as ie, createHash as E, createHmac as ae, randomBytes as
|
|
5
|
-
import { STORAGE_REFS_TABLE as
|
|
6
|
-
import * as
|
|
7
|
-
import { PassThrough as
|
|
4
|
+
import { createCipheriv as T, createDecipheriv as ie, createHash as E, createHmac as ae, randomBytes as D, scrypt as oe } from "node:crypto";
|
|
5
|
+
import { STORAGE_REFS_TABLE as se, fromNodeReadable as ce, getObjectStream as le, putObjectStream as O, toNodeReadable as k } from "@voltro/plugin-storage";
|
|
6
|
+
import * as A from "node:zlib";
|
|
7
|
+
import { PassThrough as ue, Readable as j } from "node:stream";
|
|
8
8
|
import { copyFile as de, createReadStream as fe, createWriteStream as M, existsSync as N, unlinkSync as pe } from "node:fs";
|
|
9
9
|
import { SqlClient as P } from "@effect/sql";
|
|
10
10
|
import { mkdir as F, readdir as me, stat as he } from "node:fs/promises";
|
|
@@ -217,7 +217,7 @@ var xe = (e) => {
|
|
|
217
217
|
["_voltro_seeds", "which seeds ran HERE — a foreign row suppresses seeding the target still needs"],
|
|
218
218
|
["_voltro_cdc_offsets", "binlog/WAL positions of the SOURCE server — meaningless and unsafe against another one"],
|
|
219
219
|
["_voltro_schedule_claims", "live leases held by THIS deployment's replicas — a foreign row hands out a lease nobody holds"],
|
|
220
|
-
["
|
|
220
|
+
["_voltro_data_transfers", "which bundles moved through HERE, in or out — a foreign row claims a transfer this deployment never ran"],
|
|
221
221
|
["_voltro_replace_in_progress", "the marker a destructive import HERE left behind — a foreign row refuses a boot over a healthy database"],
|
|
222
222
|
["_voltro_wakeups", "pending wakeups addressed to THIS deployment's runners"],
|
|
223
223
|
["_voltro_workflow_watermarks", "how far a consumer has read THIS deployment's event journal — a foreign position skips events"],
|
|
@@ -416,16 +416,16 @@ var xe = (e) => {
|
|
|
416
416
|
};
|
|
417
417
|
}), rt = (e, t) => ({
|
|
418
418
|
list: t,
|
|
419
|
-
open: (t) =>
|
|
419
|
+
open: (t) => le(e, t)
|
|
420
420
|
}), it = (e) => ({
|
|
421
|
-
write: (t, n, r) =>
|
|
421
|
+
write: (t, n, r) => O(e, t, n, r),
|
|
422
422
|
has: (t) => e.head(t).pipe(n.map((e) => e !== null))
|
|
423
423
|
}), at = (e, t) => n.tryPromise({
|
|
424
424
|
try: async () => {
|
|
425
425
|
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) {
|
|
426
426
|
u.update(e), d += e.length, n(null, e);
|
|
427
427
|
} });
|
|
428
|
-
await o(await
|
|
428
|
+
await o(await k(e.stream), f, n(l));
|
|
429
429
|
let p = u.digest("hex"), m = c.join(t, p);
|
|
430
430
|
try {
|
|
431
431
|
await r.access(m), await r.rm(l, { force: !0 });
|
|
@@ -443,7 +443,7 @@ var xe = (e) => {
|
|
|
443
443
|
path: t
|
|
444
444
|
})
|
|
445
445
|
}), ot = (e, t, r) => n.gen(function* () {
|
|
446
|
-
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 =
|
|
446
|
+
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 = ce("bundle", () => a(s)).pipe(l.tap((e) => n.sync(() => c.update(e))));
|
|
447
447
|
yield* e.write(r.key, u, {
|
|
448
448
|
contentType: r.contentType,
|
|
449
449
|
totalSize: r.size
|
|
@@ -454,7 +454,7 @@ var xe = (e) => {
|
|
|
454
454
|
expected: r.sha256,
|
|
455
455
|
actual: d
|
|
456
456
|
}));
|
|
457
|
-
}), st = () => typeof
|
|
457
|
+
}), st = () => typeof A.createZstdCompress == "function", ct = (e) => e === "none" ? "none" : e === "gzip" ? "gzip" : st() ? "zstd" : "gzip", lt = (e) => e === "zstd" ? ".zst" : e === "gzip" ? ".gz" : "", ut = (e) => e === "zstd" ? A.createZstdCompress() : e === "gzip" ? A.createGzip() : new ue(), dt = (e) => e === "zstd" ? A.createZstdDecompress() : e === "gzip" ? A.createGunzip() : new ue(), ft = 1, pt = c.Struct({
|
|
458
458
|
name: c.String,
|
|
459
459
|
file: c.String,
|
|
460
460
|
rowCount: c.Number,
|
|
@@ -1150,7 +1150,7 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
1150
1150
|
rows: r.tables.reduce((e, t) => e + t.rowCount, 0),
|
|
1151
1151
|
tables: r.tables.length
|
|
1152
1152
|
};
|
|
1153
|
-
}), Rn = (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`, zn = (e, t) => e.tables.find((e) => e.name === t), Bn = (e, t) => new Map((zn(e, t)?.columns ?? []).map((e) => [e.name, e])), Vn = (e, t) => {
|
|
1153
|
+
}), Rn = (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`, zn = (e, t) => e.tables.find((e) => e.name === t), Bn = (e, t) => new Map((zn(e, t)?.columns ?? []).map((e) => [e.name, e])), Vn = /__dropped_\d+$/, Hn = (e, t) => {
|
|
1154
1154
|
let n = [];
|
|
1155
1155
|
for (let r of [...e.tables].sort((e, t) => e.name.localeCompare(t.name))) {
|
|
1156
1156
|
if (zn(t, r.name) === void 0) {
|
|
@@ -1161,7 +1161,7 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
1161
1161
|
for (let [t, a] of i) {
|
|
1162
1162
|
let i = e.get(t);
|
|
1163
1163
|
if (i === void 0) {
|
|
1164
|
-
n.push(`${r.name}.${t}: in the bundle, MISSING from the target — the value has nowhere to go`);
|
|
1164
|
+
n.push(Vn.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`);
|
|
1165
1165
|
continue;
|
|
1166
1166
|
}
|
|
1167
1167
|
i.type !== a.type && n.push(`${r.name}.${t}: type '${a.type}' (bundle) vs '${i.type}' (target)`);
|
|
@@ -1169,7 +1169,7 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
1169
1169
|
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`);
|
|
1170
1170
|
}
|
|
1171
1171
|
return n.length > 30 ? [...n.slice(0, 30), `… and ${n.length - 30} more difference(s)`] : n;
|
|
1172
|
-
},
|
|
1172
|
+
}, Un = (e, t, n) => {
|
|
1173
1173
|
let r = re(t);
|
|
1174
1174
|
if (r === e || n === void 0) return {
|
|
1175
1175
|
drifted: !1,
|
|
@@ -1177,14 +1177,14 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
1177
1177
|
targetFingerprint: r,
|
|
1178
1178
|
diff: []
|
|
1179
1179
|
};
|
|
1180
|
-
let i =
|
|
1180
|
+
let i = Hn(n, t);
|
|
1181
1181
|
return {
|
|
1182
1182
|
drifted: i.length > 0,
|
|
1183
1183
|
bundleFingerprint: e,
|
|
1184
1184
|
targetFingerprint: r,
|
|
1185
1185
|
diff: i
|
|
1186
1186
|
};
|
|
1187
|
-
},
|
|
1187
|
+
}, Wn = 2e3, Gn = 200, Kn = /* @__PURE__ */ new Set([
|
|
1188
1188
|
"BundleError",
|
|
1189
1189
|
"CodecError",
|
|
1190
1190
|
"IntegrityError",
|
|
@@ -1193,17 +1193,17 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
1193
1193
|
"RowsRefusedError",
|
|
1194
1194
|
"SchemaDriftError",
|
|
1195
1195
|
"StorageError"
|
|
1196
|
-
]),
|
|
1196
|
+
]), qn = (t) => {
|
|
1197
1197
|
let n = o.isFiberFailure(t) ? [...e.failures(t[o.FiberFailureCauseId]), ...e.defects(t[o.FiberFailureCauseId])] : [t];
|
|
1198
1198
|
for (let e of n) {
|
|
1199
1199
|
let t = e?._tag;
|
|
1200
|
-
if (typeof t == "string" &&
|
|
1200
|
+
if (typeof t == "string" && Kn.has(t)) return e;
|
|
1201
1201
|
if (o.isFiberFailure(e)) {
|
|
1202
|
-
let t =
|
|
1202
|
+
let t = qn(e);
|
|
1203
1203
|
if (t) return t;
|
|
1204
1204
|
}
|
|
1205
1205
|
}
|
|
1206
|
-
},
|
|
1206
|
+
}, Jn = (t) => [...e.failures(t)][0] ?? Error(e.pretty(t)), Yn = (e) => n.tryPromise({
|
|
1207
1207
|
try: async () => {
|
|
1208
1208
|
let t = await import("node:fs/promises"), n = await import("node:path");
|
|
1209
1209
|
return vt(await t.readFile(n.join(e, K), "utf8"));
|
|
@@ -1212,10 +1212,10 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
1212
1212
|
reason: `manifest read/parse failed: ${String(e?.message ?? e)}`,
|
|
1213
1213
|
path: K
|
|
1214
1214
|
})
|
|
1215
|
-
}),
|
|
1215
|
+
}), Xn = (e) => {
|
|
1216
1216
|
let t;
|
|
1217
1217
|
return n.gen(function* () {
|
|
1218
|
-
let i = yield* n.promise(() => import("node:path")), a = yield*
|
|
1218
|
+
let i = yield* n.promise(() => import("node:path")), a = yield* Yn(e.bundleDir);
|
|
1219
1219
|
if (a.formatVersion !== 1) return yield* n.fail(new H({ reason: `unsupported bundle formatVersion ${a.formatVersion} (expected 1)` }));
|
|
1220
1220
|
if (e.tables !== void 0) {
|
|
1221
1221
|
let t = new Set(a.tables.map((e) => e.name)), r = e.tables.filter((e) => !t.has(e));
|
|
@@ -1236,7 +1236,7 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
1236
1236
|
unique: !1,
|
|
1237
1237
|
hasDefault: !1
|
|
1238
1238
|
}))
|
|
1239
|
-
})) }, r =
|
|
1239
|
+
})) }, r = Un(s.source.schemaFingerprint, e.targetSnapshot, t);
|
|
1240
1240
|
if (r.drifted) {
|
|
1241
1241
|
if (!e.force) return yield* n.fail(new Je({
|
|
1242
1242
|
bundleFingerprint: r.bundleFingerprint,
|
|
@@ -1295,7 +1295,12 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
1295
1295
|
reason: sn(i)
|
|
1296
1296
|
}));
|
|
1297
1297
|
}
|
|
1298
|
-
if (e.dryRun === !0) return {
|
|
1298
|
+
if (e.dryRun === !0) return e.traceId !== void 0 && (yield* n.promise(() => e.store.update(u, e.traceId, {
|
|
1299
|
+
finishedAt: /* @__PURE__ */ new Date(),
|
|
1300
|
+
tablesWritten: 0,
|
|
1301
|
+
rowsWritten: 0,
|
|
1302
|
+
failure: null
|
|
1303
|
+
}).then(() => void 0, () => void 0))), {
|
|
1299
1304
|
manifest: s,
|
|
1300
1305
|
tablesWritten: 0,
|
|
1301
1306
|
rowsWritten: 0,
|
|
@@ -1319,16 +1324,16 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
1319
1324
|
return p === "append" ? _ === "fail" ? e.insert(i, o) : e.insertIgnore(i, o, { conflictColumns: [a] }) : p === "replace" ? r ? e.upsert(i, o, { conflictColumns: [a] }) : e.insert(i, o) : e.upsert(i, o, { conflictColumns: [a] });
|
|
1320
1325
|
}, ie = (e, t) => e.savepoint ? e.savepoint(t) : t(), E = 0, ae = (t, n, r) => {
|
|
1321
1326
|
r.unclassified && (E++, !(E > 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}` + (E === 3 ? " (further unclassified refusals are counted, not logged)" : "")));
|
|
1322
|
-
},
|
|
1327
|
+
}, D = (e, t, r = !0) => n.tryPromise({
|
|
1323
1328
|
try: e,
|
|
1324
1329
|
catch: (e) => _n(e)
|
|
1325
|
-
}).pipe(n.map(() => !0), n.catchAll((e) => n.sync(() => (r && (t.reason = e.reason, ae(t.entry, t.row, e)), !1)))),
|
|
1330
|
+
}).pipe(n.map(() => !0), n.catchAll((e) => n.sync(() => (r && (t.reason = e.reason, ae(t.entry, t.row, e)), !1)))), oe = (e) => {
|
|
1326
1331
|
let t = Object.entries(e.entry.columnTypes).filter(([t, n]) => n === "reference" && e.row[t] !== null && e.row[t] !== void 0).map(([e]) => e);
|
|
1327
1332
|
if (t.length !== 0) return {
|
|
1328
1333
|
...e.row,
|
|
1329
1334
|
...Object.fromEntries(t.map((e) => [e, null]))
|
|
1330
1335
|
};
|
|
1331
|
-
},
|
|
1336
|
+
}, se = (e) => {
|
|
1332
1337
|
let t = new Set(e.map((e) => String(e.row[e.entry.primaryKey]))), n = (e) => Object.entries(e.entry.columnTypes).some(([n, r]) => {
|
|
1333
1338
|
if (r !== "reference") return !1;
|
|
1334
1339
|
let i = e.row[n];
|
|
@@ -1356,31 +1361,31 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
1356
1361
|
primary: t.primary
|
|
1357
1362
|
})).sort((e, t) => t.refused - e.refused || e.table.localeCompare(t.table)).slice(0, 100)
|
|
1358
1363
|
});
|
|
1359
|
-
},
|
|
1364
|
+
}, le = (e, t) => n.gen(function* () {
|
|
1360
1365
|
let r = t, i = [], a = !0;
|
|
1361
1366
|
for (; r.length > 0 && a;) {
|
|
1362
1367
|
a = !1;
|
|
1363
1368
|
let t = [];
|
|
1364
|
-
for (let n of r) (yield*
|
|
1369
|
+
for (let n of r) (yield* D(() => ie(e, () => T(e, n.entry, n.row, !0)), n)) ? a = !0 : t.push(n);
|
|
1365
1370
|
if (!a && t.length > 0) for (let n = t.length - 1; n >= 0; n--) {
|
|
1366
|
-
let r = t[n], o =
|
|
1367
|
-
o !== void 0 && (yield*
|
|
1371
|
+
let r = t[n], o = oe(r);
|
|
1372
|
+
o !== void 0 && (yield* D(() => ie(e, () => T(e, r.entry, o, !0)), r, !1)) && (i.push(r), t.splice(n, 1), a = !0);
|
|
1368
1373
|
}
|
|
1369
1374
|
r = t;
|
|
1370
1375
|
}
|
|
1371
|
-
for (let t of i) (yield*
|
|
1372
|
-
if (r.length > 0) return yield* n.fail(
|
|
1373
|
-
}),
|
|
1376
|
+
for (let t of i) (yield* D(() => ie(e, () => e.upsert(t.entry.name, t.row, { conflictColumns: [t.entry.primaryKey] })), t)) || (r = [...r, t]);
|
|
1377
|
+
if (r.length > 0) return yield* n.fail(se(r));
|
|
1378
|
+
}), O = (() => {
|
|
1374
1379
|
let t = e.targetDialect;
|
|
1375
1380
|
return t === "postgres" || t === "mysql" || t === "mariadb" || t === "sqlite" || t === "mssql" ? t : void 0;
|
|
1376
|
-
})(),
|
|
1381
|
+
})(), k = In({
|
|
1377
1382
|
mode: p,
|
|
1378
1383
|
...e.targetDialect === void 0 ? {} : { targetDialect: e.targetDialect },
|
|
1379
1384
|
...e.targetSnapshot === void 0 ? {} : { targetSnapshot: e.targetSnapshot },
|
|
1380
1385
|
bundleTables: s.tables.map((e) => e.name),
|
|
1381
1386
|
isSkipped: V,
|
|
1382
1387
|
canRunSql: xn(e.store)
|
|
1383
|
-
}),
|
|
1388
|
+
}), A = k.tables, ue = s.tables.filter((e) => !V(e.name) && S(e.name)).map((e) => e.name), j = k.active, de = !1, M = 0, N = 0, pe, P = 0, F = 0, me = (t, r) => n.gen(function* () {
|
|
1384
1389
|
if (p === "replace" && !j && !(r && x.truncated)) {
|
|
1385
1390
|
e.recordInterruption === !0 && (yield* n.tryPromise({
|
|
1386
1391
|
try: () => t.insert(d, {
|
|
@@ -1433,7 +1438,7 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
1433
1438
|
total: m.rowCount
|
|
1434
1439
|
});
|
|
1435
1440
|
let v = a.length, b = n.gen(function* () {
|
|
1436
|
-
let { createHash: r } = yield* n.promise(() => import("node:crypto")), i = r("sha256"), o = 0, c =
|
|
1441
|
+
let { createHash: r } = yield* n.promise(() => import("node:crypto")), i = r("sha256"), o = 0, c = ce("bundle", () => fe(_).pipe(dt(s.compression))).pipe(l.tap((e) => n.sync(() => i.update(e)))), u = async (e) => {
|
|
1437
1442
|
let n = {
|
|
1438
1443
|
entry: m,
|
|
1439
1444
|
row: e,
|
|
@@ -1533,7 +1538,7 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
1533
1538
|
checksum: m.checksum
|
|
1534
1539
|
}, yield* J(y, x)));
|
|
1535
1540
|
}
|
|
1536
|
-
if (a.length > 0 && (yield*
|
|
1541
|
+
if (a.length > 0 && (yield* le(t, a)), p === "replace" && (yield* n.promise(() => t.deleteMany(d, { where: {
|
|
1537
1542
|
column: "startedAt",
|
|
1538
1543
|
op: "lte",
|
|
1539
1544
|
value: ge
|
|
@@ -1571,26 +1576,31 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
1571
1576
|
path: I.dir
|
|
1572
1577
|
})
|
|
1573
1578
|
})), e.onWarn?.(Rn(I)));
|
|
1574
|
-
let _e = (e) => p === "replace" ? ee(e) : e(), L = (e) => p === "replace" ? te(e) : e, R = m("dimp", `${Date.now()}-${s.source.schemaFingerprint ?? ""}`), ve =
|
|
1575
|
-
ye && h(f), ye && (yield* n.promise(() => e.store.insert(u, {
|
|
1579
|
+
let _e = (e) => p === "replace" ? ee(e) : e(), L = (e) => p === "replace" ? te(e) : e, R = e.traceId ?? m("dimp", `${Date.now()}-${s.source.schemaFingerprint ?? ""}`), ve = e.traceId !== void 0, ye = (e.targetSnapshot?.tables.some((e) => e.name === u) ?? !1) || v(u) !== void 0;
|
|
1580
|
+
ye && h(f), ye && e.traceId === void 0 && (yield* n.promise(() => e.store.insert(u, {
|
|
1576
1581
|
id: R,
|
|
1577
1582
|
mode: p,
|
|
1578
1583
|
via: e.via ?? "direct",
|
|
1584
|
+
direction: "import",
|
|
1579
1585
|
bundle: e.bundleDir,
|
|
1580
1586
|
sourceFingerprint: s.source.schemaFingerprint ?? null,
|
|
1581
1587
|
tablesWritten: 0,
|
|
1582
|
-
rowsWritten: 0
|
|
1588
|
+
rowsWritten: 0,
|
|
1589
|
+
staged: p === "replace" ? j : null
|
|
1583
1590
|
}).then(() => {
|
|
1584
1591
|
ve = !0;
|
|
1585
1592
|
}, (t) => {
|
|
1586
1593
|
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
|
|
1587
1594
|
\`voltro db apply\` so the next one is recorded.`);
|
|
1588
|
-
})))
|
|
1595
|
+
}))), e.traceId !== void 0 && ye && (yield* n.promise(() => e.store.update(u, R, {
|
|
1596
|
+
staged: p === "replace" ? j : null,
|
|
1597
|
+
sourceFingerprint: s.source.schemaFingerprint ?? null
|
|
1598
|
+
}).then(() => void 0, () => void 0)));
|
|
1589
1599
|
let be = 0, xe = !1;
|
|
1590
1600
|
pe = () => {
|
|
1591
1601
|
if (!ve || xe) return;
|
|
1592
1602
|
let t = Date.now();
|
|
1593
|
-
t - be <
|
|
1603
|
+
t - be < Wn || (be = t, e.store.update(u, R, {
|
|
1594
1604
|
tablesWritten: N,
|
|
1595
1605
|
rowsWritten: M
|
|
1596
1606
|
}).then(() => void 0, () => {
|
|
@@ -1603,11 +1613,11 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
1603
1613
|
rowsWritten: M,
|
|
1604
1614
|
failure: t
|
|
1605
1615
|
}).then(() => void 0, () => void 0) : Promise.resolve();
|
|
1606
|
-
if (t = (e) => Se(e), p === "replace" && !j &&
|
|
1616
|
+
if (t = (e) => Se(e), p === "replace" && !j && k.blocker !== void 0 && e.onWarn?.(Sn(k.blocker)), p === "replace" && ue.length > 0 && e.onWarn?.(`write recorders are SUSPENDED for this replace (${ue.length} table(s) have one).\n A replace sets a state rather than changing rows, so a per-row history entry would describe
|
|
1607
1617
|
something that did not happen — and this path already writes through the raw store, without
|
|
1608
1618
|
tenant scoping or \`audit()\` stamping, for the same reason.`), j) {
|
|
1609
|
-
e.onWarn?.(`staging ${
|
|
1610
|
-
let t = e.store, r =
|
|
1619
|
+
e.onWarn?.(`staging ${A.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.`);
|
|
1620
|
+
let t = e.store, r = A.map((e) => e.name), i = Dn(r, {
|
|
1611
1621
|
getTable: (e) => v(e),
|
|
1612
1622
|
registerTable: (e) => {
|
|
1613
1623
|
C(e);
|
|
@@ -1618,30 +1628,30 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
1618
1628
|
let i = g ? r : r.filter((e) => !Mt(x, e));
|
|
1619
1629
|
yield* n.tryPromise({
|
|
1620
1630
|
try: async () => {
|
|
1621
|
-
await jn(t, i.map((e) => Tn(e,
|
|
1631
|
+
await jn(t, i.map((e) => Tn(e, O))), await jn(t, i.map((e) => wn(e, O)));
|
|
1622
1632
|
},
|
|
1623
1633
|
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)}` })
|
|
1624
1634
|
}), yield* L(me(e.store, !g)), !g && x.truncated === !0 ? a = !0 : yield* n.tryPromise({
|
|
1625
|
-
try: () => Mn(t,
|
|
1635
|
+
try: () => Mn(t, A, O).then(() => {
|
|
1626
1636
|
a = !0;
|
|
1627
1637
|
}),
|
|
1628
1638
|
catch: (e) => new H({ reason: String(e?.message ?? e) })
|
|
1629
1639
|
}).pipe(n.catchAll((i) => n.gen(function* () {
|
|
1630
|
-
let a = An(yield* n.promise(() => Nn(t, On(e.targetSnapshot, r),
|
|
1640
|
+
let a = An(yield* n.promise(() => Nn(t, On(e.targetSnapshot, r), O).then((e) => e, () => [])));
|
|
1631
1641
|
return yield* n.fail(new H({ reason: a ?? `the swap failed and the target is UNCHANGED: ${i.reason}` }));
|
|
1632
1642
|
}))), !g && a && x.truncated !== !0 && (x.truncated = !0, yield* J(y, x));
|
|
1633
1643
|
} finally {
|
|
1634
|
-
i.undo(), a || g ? yield* n.promise(() => jn(t, r.map((e) => Tn(e,
|
|
1644
|
+
i.undo(), a || g ? yield* n.promise(() => jn(t, r.map((e) => Tn(e, O))).then(() => void 0, () => void 0)) : 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");
|
|
1635
1645
|
}
|
|
1636
1646
|
} else g ? yield* n.tryPromise({
|
|
1637
1647
|
try: () => e.store.transactional(async (e) => {
|
|
1638
1648
|
let t = await _e(() => n.runPromiseExit(me(e, !1)));
|
|
1639
|
-
if (r.isFailure(t)) throw
|
|
1649
|
+
if (r.isFailure(t)) throw Jn(t.cause);
|
|
1640
1650
|
}),
|
|
1641
|
-
catch: (e) =>
|
|
1651
|
+
catch: (e) => qn(e) ?? new H({ reason: `atomic import failed (rolled back): ${String(e?.message ?? e)}` })
|
|
1642
1652
|
}) : yield* L(me(e.store, !0));
|
|
1643
1653
|
if (e.assets && s.assets.index && !e.assetsAlreadyRestored) {
|
|
1644
|
-
let t = e.assets, r = i.join(e.bundleDir, xt), a = i.join(e.bundleDir, s.assets.index ?? "assets/index.ndjson"), o =
|
|
1654
|
+
let t = e.assets, r = i.join(e.bundleDir, xt), a = i.join(e.bundleDir, s.assets.index ?? "assets/index.ndjson"), o = ce("bundle", () => fe(a)).pipe(l.decodeText(), l.splitLines, l.filter((e) => e.trim().length > 0), l.map((e) => JSON.parse(e)));
|
|
1645
1655
|
yield* l.runForEach(o, (e) => e.key in x.assets ? n.void : ot(t, r, e).pipe(n.andThen(n.sync(() => {
|
|
1646
1656
|
x.assets[e.key] = !0;
|
|
1647
1657
|
})), n.andThen(J(y, x))));
|
|
@@ -1656,14 +1666,14 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
1656
1666
|
...I === void 0 ? {} : { rollback: I }
|
|
1657
1667
|
};
|
|
1658
1668
|
}).pipe(n.tapError((e) => n.promise(() => t?.(e?.reason ?? e?._tag ?? "the import did not finish") ?? Promise.resolve())));
|
|
1659
|
-
},
|
|
1669
|
+
}, Zn = (e) => e, Qn = (e) => {
|
|
1660
1670
|
if (e.allowLive || e.liveInstance === null || e.sameTarget === "different") return { refuse: !1 };
|
|
1661
1671
|
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.";
|
|
1662
1672
|
return {
|
|
1663
1673
|
refuse: !0,
|
|
1664
1674
|
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).`
|
|
1665
1675
|
};
|
|
1666
|
-
}, Q = Buffer.from("VBUNDLE2"),
|
|
1676
|
+
}, Q = Buffer.from("VBUNDLE2"), $n = 0, er = 1, tr = 2, nr = 32, rr = async (e) => {
|
|
1667
1677
|
let t = [], n = async (r) => {
|
|
1668
1678
|
let i;
|
|
1669
1679
|
try {
|
|
@@ -1677,21 +1687,21 @@ voltro data import <this-directory> --target api --api-url <url> --token <secret
|
|
|
1677
1687
|
}
|
|
1678
1688
|
};
|
|
1679
1689
|
return await n(""), t.sort();
|
|
1680
|
-
},
|
|
1690
|
+
}, ir = (e, t) => {
|
|
1681
1691
|
let n = Buffer.from(e, "utf8"), r = Buffer.alloc(5 + n.length + 8);
|
|
1682
|
-
return r.writeUInt8(
|
|
1683
|
-
},
|
|
1692
|
+
return r.writeUInt8(er, 0), r.writeUInt32BE(n.length, 1), n.copy(r, 5), r.writeBigUInt64BE(BigInt(t), 5 + n.length), r;
|
|
1693
|
+
}, ar = (e, t, n) => {
|
|
1684
1694
|
let r = Buffer.from(e, "utf8"), i = Buffer.from(t, "utf8"), a = Buffer.alloc(5 + r.length + 2 + i.length + 8), o = 0;
|
|
1685
|
-
return a.writeUInt8(
|
|
1695
|
+
return a.writeUInt8(tr, 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;
|
|
1686
1696
|
};
|
|
1687
|
-
async function*
|
|
1697
|
+
async function* or(e) {
|
|
1688
1698
|
yield new Uint8Array(Q);
|
|
1689
|
-
for (let t of await
|
|
1699
|
+
for (let t of await rr(e.dir)) {
|
|
1690
1700
|
let n = L(e.dir, t), r = await he(n);
|
|
1691
|
-
if (yield new Uint8Array(
|
|
1701
|
+
if (yield new Uint8Array(ir(t, r.size)), r.size > 0) for await (let e of fe(n)) yield new Uint8Array(e);
|
|
1692
1702
|
}
|
|
1693
1703
|
if (e.blobs) for await (let t of e.blobs.list()) {
|
|
1694
|
-
yield new Uint8Array(
|
|
1704
|
+
yield new Uint8Array(ar(t.key, t.contentType, t.size));
|
|
1695
1705
|
let n = E("sha256"), r = 0;
|
|
1696
1706
|
for await (let i of e.blobs.open(t.key)) {
|
|
1697
1707
|
let e = Buffer.from(i);
|
|
@@ -1700,9 +1710,9 @@ async function* ar(e) {
|
|
|
1700
1710
|
if (r !== t.size) throw Error(`blob '${t.key}' size mismatch: header ${t.size}, streamed ${r}`);
|
|
1701
1711
|
yield new Uint8Array(n.digest());
|
|
1702
1712
|
}
|
|
1703
|
-
yield new Uint8Array(Buffer.from([
|
|
1713
|
+
yield new Uint8Array(Buffer.from([$n]));
|
|
1704
1714
|
}
|
|
1705
|
-
var
|
|
1715
|
+
var sr = (e, t) => new Promise((n, r) => e.write(t, (e) => e ? r(e) : n())), cr = (e) => new Promise((t) => e.end(t)), lr = async (e, t) => {
|
|
1706
1716
|
let n = R(t.dir);
|
|
1707
1717
|
await F(n, { recursive: !0 });
|
|
1708
1718
|
let r = Buffer.alloc(0), i = e[Symbol.asyncIterator](), a = !1, o = async () => {
|
|
@@ -1719,8 +1729,8 @@ var or = (e, t) => new Promise((n, r) => e.write(t, (e) => e ? r(e) : n())), sr
|
|
|
1719
1729
|
for (;;) {
|
|
1720
1730
|
await s(1);
|
|
1721
1731
|
let e = c(1).readUInt8(0);
|
|
1722
|
-
if (e ===
|
|
1723
|
-
if (e ===
|
|
1732
|
+
if (e === $n) return;
|
|
1733
|
+
if (e === er) {
|
|
1724
1734
|
await s(4);
|
|
1725
1735
|
let e = c(4).readUInt32BE(0);
|
|
1726
1736
|
await s(e);
|
|
@@ -1733,10 +1743,10 @@ var or = (e, t) => new Promise((n, r) => e.write(t, (e) => e ? r(e) : n())), sr
|
|
|
1733
1743
|
for (; i > 0n;) {
|
|
1734
1744
|
r.length === 0 && await s(1);
|
|
1735
1745
|
let e = i < BigInt(r.length) ? Number(i) : r.length;
|
|
1736
|
-
await
|
|
1746
|
+
await sr(o, c(e)), i -= BigInt(e);
|
|
1737
1747
|
}
|
|
1738
|
-
await
|
|
1739
|
-
} else if (e ===
|
|
1748
|
+
await cr(o);
|
|
1749
|
+
} else if (e === tr) {
|
|
1740
1750
|
await s(4);
|
|
1741
1751
|
let e = c(4).readUInt32BE(0);
|
|
1742
1752
|
await s(e);
|
|
@@ -1746,24 +1756,24 @@ var or = (e, t) => new Promise((n, r) => e.write(t, (e) => e ? r(e) : n())), sr
|
|
|
1746
1756
|
await s(i);
|
|
1747
1757
|
let a = c(i).toString("utf8");
|
|
1748
1758
|
await s(8);
|
|
1749
|
-
let o = c(8).readBigUInt64BE(0), l = await t.blobs.has(n), u = E("sha256"), d = new
|
|
1759
|
+
let o = c(8).readBigUInt64BE(0), l = await t.blobs.has(n), u = E("sha256"), d = new ue(), f = l ? Promise.resolve() : t.blobs.write(n, d, {
|
|
1750
1760
|
contentType: a,
|
|
1751
1761
|
size: Number(o)
|
|
1752
1762
|
}), p = o;
|
|
1753
1763
|
for (; p > 0n;) {
|
|
1754
1764
|
r.length === 0 && await s(1);
|
|
1755
1765
|
let e = p < BigInt(r.length) ? Number(p) : r.length, t = c(e);
|
|
1756
|
-
u.update(t), l || await
|
|
1766
|
+
u.update(t), l || await sr(d, t), p -= BigInt(e);
|
|
1757
1767
|
}
|
|
1758
|
-
l ? d.destroy() : await
|
|
1759
|
-
let m = c(
|
|
1768
|
+
l ? d.destroy() : await cr(d), await f, await s(nr);
|
|
1769
|
+
let m = c(nr);
|
|
1760
1770
|
if (!u.digest().equals(m)) throw Error(`blob '${n}' failed integrity (sha mismatch)`);
|
|
1761
1771
|
} else throw Error(`unknown bundle entry kind ${e}`);
|
|
1762
1772
|
}
|
|
1763
1773
|
} finally {
|
|
1764
1774
|
a || await Promise.resolve(i.return?.()).catch(() => void 0);
|
|
1765
1775
|
}
|
|
1766
|
-
},
|
|
1776
|
+
}, ur = async (e, t) => {
|
|
1767
1777
|
let n = new Set(t), r = /* @__PURE__ */ new Map(), i = Buffer.alloc(0), a = e[Symbol.asyncIterator](), o = async () => {
|
|
1768
1778
|
let { value: e, done: t } = await a.next();
|
|
1769
1779
|
return !t && (i = i.length === 0 ? Buffer.from(e) : Buffer.concat([i, Buffer.from(e)]), !0);
|
|
@@ -1785,8 +1795,8 @@ var or = (e, t) => new Promise((n, r) => e.write(t, (e) => e ? r(e) : n())), sr
|
|
|
1785
1795
|
if (!await s(Q.length) || !c(Q.length).equals(Q)) throw Error("not a bundle archive (bad magic)");
|
|
1786
1796
|
for (; await s(1);) {
|
|
1787
1797
|
let e = c(1).readUInt8(0);
|
|
1788
|
-
if (e ===
|
|
1789
|
-
if (e !==
|
|
1798
|
+
if (e === $n || e === tr) break;
|
|
1799
|
+
if (e !== er) throw Error(`unknown bundle entry kind ${e}`);
|
|
1790
1800
|
if (!await s(4)) break;
|
|
1791
1801
|
let t = c(4).readUInt32BE(0);
|
|
1792
1802
|
if (!await s(t)) break;
|
|
@@ -1796,10 +1806,10 @@ var or = (e, t) => new Promise((n, r) => e.write(t, (e) => e ? r(e) : n())), sr
|
|
|
1796
1806
|
if (a === null || n.has(i) && (r.set(i, a), n.delete(i), n.size === 0)) break;
|
|
1797
1807
|
}
|
|
1798
1808
|
return r;
|
|
1799
|
-
},
|
|
1809
|
+
}, dr = (e, t) => lr(e, {
|
|
1800
1810
|
dir: t,
|
|
1801
|
-
blobs:
|
|
1802
|
-
}),
|
|
1811
|
+
blobs: fr(t)
|
|
1812
|
+
}), fr = (e) => {
|
|
1803
1813
|
let t = /* @__PURE__ */ new Set();
|
|
1804
1814
|
return {
|
|
1805
1815
|
has: async (e) => t.has(e),
|
|
@@ -1819,33 +1829,33 @@ var or = (e, t) => new Promise((n, r) => e.write(t, (e) => e ? r(e) : n())), sr
|
|
|
1819
1829
|
})}\n`), t.add(n);
|
|
1820
1830
|
}
|
|
1821
1831
|
};
|
|
1822
|
-
},
|
|
1832
|
+
}, pr = ye(oe), mr = Buffer.from("VENC1\0\0\0"), hr = 32, gr = 16, _r = 7, vr = 16, yr = 262144, br = {
|
|
1823
1833
|
N: 32768,
|
|
1824
1834
|
r: 8,
|
|
1825
1835
|
p: 1
|
|
1826
|
-
},
|
|
1836
|
+
}, xr = 134217728, Sr = 43, Cr = (e, t, n) => {
|
|
1827
1837
|
let r = Buffer.alloc(12);
|
|
1828
|
-
return e.copy(r, 0, 0,
|
|
1838
|
+
return e.copy(r, 0, 0, _r), r.writeUInt32BE(t >>> 0, _r), r.writeUInt8(+!!n, 11), r;
|
|
1829
1839
|
};
|
|
1830
|
-
async function*
|
|
1840
|
+
async function* wr(e, t) {
|
|
1831
1841
|
if (!t) throw Error("encryptStream: a non-empty passphrase is required");
|
|
1832
|
-
let n =
|
|
1833
|
-
...
|
|
1834
|
-
maxmem:
|
|
1835
|
-
}), a = Buffer.alloc(
|
|
1836
|
-
|
|
1842
|
+
let n = D(gr), r = D(_r), i = await pr(t, n, hr, {
|
|
1843
|
+
...br,
|
|
1844
|
+
maxmem: xr
|
|
1845
|
+
}), a = Buffer.alloc(Sr);
|
|
1846
|
+
mr.copy(a, 0), a.writeUInt32BE(br.N, 8), a.writeUInt32BE(br.r, 12), a.writeUInt32BE(br.p, 16), n.copy(a, 20), r.copy(a, 36), yield new Uint8Array(a);
|
|
1837
1847
|
let o = 0, s = (e, t) => {
|
|
1838
|
-
let n = T("aes-256-gcm", i,
|
|
1848
|
+
let n = T("aes-256-gcm", i, Cr(r, o, t));
|
|
1839
1849
|
o === 0 && n.setAAD(a);
|
|
1840
1850
|
let s = Buffer.concat([n.update(e), n.final()]), c = n.getAuthTag();
|
|
1841
1851
|
o++;
|
|
1842
|
-
let l = Buffer.alloc(5 + s.length +
|
|
1843
|
-
return l.writeUInt8(+!!t, 0), l.writeUInt32BE(s.length +
|
|
1852
|
+
let l = Buffer.alloc(5 + s.length + vr);
|
|
1853
|
+
return l.writeUInt8(+!!t, 0), l.writeUInt32BE(s.length + vr, 1), s.copy(l, 5), c.copy(l, 5 + s.length), new Uint8Array(l);
|
|
1844
1854
|
}, c = Buffer.alloc(0);
|
|
1845
|
-
for await (let t of e) for (c = c.length === 0 ? Buffer.from(t) : Buffer.concat([c, Buffer.from(t)]); c.length >
|
|
1855
|
+
for await (let t of e) for (c = c.length === 0 ? Buffer.from(t) : Buffer.concat([c, Buffer.from(t)]); c.length > yr;) yield s(c.subarray(0, yr), !1), c = c.subarray(yr);
|
|
1846
1856
|
yield s(c, !0);
|
|
1847
1857
|
}
|
|
1848
|
-
async function*
|
|
1858
|
+
async function* Tr(e, t) {
|
|
1849
1859
|
if (!t) throw Error("decryptStream: a non-empty passphrase is required");
|
|
1850
1860
|
let n = e[Symbol.asyncIterator](), r = Buffer.alloc(0), i = !1, a = async () => {
|
|
1851
1861
|
let { value: e, done: t } = await n.next();
|
|
@@ -1854,16 +1864,16 @@ async function* wr(e, t) {
|
|
|
1854
1864
|
for (; r.length < e && !i && await a(););
|
|
1855
1865
|
return r.length >= e;
|
|
1856
1866
|
};
|
|
1857
|
-
if (!await o(
|
|
1858
|
-
let s = r.subarray(0,
|
|
1859
|
-
if (!s.subarray(0, 8).equals(
|
|
1860
|
-
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,
|
|
1867
|
+
if (!await o(Sr)) throw Error("encrypted bundle truncated (no header)");
|
|
1868
|
+
let s = r.subarray(0, Sr);
|
|
1869
|
+
if (!s.subarray(0, 8).equals(mr)) throw Error("not an encrypted bundle (bad magic / wrong passphrase target)");
|
|
1870
|
+
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, Sr)), p = await pr(t, d, hr, {
|
|
1861
1871
|
N: c,
|
|
1862
1872
|
r: l,
|
|
1863
1873
|
p: u,
|
|
1864
|
-
maxmem:
|
|
1874
|
+
maxmem: xr
|
|
1865
1875
|
});
|
|
1866
|
-
r = r.subarray(
|
|
1876
|
+
r = r.subarray(Sr);
|
|
1867
1877
|
let m = 0, h = !1;
|
|
1868
1878
|
for (;;) {
|
|
1869
1879
|
if (!await o(5)) {
|
|
@@ -1872,11 +1882,11 @@ async function* wr(e, t) {
|
|
|
1872
1882
|
}
|
|
1873
1883
|
if (h) throw Error("encrypted bundle has trailing data after the final frame");
|
|
1874
1884
|
let e = r.readUInt8(0) === 1, t = r.readUInt32BE(1);
|
|
1875
|
-
if (t <
|
|
1885
|
+
if (t < vr) throw Error("encrypted bundle corrupt (short frame)");
|
|
1876
1886
|
if (!await o(5 + t)) throw Error("encrypted bundle truncated (frame body)");
|
|
1877
|
-
let n = r.subarray(5, 5 + t -
|
|
1887
|
+
let n = r.subarray(5, 5 + t - vr), i = r.subarray(5 + t - vr, 5 + t);
|
|
1878
1888
|
r = r.subarray(5 + t);
|
|
1879
|
-
let a = ie("aes-256-gcm", p,
|
|
1889
|
+
let a = ie("aes-256-gcm", p, Cr(f, m, e));
|
|
1880
1890
|
m === 0 && a.setAAD(s), a.setAuthTag(i);
|
|
1881
1891
|
let c = Buffer.concat([a.update(n), a.final()]);
|
|
1882
1892
|
m++, e && (h = !0), c.length > 0 && (yield new Uint8Array(c));
|
|
@@ -1884,7 +1894,7 @@ async function* wr(e, t) {
|
|
|
1884
1894
|
}
|
|
1885
1895
|
//#endregion
|
|
1886
1896
|
//#region src/blobStorage.ts
|
|
1887
|
-
var
|
|
1897
|
+
var Er = (e, t) => ({
|
|
1888
1898
|
list: () => {
|
|
1889
1899
|
let e = t();
|
|
1890
1900
|
return { async *[Symbol.asyncIterator]() {
|
|
@@ -1897,29 +1907,29 @@ var Tr = (e, t) => ({
|
|
|
1897
1907
|
} };
|
|
1898
1908
|
},
|
|
1899
1909
|
open: (t) => ({ async *[Symbol.asyncIterator]() {
|
|
1900
|
-
let r = await n.runPromise(
|
|
1910
|
+
let r = await n.runPromise(le(e, t)), i = await k(r.stream);
|
|
1901
1911
|
for await (let e of i) yield e instanceof Uint8Array ? e : new Uint8Array(e);
|
|
1902
1912
|
} })
|
|
1903
|
-
}),
|
|
1904
|
-
table:
|
|
1913
|
+
}), Dr = (e, t) => Er(e, () => w(t, {
|
|
1914
|
+
table: se,
|
|
1905
1915
|
chunkSize: 500
|
|
1906
1916
|
}).pipe(l.map((e) => ({
|
|
1907
1917
|
key: String(e.key),
|
|
1908
1918
|
contentType: String(e.contentType ?? "application/octet-stream"),
|
|
1909
1919
|
size: Number(e.size ?? 0)
|
|
1910
|
-
})))),
|
|
1920
|
+
})))), Or = (e) => ({
|
|
1911
1921
|
has: (t) => n.runPromise(e.head(t).pipe(n.map((e) => e !== null))),
|
|
1912
1922
|
write: async (t, r, i) => {
|
|
1913
|
-
let a =
|
|
1914
|
-
await n.runPromise(
|
|
1923
|
+
let a = ce("storage", () => j.from(r));
|
|
1924
|
+
await n.runPromise(O(e, t, a, {
|
|
1915
1925
|
contentType: i.contentType,
|
|
1916
1926
|
totalSize: i.size
|
|
1917
1927
|
}));
|
|
1918
1928
|
}
|
|
1919
|
-
}),
|
|
1929
|
+
}), kr = (e, t) => {
|
|
1920
1930
|
let n = t === "dump" ? "mariadb-dump" : "mariadb", r = t === "dump" ? "mysqldump" : "mysql";
|
|
1921
|
-
return e === "mariadb" &&
|
|
1922
|
-
},
|
|
1931
|
+
return e === "mariadb" && Ar(n) ? n : r;
|
|
1932
|
+
}, Ar = (e) => (process.env.PATH ?? "").split(I).filter((e) => e !== "").some((t) => N(L(t, e))), jr = (e) => {
|
|
1923
1933
|
switch (e) {
|
|
1924
1934
|
case "postgres": return "db.dump";
|
|
1925
1935
|
case "mysql":
|
|
@@ -1929,7 +1939,7 @@ var Tr = (e, t) => ({
|
|
|
1929
1939
|
case "mssql": return "db.bacpac";
|
|
1930
1940
|
default: return "db.dump";
|
|
1931
1941
|
}
|
|
1932
|
-
},
|
|
1942
|
+
}, Mr = (e) => e.filename ?? e.database ?? ((e.url ?? "").replace(/^file:/, "") || "app.sqlite"), $ = (e) => {
|
|
1933
1943
|
if (e.host || e.database) return {
|
|
1934
1944
|
host: e.host ?? "localhost",
|
|
1935
1945
|
port: e.port ?? 3306,
|
|
@@ -1945,7 +1955,7 @@ var Tr = (e, t) => ({
|
|
|
1945
1955
|
password: decodeURIComponent(t.password) || "",
|
|
1946
1956
|
database: t.pathname.replace(/^\//, "") || ""
|
|
1947
1957
|
};
|
|
1948
|
-
},
|
|
1958
|
+
}, Nr = (e) => `Server=${e.host},${e.port};Database=${e.database};User ID=${e.username};Password=${e.password};TrustServerCertificate=True`, Pr = (e, t, n) => {
|
|
1949
1959
|
switch (e) {
|
|
1950
1960
|
case "postgres": {
|
|
1951
1961
|
if (t.url) return {
|
|
@@ -1992,7 +2002,7 @@ var Tr = (e, t) => ({
|
|
|
1992
2002
|
let r = $(t);
|
|
1993
2003
|
return {
|
|
1994
2004
|
kind: "spawn",
|
|
1995
|
-
tool:
|
|
2005
|
+
tool: kr(e, "dump"),
|
|
1996
2006
|
args: [
|
|
1997
2007
|
"--single-transaction",
|
|
1998
2008
|
"--routines",
|
|
@@ -2014,7 +2024,7 @@ var Tr = (e, t) => ({
|
|
|
2014
2024
|
case "sqlite":
|
|
2015
2025
|
case "turso": return {
|
|
2016
2026
|
kind: "copy",
|
|
2017
|
-
from:
|
|
2027
|
+
from: Mr(t),
|
|
2018
2028
|
to: n
|
|
2019
2029
|
};
|
|
2020
2030
|
case "mssql": return {
|
|
@@ -2022,7 +2032,7 @@ var Tr = (e, t) => ({
|
|
|
2022
2032
|
tool: "sqlpackage",
|
|
2023
2033
|
args: [
|
|
2024
2034
|
"/Action:Export",
|
|
2025
|
-
`/SourceConnectionString:${
|
|
2035
|
+
`/SourceConnectionString:${Nr($({
|
|
2026
2036
|
...t,
|
|
2027
2037
|
port: t.port ?? 1433
|
|
2028
2038
|
}))}`,
|
|
@@ -2035,7 +2045,7 @@ var Tr = (e, t) => ({
|
|
|
2035
2045
|
reason: `no native backup for dialect '${e}'`
|
|
2036
2046
|
});
|
|
2037
2047
|
}
|
|
2038
|
-
},
|
|
2048
|
+
}, Fr = (e, t, n) => {
|
|
2039
2049
|
switch (e) {
|
|
2040
2050
|
case "postgres": {
|
|
2041
2051
|
if (t.url) return {
|
|
@@ -2080,7 +2090,7 @@ var Tr = (e, t) => ({
|
|
|
2080
2090
|
let r = $(t);
|
|
2081
2091
|
return {
|
|
2082
2092
|
kind: "spawn",
|
|
2083
|
-
tool:
|
|
2093
|
+
tool: kr(e, "client"),
|
|
2084
2094
|
args: [
|
|
2085
2095
|
"--protocol=TCP",
|
|
2086
2096
|
"-h",
|
|
@@ -2099,14 +2109,14 @@ var Tr = (e, t) => ({
|
|
|
2099
2109
|
case "turso": return {
|
|
2100
2110
|
kind: "copy",
|
|
2101
2111
|
from: n,
|
|
2102
|
-
to:
|
|
2112
|
+
to: Mr(t)
|
|
2103
2113
|
};
|
|
2104
2114
|
case "mssql": return {
|
|
2105
2115
|
kind: "spawn",
|
|
2106
2116
|
tool: "sqlpackage",
|
|
2107
2117
|
args: [
|
|
2108
2118
|
"/Action:Import",
|
|
2109
|
-
`/TargetConnectionString:${
|
|
2119
|
+
`/TargetConnectionString:${Nr($({
|
|
2110
2120
|
...t,
|
|
2111
2121
|
port: t.port ?? 1433
|
|
2112
2122
|
}))}`,
|
|
@@ -2119,7 +2129,7 @@ var Tr = (e, t) => ({
|
|
|
2119
2129
|
reason: `no native restore for dialect '${e}'`
|
|
2120
2130
|
});
|
|
2121
2131
|
}
|
|
2122
|
-
},
|
|
2132
|
+
}, Ir = (e) => e.kind === "copy" ? n.async((t) => {
|
|
2123
2133
|
de(e.from, e.to, (r) => t(r ? n.fail(new W({
|
|
2124
2134
|
tool: "copy",
|
|
2125
2135
|
reason: `copy ${e.from} → ${e.to}: ${r.message}`
|
|
@@ -2160,7 +2170,7 @@ var Tr = (e, t) => ({
|
|
|
2160
2170
|
stderr: i.slice(-2e3)
|
|
2161
2171
|
})));
|
|
2162
2172
|
});
|
|
2163
|
-
}),
|
|
2173
|
+
}), Lr = (e) => typeof e == "object" && e ? "fake" in e ? `fake:${e.fake}` : "custom" : String(e), Rr = (e) => n.gen(function* () {
|
|
2164
2174
|
let t = yield* nt(e.scope ?? { kind: "all" }, e.snapshot, {
|
|
2165
2175
|
store: e.store,
|
|
2166
2176
|
...e.tenantTables ? { tenantTables: e.tenantTables } : {}
|
|
@@ -2184,7 +2194,7 @@ var Tr = (e, t) => ({
|
|
|
2184
2194
|
let n = e.slice(i.length + 1);
|
|
2185
2195
|
m.push({
|
|
2186
2196
|
column: n,
|
|
2187
|
-
action:
|
|
2197
|
+
action: Lr(t),
|
|
2188
2198
|
before: f[n],
|
|
2189
2199
|
after: p[n]
|
|
2190
2200
|
});
|
|
@@ -2199,7 +2209,7 @@ var Tr = (e, t) => ({
|
|
|
2199
2209
|
leaks: c,
|
|
2200
2210
|
unclassified: o.unclassified
|
|
2201
2211
|
};
|
|
2202
|
-
}),
|
|
2212
|
+
}), zr = (e, t) => {
|
|
2203
2213
|
let n = new Map(t.map((e) => [e.name, e])), r = [], i = {};
|
|
2204
2214
|
for (let t of e) {
|
|
2205
2215
|
let e = n.get(t.name);
|
|
@@ -2254,7 +2264,7 @@ var Tr = (e, t) => ({
|
|
|
2254
2264
|
skipColumns: i,
|
|
2255
2265
|
refuse: r.some((e) => e.verdict === "refuse")
|
|
2256
2266
|
};
|
|
2257
|
-
},
|
|
2267
|
+
}, Br = (e) => {
|
|
2258
2268
|
if (e.findings.length === 0) return [" schema matches the bundle"];
|
|
2259
2269
|
let t = {
|
|
2260
2270
|
safe: "✓",
|
|
@@ -2265,4 +2275,4 @@ var Tr = (e, t) => ({
|
|
|
2265
2275
|
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;
|
|
2266
2276
|
};
|
|
2267
2277
|
//#endregion
|
|
2268
|
-
export { xt as ASSETS_DIR, St as ASSET_INDEX_FILE, H as BundleError, We as CodecError, Ke as CompressionError, Ze as CrossDialectError, bt as DATA_DIR, Se as DEFAULT_CLASS_ACTIONS, Be as ENVIRONMENT_LOCAL_TABLES, Ve as ENVIRONMENT_PORTABLE_TABLES, ft as FORMAT_VERSION, Xe as ImportModeError, Ge as IntegrityError, Ct as LEDGER_FILE, K as MANIFEST_FILE, Ye as MaskingError, W as NativeToolError, qe as RowsRefusedError,
|
|
2278
|
+
export { xt as ASSETS_DIR, St as ASSET_INDEX_FILE, H as BundleError, We as CodecError, Ke as CompressionError, Ze as CrossDialectError, bt as DATA_DIR, Se as DEFAULT_CLASS_ACTIONS, Be as ENVIRONMENT_LOCAL_TABLES, Ve as ENVIRONMENT_PORTABLE_TABLES, ft as FORMAT_VERSION, Xe as ImportModeError, Ge as IntegrityError, Ct as LEDGER_FILE, K as MANIFEST_FILE, Ye as MaskingError, W as NativeToolError, qe as RowsRefusedError, Gn as SAVEPOINT_BATCH_SIZE, bn as STAGING_PREFIX, Je as SchemaDriftError, U as ScopeError, Pe as applyAction, qn as asImportError, Qn as assessLiveImport, Nt as assetDone, jr as backupArtifactName, Pr as backupCommand, cn as canonicalType, dn as checkPortability, Un as checkSchemaDrift, Ce as classificationFromSnapshot, zr as classifyImportDrift, lt as compressionExt, $e as computeSubsetIds, In as decideStaging, vt as decodeManifest, Ut as decodeRow, Vt as decodeValue, Tr as decryptStream, Zn as defineDataProfile, Hn as diffSnapshots, fr as dirBlobSink, Tn as dropStagingSql, At as emptyLedger, _t as encodeManifest, Ht as encodeRow, zt as encodeValue, wr as encryptStream, Ue as environmentLocalNotice, He as environmentLocalReason, jn as execStatements, Br as formatImportDrift, fn as formatIssue, st as hasZstd, V as isEnvironmentLocal, ut as makeCompressor, dt as makeDecompressor, ze as maskRow, Kt as ndjsonToRows, sn as outsideReferenceRefusal, on as outsideReferencesInto, or as packBundle, ur as peekBundle, ct as pickCompression, Ie as planMasking, Rr as previewMasking, jt as readLedger, we as resolveAction, nt as resolveScope, ot as restoreAssetFromCas, Fr as restoreCommand, Gt as rowsToNdjson, an as runExport, Xn as runImport, Ir as runNativeStep, Re as scanForLeaks, X as stagingNameFor, it as storageAssetSink, rt as storageAssetSource, Or as storageBlobSink, Er as storageBlobSource, Dr as storageRefsBlobSource, et as subsetToScope, Mt as tableDone, qt as topoSortTables, lr as unpackBundle, dr as unpackBundleToDir, at as writeAssetToCas, J as writeLedger };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@voltro/data-transfer",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.49.0",
|
|
4
4
|
"description": "Portable export/import for a Voltro app's data + assets — typed-NDJSON row codec, content-addressed assets, framed compression, a resumable chunk ledger, and FK-ordered idempotent import. Dialect-agnostic; the resilient backbone under `voltro data export|import` and native backups.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"voltro",
|
|
@@ -33,8 +33,8 @@
|
|
|
33
33
|
"node": ">=24.0.0"
|
|
34
34
|
},
|
|
35
35
|
"dependencies": {
|
|
36
|
-
"@voltro/database": "0.
|
|
37
|
-
"@voltro/plugin-storage": "0.
|
|
36
|
+
"@voltro/database": "0.49.0",
|
|
37
|
+
"@voltro/plugin-storage": "0.49.0"
|
|
38
38
|
},
|
|
39
39
|
"peerDependencies": {
|
|
40
40
|
"effect": "^3.22.0"
|