@voltro/plugin-storage 0.85.0 → 0.87.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 +5987 -0
- package/README.md +77 -0
- package/THIRD-PARTY-NOTICES.md +860 -249
- package/dist/access.js +47 -0
- package/dist/assetRef.js +13 -0
- package/dist/avatar.js +39 -0
- package/dist/byteSecurity.d.ts +3 -0
- package/dist/byteSecurity.js +7 -0
- package/dist/connection.js +99 -0
- package/dist/constraints.js +93 -0
- package/dist/custody.js +132 -0
- package/dist/derivatives.js +30 -0
- package/dist/env.js +162 -0
- package/dist/grant.js +132 -0
- package/dist/index.d.ts +525 -203
- package/dist/index.js +765 -3196
- package/dist/ingest.js +87 -0
- package/dist/ingestPolicy.js +1 -0
- package/dist/metadataError.js +19 -0
- package/dist/objectAbandon.js +16 -0
- package/dist/objectLifecycle.js +243 -0
- package/dist/objectMetadata.js +308 -0
- package/dist/objectWriter.js +87 -0
- package/dist/pathDurability.js +16 -0
- package/dist/physicalReferences.js +54 -0
- package/dist/providers.js +638 -0
- package/dist/referenceCatalogue.js +31 -0
- package/dist/renditionProof.js +82 -0
- package/dist/retainedCapture.js +391 -0
- package/dist/retainedObjects.js +190 -0
- package/dist/rpc.d.ts +3 -15
- package/dist/rpc.js +3 -1
- package/dist/scanners.js +46 -0
- package/dist/server.d.ts +153 -0
- package/dist/server.js +4 -0
- package/dist/service.js +1418 -0
- package/dist/sourceIdentity.js +14 -0
- package/dist/sourcePin.js +35 -0
- package/dist/storageNamespaces.js +80 -0
- package/dist/storageNumbers.js +13 -0
- package/dist/storageObjectNamespaces.js +243 -0
- package/dist/storageReferenceInstances.js +52 -0
- package/dist/storageRequest.js +10 -0
- package/dist/storageRouting.js +46 -0
- package/dist/streamBridge.js +33 -0
- package/dist/table.js +54 -0
- package/dist/transcodeVideo.js +91 -0
- package/dist/transform.js +94 -0
- package/dist/transformCache.js +31 -0
- package/dist/types.d.ts +116 -134
- package/dist/types.js +14 -14
- package/package.json +17 -6
package/dist/rpc.d.ts
CHANGED
|
@@ -3,6 +3,7 @@ import { MutationProcedureDescriptor } from '@voltro/protocol';
|
|
|
3
3
|
import { PluginRpcClientDescriptor } from '@voltro/protocol';
|
|
4
4
|
import { QueryProcedureDescriptor } from '@voltro/protocol';
|
|
5
5
|
import { Schema } from 'effect';
|
|
6
|
+
import { StorageError } from '@voltro/kv/storage';
|
|
6
7
|
import { YieldableError } from 'effect/Cause';
|
|
7
8
|
|
|
8
9
|
export declare const abortMultipartUploadDescriptor: ActionProcedureDescriptor<"storage.abortMultipartUpload", Schema.Struct<{
|
|
@@ -178,6 +179,7 @@ export declare const mintPresignedUploadDescriptor: ActionProcedureDescriptor<"s
|
|
|
178
179
|
}>, typeof StorageError>;
|
|
179
180
|
|
|
180
181
|
export declare const mintUploadTicketDescriptor: ActionProcedureDescriptor<"storage.mintUploadTicket", Schema.Struct<{
|
|
182
|
+
readonly operationId: Schema.optional<Schema.String>;
|
|
181
183
|
readonly contentType: Schema.String;
|
|
182
184
|
readonly visibility: Schema.optional<Schema.Literals<readonly ["public", "private"]>>;
|
|
183
185
|
readonly access: Schema.optional<Schema.$Array<Schema.Struct<{
|
|
@@ -199,6 +201,7 @@ export declare const mintUploadTicketDescriptor: ActionProcedureDescriptor<"stor
|
|
|
199
201
|
}>, Schema.Struct<{
|
|
200
202
|
readonly uploadUrl: Schema.String;
|
|
201
203
|
readonly expiresInSec: Schema.Number;
|
|
204
|
+
readonly operationId: Schema.optional<Schema.String>;
|
|
202
205
|
}>, typeof StorageError>;
|
|
203
206
|
|
|
204
207
|
export declare const mintUploadUrlDescriptor: ActionProcedureDescriptor<"storage.mintUploadUrl", Schema.Struct<{
|
|
@@ -253,21 +256,6 @@ declare const StorageAccessDenied_base: Schema.Class<StorageAccessDenied, Schema
|
|
|
253
256
|
readonly reason: Schema.String;
|
|
254
257
|
}>, YieldableError>;
|
|
255
258
|
|
|
256
|
-
/**
|
|
257
|
-
* Storage failure. `transient` drives retry — `true` for 429 / 5xx /
|
|
258
|
-
* network blips, `false` for 4xx / config / not-found. Surfaced typed so
|
|
259
|
-
* handlers can `Effect.catchTag('StorageError', …)`.
|
|
260
|
-
*/
|
|
261
|
-
declare class StorageError extends StorageError_base {
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
declare const StorageError_base: Schema.Class<StorageError, Schema.TaggedStruct<"StorageError", {
|
|
265
|
-
readonly provider: Schema.String;
|
|
266
|
-
readonly message: Schema.String;
|
|
267
|
-
readonly transient: Schema.Boolean;
|
|
268
|
-
readonly status: Schema.optional<Schema.Number>;
|
|
269
|
-
}>, YieldableError>;
|
|
270
|
-
|
|
271
259
|
/** An upload was rejected by a constraint (size / content-type / magic-byte
|
|
272
260
|
* mismatch). `reason` is a stable code; `detail` is human-readable. */
|
|
273
261
|
declare class StorageRejected extends StorageRejected_base {
|
package/dist/rpc.js
CHANGED
|
@@ -76,6 +76,7 @@ var l = i.Literals([
|
|
|
76
76
|
}), g = o({
|
|
77
77
|
name: "storage.mintUploadTicket",
|
|
78
78
|
input: i.Struct({
|
|
79
|
+
operationId: i.optional(i.String.pipe(i.check(i.makeFilter((e) => e.trim().length > 0)), i.check(i.isMaxLength(200)))),
|
|
79
80
|
contentType: i.String,
|
|
80
81
|
visibility: i.optional(i.Literals(["public", "private"])),
|
|
81
82
|
access: i.optional(a),
|
|
@@ -88,7 +89,8 @@ var l = i.Literals([
|
|
|
88
89
|
}),
|
|
89
90
|
output: i.Struct({
|
|
90
91
|
uploadUrl: i.String,
|
|
91
|
-
expiresInSec: i.Number
|
|
92
|
+
expiresInSec: i.Number,
|
|
93
|
+
operationId: i.optional(i.String)
|
|
92
94
|
}),
|
|
93
95
|
error: t,
|
|
94
96
|
openAccess: "self-service upload: the ticket binds the calling subject + tenant, caps size, and the finalize path runs limits + scan; an unidentified caller is refused in-handler unless the app set `anonymousUploads`"
|
package/dist/scanners.js
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { storageEnv as e } from "./env.js";
|
|
2
|
+
//#region src/scanners.ts
|
|
3
|
+
var t = (e, t = 65536) => {
|
|
4
|
+
let n = [Buffer.from("zINSTREAM\0", "utf8")];
|
|
5
|
+
for (let r = 0; r < e.length; r += t) {
|
|
6
|
+
let i = e.subarray(r, Math.min(r + t, e.length)), a = Buffer.alloc(4);
|
|
7
|
+
a.writeUInt32BE(i.length, 0), n.push(a, Buffer.from(i));
|
|
8
|
+
}
|
|
9
|
+
let r = Buffer.alloc(4);
|
|
10
|
+
return r.writeUInt32BE(0, 0), n.push(r), Buffer.concat(n);
|
|
11
|
+
}, n = (e) => {
|
|
12
|
+
let t = e.replace(/\0+$/, "").trim();
|
|
13
|
+
if (/\bOK$/.test(t)) return { clean: !0 };
|
|
14
|
+
let n = /:\s*(.+?)\s+FOUND$/.exec(t);
|
|
15
|
+
if (n) return {
|
|
16
|
+
clean: !1,
|
|
17
|
+
threat: n[1] ?? "unknown"
|
|
18
|
+
};
|
|
19
|
+
throw Error(`clamav: unexpected response: ${t}`);
|
|
20
|
+
}, r = async (r, i) => {
|
|
21
|
+
let a = await import("node:net"), o = e.read("CLAMAV_HOST", i.host) ?? "127.0.0.1", s = e.read("CLAMAV_PORT"), c = i.port ?? (s ? Number(s) : 3310), l = i.timeoutMs ?? 3e4;
|
|
22
|
+
return new Promise((e, s) => {
|
|
23
|
+
let u = a.createConnection({
|
|
24
|
+
host: o,
|
|
25
|
+
port: c
|
|
26
|
+
}), d = "", f = setTimeout(() => {
|
|
27
|
+
u.destroy(), s(/* @__PURE__ */ Error("clamav scan timed out"));
|
|
28
|
+
}, l);
|
|
29
|
+
u.on("error", (e) => {
|
|
30
|
+
clearTimeout(f), s(e);
|
|
31
|
+
}), u.on("connect", () => {
|
|
32
|
+
u.end(t(r, i.chunkSize));
|
|
33
|
+
}), u.on("data", (e) => {
|
|
34
|
+
d += e.toString("utf8");
|
|
35
|
+
}), u.on("close", () => {
|
|
36
|
+
clearTimeout(f);
|
|
37
|
+
try {
|
|
38
|
+
e(n(d));
|
|
39
|
+
} catch (e) {
|
|
40
|
+
s(e);
|
|
41
|
+
}
|
|
42
|
+
});
|
|
43
|
+
});
|
|
44
|
+
}, i = (e = {}) => (t) => r(t.bytes, e);
|
|
45
|
+
//#endregion
|
|
46
|
+
export { i as clamavScanner, t as encodeInstream, n as parseClamavResponse };
|
package/dist/server.d.ts
ADDED
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
import { DataStore } from '@voltro/database';
|
|
2
|
+
import { StorageAccessPolicy } from '@voltro/protocol';
|
|
3
|
+
import { StorageConnectionConnector } from '@voltro/kv/storage';
|
|
4
|
+
import { StorageProvider } from '@voltro/kv/storage';
|
|
5
|
+
|
|
6
|
+
declare type AccessPolicy = StorageAccessPolicy;
|
|
7
|
+
|
|
8
|
+
/** The CLI injects this server adapter into the leaf registry. No plugin imports enter KV. */
|
|
9
|
+
export declare const connectStorage: StorageConnectionConnector;
|
|
10
|
+
|
|
11
|
+
/** What a finalize token authorizes: promoting ONE temp-key blob into a real
|
|
12
|
+
* ref under the bound identity, until `exp`. */
|
|
13
|
+
export declare interface FinalizeTicketPayload extends Omit<UploadTicketPayload, 'key' | 'operationId'> {
|
|
14
|
+
/** The TEMP bucket key the client PUT its bytes to (required — finalize reads
|
|
15
|
+
* exactly this key, so it can't be aimed at another object). */
|
|
16
|
+
readonly key: string;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/** What a grant token authorizes: read access to one ref at its storage HTTP mount until `exp`. */
|
|
20
|
+
export declare interface GrantTokenPayload {
|
|
21
|
+
readonly refId: string;
|
|
22
|
+
/** Exact storage HTTP mount allowed to serve this reference. */
|
|
23
|
+
readonly audience: string;
|
|
24
|
+
/** Unix seconds when the token expires. */
|
|
25
|
+
readonly exp: number;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/** What a multipart ticket authorizes: one direct-to-bucket multipart session. */
|
|
29
|
+
export declare interface MultipartTicketPayload extends Omit<UploadTicketPayload, 'key' | 'operationId'> {
|
|
30
|
+
/** The FINAL bucket key the parts assemble into. */
|
|
31
|
+
readonly key: string;
|
|
32
|
+
/** The provider's multipart upload id. */
|
|
33
|
+
readonly uploadId: string;
|
|
34
|
+
/** Total expected byte size. */
|
|
35
|
+
readonly size: number;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/** After a verified snapshot asset restore, with serving replicas stopped.
|
|
39
|
+
* The caller owns the transaction and explicitly identifies every old and new
|
|
40
|
+
* physical scope. This does no provider I/O and never changes plugin ownership.
|
|
41
|
+
* Ordinary namespace assignment continues to refuse moving assigned objects. */
|
|
42
|
+
export declare const relocateRestoredStorageObjectNamespacesInTransaction: (store: DataStore, scopes: readonly StorageReferenceScope[], relocations: readonly StorageObjectNamespaceRelocation[]) => Promise<StorageObjectNamespaceMigrationResult>;
|
|
43
|
+
|
|
44
|
+
/** The secret new storage tokens are signed with — the first of {@link resolveStorageSecrets}. */
|
|
45
|
+
export declare const resolveStorageSecret: () => string;
|
|
46
|
+
|
|
47
|
+
/** What a resumable ticket authorizes: one chunked upload session, until `exp`. */
|
|
48
|
+
export declare interface ResumableTicketPayload extends Omit<UploadTicketPayload, 'key' | 'operationId'> {
|
|
49
|
+
/** Upload-session id (random) — namespaces this upload's chunk objects. */
|
|
50
|
+
readonly id: string;
|
|
51
|
+
/** Total expected byte size (validated at finalize; also the effective cap). */
|
|
52
|
+
readonly size: number;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/** Sign a finalize token valid for `ttlSeconds`. */
|
|
56
|
+
export declare const signFinalizeTicket: (fields: Omit<FinalizeTicketPayload, "exp" | "version">, ttlSeconds: number, secret?: string) => string;
|
|
57
|
+
|
|
58
|
+
/** Mint a token granting read access to `refId` for `ttlSeconds`. */
|
|
59
|
+
export declare const signGrant: (refId: string, ttlSeconds: number, secret?: string, audience?: string) => string;
|
|
60
|
+
|
|
61
|
+
/** Sign a multipart ticket valid for `ttlSeconds`. */
|
|
62
|
+
export declare const signMultipartTicket: (fields: Omit<MultipartTicketPayload, "exp" | "version">, ttlSeconds: number, secret?: string) => string;
|
|
63
|
+
|
|
64
|
+
/** Sign a resumable ticket valid for `ttlSeconds`. */
|
|
65
|
+
export declare const signResumableTicket: (fields: Omit<ResumableTicketPayload, "exp" | "version">, ttlSeconds: number, secret?: string) => string;
|
|
66
|
+
|
|
67
|
+
/** Sign an upload ticket valid for `ttlSeconds`. */
|
|
68
|
+
export declare const signUploadTicket: (fields: Omit<UploadTicketPayload, "exp" | "version">, ttlSeconds: number, secret?: string) => string;
|
|
69
|
+
|
|
70
|
+
declare interface StorageObjectNamespaceAssignment extends StorageReferenceScope {
|
|
71
|
+
readonly refId: string;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
declare interface StorageObjectNamespaceMigrationResult {
|
|
75
|
+
readonly assigned: number;
|
|
76
|
+
readonly pendingDeletes: readonly StorageObjectNamespaceAssignment[];
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export declare interface StorageObjectNamespaceRelocation extends StorageObjectNamespaceAssignment {
|
|
80
|
+
readonly from: StorageReferenceScope;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
declare interface StorageReferenceScope {
|
|
84
|
+
readonly storageInstance: string;
|
|
85
|
+
readonly objectNamespace: string;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/** A secret, or the set a rotation keeps accepting (the signing one first). */
|
|
89
|
+
declare type StorageSecrets = string | ReadonlyArray<string>;
|
|
90
|
+
|
|
91
|
+
/** What an upload ticket authorizes: a single through-app upload bound to an
|
|
92
|
+
* owner/tenant/content-type/visibility, until `exp`. */
|
|
93
|
+
export declare interface UploadTicketPayload {
|
|
94
|
+
/** Frozen-policy ticket contract. Previous tickets must be minted again. */
|
|
95
|
+
readonly version: 2;
|
|
96
|
+
/** Optional durable write identity, preserved across ticket renewal. */
|
|
97
|
+
readonly operationId?: string;
|
|
98
|
+
/** Exact reference catalogue and physical byte destination authorized by the issuer. */
|
|
99
|
+
readonly writeScope: string;
|
|
100
|
+
/** Optional signed routing hint for the binary relay; destination authorization still uses writeScope. */
|
|
101
|
+
readonly issuerReplicaId?: string;
|
|
102
|
+
/** Exact storage plugin instance authorized to accept the bytes. */
|
|
103
|
+
readonly instance: string;
|
|
104
|
+
/** Logical destination selected before issuing the upload/session. */
|
|
105
|
+
readonly destination: string;
|
|
106
|
+
/** ownerId (subject id) the stored object is attributed to. */
|
|
107
|
+
readonly sub: string | null;
|
|
108
|
+
/** tenantId that scopes the key prefix + ref row. */
|
|
109
|
+
readonly tenant: string | null;
|
|
110
|
+
/** Authorized content-type — the stored object uses this. */
|
|
111
|
+
readonly ct: string;
|
|
112
|
+
readonly vis: 'public' | 'private';
|
|
113
|
+
/** Server-authorized policy, frozen into the signed ticket. */
|
|
114
|
+
readonly access?: AccessPolicy;
|
|
115
|
+
/** Optional fixed logical key (else content-addressed). */
|
|
116
|
+
readonly key?: string;
|
|
117
|
+
/** Max bytes the route will accept for this ticket (0/undefined = no cap). */
|
|
118
|
+
readonly max?: number;
|
|
119
|
+
/** App metadata carried onto the stored ref (so apps need no parallel table). */
|
|
120
|
+
readonly folder?: string;
|
|
121
|
+
readonly tags?: ReadonlyArray<string>;
|
|
122
|
+
readonly alt?: string;
|
|
123
|
+
readonly caption?: string;
|
|
124
|
+
/** Unix seconds when the ticket expires. */
|
|
125
|
+
readonly exp: number;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/** Verify a finalize token. Returns the payload on success, null on any failure
|
|
129
|
+
* (malformed, bad signature, expired, missing temp key). Never throws. */
|
|
130
|
+
export declare const verifyFinalizeTicket: (token: string, secret?: StorageSecrets) => FinalizeTicketPayload | null;
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Verify a grant token. Returns the payload on success, null on any
|
|
134
|
+
* failure (malformed, bad signature, expired). Never throws.
|
|
135
|
+
*/
|
|
136
|
+
export declare const verifyGrant: (token: string, secret?: StorageSecrets) => GrantTokenPayload | null;
|
|
137
|
+
|
|
138
|
+
/** Verify a multipart ticket. Returns the payload on success, null on any
|
|
139
|
+
* failure (malformed, bad signature, expired, missing key/uploadId). */
|
|
140
|
+
export declare const verifyMultipartTicket: (token: string, secret?: StorageSecrets) => MultipartTicketPayload | null;
|
|
141
|
+
|
|
142
|
+
/** Verify a resumable ticket. Returns the payload on success, null on any
|
|
143
|
+
* failure (malformed, bad signature, expired, missing id/size). Never throws. */
|
|
144
|
+
export declare const verifyResumableTicket: (token: string, secret?: StorageSecrets) => ResumableTicketPayload | null;
|
|
145
|
+
|
|
146
|
+
/** Verify an upload ticket. Returns the payload on success, null on any
|
|
147
|
+
* failure (malformed, bad signature, expired). Never throws. */
|
|
148
|
+
export declare const verifyUploadTicket: (token: string, secret?: StorageSecrets) => UploadTicketPayload | null;
|
|
149
|
+
|
|
150
|
+
/** All keyed operations share the same namespace, including presigned and multipart paths. */
|
|
151
|
+
export declare const withStorageKeyPrefix: (provider: StorageProvider, prefix?: string) => StorageProvider;
|
|
152
|
+
|
|
153
|
+
export { }
|
package/dist/server.js
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { relocateRestoredStorageObjectNamespacesInTransaction as e } from "./storageObjectNamespaces.js";
|
|
2
|
+
import { resolveStorageSecret as t, signFinalizeTicket as n, signGrant as r, signMultipartTicket as i, signResumableTicket as a, signUploadTicket as o, verifyFinalizeTicket as s, verifyGrant as c, verifyMultipartTicket as l, verifyResumableTicket as u, verifyUploadTicket as d } from "./grant.js";
|
|
3
|
+
import { connectStorage as f, withStorageKeyPrefix as p } from "./connection.js";
|
|
4
|
+
export { f as connectStorage, e as relocateRestoredStorageObjectNamespacesInTransaction, t as resolveStorageSecret, n as signFinalizeTicket, r as signGrant, i as signMultipartTicket, a as signResumableTicket, o as signUploadTicket, s as verifyFinalizeTicket, c as verifyGrant, l as verifyMultipartTicket, u as verifyResumableTicket, d as verifyUploadTicket, p as withStorageKeyPrefix };
|