@voltro/data-transfer 0.86.0 → 0.88.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 +5484 -0
- package/THIRD-PARTY-NOTICES.md +2503 -690
- package/dist/assetAdmission.js +91 -0
- package/dist/assets.js +62 -42
- package/dist/blobStorage.js +55 -32
- package/dist/bundleArchive.js +249 -105
- package/dist/bundleCrypto.js +1 -2
- package/dist/bundlePaths.js +3 -0
- package/dist/casAssetPhase.js +78 -35
- package/dist/compress.js +4 -5
- package/dist/consistency.js +1 -2
- package/dist/crossDialect.js +1 -2
- package/dist/driftClassification.js +1 -2
- package/dist/environmentLocal.js +267 -4
- package/dist/errors.js +13 -7
- package/dist/exporter.js +146 -133
- package/dist/filesystemAdmission.js +32 -0
- package/dist/importer.js +326 -287
- package/dist/index.d.ts +200 -46
- package/dist/index.js +28 -26
- package/dist/ledger.js +1 -2
- package/dist/liveGuard.js +1 -2
- package/dist/manifest.js +45 -42
- package/dist/masking.js +1 -2
- package/dist/maskingPreview.js +1 -2
- package/dist/nativeDump.js +134 -86
- package/dist/ndjson.js +1 -2
- package/dist/physicalRequest.js +9 -0
- package/dist/profile.js +1 -2
- package/dist/progress.js +1 -2
- package/dist/readme.js +1 -2
- package/dist/replacePreflight.js +1 -2
- package/dist/rollbackCapture.js +1 -2
- package/dist/rowFailureReason.js +1 -2
- package/dist/schemaDrift.js +1 -2
- package/dist/scope.js +1 -2
- package/dist/sealedKeys.js +39 -0
- package/dist/stagedSwap.js +1 -2
- package/dist/storageAssetMetadata.js +46 -0
- package/dist/subset.js +1 -2
- package/dist/topo.js +1 -2
- package/dist/typedCodec.js +1 -2
- package/package.json +4 -4
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { BundleError as e, IntegrityError as t } from "./errors.js";
|
|
2
|
+
import { admitFilesystemPath as n } from "./filesystemAdmission.js";
|
|
3
|
+
import { AssetEntry as r } from "./manifest.js";
|
|
4
|
+
import { physicalRequest as i } from "./physicalRequest.js";
|
|
5
|
+
import { Effect as a, Schema as o } from "effect";
|
|
6
|
+
import { createHash as s } from "node:crypto";
|
|
7
|
+
import { constants as c, createWriteStream as l } from "node:fs";
|
|
8
|
+
import { lstat as u, mkdtemp as d, open as f, rm as p } from "node:fs/promises";
|
|
9
|
+
import { join as m } from "node:path";
|
|
10
|
+
import { tmpdir as h } from "node:os";
|
|
11
|
+
import { Transform as g } from "node:stream";
|
|
12
|
+
import { pipeline as _ } from "node:stream/promises";
|
|
13
|
+
import { storageAddressIdentity as v } from "@voltro/plugin-storage/errors";
|
|
14
|
+
// src/assetAdmission.ts
|
|
15
|
+
var y = Symbol("admitted-assets"), b = /* @__PURE__ */ new WeakMap(), x = (t) => o.decodeUnknownEffect(r)(t).pipe(a.mapError(() => new e({ reason: "asset index contains invalid key, digest, size or content type" }))), S = o.Struct({
|
|
16
|
+
...r.fields,
|
|
17
|
+
sha256: o.optionalKey(r.fields.sha256)
|
|
18
|
+
}), C = (t) => o.decodeUnknownEffect(S)(t).pipe(a.mapError(() => new e({ reason: "asset source metadata contains invalid destination, tenant, key, digest, size or content type" }))), w = (t, n) => b.get(t) === n ? a.void : a.fail(new e({ reason: "asset admission is absent, belongs to another sink or its scope has closed" })), T = (e) => w(e.prepared, e.previousSink).pipe(a.flatMap(() => E({
|
|
19
|
+
entries: e.prepared.entries,
|
|
20
|
+
assetsDir: e.prepared.assetsDir,
|
|
21
|
+
sink: e.sink
|
|
22
|
+
}))), E = (r) => a.gen(function* () {
|
|
23
|
+
yield* a.tryPromise({
|
|
24
|
+
try: () => n(r.assetsDir, "directory"),
|
|
25
|
+
catch: () => new e({ reason: "asset source directory could not be admitted" })
|
|
26
|
+
});
|
|
27
|
+
let o = [], S = /* @__PURE__ */ new Map();
|
|
28
|
+
for (let t of r.entries) {
|
|
29
|
+
let n = yield* x(t), r = v(n), i = S.get(r);
|
|
30
|
+
if (i !== void 0) {
|
|
31
|
+
if (i.sha256 !== n.sha256 || i.size !== n.size || i.contentType !== n.contentType) return yield* a.fail(new e({ reason: "asset index contains conflicting entries for one key" }));
|
|
32
|
+
} else S.set(r, n), o.push(n);
|
|
33
|
+
}
|
|
34
|
+
let C = yield* a.acquireRelease(a.tryPromise({
|
|
35
|
+
try: () => d(m(h(), "voltro-admitted-assets-")),
|
|
36
|
+
catch: () => new e({ reason: "cannot create asset admission directory" })
|
|
37
|
+
}), (e) => a.promise(() => p(e, {
|
|
38
|
+
recursive: !0,
|
|
39
|
+
force: !0
|
|
40
|
+
}))), w = /* @__PURE__ */ new Set();
|
|
41
|
+
for (let d of o) if (yield* r.sink.has(d), w.has(d.sha256)) {
|
|
42
|
+
let n = yield* a.tryPromise({
|
|
43
|
+
try: () => u(m(C, d.sha256)).then((e) => e.size),
|
|
44
|
+
catch: () => new e({ reason: "admitted asset body is unavailable" })
|
|
45
|
+
});
|
|
46
|
+
if (n !== d.size) return yield* a.fail(new t({
|
|
47
|
+
what: `asset ${d.key} size`,
|
|
48
|
+
expected: String(d.size),
|
|
49
|
+
actual: String(n)
|
|
50
|
+
}));
|
|
51
|
+
} else {
|
|
52
|
+
let o = yield* i(async (e) => {
|
|
53
|
+
let t = m(r.assetsDir, d.sha256);
|
|
54
|
+
await n(t, "file");
|
|
55
|
+
let i = await f(t, c.O_RDONLY | c.O_NOFOLLOW | c.O_NONBLOCK);
|
|
56
|
+
try {
|
|
57
|
+
if (!(await i.stat()).isFile()) throw Error("asset body must be a regular file");
|
|
58
|
+
let t = s("sha256"), n = 0, r = new g({ transform(e, r, i) {
|
|
59
|
+
t.update(e), n += e.length, i(null, e);
|
|
60
|
+
} });
|
|
61
|
+
return await _(i.createReadStream({ autoClose: !1 }), r, l(m(C, d.sha256), {
|
|
62
|
+
flags: "wx",
|
|
63
|
+
mode: 384
|
|
64
|
+
}), { signal: e }), {
|
|
65
|
+
sha256: t.digest("hex"),
|
|
66
|
+
size: n
|
|
67
|
+
};
|
|
68
|
+
} finally {
|
|
69
|
+
await i.close();
|
|
70
|
+
}
|
|
71
|
+
}, () => new e({
|
|
72
|
+
reason: "asset body could not be admitted",
|
|
73
|
+
path: d.sha256
|
|
74
|
+
}));
|
|
75
|
+
if (o.sha256 !== d.sha256 || o.size !== d.size) return yield* a.fail(new t({
|
|
76
|
+
what: `asset ${d.key}`,
|
|
77
|
+
expected: `${d.sha256}/${d.size}`,
|
|
78
|
+
actual: `${o.sha256}/${o.size}`
|
|
79
|
+
}));
|
|
80
|
+
w.add(d.sha256);
|
|
81
|
+
}
|
|
82
|
+
let T = Object.freeze({
|
|
83
|
+
[y]: !0,
|
|
84
|
+
assetsDir: C,
|
|
85
|
+
entries: Object.freeze(o.map((e) => Object.freeze(e)))
|
|
86
|
+
});
|
|
87
|
+
return b.set(T, r.sink), yield* a.addFinalizer(() => a.sync(() => {
|
|
88
|
+
b.delete(T);
|
|
89
|
+
})), T;
|
|
90
|
+
});
|
|
91
|
+
export { S as AssetSourceInfo, w as assertPreparedAssets, x as decodeAssetEntry, C as decodeAssetSourceInfo, E as prepareAssetEntries, T as readmitPreparedAssets };
|
package/dist/assets.js
CHANGED
|
@@ -1,47 +1,67 @@
|
|
|
1
|
-
import { BundleError as e
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
|
|
1
|
+
import { BundleError as e } from "./errors.js";
|
|
2
|
+
import { admitFilesystemPath as t } from "./filesystemAdmission.js";
|
|
3
|
+
import { physicalRequest as n } from "./physicalRequest.js";
|
|
4
|
+
import { assertPreparedAssets as r, prepareAssetEntries as i } from "./assetAdmission.js";
|
|
5
|
+
import { Effect as a, Stream as o } from "effect";
|
|
6
|
+
import { createHash as s } from "node:crypto";
|
|
7
|
+
import { fromNodeReadable as c, getObjectStream as l, putObjectStream as u, toNodeReadable as d } from "@voltro/plugin-storage";
|
|
8
|
+
import { storageAddressIdentity as f } from "@voltro/plugin-storage/errors";
|
|
9
|
+
// src/assets.ts
|
|
10
|
+
var p = (e, t) => ({
|
|
6
11
|
list: t,
|
|
7
|
-
open: (t) => a(e, t)
|
|
8
|
-
}),
|
|
9
|
-
write: (t, n, r) =>
|
|
10
|
-
has: (t) => e.
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
12
|
+
open: (t) => e.resolve(t).pipe(a.flatMap((e) => l(e, t.key)))
|
|
13
|
+
}), m = (e) => ({
|
|
14
|
+
write: (t, n, r) => e.resolve(t).pipe(a.flatMap((e) => u(e, t.key, n, r))),
|
|
15
|
+
has: (t) => e.resolve(t).pipe(a.flatMap((e) => e.head(t.key)), a.map((e) => e !== null)),
|
|
16
|
+
matches: (t) => a.gen(function* () {
|
|
17
|
+
let n = yield* e.resolve(t), r = yield* n.head(t.key);
|
|
18
|
+
if (r === null || r.size !== t.size || r.contentType !== void 0 && r.contentType !== t.contentType) return !1;
|
|
19
|
+
let i = yield* l(n, t.key);
|
|
20
|
+
if (i.contentType !== t.contentType) return !1;
|
|
21
|
+
let a = s("sha256");
|
|
22
|
+
return (yield* o.runFold(i.stream, () => 0, (e, t) => (a.update(t), e + t.byteLength))) === t.size && a.digest("hex") === t.sha256;
|
|
23
|
+
})
|
|
24
|
+
}), h = (r, i) => n(async (e) => {
|
|
25
|
+
let { createWriteStream: n } = await import("node:fs"), a = await import("node:fs/promises"), { pipeline: o, finished: c } = await import("node:stream/promises"), { Transform: l } = await import("node:stream"), u = await import("node:path");
|
|
26
|
+
await t(i, "directory");
|
|
27
|
+
let f = await a.mkdtemp(u.join(i, ".voltro-capture-")), p;
|
|
28
|
+
try {
|
|
29
|
+
let c = u.join(f, "body"), m = s("sha256"), h = 0, g = new l({ transform(e, t, n) {
|
|
30
|
+
m.update(e), h += e.length, n(null, e);
|
|
15
31
|
} });
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
size: f,
|
|
26
|
-
contentType: t.contentType
|
|
32
|
+
p = await d(r.stream), await o(p, g, n(c, {
|
|
33
|
+
flags: "wx",
|
|
34
|
+
mode: 384
|
|
35
|
+
}), { signal: e });
|
|
36
|
+
let _ = m.digest("hex"), v = u.join(i, _);
|
|
37
|
+
return await t(v, "file"), await a.rename(c, v), {
|
|
38
|
+
sha256: _,
|
|
39
|
+
size: h,
|
|
40
|
+
contentType: r.contentType
|
|
27
41
|
};
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
42
|
+
} finally {
|
|
43
|
+
p !== void 0 && (p.destroy(), await c(p, { cleanup: !0 }).catch(() => void 0)), await a.rm(f, {
|
|
44
|
+
recursive: !0,
|
|
45
|
+
force: !0
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
}, () => new e({
|
|
49
|
+
reason: "asset capture failed",
|
|
50
|
+
path: i
|
|
51
|
+
})), g = (e, t, n) => a.scoped(a.gen(function* () {
|
|
52
|
+
yield* _(e, yield* i({
|
|
53
|
+
sink: e,
|
|
54
|
+
assetsDir: t,
|
|
55
|
+
entries: [n]
|
|
56
|
+
}), n);
|
|
57
|
+
})), _ = (t, n, i) => a.gen(function* () {
|
|
58
|
+
yield* r(n, t);
|
|
59
|
+
let o = yield* a.promise(() => import("node:path")), { createReadStream: s } = yield* a.promise(() => import("node:fs"));
|
|
60
|
+
if (!n.entries.some((e) => f(e) === f(i) && e.sha256 === i.sha256 && e.size === i.size && e.contentType === i.contentType)) return yield* a.fail(new e({ reason: "asset is outside the admitted index" }));
|
|
61
|
+
let l = o.join(n.assetsDir, i.sha256), u = c("bundle", () => s(l));
|
|
62
|
+
yield* t.write(i, u, {
|
|
63
|
+
contentType: i.contentType,
|
|
64
|
+
totalSize: i.size
|
|
38
65
|
});
|
|
39
|
-
let p = d.digest("hex");
|
|
40
|
-
if (p !== o.sha256) return yield* n.fail(new t({
|
|
41
|
-
what: `asset ${o.key}`,
|
|
42
|
-
expected: o.sha256,
|
|
43
|
-
actual: p
|
|
44
|
-
}));
|
|
45
66
|
});
|
|
46
|
-
|
|
47
|
-
export { d as restoreAssetFromCas, l as storageAssetSink, c as storageAssetSource, u as writeAssetToCas };
|
|
67
|
+
export { _ as applyAdmittedAsset, g as restoreAssetFromCas, m as storageAssetSink, p as storageAssetSource, h as writeAssetToCas };
|
package/dist/blobStorage.js
CHANGED
|
@@ -1,40 +1,63 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
1
|
+
import { physicalRequest as e } from "./physicalRequest.js";
|
|
2
|
+
import { storageAssetSink as t } from "./assets.js";
|
|
3
|
+
import { assetBundleContext as n, bundleAssetInfoStream as r, storageAssetInfo as i } from "./storageAssetMetadata.js";
|
|
4
|
+
import { Effect as a, Stream as o } from "effect";
|
|
5
|
+
import { streamTable as s } from "@voltro/database";
|
|
6
|
+
import { STORAGE_REFS_TABLE as c, StorageError as l, fromNodeReadable as u, getObjectStream as d, putObjectStream as f, toNodeReadable as p } from "@voltro/plugin-storage";
|
|
7
|
+
import { Readable as m } from "node:stream";
|
|
8
|
+
import { finished as h } from "node:stream/promises";
|
|
9
|
+
// src/blobStorage.ts
|
|
10
|
+
var g = (e, t) => ({
|
|
11
|
+
list: (e) => {
|
|
12
|
+
let n = t(e);
|
|
9
13
|
return { async *[Symbol.asyncIterator]() {
|
|
10
|
-
let
|
|
11
|
-
for (let
|
|
12
|
-
key: e.key,
|
|
13
|
-
contentType: e.contentType,
|
|
14
|
-
size: e.size
|
|
15
|
-
};
|
|
14
|
+
let e = await a.runPromise(o.runCollect(n));
|
|
15
|
+
for (let t of e) yield t;
|
|
16
16
|
} };
|
|
17
17
|
},
|
|
18
18
|
open: (t) => ({ async *[Symbol.asyncIterator]() {
|
|
19
|
-
let
|
|
20
|
-
|
|
19
|
+
let n = await a.runPromise(e.resolve(t)), r = await a.runPromise(n.head(t.key));
|
|
20
|
+
if (r !== null && (r.contentType !== void 0 && r.contentType !== t.contentType || r.size !== t.size)) throw Error("archive blob contradicts source metadata");
|
|
21
|
+
let i = await a.runPromise(d(n, t.key));
|
|
22
|
+
if (r?.contentType !== void 0 && i.contentType !== t.contentType || i.size !== void 0 && i.size !== t.size) throw i.close !== void 0 && await a.runPromise(i.close), Error("archive blob contradicts source metadata");
|
|
23
|
+
let o = await p(i.stream);
|
|
24
|
+
for await (let e of o) yield e instanceof Uint8Array ? e : new Uint8Array(e);
|
|
21
25
|
} })
|
|
22
|
-
}),
|
|
23
|
-
table:
|
|
26
|
+
}), _ = (e, t) => g(e, (e) => e === void 0 ? s(t, {
|
|
27
|
+
table: c,
|
|
24
28
|
chunkSize: 500
|
|
25
|
-
}).pipe(
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
contentType: a.contentType,
|
|
35
|
-
totalSize: a.size
|
|
36
|
-
}));
|
|
29
|
+
}).pipe(o.map(i)) : o.unwrap(n(e).pipe(a.map(r)))), v = (e) => ({
|
|
30
|
+
has: (n, r) => a.runPromise(t(e).has(n), r),
|
|
31
|
+
matches: (n, r) => a.runPromise(t(e).matches(n), r),
|
|
32
|
+
write: async (t, n, r, i) => {
|
|
33
|
+
let o = u("storage", () => m.from(n));
|
|
34
|
+
await a.runPromise(e.resolve(t).pipe(a.flatMap((e) => f(e, t.key, o, {
|
|
35
|
+
contentType: r.contentType,
|
|
36
|
+
totalSize: r.size
|
|
37
|
+
}))), i);
|
|
37
38
|
}
|
|
39
|
+
}), y = (t, n) => e(t, () => new l({
|
|
40
|
+
provider: "archive",
|
|
41
|
+
message: n,
|
|
42
|
+
transient: !1
|
|
43
|
+
})), b = (e) => ({
|
|
44
|
+
has: (t) => y((n) => e.has(t, { signal: n }), "asset destination admission failed"),
|
|
45
|
+
matches: (t) => y((n) => e.matches(t, { signal: n }), "asset destination content verification failed"),
|
|
46
|
+
write: (t, n, r) => y(async (i) => {
|
|
47
|
+
if (r.totalSize === void 0) throw Error("admitted asset size is required");
|
|
48
|
+
let a = await p(n), o = () => {
|
|
49
|
+
a.destroy();
|
|
50
|
+
};
|
|
51
|
+
i.addEventListener("abort", o, { once: !0 });
|
|
52
|
+
try {
|
|
53
|
+
if (i.aborted) throw o(), Error("asset write interrupted");
|
|
54
|
+
await e.write(t, a, {
|
|
55
|
+
contentType: r.contentType,
|
|
56
|
+
size: r.totalSize
|
|
57
|
+
}, { signal: i });
|
|
58
|
+
} finally {
|
|
59
|
+
i.removeEventListener("abort", o), a.destroy(), await h(a, { cleanup: !0 }).catch(() => void 0);
|
|
60
|
+
}
|
|
61
|
+
}, "admitted asset write failed")
|
|
38
62
|
});
|
|
39
|
-
|
|
40
|
-
export { d as storageBlobSink, l as storageBlobSource, u as storageRefsBlobSource };
|
|
63
|
+
export { b as blobAssetSink, v as storageBlobSink, g as storageBlobSource, _ as storageRefsBlobSource };
|