@voltro/plugin-storage 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/README.md +27 -0
- package/THIRD-PARTY-NOTICES.md +2503 -690
- package/dist/access.js +26 -27
- package/dist/assetRef.js +1 -2
- package/dist/avatar.js +1 -2
- package/dist/byteSecurity.d.ts +3 -0
- package/dist/byteSecurity.js +6 -0
- package/dist/connection.js +98 -0
- package/dist/constraints.js +1 -2
- package/dist/custody.js +131 -0
- package/dist/derivatives.js +1 -2
- package/dist/env.js +8 -3
- package/dist/grant.js +90 -71
- package/dist/index.d.ts +453 -215
- package/dist/index.js +709 -537
- package/dist/ingest.js +7 -2
- package/dist/ingestPolicy.js +1 -1
- package/dist/metadataError.js +8 -9
- package/dist/objectAbandon.js +15 -0
- package/dist/objectLifecycle.js +135 -102
- package/dist/objectMetadata.js +253 -96
- package/dist/objectWriter.js +51 -23
- package/dist/pathDurability.js +1 -2
- package/dist/physicalReferences.js +53 -0
- package/dist/providers.js +451 -307
- package/dist/referenceCatalogue.js +1 -2
- package/dist/renditionProof.js +81 -0
- package/dist/retainedCapture.js +390 -0
- package/dist/retainedObjects.js +189 -0
- package/dist/rpc.d.ts +1 -15
- package/dist/rpc.js +1 -2
- package/dist/scanners.js +1 -2
- package/dist/server.d.ts +153 -0
- package/dist/server.js +4 -0
- package/dist/service.js +879 -546
- package/dist/sourceIdentity.js +13 -0
- package/dist/sourcePin.js +34 -0
- package/dist/storageNamespaces.js +52 -29
- package/dist/storageNumbers.js +1 -2
- package/dist/storageObjectNamespaces.js +170 -122
- package/dist/storageReferenceInstances.js +1 -2
- package/dist/storageRequest.js +9 -0
- package/dist/storageRouting.js +45 -0
- package/dist/streamBridge.js +5 -3
- package/dist/table.js +2 -2
- package/dist/transcodeVideo.js +85 -48
- package/dist/transform.js +30 -27
- package/dist/transformCache.js +1 -2
- package/dist/types.d.ts +115 -137
- package/dist/types.js +15 -16
- package/package.json +22 -11
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { createHash as e } from "node:crypto";
|
|
2
|
+
import { canonicalJson as t } from "@voltro/protocol";
|
|
3
|
+
// src/sourceIdentity.ts
|
|
4
|
+
var n = (n) => e("sha256").update(t({
|
|
5
|
+
id: n.id,
|
|
6
|
+
tenantId: n.tenantId,
|
|
7
|
+
bucket: n.bucket,
|
|
8
|
+
key: n.key,
|
|
9
|
+
contentType: n.contentType,
|
|
10
|
+
size: n.size,
|
|
11
|
+
checksum: n.checksum
|
|
12
|
+
})).digest("hex");
|
|
13
|
+
export { n as retainedSourceDigest };
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { StorageError as e } from "./types.js";
|
|
2
|
+
import { retainedSourceDigest as t } from "./sourceIdentity.js";
|
|
3
|
+
import { ownRenditionRef as n } from "./renditionProof.js";
|
|
4
|
+
import { createHash as r } from "node:crypto";
|
|
5
|
+
import { canonicalJson as i } from "@voltro/protocol";
|
|
6
|
+
// src/sourcePin.ts
|
|
7
|
+
var a = (e) => r("sha256").update(i(e)).digest("hex"), o = (e, t) => typeof e == "string" && e.length > 0 && e.length <= t, s = (e, t) => e == null || typeof e == "string" && e.length <= t, c = (r, i) => {
|
|
8
|
+
let c = n(r);
|
|
9
|
+
if (!o(i, 256) || !o(c.id, 64) || !o(c.bucket, 128) || c.tenantId !== null && !o(c.tenantId, 64) || !o(c.checksum, 512) || !o(c.contentType, 512) || !Number.isSafeInteger(c.size) || c.size < 0 || !s(c.derivedFrom, 64) || !s(c.kind, 512)) throw new e({
|
|
10
|
+
provider: "custody",
|
|
11
|
+
message: "Invalid custody source metadata",
|
|
12
|
+
status: 409,
|
|
13
|
+
transient: !1
|
|
14
|
+
});
|
|
15
|
+
let l = {
|
|
16
|
+
version: 1,
|
|
17
|
+
instance: i,
|
|
18
|
+
tenantId: c.tenantId,
|
|
19
|
+
bucket: c.bucket,
|
|
20
|
+
id: c.id,
|
|
21
|
+
sourceDigest: t(c),
|
|
22
|
+
checksum: c.checksum,
|
|
23
|
+
size: c.size,
|
|
24
|
+
contentType: c.contentType,
|
|
25
|
+
derivedFrom: c.derivedFrom ?? null,
|
|
26
|
+
kind: c.kind ?? null,
|
|
27
|
+
renditionProof: c.renditionProof ?? null
|
|
28
|
+
};
|
|
29
|
+
return {
|
|
30
|
+
...l,
|
|
31
|
+
digest: a(l)
|
|
32
|
+
};
|
|
33
|
+
};
|
|
34
|
+
export { c as pinStorageSource };
|
|
@@ -1,56 +1,79 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
1
|
+
import { StorageError as e } from "@voltro/kv/storage";
|
|
2
|
+
import { Effect as t } from "effect";
|
|
3
|
+
import { createHash as n, randomUUID as r } from "node:crypto";
|
|
4
|
+
import { authoredError as i } from "@voltro/database";
|
|
5
|
+
import { linkSync as a, mkdirSync as o, readFileSync as s, realpathSync as c, rmSync as l, writeFileSync as u } from "node:fs";
|
|
6
|
+
import { basename as d, dirname as f, join as p, resolve as m } from "node:path";
|
|
7
|
+
// src/storageNamespaces.ts
|
|
8
|
+
var h = (e) => n("sha256").update(JSON.stringify(e)).digest("hex"), g = (n, r) => ("resolveNamespace" in n ? n.resolveNamespace(r) : t.succeed(n.objectNamespace)).pipe(t.flatMap((r) => t.try({
|
|
9
|
+
try: () => {
|
|
10
|
+
let e = {
|
|
11
|
+
storageInstance: n.storageInstance,
|
|
12
|
+
objectNamespace: r
|
|
13
|
+
};
|
|
14
|
+
return _(e), e;
|
|
15
|
+
},
|
|
16
|
+
catch: () => new e({
|
|
17
|
+
provider: "metadata",
|
|
18
|
+
message: "Storage reference scope is invalid",
|
|
19
|
+
transient: !1
|
|
20
|
+
})
|
|
21
|
+
}))), _ = (e) => {
|
|
22
|
+
if (!e?.storageInstance?.trim() || !/^[a-f0-9]{64}$/.test(e.objectNamespace)) throw i("Storage requires a configured instance and a stable physical objectNamespace SHA-256 identity");
|
|
23
|
+
}, v = (e) => {
|
|
24
|
+
let t = m(e), n = [];
|
|
10
25
|
for (;;) try {
|
|
11
|
-
return
|
|
26
|
+
return p(c(t), ...n.reverse());
|
|
12
27
|
} catch (e) {
|
|
13
28
|
if (!(e instanceof Error && "code" in e && e.code === "ENOENT")) throw e;
|
|
14
|
-
let r =
|
|
29
|
+
let r = f(t);
|
|
15
30
|
if (r === t) throw e;
|
|
16
|
-
n.push(
|
|
31
|
+
n.push(d(t)), t = r;
|
|
17
32
|
}
|
|
18
|
-
},
|
|
33
|
+
}, y = (e) => {
|
|
19
34
|
let t = new URL(e);
|
|
20
35
|
return t.username = "", t.password = "", t.search = "", t.hash = "", t.href.replace(/\/+$/, "");
|
|
21
|
-
},
|
|
22
|
-
|
|
23
|
-
let
|
|
36
|
+
}, b = ".voltro-object-namespace", x = (e) => {
|
|
37
|
+
o(e, { recursive: !0 });
|
|
38
|
+
let t = p(e, b), n;
|
|
24
39
|
try {
|
|
25
|
-
|
|
40
|
+
n = s(t, "utf8");
|
|
26
41
|
} catch (e) {
|
|
27
42
|
if (!(e instanceof Error && "code" in e && e.code === "ENOENT")) throw e;
|
|
28
|
-
let
|
|
43
|
+
let i = h(["filesystem-volume", r()]), o = `${t}-${r()}`;
|
|
29
44
|
try {
|
|
30
|
-
|
|
45
|
+
u(o, i, {
|
|
31
46
|
flag: "wx",
|
|
32
47
|
mode: 384
|
|
33
48
|
});
|
|
34
49
|
try {
|
|
35
|
-
|
|
50
|
+
a(o, t);
|
|
36
51
|
} catch (e) {
|
|
37
52
|
if (!(e instanceof Error && "code" in e && e.code === "EEXIST")) throw e;
|
|
38
53
|
}
|
|
39
|
-
|
|
54
|
+
n = s(t, "utf8");
|
|
40
55
|
} finally {
|
|
41
|
-
|
|
56
|
+
l(o, { force: !0 });
|
|
42
57
|
}
|
|
43
58
|
}
|
|
44
|
-
if (!/^[a-f0-9]{64}$/.test(
|
|
45
|
-
return
|
|
46
|
-
},
|
|
47
|
-
|
|
48
|
-
|
|
59
|
+
if (!/^[a-f0-9]{64}$/.test(n)) throw i("Filesystem storage object namespace marker is invalid; restore the volume marker before serving storage");
|
|
60
|
+
return n;
|
|
61
|
+
}, S = (e) => {
|
|
62
|
+
let t;
|
|
63
|
+
try {
|
|
64
|
+
t = s(p(e, b), "utf8");
|
|
65
|
+
} catch (t) {
|
|
66
|
+
throw t instanceof Error && "code" in t && t.code === "ENOENT" ? i(`Filesystem storage volume at ${e} carries no ${b} marker; mount the volume the serving replicas use before assigning namespaces`) : t;
|
|
67
|
+
}
|
|
68
|
+
if (!/^[a-f0-9]{64}$/.test(t)) throw i("Filesystem storage object namespace marker is invalid; restore the volume marker before serving storage");
|
|
69
|
+
return t;
|
|
70
|
+
}, C = (e) => {
|
|
71
|
+
if (_(e), typeof e.catalogueId != "string" || !e.catalogueId.trim()) throw i("Storage upload tickets require an actual reference catalogue identity");
|
|
72
|
+
return h([
|
|
49
73
|
"upload-ticket-destination",
|
|
50
74
|
e.storageInstance,
|
|
51
75
|
e.catalogueId,
|
|
52
76
|
e.objectNamespace
|
|
53
77
|
]);
|
|
54
78
|
};
|
|
55
|
-
|
|
56
|
-
export { _ as FILESYSTEM_NAMESPACE_FILE, h as canonicalStorageRoot, v as filesystemObjectNamespace, m as requireStorageReferenceScope, g as storageEndpointIdentity, p as storageObjectNamespace, y as storageUploadTicketScope };
|
|
79
|
+
export { b as FILESYSTEM_NAMESPACE_FILE, v as canonicalStorageRoot, S as existingFilesystemObjectNamespace, x as filesystemObjectNamespace, _ as requireStorageReferenceScope, y as storageEndpointIdentity, h as storageObjectNamespace, g as storageReferenceScopeFor, C as storageUploadTicketScope };
|
package/dist/storageNumbers.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { StorageError as e } from "./types.js";
|
|
2
|
-
|
|
2
|
+
// src/storageNumbers.ts
|
|
3
3
|
var t = (t, n) => {
|
|
4
4
|
let r = typeof t == "number" ? t : typeof t == "bigint" || typeof t == "string" && /^\d+$/.test(t) ? Number(t) : NaN;
|
|
5
5
|
if (!Number.isSafeInteger(r) || r < 0) throw new e({
|
|
@@ -9,5 +9,4 @@ var t = (t, n) => {
|
|
|
9
9
|
});
|
|
10
10
|
return r;
|
|
11
11
|
}, n = (e, n, r) => t(e + n, r);
|
|
12
|
-
//#endregion
|
|
13
12
|
export { t as storageInteger, n as storageIntegerSum };
|
|
@@ -2,37 +2,37 @@ import { requireStorageReferenceScope as e } from "./storageNamespaces.js";
|
|
|
2
2
|
import { STORAGE_GRANTS_TABLE as t, STORAGE_REFS_TABLE as n } from "./table.js";
|
|
3
3
|
import { storageInteger as r, storageIntegerSum as i } from "./storageNumbers.js";
|
|
4
4
|
import { storageObjectClaimId as a, storageObjectIdentifiers as o } from "./objectLifecycle.js";
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
|
|
9
|
-
var
|
|
5
|
+
import { Schema as s } from "effect";
|
|
6
|
+
import { createHash as c } from "node:crypto";
|
|
7
|
+
import { authoredError as l, inSet as u, isNull as d, or as f } from "@voltro/database";
|
|
8
|
+
// src/storageObjectNamespaces.ts
|
|
9
|
+
var p = "_voltro_storage_put_intents", m = "_voltro_storage_operations", h = "_voltro_storage_object_heads", g = "_voltro_storage_object_claims", _ = [
|
|
10
10
|
n,
|
|
11
11
|
t,
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
],
|
|
15
|
-
tenantId:
|
|
16
|
-
bucket:
|
|
17
|
-
operationId:
|
|
18
|
-
fingerprint:
|
|
19
|
-
checksum:
|
|
20
|
-
logicalKey:
|
|
21
|
-
}),
|
|
22
|
-
id:
|
|
23
|
-
objectId:
|
|
24
|
-
fingerprint:
|
|
25
|
-
generation:
|
|
26
|
-
key:
|
|
27
|
-
refId:
|
|
28
|
-
state:
|
|
12
|
+
p,
|
|
13
|
+
m
|
|
14
|
+
], v = s.Struct({
|
|
15
|
+
tenantId: s.NullOr(s.String),
|
|
16
|
+
bucket: s.String,
|
|
17
|
+
operationId: s.String,
|
|
18
|
+
fingerprint: s.String,
|
|
19
|
+
checksum: s.String,
|
|
20
|
+
logicalKey: s.String
|
|
21
|
+
}), y = s.Struct({
|
|
22
|
+
id: s.String,
|
|
23
|
+
objectId: s.String,
|
|
24
|
+
fingerprint: s.String,
|
|
25
|
+
generation: s.String,
|
|
26
|
+
key: s.String,
|
|
27
|
+
refId: s.String,
|
|
28
|
+
state: s.Literals([
|
|
29
29
|
"reserved",
|
|
30
30
|
"ready",
|
|
31
31
|
"deleting",
|
|
32
32
|
"deleted"
|
|
33
33
|
]),
|
|
34
|
-
deleteKey:
|
|
35
|
-
}),
|
|
34
|
+
deleteKey: s.NullOr(s.String)
|
|
35
|
+
}), b = (e) => c("sha256").update(JSON.stringify(e)).digest("hex"), x = (e) => JSON.stringify([e.storageInstance, e.objectNamespace]), S = (e, t) => JSON.stringify([e.objectNamespace, t]), C = (e, t) => e.query({
|
|
36
36
|
table: t,
|
|
37
37
|
predicate: void 0,
|
|
38
38
|
lock: "update",
|
|
@@ -40,78 +40,108 @@ var f = "_voltro_storage_put_intents", p = "_voltro_storage_operations", m = "_v
|
|
|
40
40
|
take: void 0,
|
|
41
41
|
skip: void 0,
|
|
42
42
|
projection: void 0
|
|
43
|
-
}),
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
43
|
+
}), w = 500, T = (e) => {
|
|
44
|
+
let t = [];
|
|
45
|
+
for (let n = 0; n < e.length; n += w) t.push(e.slice(n, n + w));
|
|
46
|
+
return t;
|
|
47
|
+
}, E = async (e) => {
|
|
48
|
+
let t = [];
|
|
49
|
+
for (let n of [..._, h]) {
|
|
50
|
+
let r = n === h ? d("objectNamespace") : f(d("storageInstance"), d("objectNamespace")), [i] = await e.query({
|
|
51
|
+
table: n,
|
|
52
|
+
predicate: r,
|
|
53
|
+
order: [],
|
|
54
|
+
take: void 0,
|
|
55
|
+
skip: void 0,
|
|
56
|
+
projection: void 0,
|
|
57
|
+
aggregations: [{
|
|
58
|
+
op: "count",
|
|
59
|
+
alias: "unassigned"
|
|
60
|
+
}]
|
|
61
|
+
}), a = Number(i?.unassigned ?? 0);
|
|
62
|
+
a > 0 && t.push(`${n}: ${a}`);
|
|
61
63
|
}
|
|
62
|
-
|
|
64
|
+
if (t.length > 0) throw l(`Storage physical namespace migration required: assign references and retained operations to their configured storageInstance and provider objectNamespace before starting the app (unassigned rows — ${t.join(", ")}). Rows written after an assignment already ran — by a replica of the previous version — need the assignment again: a recorded file migration does not re-run, so repeat the idempotent assignment over every reference in a new migration.`);
|
|
65
|
+
}, D = async (e, t, n) => k(e, t, n), O = async (t, n, r) => {
|
|
66
|
+
let i = /* @__PURE__ */ new Map();
|
|
67
|
+
for (let t of r) {
|
|
68
|
+
if (e(t.from), t.from.storageInstance !== t.storageInstance) throw l("Storage snapshot relocation must preserve the configured plugin instance");
|
|
69
|
+
let n = i.get(t.refId);
|
|
70
|
+
if (n && x(n) !== x(t.from)) throw l("Storage snapshot source scope is ambiguous");
|
|
71
|
+
i.set(t.refId, t.from);
|
|
72
|
+
}
|
|
73
|
+
return k(t, n, r.map(({ from: e, ...t }) => t), i);
|
|
74
|
+
}, k = async (c, d, f, _) => {
|
|
75
|
+
for (let t of d) e(t);
|
|
76
|
+
if (!d.length || new Set(d.map(x)).size !== d.length) throw l("Provide distinct configured storage instance and physical namespace pairs");
|
|
77
|
+
let w = new Set(d.map(x)), D = /* @__PURE__ */ new Map();
|
|
78
|
+
for (let { refId: t, ...n } of f) {
|
|
79
|
+
if (e(n), !t.trim() || !w.has(x(n))) throw l("Storage namespace assignment must name a reference and a configured physical scope");
|
|
80
|
+
let r = D.get(t);
|
|
81
|
+
if (r && x(r) !== x(n)) throw l("Storage physical namespace assignment is ambiguous");
|
|
82
|
+
D.set(t, n);
|
|
83
|
+
}
|
|
84
|
+
let O = [];
|
|
63
85
|
for (let e of [
|
|
64
86
|
n,
|
|
65
87
|
t,
|
|
66
|
-
f,
|
|
67
88
|
p,
|
|
68
89
|
m,
|
|
69
|
-
h
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
90
|
+
h,
|
|
91
|
+
g
|
|
92
|
+
]) O.push(await C(c, e));
|
|
93
|
+
let [k, A, j, M, N, P] = O, F = /* @__PURE__ */ new Set(), I = (e, t) => {
|
|
94
|
+
let n = D.get(e);
|
|
95
|
+
if (!n) throw l("Storage physical namespace assignment is incomplete");
|
|
96
|
+
if (_ !== void 0) {
|
|
97
|
+
let r = _.get(e);
|
|
98
|
+
if (r === void 0 || ![r, n].some((e) => t.storageInstance === e.storageInstance && t.objectNamespace === e.objectNamespace)) throw l("Storage snapshot metadata does not match its declared source or restored target scope");
|
|
99
|
+
} else for (let e of ["storageInstance", "objectNamespace"]) if (t[e] != null && t[e] !== n[e]) throw l("Storage metadata already belongs to another physical scope; assignment does not move objects");
|
|
100
|
+
return F.add(e), n;
|
|
76
101
|
};
|
|
77
|
-
for (let e of
|
|
78
|
-
|
|
79
|
-
let
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
102
|
+
for (let e of k) I(String(e.id), e);
|
|
103
|
+
let L = new Map(k.map((e) => [e.id, e]));
|
|
104
|
+
for (let e of A) if (I(String(e.refId), e), !L.has(e.refId)) throw l("Storage grant has no readable reference");
|
|
105
|
+
let R = /* @__PURE__ */ new Map();
|
|
106
|
+
for (let e of j) {
|
|
107
|
+
if (I(String(e.refId), e), R.has(String(e.id))) throw l("Storage put intent ownership is ambiguous");
|
|
108
|
+
R.set(String(e.id), e);
|
|
83
109
|
}
|
|
84
|
-
let
|
|
85
|
-
let t =
|
|
86
|
-
if (!a || a.refId !== t.refId) throw
|
|
87
|
-
let
|
|
88
|
-
...
|
|
110
|
+
let z = /* @__PURE__ */ new Map(), B = M.map((e) => {
|
|
111
|
+
let t = s.decodeUnknownSync(y)(e), n = I(t.refId, e), a = R.get(t.id);
|
|
112
|
+
if (!a || a.refId !== t.refId) throw l("Storage operation lost its retained put intent");
|
|
113
|
+
let c = {
|
|
114
|
+
...s.decodeUnknownSync(v)(a.identity),
|
|
89
115
|
...n
|
|
90
116
|
};
|
|
91
|
-
typeof a.identity == "object" && a.identity !== null &&
|
|
92
|
-
let
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
]), f =
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
])
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
117
|
+
typeof a.identity == "object" && a.identity !== null && I(t.refId, a.identity);
|
|
118
|
+
let u = o(c), d = b([
|
|
119
|
+
c.bucket,
|
|
120
|
+
c.tenantId,
|
|
121
|
+
c.operationId
|
|
122
|
+
]), f = b([
|
|
123
|
+
c.bucket,
|
|
124
|
+
c.tenantId,
|
|
125
|
+
c.logicalKey,
|
|
126
|
+
c.checksum
|
|
127
|
+
]), p = _ === void 0 ? void 0 : o({
|
|
128
|
+
...c,
|
|
129
|
+
storageInstance: String(e.storageInstance),
|
|
130
|
+
objectNamespace: String(e.objectNamespace)
|
|
131
|
+
});
|
|
132
|
+
if (!(p === void 0 ? [d, u.id].includes(t.id) && [f, u.objectId].includes(t.objectId) : t.id === p.id && t.objectId === p.objectId) || t.fingerprint !== c.fingerprint) throw l("Storage operation identity does not match its retained intent");
|
|
133
|
+
if (typeof a.ref != "object" || a.ref === null || Array.isArray(a.ref)) throw l("Storage put intent reference is unreadable");
|
|
134
|
+
let m = a.ref;
|
|
135
|
+
if (m.id !== t.refId || m.key !== t.key || m.checksum !== c.checksum || m.tenantId !== c.tenantId || m.bucket !== c.bucket) throw l("Storage operation reference does not match its retained intent");
|
|
136
|
+
let h = L.get(t.refId);
|
|
107
137
|
if (t.state === "ready") {
|
|
108
|
-
if (!
|
|
109
|
-
} else if (
|
|
138
|
+
if (!h || h.key !== t.key || h.checksum !== c.checksum) throw l("Ready storage operation lost its readable reference");
|
|
139
|
+
} else if (h) throw l("Unreadable storage operation still owns a readable reference");
|
|
110
140
|
if (t.state === "ready" || t.state === "reserved") {
|
|
111
|
-
let e =
|
|
112
|
-
if (e && (e.generation !== t.generation || e.key !== t.key)) throw
|
|
113
|
-
|
|
114
|
-
id:
|
|
141
|
+
let e = z.get(u.objectId);
|
|
142
|
+
if (e && (e.generation !== t.generation || e.key !== t.key)) throw l("Storage physical namespace has conflicting active generations");
|
|
143
|
+
z.set(u.objectId, {
|
|
144
|
+
id: u.objectId,
|
|
115
145
|
objectNamespace: n.objectNamespace,
|
|
116
146
|
generation: t.generation,
|
|
117
147
|
key: t.key,
|
|
@@ -120,75 +150,93 @@ var f = "_voltro_storage_put_intents", p = "_voltro_storage_operations", m = "_v
|
|
|
120
150
|
}
|
|
121
151
|
return {
|
|
122
152
|
previous: t,
|
|
153
|
+
previousNamespace: e.objectNamespace,
|
|
123
154
|
row: {
|
|
124
155
|
...t,
|
|
125
156
|
...n,
|
|
126
|
-
id:
|
|
127
|
-
objectId:
|
|
157
|
+
id: u.id,
|
|
158
|
+
objectId: u.objectId
|
|
128
159
|
},
|
|
129
160
|
intent: a,
|
|
130
|
-
identity:
|
|
161
|
+
identity: c
|
|
131
162
|
};
|
|
132
163
|
});
|
|
133
|
-
if (
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
164
|
+
if (B.length !== j.length || new Set(B.map((e) => e.row.id)).size !== B.length) throw l("Storage operation namespace migration has unmatched or conflicting identities");
|
|
165
|
+
let V = /* @__PURE__ */ new Map();
|
|
166
|
+
for (let e of B) (e.previous.state === "ready" || e.previous.state === "reserved") && V.set(e.previous.objectId, [...V.get(e.previous.objectId) ?? [], e]);
|
|
167
|
+
for (let e of N) {
|
|
168
|
+
let t = V.get(String(e.id)) ?? [];
|
|
169
|
+
if (!t.length || t.length !== r(e.reservations, "shared-object reservation count") || t.some(({ previous: t, previousNamespace: n, identity: r }) => t.generation !== e.generation || t.key !== e.key || e.objectNamespace != null && e.objectNamespace !== (_ === void 0 ? r.objectNamespace : n))) throw l("Storage object head does not match its active reservations");
|
|
137
170
|
}
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
171
|
+
let H = new Set(N.map((e) => e.id));
|
|
172
|
+
for (let { previous: e } of B) if ((e.state === "ready" || e.state === "reserved") && !H.has(e.objectId)) throw l("Storage operation lost its active object head");
|
|
173
|
+
if ([...D.keys()].some((e) => !F.has(e))) throw l("Storage namespace assignment target does not exist");
|
|
174
|
+
let U = new Map(B.map((e) => [e.previous.id, e])), W = P.map((e) => {
|
|
175
|
+
let t = U.get(String(e.operationId));
|
|
176
|
+
if (!t || typeof e.claim != "string" || !e.claim || e.id !== a(String(e.operationId), e.claim)) throw l("Storage operation claim does not match its retained operation");
|
|
143
177
|
return {
|
|
144
178
|
...e,
|
|
145
179
|
id: a(t.row.id, e.claim),
|
|
146
180
|
operationId: t.row.id
|
|
147
181
|
};
|
|
148
|
-
}),
|
|
149
|
-
for (let e of
|
|
150
|
-
let t =
|
|
151
|
-
(e.row.state === "deleting" || e.row.state === "deleted") && (t ? e.row.deleteKey = null : e.row.state === "deleted" && e.row.deleteKey === null && (e.row.state = "deleting", e.row.deleteKey = e.row.key), e.row.state === "deleting" && e.row.deleteKey !== null &&
|
|
182
|
+
}), G = /* @__PURE__ */ new Set([...k.map((e) => S(D.get(String(e.id)), String(e.key))), ...[...z.values()].map((e) => JSON.stringify([e.objectNamespace, e.key]))]), K = [];
|
|
183
|
+
for (let e of B) {
|
|
184
|
+
let t = G.has(S(e.identity, e.row.key));
|
|
185
|
+
(e.row.state === "deleting" || e.row.state === "deleted") && (t ? e.row.deleteKey = null : e.row.state === "deleted" && e.row.deleteKey === null && (e.row.state = "deleting", e.row.deleteKey = e.row.key), e.row.state === "deleting" && e.row.deleteKey !== null && K.push({
|
|
152
186
|
refId: e.row.refId,
|
|
153
187
|
storageInstance: e.identity.storageInstance,
|
|
154
188
|
objectNamespace: e.identity.objectNamespace
|
|
155
189
|
}));
|
|
156
190
|
}
|
|
157
|
-
let
|
|
191
|
+
let q = 0;
|
|
158
192
|
for (let [e, r, i] of [[
|
|
159
193
|
n,
|
|
160
|
-
|
|
194
|
+
k,
|
|
161
195
|
"id"
|
|
162
196
|
], [
|
|
163
197
|
t,
|
|
164
|
-
|
|
198
|
+
A,
|
|
165
199
|
"refId"
|
|
166
|
-
]])
|
|
167
|
-
let
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
200
|
+
]]) {
|
|
201
|
+
let t = /* @__PURE__ */ new Map();
|
|
202
|
+
for (let e of r) {
|
|
203
|
+
let n = D.get(String(e[i]));
|
|
204
|
+
if (e.storageInstance === n.storageInstance && e.objectNamespace === n.objectNamespace) continue;
|
|
205
|
+
let r = t.get(x(n)) ?? {
|
|
206
|
+
scope: n,
|
|
207
|
+
ids: []
|
|
208
|
+
};
|
|
209
|
+
r.ids.push(String(e.id)), t.set(x(n), r);
|
|
210
|
+
}
|
|
211
|
+
for (let { scope: n, ids: r } of t.values()) for (let t of T(r)) {
|
|
212
|
+
let r = await c.updateMany(e, {
|
|
213
|
+
storageInstance: n.storageInstance,
|
|
214
|
+
objectNamespace: n.objectNamespace
|
|
215
|
+
}, { where: u("id", t) });
|
|
216
|
+
if (r !== t.length) throw l("Storage physical namespace assignment lost its metadata row");
|
|
217
|
+
q += r;
|
|
171
218
|
}
|
|
172
219
|
}
|
|
173
220
|
for (let [e, t] of [
|
|
174
|
-
[
|
|
175
|
-
[
|
|
176
|
-
[
|
|
177
|
-
[
|
|
178
|
-
]) for (let n of t) await
|
|
179
|
-
|
|
180
|
-
|
|
221
|
+
[g, P],
|
|
222
|
+
[p, j],
|
|
223
|
+
[m, M],
|
|
224
|
+
[h, N]
|
|
225
|
+
]) for (let n of T(t.map((e) => String(e.id)))) if (await c.deleteMany(e, { where: u("id", n) }) !== n.length) throw l("Storage physical namespace assignment lost a retained row");
|
|
226
|
+
let J = async (e, t) => {
|
|
227
|
+
for (let n of T(t)) await c.insertMany(e, n, { returning: "none" });
|
|
228
|
+
};
|
|
229
|
+
await J(h, [...z.values()]), await J(m, B.map((e) => e.row)), await J(p, B.map((e) => ({
|
|
181
230
|
...e.intent,
|
|
182
231
|
id: e.row.id,
|
|
183
232
|
storageInstance: e.identity.storageInstance,
|
|
184
233
|
objectNamespace: e.identity.objectNamespace,
|
|
185
234
|
identity: e.identity
|
|
186
|
-
})
|
|
187
|
-
for (let e of
|
|
188
|
-
return await
|
|
189
|
-
assigned:
|
|
190
|
-
pendingDeletes:
|
|
235
|
+
})));
|
|
236
|
+
for (let e of B) (e.previous.id !== e.row.id || e.intent.objectNamespace !== e.identity.objectNamespace || e.previous.state !== e.row.state || e.previous.deleteKey !== e.row.deleteKey) && q++;
|
|
237
|
+
return await J(g, W), await E(c), {
|
|
238
|
+
assigned: q,
|
|
239
|
+
pendingDeletes: K
|
|
191
240
|
};
|
|
192
241
|
};
|
|
193
|
-
|
|
194
|
-
export { w as assignStorageObjectNamespacesInTransaction, C as requireStorageObjectNamespaces };
|
|
242
|
+
export { D as assignStorageObjectNamespacesInTransaction, O as relocateRestoredStorageObjectNamespacesInTransaction, E as requireStorageObjectNamespaces };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { STORAGE_GRANTS_TABLE as e, STORAGE_REFS_TABLE as t } from "./table.js";
|
|
2
2
|
import { authoredError as n, eq as r, isNull as i } from "@voltro/database";
|
|
3
|
-
|
|
3
|
+
// src/storageReferenceInstances.ts
|
|
4
4
|
var a = "@voltro/plugin-storage", o = [
|
|
5
5
|
t,
|
|
6
6
|
e,
|
|
@@ -48,5 +48,4 @@ var a = "@voltro/plugin-storage", o = [
|
|
|
48
48
|
}
|
|
49
49
|
return { assigned: l };
|
|
50
50
|
};
|
|
51
|
-
//#endregion
|
|
52
51
|
export { a as DEFAULT_STORAGE_INSTANCE, c as assignStorageReferenceInstancesInTransaction, s as requireStorageReferenceOwnership };
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { Effect as e } from "effect";
|
|
2
|
+
// src/storageRequest.ts
|
|
3
|
+
var t = (t, n, r) => e.callback((i) => {
|
|
4
|
+
let a = new AbortController(), o = Promise.resolve().then(() => t(a.signal));
|
|
5
|
+
return o.then((t) => i(e.succeed(t)), (t) => i(e.fail(n(t)))), e.sync(() => {
|
|
6
|
+
a.abort();
|
|
7
|
+
}).pipe(e.andThen(e.promise(() => o.then((e) => ({ value: e }), () => void 0))), e.flatMap((t) => t !== void 0 && r !== void 0 ? r(t.value) : e.void));
|
|
8
|
+
});
|
|
9
|
+
export { t as storageRequest };
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { StorageAddress as e, StorageError as t } from "@voltro/kv/storage";
|
|
2
|
+
import { Effect as n, Schema as r } from "effect";
|
|
3
|
+
// src/storageRouting.ts
|
|
4
|
+
var i = () => new t({
|
|
5
|
+
provider: "storage",
|
|
6
|
+
message: "Storage destination is unknown, ambiguous or unavailable for this tenant",
|
|
7
|
+
transient: !1
|
|
8
|
+
}), a = (e, t, r) => n.suspend(() => {
|
|
9
|
+
if (e === void 0 || !t.startsWith("storage:")) return n.fail(i());
|
|
10
|
+
let a = t;
|
|
11
|
+
return e.validate(a).pipe(n.mapError(() => i()), n.flatMap((t) => t.tenantScoped && r === null ? n.fail(i()) : e.storage(a, r === null ? void 0 : { tenantId: r }).pipe(n.mapError(() => i()))));
|
|
12
|
+
}), o = (t) => {
|
|
13
|
+
let o = (e, r) => e.startsWith("storage:") ? a(t.registry(), e, r) : e === t.directDestination ? n.try({
|
|
14
|
+
try: t.directProvider,
|
|
15
|
+
catch: () => i()
|
|
16
|
+
}) : n.fail(i());
|
|
17
|
+
return {
|
|
18
|
+
select: (a) => n.suspend(() => {
|
|
19
|
+
let s = t.selected();
|
|
20
|
+
return r.decodeUnknownEffect(e)({
|
|
21
|
+
destination: s,
|
|
22
|
+
tenantId: a,
|
|
23
|
+
key: "selection"
|
|
24
|
+
}).pipe(n.mapError(() => i()), n.flatMap((e) => o(e.destination, e.tenantId)), n.map((e) => ({
|
|
25
|
+
destination: s,
|
|
26
|
+
provider: e
|
|
27
|
+
})));
|
|
28
|
+
}),
|
|
29
|
+
resolve: (t) => r.decodeUnknownEffect(e)(t).pipe(n.mapError(() => i()), n.flatMap((e) => o(e.destination, e.tenantId)))
|
|
30
|
+
};
|
|
31
|
+
}, s = (t) => {
|
|
32
|
+
let o = t.flatMap((e) => e.capabilities?.storageDestinations === void 0 ? [] : [e.capabilities.storageDestinations]);
|
|
33
|
+
return {
|
|
34
|
+
select: (e) => o.length === 1 ? o[0].router.select(e) : n.fail(i()),
|
|
35
|
+
resolve: (t) => r.decodeUnknownEffect(e)(t).pipe(n.mapError(() => i()), n.flatMap((e) => {
|
|
36
|
+
if (e.destination.startsWith("storage:")) {
|
|
37
|
+
let t = new Set(o.map((e) => e.registry()).filter((e) => e !== void 0));
|
|
38
|
+
return t.size === 1 ? a([...t][0], e.destination, e.tenantId) : n.fail(i());
|
|
39
|
+
}
|
|
40
|
+
let t = o.filter((t) => t.directDestination === e.destination);
|
|
41
|
+
return t.length === 1 ? t[0].router.resolve(e) : n.fail(i());
|
|
42
|
+
}))
|
|
43
|
+
};
|
|
44
|
+
};
|
|
45
|
+
export { s as appStorageRouter, o as makeStorageDestinationRouter };
|
package/dist/streamBridge.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { StorageError as e } from "./types.js";
|
|
2
2
|
import { Effect as t, Stream as n } from "effect";
|
|
3
|
-
|
|
3
|
+
// src/streamBridge.ts
|
|
4
4
|
var r = 1 << 20, i = (t, n, r = !1) => new e({
|
|
5
5
|
provider: t,
|
|
6
6
|
message: n,
|
|
@@ -18,7 +18,10 @@ var r = 1 << 20, i = (t, n, r = !1) => new e({
|
|
|
18
18
|
}, s = (e) => e.pipe(n.runCollect, t.map((e) => a(e))), c = (e, t) => n.suspend(() => n.fromAsyncIterable(t(), (t) => i(e, `read stream failed: ${String(t?.message ?? t)}`, !0))).pipe(n.map((e) => e instanceof Uint8Array ? e : new Uint8Array(e))), l = async (e) => {
|
|
19
19
|
let { Readable: t } = await import("node:stream");
|
|
20
20
|
return t.fromWeb(n.toReadableStream(e));
|
|
21
|
-
}, u = (e,
|
|
21
|
+
}, u = (e, r) => e.getStream ? e.getStream(r).pipe(t.map((e) => e.close === void 0 ? e : {
|
|
22
|
+
...e,
|
|
23
|
+
stream: e.stream.pipe(n.ensuring(e.close))
|
|
24
|
+
})) : e.get(r).pipe(t.map((e) => ({
|
|
22
25
|
stream: o(e.bytes),
|
|
23
26
|
contentType: e.contentType,
|
|
24
27
|
size: e.bytes.byteLength
|
|
@@ -26,5 +29,4 @@ var r = 1 << 20, i = (t, n, r = !1) => new e({
|
|
|
26
29
|
contentType: i.contentType,
|
|
27
30
|
...i.public === void 0 ? {} : { public: i.public }
|
|
28
31
|
})));
|
|
29
|
-
//#endregion
|
|
30
32
|
export { o as bytesToStream, s as collectStream, a as concatBytes, c as fromNodeReadable, u as getObjectStream, d as putObjectStream, l as toNodeReadable };
|