@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
package/dist/index.js
CHANGED
|
@@ -1,80 +1,128 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
15
|
-
import {
|
|
16
|
-
import {
|
|
17
|
-
import {
|
|
18
|
-
import {
|
|
19
|
-
import {
|
|
20
|
-
import {
|
|
21
|
-
import {
|
|
22
|
-
import {
|
|
23
|
-
import {
|
|
24
|
-
import {
|
|
25
|
-
import {
|
|
26
|
-
import {
|
|
27
|
-
import {
|
|
28
|
-
import {
|
|
29
|
-
import {
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
1
|
+
import { appStorageRouter as e, makeStorageDestinationRouter as t } from "./storageRouting.js";
|
|
2
|
+
import { storageByteSecurityHeaders as n } from "./byteSecurity.js";
|
|
3
|
+
import { existingFilesystemObjectNamespace as r, storageObjectNamespace as i } from "./storageNamespaces.js";
|
|
4
|
+
import { STORAGE_REFERENCE_CATALOGUE_TABLE as a, ensureStorageReferenceCatalogue as o, storageReferenceCatalogueTable as s } from "./referenceCatalogue.js";
|
|
5
|
+
import { STORAGE_BLOBS_TABLE as c, STORAGE_GRANTS_TABLE as l, STORAGE_REFS_TABLE as u, STORAGE_USAGE_TABLE as d, _voltroStorageBlobsTable as ee, _voltroStorageGrantsTable as f, _voltroStorageRefsTable as p, _voltroStorageUsageTable as m } from "./table.js";
|
|
6
|
+
import { assignStorageReferenceInstancesInTransaction as h, requireStorageReferenceOwnership as te } from "./storageReferenceInstances.js";
|
|
7
|
+
import { StorageAccessDenied as ne, StorageError as g, StorageRejected as re, StorageScanRejected as ie, StorageService as _, storageAddressIdentity as ae, storageRefAddress as v } from "./types.js";
|
|
8
|
+
import { storageObjectLifecycleTables as oe } from "./objectLifecycle.js";
|
|
9
|
+
import { assignStorageObjectNamespacesInTransaction as y, requireStorageObjectNamespaces as se } from "./storageObjectNamespaces.js";
|
|
10
|
+
import { bytesToStream as b, collectStream as x, concatBytes as S, fromNodeReadable as C, getObjectStream as ce, putObjectStream as w, toNodeReadable as T } from "./streamBridge.js";
|
|
11
|
+
import { storageEnv as E } from "./env.js";
|
|
12
|
+
import { azureProvider as D, clearStorageBuffer as O, databaseProvider as k, filesystemProvider as A, memoryProvider as j, memoryProviderWithState as M, readStorageBuffer as N, s3Provider as P } from "./providers.js";
|
|
13
|
+
import { createTransformCache as le } from "./transformCache.js";
|
|
14
|
+
import { editImage as ue, parseTransformParams as de, transformCached as fe, transformFallbackReason as pe, transformImage as me, transformKey as he } from "./transform.js";
|
|
15
|
+
import { hashPassword as F, verifyPassword as I } from "./access.js";
|
|
16
|
+
import { resolveStorageSecret as L, signFinalizeTicket as ge, signGrant as R, signMultipartTicket as _e, signResumableTicket as ve, signUploadTicket as z, verifyFinalizeTicket as ye, verifyGrant as be, verifyMultipartTicket as B, verifyResumableTicket as xe, verifyUploadTicket as Se } from "./grant.js";
|
|
17
|
+
import { checkLimits as V, contentTypeAllowed as Ce, sniffMatches as we } from "./constraints.js";
|
|
18
|
+
import { fetchIngestBody as H } from "./ingest.js";
|
|
19
|
+
import { buildStorageService as Te, dataStoreGrantStore as Ee, dataStoreRefStore as De, memoryGrantStore as Oe, memoryRefStore as ke, refMatchesListQuery as Ae, storageServiceLayer as je } from "./service.js";
|
|
20
|
+
import { makeStorageObjectMetadata as Me, storagePutIntentsTable as Ne } from "./objectMetadata.js";
|
|
21
|
+
import { retainedCaptureTables as Pe } from "./retainedCapture.js";
|
|
22
|
+
import { StorageCustody as Fe, storageCustodyLayer as Ie } from "./custody.js";
|
|
23
|
+
import { abortMultipartUploadDescriptor as Le, beginMultipartUploadDescriptor as Re, beginResumableUploadDescriptor as ze, completeMultipartUploadDescriptor as Be, finalizeUploadDescriptor as Ve, ingestUrlDescriptor as He, listGrantsDescriptor as Ue, listRefsDescriptor as We, mintPresignedUploadDescriptor as Ge, mintUploadTicketDescriptor as Ke, mintUploadUrlDescriptor as qe, mintUrlDescriptor as Je, revokeDescriptor as Ye, shareDescriptor as Xe, signMultipartPartDescriptor as Ze, storageRpcClientImports as Qe, uploadDescriptor as $e } from "./rpc.js";
|
|
24
|
+
import { clamavScanner as U, encodeInstream as W, parseClamavResponse as G } from "./scanners.js";
|
|
25
|
+
import { ffmpegTranscoder as K } from "./transcodeVideo.js";
|
|
26
|
+
import { assetRef as et, withStorage as tt } from "./assetRef.js";
|
|
27
|
+
import { decodeDataUri as nt, putAvatar as rt } from "./avatar.js";
|
|
28
|
+
import { durabilityNotice as it, pathDurability as at } from "./pathDurability.js";
|
|
29
|
+
import { connectStorage as ot, withStorageKeyPrefix as st } from "./connection.js";
|
|
30
|
+
import { StorageAddress as ct, forwardStorageProvider as lt, isStorageKey as ut, storageAddressIdentity as dt } from "@voltro/kv/storage";
|
|
31
|
+
import { Effect as q, Layer as ft, Schema as J, Stream as pt } from "effect";
|
|
32
|
+
import { createHash as mt, randomUUID as ht } from "node:crypto";
|
|
33
|
+
import { authoredError as gt } from "@voltro/database";
|
|
34
|
+
import { processIdentity as _t } from "@voltro/protocol/identity";
|
|
35
|
+
import { StorageAccessPolicySchema as vt, definePlugin as yt, effectiveScopes as bt, pluginInstanceName as xt } from "@voltro/protocol";
|
|
36
|
+
import { readCookie as St, resolveSessionSecrets as Ct, verifySessionKeyed as wt } from "@voltro/protocol/session";
|
|
37
|
+
import { ifRangeAllowsRange as Tt, parseByteRange as Et } from "@voltro/runtime/http-range";
|
|
38
|
+
// src/index.ts
|
|
39
|
+
var Dt = E.read("VOLTRO_SESSION_COOKIE") ?? "voltro:session", Ot = (e) => {
|
|
40
|
+
let t = e.filter((e) => e.capabilities?.storageProvider !== void 0);
|
|
41
|
+
if (t.length > 1) throw new g({
|
|
42
|
+
provider: "storage",
|
|
43
|
+
message: "Storage destination is ambiguous; installed instances: " + t.map((e) => e.name).sort().join(", "),
|
|
44
|
+
transient: !1
|
|
45
|
+
});
|
|
46
|
+
return t.length === 1 ? t[0].capabilities.storageProvider() : void 0;
|
|
47
|
+
}, kt = (e) => {
|
|
48
|
+
let t = Ot(e);
|
|
49
|
+
return t === void 0 || Y.has(t) ? void 0 : t;
|
|
50
|
+
}, Y = /* @__PURE__ */ new WeakSet(), At = (e) => {
|
|
51
|
+
if (Y.has(e) && process.env.NODE_ENV === "production") throw gt("storage: no provider is configured in this production process — `storagePlugin()` has no `provider` and STORAGE_PROVIDER is unset, so storage would fall back to process memory, which no other replica or later process can see. Set STORAGE_PROVIDER (s3 | minio | azure | filesystem | database) for every process that reaches storage, migrate jobs included, or pass `provider: 'memory'` to choose memory deliberately.");
|
|
52
|
+
return e;
|
|
53
|
+
}, jt = (e) => {
|
|
54
|
+
let t = Ot(e);
|
|
55
|
+
if (t === void 0) throw new g({
|
|
56
|
+
provider: "storage",
|
|
57
|
+
message: "This app has no configured storage destination",
|
|
58
|
+
transient: !1
|
|
59
|
+
});
|
|
60
|
+
return At(t);
|
|
61
|
+
}, X = (e) => {
|
|
34
62
|
if (e.provider && typeof e.provider == "object") return e.provider;
|
|
35
|
-
let t =
|
|
36
|
-
|
|
63
|
+
let t = e.provider ?? E.read("STORAGE_PROVIDER");
|
|
64
|
+
if (t === void 0) {
|
|
65
|
+
let t = X({
|
|
66
|
+
...e,
|
|
67
|
+
provider: "memory"
|
|
68
|
+
});
|
|
69
|
+
return Y.add(t), t;
|
|
70
|
+
}
|
|
71
|
+
let n = t.toLowerCase(), r = E.read("S3_BUCKET", e.bucket) ?? E.read("STORAGE_BUCKET") ?? "voltro";
|
|
72
|
+
switch (n) {
|
|
37
73
|
case "s3":
|
|
38
74
|
case "minio": {
|
|
39
|
-
let
|
|
40
|
-
bucket:
|
|
41
|
-
name:
|
|
42
|
-
...
|
|
75
|
+
let t = E.read("S3_REGION", e.region) ?? E.read("AWS_REGION"), i = E.read("S3_ENDPOINT", e.endpoint) ?? E.read("MINIO_ENDPOINT"), a = E.read("S3_ACCESS_KEY_ID", e.accessKeyId) ?? E.read("AWS_ACCESS_KEY_ID"), o = E.read("S3_SECRET_ACCESS_KEY", e.secretAccessKey) ?? E.read("AWS_SECRET_ACCESS_KEY"), s = E.read("STORAGE_CDN_URL", e.cdnBaseUrl), c = {
|
|
76
|
+
bucket: r,
|
|
77
|
+
name: n,
|
|
78
|
+
...t ? { region: t } : {},
|
|
43
79
|
...i ? { endpoint: i } : {},
|
|
44
80
|
...a ? { accessKeyId: a } : {},
|
|
45
81
|
...o ? { secretAccessKey: o } : {},
|
|
46
82
|
...s ? { cdnBaseUrl: s } : {},
|
|
47
83
|
...e.publicAcl === void 0 ? {} : { publicAcl: e.publicAcl },
|
|
48
|
-
...
|
|
84
|
+
...n === "minio" || E.read("S3_FORCE_PATH_STYLE") === "1" ? { forcePathStyle: !0 } : {}
|
|
49
85
|
};
|
|
50
|
-
return
|
|
86
|
+
return P(c);
|
|
51
87
|
}
|
|
52
88
|
case "azure": {
|
|
53
|
-
let t =
|
|
54
|
-
container:
|
|
89
|
+
let t = E.read("AZURE_STORAGE_ACCOUNT", e.accountName), n = E.read("AZURE_STORAGE_KEY", e.accountKey), i = E.read("AZURE_STORAGE_CONNECTION_STRING", e.connectionString), a = E.read("AZURE_STORAGE_ENDPOINT", e.endpoint), o = E.read("STORAGE_CDN_URL", e.cdnBaseUrl), s = {
|
|
90
|
+
container: E.read("AZURE_STORAGE_CONTAINER", e.bucket) ?? r,
|
|
55
91
|
...t ? { accountName: t } : {},
|
|
56
|
-
...
|
|
92
|
+
...n ? { accountKey: n } : {},
|
|
57
93
|
...i ? { connectionString: i } : {},
|
|
58
94
|
...a ? { endpoint: a } : {},
|
|
59
95
|
...o ? { cdnBaseUrl: o } : {}
|
|
60
96
|
};
|
|
61
|
-
return
|
|
97
|
+
return D(s);
|
|
62
98
|
}
|
|
63
|
-
case "database": return
|
|
64
|
-
case "filesystem": return
|
|
65
|
-
|
|
99
|
+
case "database": return k();
|
|
100
|
+
case "filesystem": return A({ root: E.read("STORAGE_ROOT", e.root) ?? ".voltro-storage" });
|
|
101
|
+
case "memory": return M(/* @__PURE__ */ new Map());
|
|
102
|
+
default: throw new g({
|
|
103
|
+
provider: "storage",
|
|
104
|
+
message: "Unknown storage provider; choose memory, filesystem, database, s3, minio or azure",
|
|
105
|
+
transient: !1
|
|
106
|
+
});
|
|
66
107
|
}
|
|
67
|
-
},
|
|
68
|
-
let t = "stored files (uploads, renditions) and their reads"
|
|
108
|
+
}, Mt = (e) => {
|
|
109
|
+
let t = "stored files (uploads, renditions) and their reads";
|
|
110
|
+
if (e.connection !== void 0) return [{
|
|
111
|
+
destination: `runtime:the app-owned ${e.connection} connection`,
|
|
112
|
+
purpose: t,
|
|
113
|
+
data: ["files"],
|
|
114
|
+
disable: "remove the storage connection binding"
|
|
115
|
+
}];
|
|
116
|
+
let n = "provider 'database' or 'filesystem' keeps the bytes inside the installation";
|
|
69
117
|
if (e.provider && typeof e.provider == "object") return [{
|
|
70
118
|
destination: `runtime:the '${e.provider.name}' storage provider`,
|
|
71
119
|
purpose: t,
|
|
72
120
|
data: ["files"],
|
|
73
121
|
disable: n
|
|
74
122
|
}];
|
|
75
|
-
let r = (e.provider ??
|
|
123
|
+
let r = (e.provider ?? E.read("STORAGE_PROVIDER") ?? "memory").toLowerCase();
|
|
76
124
|
if (r === "s3" || r === "minio") {
|
|
77
|
-
let r =
|
|
125
|
+
let r = E.read("S3_ENDPOINT", e.endpoint) ?? E.read("MINIO_ENDPOINT"), i = E.read("S3_REGION", e.region) ?? E.read("AWS_REGION") ?? "us-east-1";
|
|
78
126
|
return [{
|
|
79
127
|
destination: r ?? `s3.${i}.amazonaws.com`,
|
|
80
128
|
purpose: t,
|
|
@@ -83,7 +131,7 @@ var lt = w.read("VOLTRO_SESSION_COOKIE") ?? "voltro:session", K, ut = (e) => {
|
|
|
83
131
|
}];
|
|
84
132
|
}
|
|
85
133
|
if (r === "azure") {
|
|
86
|
-
let r =
|
|
134
|
+
let r = E.read("AZURE_STORAGE_ENDPOINT", e.endpoint), i = E.read("AZURE_STORAGE_ACCOUNT", e.accountName);
|
|
87
135
|
return [{
|
|
88
136
|
destination: r ?? (i === void 0 ? "runtime:the Azure storage connection string" : `${i}.blob.core.windows.net`),
|
|
89
137
|
purpose: t,
|
|
@@ -92,11 +140,11 @@ var lt = w.read("VOLTRO_SESSION_COOKIE") ?? "voltro:session", K, ut = (e) => {
|
|
|
92
140
|
}];
|
|
93
141
|
}
|
|
94
142
|
return [];
|
|
95
|
-
},
|
|
143
|
+
}, Nt = (e) => {
|
|
96
144
|
if (e !== void 0) return e;
|
|
97
|
-
let t =
|
|
145
|
+
let t = E.read("STORAGE_ALLOWED_ORIGINS");
|
|
98
146
|
return t ? t.trim() === "*" ? "*" : t.split(",").map((e) => e.trim()).filter(Boolean) : [];
|
|
99
|
-
},
|
|
147
|
+
}, Pt = (e, t) => {
|
|
100
148
|
if (!e || t !== "*" && !t.includes(e)) return {};
|
|
101
149
|
let n = {
|
|
102
150
|
"access-control-allow-origin": t === "*" ? "*" : e,
|
|
@@ -106,7 +154,7 @@ var lt = w.read("VOLTRO_SESSION_COOKIE") ?? "voltro:session", K, ut = (e) => {
|
|
|
106
154
|
vary: "Origin"
|
|
107
155
|
};
|
|
108
156
|
return t !== "*" && (n["access-control-allow-credentials"] = "true"), n;
|
|
109
|
-
},
|
|
157
|
+
}, Ft = (e) => ({
|
|
110
158
|
id: e.id,
|
|
111
159
|
tenantId: e.tenantId,
|
|
112
160
|
ownerId: e.ownerId,
|
|
@@ -129,29 +177,29 @@ var lt = w.read("VOLTRO_SESSION_COOKIE") ?? "voltro:session", K, ut = (e) => {
|
|
|
129
177
|
caption: e.caption ?? null,
|
|
130
178
|
derivedFrom: e.derivedFrom ?? null,
|
|
131
179
|
kind: e.kind ?? null
|
|
132
|
-
}),
|
|
180
|
+
}), It = () => new g({
|
|
133
181
|
provider: "storage",
|
|
134
182
|
message: "not permitted to administer sharing for this object",
|
|
135
183
|
transient: !1,
|
|
136
184
|
status: 403
|
|
137
|
-
}),
|
|
185
|
+
}), Lt = (e, t, n) => {
|
|
138
186
|
let r = n.request.subject;
|
|
139
|
-
return (r
|
|
187
|
+
return bt(r).includes("admin:full") ? q.void : e.head(t, { tenantId: r.tenantId ?? null }).pipe(q.catch(() => q.fail(It())), q.flatMap((e) => {
|
|
140
188
|
let t = e?.ownerId;
|
|
141
|
-
return t != null && t === r.id ?
|
|
189
|
+
return t != null && t === r.id ? q.void : q.fail(It());
|
|
142
190
|
}));
|
|
143
|
-
},
|
|
191
|
+
}, Rt = () => new g({
|
|
144
192
|
provider: "storage",
|
|
145
193
|
message: "an upload needs an identified caller: this request carries no subject, and the app has not set `anonymousUploads: true` on storagePlugin. The ticket attributes the object to whoever minted it — with no subject there is nobody to attribute it to, so the finalized object would carry no owner and no tenant and no later owner check, tenant filter or quota could reach it.",
|
|
146
194
|
transient: !1,
|
|
147
195
|
status: 401
|
|
148
196
|
}), Z = (e, t) => {
|
|
149
197
|
let n = e.request.subject.id ?? null, r = e.request.subject.tenantId ?? null;
|
|
150
|
-
return n === null && !t ?
|
|
198
|
+
return n === null && !t ? q.fail(Rt()) : q.succeed({
|
|
151
199
|
id: n,
|
|
152
200
|
tenantId: r
|
|
153
201
|
});
|
|
154
|
-
},
|
|
202
|
+
}, zt = (e, t) => e !== null && e !== (t ?? null), Bt = (e) => ({
|
|
155
203
|
id: e.id,
|
|
156
204
|
refId: e.refId,
|
|
157
205
|
principalType: e.principalType,
|
|
@@ -160,32 +208,79 @@ var lt = w.read("VOLTRO_SESSION_COOKIE") ?? "voltro:session", K, ut = (e) => {
|
|
|
160
208
|
createdAt: e.createdAt.toISOString(),
|
|
161
209
|
expiresAt: e.expiresAt ? e.expiresAt.toISOString() : null,
|
|
162
210
|
createdBy: e.createdBy
|
|
163
|
-
}),
|
|
164
|
-
base:
|
|
211
|
+
}), Q = "@voltro/plugin-storage", Vt = (e = {}) => xt({
|
|
212
|
+
base: Q,
|
|
165
213
|
alias: e.alias,
|
|
166
214
|
instance: e.name
|
|
167
|
-
}),
|
|
168
|
-
let
|
|
169
|
-
base:
|
|
215
|
+
}), Ht = (e) => e.reason === "too-large" ? 413 : e.reason === "operation-identity-reused" || e.reason === "operation-store-unbound" || e.reason === "claim-not-held" ? 409 : 415, Ut = (e = {}) => {
|
|
216
|
+
let r = xt({
|
|
217
|
+
base: Q,
|
|
170
218
|
alias: e.alias,
|
|
171
219
|
instance: e.name
|
|
172
|
-
}),
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
220
|
+
}), i = r === Q ? "/_voltro/storage" : `/_voltro/storage/i/${Buffer.from(r).toString("hex")}`, a = [
|
|
221
|
+
"provider",
|
|
222
|
+
"bucket",
|
|
223
|
+
"region",
|
|
224
|
+
"endpoint",
|
|
225
|
+
"accessKeyId",
|
|
226
|
+
"secretAccessKey",
|
|
227
|
+
"root",
|
|
228
|
+
"accountName",
|
|
229
|
+
"accountKey",
|
|
230
|
+
"connectionString",
|
|
231
|
+
"cdnBaseUrl"
|
|
232
|
+
].some((t) => e[t] !== void 0);
|
|
233
|
+
if (e.connection !== void 0 && a) throw Error("Storage selects either a named connection or direct transport options");
|
|
234
|
+
let s = e.connection !== void 0 || !a;
|
|
235
|
+
if (e.connection === void 0 && typeof e.provider != "object" && ![
|
|
236
|
+
"memory",
|
|
237
|
+
"filesystem",
|
|
238
|
+
"database",
|
|
239
|
+
"s3",
|
|
240
|
+
"minio",
|
|
241
|
+
"azure"
|
|
242
|
+
].includes((e.provider ?? E.read("STORAGE_PROVIDER") ?? "memory").toLowerCase())) throw new g({
|
|
243
|
+
provider: "storage",
|
|
244
|
+
message: "Unknown storage provider; choose memory, filesystem, database, s3, minio or azure",
|
|
245
|
+
transient: !1
|
|
246
|
+
});
|
|
247
|
+
let c = E.read("S3_BUCKET", e.bucket) ?? E.read("STORAGE_BUCKET") ?? "voltro", l = a ? X(e) : void 0, u = () => (l === void 0 && (l = X(e)), l), d = l, ee = e.connection, f, p = !1, m = s ? lt(() => {
|
|
248
|
+
if (d === void 0) {
|
|
249
|
+
if (ee !== void 0) throw new g({
|
|
250
|
+
provider: "storage",
|
|
251
|
+
message: "Named storage requires a bound tenant-aware destination",
|
|
252
|
+
transient: !1
|
|
253
|
+
});
|
|
254
|
+
d = u();
|
|
255
|
+
}
|
|
256
|
+
return d;
|
|
257
|
+
}) : d;
|
|
258
|
+
e.provider === void 0 && e.connection === void 0 && E.read("STORAGE_PROVIDER") === void 0 && Y.add(m);
|
|
259
|
+
let h = e.connection ?? c, _ = t({
|
|
260
|
+
selected: () => h,
|
|
261
|
+
directDestination: e.connection === void 0 ? c : void 0,
|
|
262
|
+
directProvider: u,
|
|
263
|
+
registry: () => f
|
|
264
|
+
}), oe = (e, t) => q.gen(function* () {
|
|
265
|
+
if (f = e, ee = t, p = !1, h = t ?? c, t === void 0) return;
|
|
266
|
+
if (Y.delete(m), e === void 0) throw Error("Named storage requires the app connection registry");
|
|
267
|
+
let n = yield* e.validate(t);
|
|
268
|
+
p = n.tenantScoped, d = n.tenantScoped ? void 0 : yield* e.storage(t);
|
|
269
|
+
}), y = E.read("VOLTRO_PUBLIC_URL", e.publicBaseUrl), b = Nt(e.allowedOrigins), x = e.limits?.maxBytes, S = e.anonymousUploads === !0, C = 5242880, ce = 21600, w = e.refStore === void 0 || e.refStore === "memory", T = e.grantStore === void 0 || e.grantStore === "memory", D = (t, n) => q.gen(function* () {
|
|
270
|
+
let r = (e) => J.decodeUnknownEffect(vt)(e, { onExcessProperty: "error" }).pipe(q.mapError(() => new g({
|
|
176
271
|
provider: "storage",
|
|
177
272
|
message: "Invalid upload access policy",
|
|
178
273
|
transient: !1,
|
|
179
274
|
status: 400
|
|
180
275
|
}))), i = t.access === void 0 ? void 0 : yield* r(t.access), a = t.visibility ?? "private";
|
|
181
|
-
if (i !== void 0 && a === "public") return yield*
|
|
276
|
+
if (i !== void 0 && a === "public") return yield* q.fail(new g({
|
|
182
277
|
provider: "storage",
|
|
183
278
|
message: "An access policy requires a private upload",
|
|
184
279
|
transient: !1,
|
|
185
280
|
status: 400
|
|
186
281
|
}));
|
|
187
282
|
let o = e.uploadAccess;
|
|
188
|
-
if (i !== void 0 && typeof o != "function") return yield*
|
|
283
|
+
if (i !== void 0 && typeof o != "function") return yield* q.fail(new g({
|
|
189
284
|
provider: "storage",
|
|
190
285
|
message: "Requested upload access requires an uploadAccess authorization function on storagePlugin",
|
|
191
286
|
transient: !1,
|
|
@@ -197,46 +292,55 @@ var lt = w.read("VOLTRO_SESSION_COOKIE") ?? "voltro:session", K, ut = (e) => {
|
|
|
197
292
|
visibility: a,
|
|
198
293
|
contentType: t.contentType
|
|
199
294
|
}) : a === "private" ? o : void 0, c = s === void 0 ? void 0 : yield* r(s);
|
|
200
|
-
return a === "public" ? c !== void 0 && c.length > 0 ? yield*
|
|
295
|
+
return a === "public" ? c !== void 0 && c.length > 0 ? yield* q.fail(new g({
|
|
201
296
|
provider: "storage",
|
|
202
297
|
message: "A public upload cannot carry an access policy",
|
|
203
298
|
transient: !1,
|
|
204
299
|
status: 400
|
|
205
300
|
})) : {} : c === void 0 ? {} : { access: c };
|
|
206
|
-
}),
|
|
301
|
+
}), O = { current: w ? ke() : e.refStore }, k = { current: T ? Oe() : e.grantStore }, A = { current: void 0 }, j = { current: void 0 }, M = {
|
|
207
302
|
get catalogueId() {
|
|
208
|
-
return
|
|
303
|
+
return O.current.catalogueId;
|
|
209
304
|
},
|
|
210
|
-
insert: (e) =>
|
|
211
|
-
getById: (e) =>
|
|
212
|
-
delete: (e) =>
|
|
213
|
-
statistics: () =>
|
|
214
|
-
listRecent: (e) =>
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
305
|
+
insert: (e) => O.current.insert(e),
|
|
306
|
+
getById: (e) => O.current.getById(e),
|
|
307
|
+
delete: (e) => O.current.delete(e),
|
|
308
|
+
statistics: () => O.current.statistics(),
|
|
309
|
+
listRecent: (e) => O.current.listRecent(e),
|
|
310
|
+
countByAddress: (e) => O.current.countByAddress(e),
|
|
311
|
+
listObjectReferences: () => O.current.listObjectReferences(),
|
|
312
|
+
hasObjectReservation: (e, t) => O.current.hasObjectReservation?.(e, t) ?? q.succeed(!1),
|
|
313
|
+
usageByTenant: (e) => O.current.usageByTenant(e),
|
|
314
|
+
consumeUsage: (e, t, n) => O.current.consumeUsage(e, t, n),
|
|
315
|
+
releaseUsage: (e, t) => O.current.releaseUsage(e, t),
|
|
316
|
+
listByDerivedFrom: (e) => O.current.listByDerivedFrom(e),
|
|
317
|
+
listRefs: (e) => O.current.listRefs(e),
|
|
221
318
|
get setVisibility() {
|
|
222
|
-
return
|
|
319
|
+
return O.current.setVisibility;
|
|
223
320
|
},
|
|
224
|
-
get
|
|
225
|
-
return
|
|
321
|
+
get countPublicByAddress() {
|
|
322
|
+
return O.current.countPublicByAddress;
|
|
226
323
|
}
|
|
227
|
-
},
|
|
228
|
-
insert: (e) =>
|
|
229
|
-
delete: (e) =>
|
|
230
|
-
getById: (e) =>
|
|
231
|
-
listByRef: (e) =>
|
|
232
|
-
deleteByRef: (e) =>
|
|
233
|
-
},
|
|
234
|
-
httpPath:
|
|
235
|
-
storageInstance:
|
|
236
|
-
provider:
|
|
237
|
-
refStore:
|
|
238
|
-
grantStore:
|
|
239
|
-
bucket
|
|
324
|
+
}, N = {
|
|
325
|
+
insert: (e) => k.current.insert(e),
|
|
326
|
+
delete: (e) => k.current.delete(e),
|
|
327
|
+
getById: (e) => k.current.getById(e),
|
|
328
|
+
listByRef: (e) => k.current.listByRef(e),
|
|
329
|
+
deleteByRef: (e) => k.current.deleteByRef(e)
|
|
330
|
+
}, P, ue = {
|
|
331
|
+
httpPath: i,
|
|
332
|
+
storageInstance: r,
|
|
333
|
+
provider: m,
|
|
334
|
+
refStore: M,
|
|
335
|
+
grantStore: N,
|
|
336
|
+
get bucket() {
|
|
337
|
+
return h;
|
|
338
|
+
},
|
|
339
|
+
destinations: _,
|
|
340
|
+
resolveObjectReference: (e) => P !== void 0 && e.storageInstance !== void 0 ? P({
|
|
341
|
+
storageInstance: e.storageInstance,
|
|
342
|
+
address: v(e)
|
|
343
|
+
}) : _.resolve(v(e)),
|
|
240
344
|
...e.tenantPrefix === void 0 ? {} : { tenantPrefix: e.tenantPrefix },
|
|
241
345
|
...e.attempts === void 0 ? {} : { attempts: e.attempts },
|
|
242
346
|
...e.urlExpiresInSec === void 0 ? {} : { urlExpiresInSec: e.urlExpiresInSec },
|
|
@@ -247,16 +351,28 @@ var lt = w.read("VOLTRO_SESSION_COOKIE") ?? "voltro:session", K, ut = (e) => {
|
|
|
247
351
|
...e.videoProbe === void 0 ? {} : { videoProbe: e.videoProbe },
|
|
248
352
|
...e.transcode === void 0 ? {} : { transcode: e.transcode },
|
|
249
353
|
...e.autoTranscode === void 0 ? {} : { autoTranscode: e.autoTranscode },
|
|
250
|
-
...
|
|
354
|
+
...y ? { publicBaseUrl: y } : {},
|
|
251
355
|
...e.normalizeImages === void 0 ? {} : { normalizeImages: e.normalizeImages },
|
|
252
356
|
...e.quota === void 0 ? {} : { quota: e.quota },
|
|
253
|
-
objects: () =>
|
|
254
|
-
},
|
|
357
|
+
objects: () => A.current
|
|
358
|
+
}, fe = ft.merge(je(ue), Ie({
|
|
359
|
+
selection: {
|
|
360
|
+
...e.alias === void 0 ? {} : { alias: e.alias },
|
|
361
|
+
...e.name === void 0 ? {} : { name: e.name }
|
|
362
|
+
},
|
|
363
|
+
bucket: h,
|
|
364
|
+
provider: m,
|
|
365
|
+
store: () => j.current,
|
|
366
|
+
...e.quota === void 0 ? {} : { quota: e.quota }
|
|
367
|
+
})), F = Te(ue), I = (e) => F.uploadTicketScope({
|
|
368
|
+
tenantId: e.tenant,
|
|
369
|
+
destination: e.destination
|
|
370
|
+
}).pipe(q.flatMap((t) => t === e.writeScope ? q.void : q.fail(new g({
|
|
255
371
|
provider: "storage",
|
|
256
372
|
message: "Upload ticket belongs to another storage destination",
|
|
257
373
|
transient: !1,
|
|
258
374
|
status: 409
|
|
259
|
-
})))),
|
|
375
|
+
})))), L = (e, t) => q.runPromise(I(e).pipe(q.match({
|
|
260
376
|
onSuccess: () => null,
|
|
261
377
|
onFailure: (e) => ({
|
|
262
378
|
status: e.status ?? 503,
|
|
@@ -264,56 +380,36 @@ var lt = w.read("VOLTRO_SESSION_COOKIE") ?? "voltro:session", K, ut = (e) => {
|
|
|
264
380
|
contentType: "text/plain",
|
|
265
381
|
headers: t
|
|
266
382
|
})
|
|
267
|
-
}))),
|
|
268
|
-
if (
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
start: Math.max(0, t - e),
|
|
277
|
-
endInclusive: t - 1
|
|
278
|
-
};
|
|
279
|
-
}
|
|
280
|
-
let a = Number(r);
|
|
281
|
-
if (!Number.isFinite(a)) return "invalid";
|
|
282
|
-
if (t > 0 && a >= t) return "unsatisfiable";
|
|
283
|
-
let o = i === "" ? Math.max(0, t - 1) : Math.min(Number(i), Math.max(0, t - 1));
|
|
284
|
-
return !Number.isFinite(o) || o < a ? "invalid" : {
|
|
285
|
-
start: a,
|
|
286
|
-
endInclusive: o
|
|
287
|
-
};
|
|
288
|
-
}, ae = e.publicCacheSeconds === void 0 ? "public, max-age=31536000, immutable" : `public, max-age=${Math.max(0, Math.floor(e.publicCacheSeconds))}`, A = /^(?:image\/(?!svg)|video\/|audio\/|application\/pdf(?:;|$)|text\/plain(?:;|$))/i, j = (e) => ({
|
|
289
|
-
"x-content-type-options": "nosniff",
|
|
290
|
-
"content-disposition": A.test(e) ? "inline" : "attachment"
|
|
291
|
-
}), ce = oe(), M = async (e, t, n, r) => {
|
|
292
|
-
if (n) {
|
|
293
|
-
let r, i = await ce.getOrCreate(de(JSON.stringify([e.id, e.checksum]), e.contentType, n), async () => {
|
|
294
|
-
let t = await O(C.get(e.id));
|
|
295
|
-
return t ? (r = t.bytes, ue(t.bytes, e.contentType, n)) : null;
|
|
383
|
+
}))), R = `${i}/`, V = (e) => q.runPromise(e.pipe(q.catch(() => q.succeed(null)))), Ce = e.publicCacheSeconds === void 0 ? "public, max-age=31536000, immutable" : `public, max-age=${Math.max(0, Math.floor(e.publicCacheSeconds))}`, we = le(), H = async (e, t, r, i, a) => {
|
|
384
|
+
if (r) {
|
|
385
|
+
let i, a = await we.getOrCreate(he(JSON.stringify([
|
|
386
|
+
ae(v(e)),
|
|
387
|
+
e.id,
|
|
388
|
+
e.checksum
|
|
389
|
+
]), e.contentType, r), async () => {
|
|
390
|
+
let t = await V(F.get(e.id));
|
|
391
|
+
return t ? (i = t.bytes, me(t.bytes, e.contentType, r)) : null;
|
|
296
392
|
}).catch(() => null);
|
|
297
|
-
if (!
|
|
393
|
+
if (!a && i === void 0 && (i = (await V(F.get(e.id)))?.bytes), !a && i === void 0) return {
|
|
298
394
|
status: 404,
|
|
299
395
|
body: "not found",
|
|
300
396
|
contentType: "text/plain"
|
|
301
397
|
};
|
|
302
|
-
let
|
|
398
|
+
let o = a ? a.bytes : i, s = a ? a.contentType : e.contentType, c = await pe(e.contentType, a !== null);
|
|
303
399
|
return {
|
|
304
400
|
status: 200,
|
|
305
|
-
body:
|
|
306
|
-
contentType:
|
|
401
|
+
body: o,
|
|
402
|
+
contentType: s,
|
|
307
403
|
headers: {
|
|
308
|
-
...
|
|
404
|
+
...n(s),
|
|
309
405
|
"cache-control": t,
|
|
310
406
|
"accept-ranges": "none",
|
|
311
|
-
...
|
|
407
|
+
...c === null ? {} : { "x-voltro-transform": `original; reason=${c}` }
|
|
312
408
|
}
|
|
313
409
|
};
|
|
314
410
|
}
|
|
315
|
-
let
|
|
316
|
-
if (
|
|
411
|
+
let o = Tt(a, {}) ? Et(i, e.size) : { _tag: "ignored" };
|
|
412
|
+
if (o._tag === "unsatisfiable") return {
|
|
317
413
|
status: 416,
|
|
318
414
|
body: "range not satisfiable",
|
|
319
415
|
contentType: "text/plain",
|
|
@@ -322,17 +418,20 @@ var lt = w.read("VOLTRO_SESSION_COOKIE") ?? "voltro:session", K, ut = (e) => {
|
|
|
322
418
|
"accept-ranges": "bytes"
|
|
323
419
|
}
|
|
324
420
|
};
|
|
325
|
-
if (
|
|
326
|
-
let
|
|
327
|
-
|
|
421
|
+
if (o._tag === "satisfiable") {
|
|
422
|
+
let r = await V(F.getRange(e.id, {
|
|
423
|
+
start: o.start,
|
|
424
|
+
endInclusive: o.end
|
|
425
|
+
}));
|
|
426
|
+
return r ? {
|
|
328
427
|
status: 206,
|
|
329
|
-
body:
|
|
428
|
+
body: r.bytes,
|
|
330
429
|
contentType: e.contentType,
|
|
331
430
|
headers: {
|
|
332
|
-
...
|
|
431
|
+
...n(e.contentType),
|
|
333
432
|
"cache-control": t,
|
|
334
433
|
"accept-ranges": "bytes",
|
|
335
|
-
"content-range": `bytes ${
|
|
434
|
+
"content-range": `bytes ${o.start}-${o.end}/${r.totalSize}`
|
|
336
435
|
}
|
|
337
436
|
} : {
|
|
338
437
|
status: 404,
|
|
@@ -340,69 +439,81 @@ var lt = w.read("VOLTRO_SESSION_COOKIE") ?? "voltro:session", K, ut = (e) => {
|
|
|
340
439
|
contentType: "text/plain"
|
|
341
440
|
};
|
|
342
441
|
}
|
|
343
|
-
let
|
|
344
|
-
return
|
|
442
|
+
let s = await V(F.getStream(e.id));
|
|
443
|
+
return s ? {
|
|
345
444
|
status: 200,
|
|
346
445
|
contentType: e.contentType,
|
|
347
446
|
headers: {
|
|
348
|
-
...
|
|
447
|
+
...n(e.contentType),
|
|
349
448
|
"cache-control": t,
|
|
350
449
|
"accept-ranges": "bytes"
|
|
351
450
|
},
|
|
352
451
|
byteStream: {
|
|
353
452
|
contentLength: e.size,
|
|
354
|
-
stream: () =>
|
|
453
|
+
stream: () => pt.toReadableStream(s.stream)
|
|
355
454
|
}
|
|
356
455
|
} : {
|
|
357
456
|
status: 404,
|
|
358
457
|
body: "not found",
|
|
359
458
|
contentType: "text/plain"
|
|
360
459
|
};
|
|
361
|
-
},
|
|
362
|
-
let t = e.path.startsWith(
|
|
460
|
+
}, Ae = async (e) => {
|
|
461
|
+
let t = e.path.startsWith(R) ? e.path.slice(R.length).split("/")[0] ?? "" : "";
|
|
363
462
|
if (!t) return {
|
|
364
463
|
status: 404,
|
|
365
464
|
body: "not found",
|
|
366
465
|
contentType: "text/plain"
|
|
367
466
|
};
|
|
368
|
-
let n = await
|
|
467
|
+
let n = await V(F.head(t));
|
|
369
468
|
if (!n) return {
|
|
370
469
|
status: 404,
|
|
371
470
|
body: "not found",
|
|
372
471
|
contentType: "text/plain"
|
|
373
472
|
};
|
|
374
|
-
let
|
|
473
|
+
let r = de(e.query), a = e.headers.range, o = e.headers["if-range"], s = n.derivedFrom == null ? null : await V(F.head(n.derivedFrom));
|
|
375
474
|
if (n.derivedFrom != null && s === null) return {
|
|
376
475
|
status: 404,
|
|
377
476
|
body: "not found",
|
|
378
477
|
contentType: "text/plain"
|
|
379
478
|
};
|
|
380
479
|
if (n.visibility === "public" && (s === null || s.visibility === "public")) {
|
|
381
|
-
let e =
|
|
382
|
-
|
|
480
|
+
let e = await V(_.resolve(v(n)));
|
|
481
|
+
if (!e) return {
|
|
482
|
+
status: 503,
|
|
483
|
+
body: "storage destination unavailable",
|
|
484
|
+
contentType: "text/plain"
|
|
485
|
+
};
|
|
486
|
+
let t = e.publicUrl?.(n.key) ?? null;
|
|
487
|
+
return t && !r ? {
|
|
383
488
|
status: 302,
|
|
384
489
|
headers: {
|
|
385
|
-
location:
|
|
490
|
+
location: t,
|
|
386
491
|
"cache-control": "public, max-age=300"
|
|
387
492
|
}
|
|
388
|
-
} :
|
|
493
|
+
} : H(n, Ce, r, a, o);
|
|
389
494
|
}
|
|
390
495
|
let c = !1, l = e.query ? new URLSearchParams(e.query).get("t") : null;
|
|
391
496
|
if (l) {
|
|
392
|
-
let e =
|
|
393
|
-
c = !!e && (e.refId === t || s !== null && e.refId === s.id) && e.audience ===
|
|
497
|
+
let e = be(l);
|
|
498
|
+
c = !!e && (e.refId === t || s !== null && e.refId === s.id) && e.audience === i;
|
|
394
499
|
}
|
|
395
500
|
if (!c) {
|
|
396
|
-
let t =
|
|
397
|
-
r && (c = await
|
|
501
|
+
let t = St(e.headers.cookie, Dt), r = t ? wt(t, Ct())?.subject ?? null : null;
|
|
502
|
+
r && (c = await V(F.checkAccess(n, r)) === !0);
|
|
398
503
|
}
|
|
399
504
|
if (!c) return {
|
|
400
505
|
status: 403,
|
|
401
506
|
body: "forbidden",
|
|
402
507
|
contentType: "text/plain"
|
|
403
508
|
};
|
|
404
|
-
|
|
405
|
-
|
|
509
|
+
let u = await V(_.resolve(v(n)));
|
|
510
|
+
if (!u) return {
|
|
511
|
+
status: 503,
|
|
512
|
+
body: "storage destination unavailable",
|
|
513
|
+
contentType: "text/plain"
|
|
514
|
+
};
|
|
515
|
+
if (u.presigns && !r) {
|
|
516
|
+
let e = await V(u.getUrl(n.key, 300));
|
|
406
517
|
if (e && /^https?:/.test(e)) return {
|
|
407
518
|
status: 302,
|
|
408
519
|
headers: {
|
|
@@ -411,12 +522,12 @@ var lt = w.read("VOLTRO_SESSION_COOKIE") ?? "voltro:session", K, ut = (e) => {
|
|
|
411
522
|
}
|
|
412
523
|
};
|
|
413
524
|
}
|
|
414
|
-
return
|
|
415
|
-
},
|
|
525
|
+
return H(n, "private, no-store", r, a, o);
|
|
526
|
+
}, Ne = {
|
|
416
527
|
method: "GET",
|
|
417
|
-
path:
|
|
528
|
+
path: i,
|
|
418
529
|
handle: async (e) => {
|
|
419
|
-
let t = await
|
|
530
|
+
let t = await Ae(e), n = Pt(e.headers.origin, b);
|
|
420
531
|
return Object.keys(n).length === 0 ? t : {
|
|
421
532
|
...t,
|
|
422
533
|
headers: {
|
|
@@ -425,47 +536,48 @@ var lt = w.read("VOLTRO_SESSION_COOKIE") ?? "voltro:session", K, ut = (e) => {
|
|
|
425
536
|
}
|
|
426
537
|
};
|
|
427
538
|
}
|
|
428
|
-
},
|
|
539
|
+
}, Pe = {
|
|
429
540
|
method: "*",
|
|
430
|
-
path: `${
|
|
541
|
+
path: `${i}/upload`,
|
|
431
542
|
originGuard: "exempt",
|
|
432
543
|
handle: async (e) => {
|
|
433
|
-
let
|
|
544
|
+
let t = Pt(e.headers.origin, b);
|
|
434
545
|
if (e.method === "OPTIONS") return {
|
|
435
546
|
status: 204,
|
|
436
|
-
headers:
|
|
547
|
+
headers: t
|
|
437
548
|
};
|
|
438
549
|
if (e.method !== "POST") return {
|
|
439
550
|
status: 405,
|
|
440
551
|
body: "method not allowed",
|
|
441
552
|
contentType: "text/plain",
|
|
442
|
-
headers:
|
|
553
|
+
headers: t
|
|
443
554
|
};
|
|
444
|
-
let
|
|
445
|
-
if (!i || i.instance !==
|
|
555
|
+
let n = e.query ? new URLSearchParams(e.query).get("ticket") : null, i = n ? Se(n) : null;
|
|
556
|
+
if (!i || i.instance !== r) return {
|
|
446
557
|
status: 401,
|
|
447
558
|
body: "invalid or expired upload ticket",
|
|
448
559
|
contentType: "text/plain",
|
|
449
|
-
headers:
|
|
560
|
+
headers: t
|
|
450
561
|
};
|
|
451
|
-
let a = await
|
|
562
|
+
let a = await L(i, t);
|
|
452
563
|
if (a) return a;
|
|
453
564
|
if (e.rawBody.length === 0) return {
|
|
454
565
|
status: 400,
|
|
455
566
|
body: "empty body",
|
|
456
567
|
contentType: "text/plain",
|
|
457
|
-
headers:
|
|
568
|
+
headers: t
|
|
458
569
|
};
|
|
459
570
|
if (i.max && e.rawBody.length > i.max) return {
|
|
460
571
|
status: 413,
|
|
461
572
|
body: "payload too large",
|
|
462
573
|
contentType: "text/plain",
|
|
463
|
-
headers:
|
|
574
|
+
headers: t
|
|
464
575
|
};
|
|
465
|
-
let o = await
|
|
576
|
+
let o = await q.runPromise(F.put({
|
|
466
577
|
bytes: e.rawBody,
|
|
467
578
|
contentType: i.ct,
|
|
468
579
|
tenantId: i.tenant,
|
|
580
|
+
destination: i.destination,
|
|
469
581
|
ownerId: i.sub,
|
|
470
582
|
visibility: i.vis,
|
|
471
583
|
...i.access === void 0 ? {} : { access: i.access },
|
|
@@ -475,21 +587,21 @@ var lt = w.read("VOLTRO_SESSION_COOKIE") ?? "voltro:session", K, ut = (e) => {
|
|
|
475
587
|
...i.tags === void 0 ? {} : { tags: i.tags },
|
|
476
588
|
...i.alt === void 0 ? {} : { alt: i.alt },
|
|
477
589
|
...i.caption === void 0 ? {} : { caption: i.caption }
|
|
478
|
-
}).pipe(
|
|
590
|
+
}).pipe(q.flatMap((e) => F.getUrl(e.id).pipe(q.map((t) => ({
|
|
479
591
|
kind: "ok",
|
|
480
592
|
ref: e,
|
|
481
593
|
url: t
|
|
482
|
-
})))),
|
|
483
|
-
StorageRejected: (e) =>
|
|
594
|
+
})))), q.catchTags({
|
|
595
|
+
StorageRejected: (e) => q.succeed({
|
|
484
596
|
kind: "rejected",
|
|
485
|
-
status:
|
|
597
|
+
status: Ht(e),
|
|
486
598
|
detail: e.detail
|
|
487
599
|
}),
|
|
488
|
-
StorageScanRejected: (e) =>
|
|
600
|
+
StorageScanRejected: (e) => q.succeed({
|
|
489
601
|
kind: "scan",
|
|
490
602
|
threat: e.threat
|
|
491
603
|
}),
|
|
492
|
-
StorageError: (e) =>
|
|
604
|
+
StorageError: (e) => q.succeed({
|
|
493
605
|
kind: "error",
|
|
494
606
|
message: e.message,
|
|
495
607
|
status: e.status ?? 500
|
|
@@ -504,48 +616,49 @@ var lt = w.read("VOLTRO_SESSION_COOKIE") ?? "voltro:session", K, ut = (e) => {
|
|
|
504
616
|
size: o.ref.size
|
|
505
617
|
}),
|
|
506
618
|
contentType: "application/json",
|
|
507
|
-
headers:
|
|
619
|
+
headers: t
|
|
508
620
|
} : o.kind === "rejected" ? {
|
|
509
621
|
status: o.status,
|
|
510
622
|
body: o.detail,
|
|
511
623
|
contentType: "text/plain",
|
|
512
|
-
headers:
|
|
624
|
+
headers: t
|
|
513
625
|
} : o.kind === "scan" ? {
|
|
514
626
|
status: 422,
|
|
515
627
|
body: `rejected: ${o.threat}`,
|
|
516
628
|
contentType: "text/plain",
|
|
517
|
-
headers:
|
|
629
|
+
headers: t
|
|
518
630
|
} : {
|
|
519
631
|
status: o.status,
|
|
520
632
|
body: o.message,
|
|
521
633
|
contentType: "text/plain",
|
|
522
|
-
headers:
|
|
634
|
+
headers: t
|
|
523
635
|
};
|
|
524
636
|
}
|
|
525
|
-
},
|
|
637
|
+
}, Fe = {
|
|
526
638
|
method: "*",
|
|
527
|
-
path: `${
|
|
639
|
+
path: `${i}/upload/resumable`,
|
|
528
640
|
originGuard: "exempt",
|
|
529
641
|
handle: async (e) => {
|
|
530
|
-
let
|
|
642
|
+
let t = Pt(e.headers.origin, b);
|
|
531
643
|
if (e.method === "OPTIONS") return {
|
|
532
644
|
status: 204,
|
|
533
|
-
headers:
|
|
645
|
+
headers: t
|
|
534
646
|
};
|
|
535
|
-
let
|
|
536
|
-
if (!i || i.instance !==
|
|
647
|
+
let n = new URLSearchParams(e.query || ""), i = xe(n.get("token") ?? "");
|
|
648
|
+
if (!i || i.instance !== r) return {
|
|
537
649
|
status: 401,
|
|
538
650
|
body: "invalid or expired resumable token",
|
|
539
651
|
contentType: "text/plain",
|
|
540
|
-
headers:
|
|
652
|
+
headers: t
|
|
541
653
|
};
|
|
542
|
-
let a = await
|
|
654
|
+
let a = await L(i, t);
|
|
543
655
|
if (a) return a;
|
|
544
656
|
if (e.method === "GET" || e.method === "HEAD") {
|
|
545
|
-
let e = await
|
|
657
|
+
let e = await q.runPromise(F.resumableStatus({
|
|
546
658
|
uploadId: i.id,
|
|
547
|
-
tenantId: i.tenant
|
|
548
|
-
|
|
659
|
+
tenantId: i.tenant,
|
|
660
|
+
destination: i.destination
|
|
661
|
+
}).pipe(q.match({
|
|
549
662
|
onFailure: (e) => ({ error: e.message }),
|
|
550
663
|
onSuccess: (e) => e
|
|
551
664
|
})));
|
|
@@ -553,13 +666,13 @@ var lt = w.read("VOLTRO_SESSION_COOKIE") ?? "voltro:session", K, ut = (e) => {
|
|
|
553
666
|
status: 500,
|
|
554
667
|
body: e.error,
|
|
555
668
|
contentType: "text/plain",
|
|
556
|
-
headers:
|
|
669
|
+
headers: t
|
|
557
670
|
} : {
|
|
558
671
|
status: 200,
|
|
559
672
|
body: JSON.stringify(e),
|
|
560
673
|
contentType: "application/json",
|
|
561
674
|
headers: {
|
|
562
|
-
...
|
|
675
|
+
...t,
|
|
563
676
|
"upload-offset": String(e.offset)
|
|
564
677
|
}
|
|
565
678
|
};
|
|
@@ -568,28 +681,30 @@ var lt = w.read("VOLTRO_SESSION_COOKIE") ?? "voltro:session", K, ut = (e) => {
|
|
|
568
681
|
status: 405,
|
|
569
682
|
body: "method not allowed",
|
|
570
683
|
contentType: "text/plain",
|
|
571
|
-
headers:
|
|
684
|
+
headers: t
|
|
572
685
|
};
|
|
573
|
-
let o = Number(
|
|
686
|
+
let o = Number(n.get("index"));
|
|
574
687
|
if (!Number.isInteger(o) || o < 0) return {
|
|
575
688
|
status: 400,
|
|
576
689
|
body: "missing/invalid chunk index",
|
|
577
690
|
contentType: "text/plain",
|
|
578
|
-
headers:
|
|
691
|
+
headers: t
|
|
579
692
|
};
|
|
580
693
|
if (e.rawBody.length === 0) return {
|
|
581
694
|
status: 400,
|
|
582
695
|
body: "empty chunk",
|
|
583
696
|
contentType: "text/plain",
|
|
584
|
-
headers:
|
|
697
|
+
headers: t
|
|
585
698
|
};
|
|
586
|
-
let
|
|
699
|
+
let s = n.get("final") === "1", c = await q.runPromise(F.putResumableChunk({
|
|
587
700
|
uploadId: i.id,
|
|
588
701
|
tenantId: i.tenant,
|
|
702
|
+
destination: i.destination,
|
|
589
703
|
index: o,
|
|
590
704
|
bytes: e.rawBody
|
|
591
|
-
}).pipe(
|
|
705
|
+
}).pipe(q.flatMap(() => s ? F.finalizeResumable({
|
|
592
706
|
uploadId: i.id,
|
|
707
|
+
destination: i.destination,
|
|
593
708
|
count: o + 1,
|
|
594
709
|
contentType: i.ct,
|
|
595
710
|
tenantId: i.tenant,
|
|
@@ -600,111 +715,120 @@ var lt = w.read("VOLTRO_SESSION_COOKIE") ?? "voltro:session", K, ut = (e) => {
|
|
|
600
715
|
...i.tags === void 0 ? {} : { tags: i.tags },
|
|
601
716
|
...i.alt === void 0 ? {} : { alt: i.alt },
|
|
602
717
|
...i.caption === void 0 ? {} : { caption: i.caption }
|
|
603
|
-
}).pipe(
|
|
718
|
+
}).pipe(q.flatMap((e) => F.getUrl(e.id).pipe(q.map((t) => ({
|
|
604
719
|
kind: "done",
|
|
605
720
|
ref: e,
|
|
606
721
|
url: t
|
|
607
|
-
}))))) :
|
|
608
|
-
StorageRejected: (e) =>
|
|
722
|
+
}))))) : q.succeed({ kind: "chunk" })), q.catchTags({
|
|
723
|
+
StorageRejected: (e) => q.succeed({
|
|
609
724
|
kind: "rejected",
|
|
610
|
-
status:
|
|
725
|
+
status: Ht(e),
|
|
611
726
|
detail: e.detail
|
|
612
727
|
}),
|
|
613
|
-
StorageScanRejected: (e) =>
|
|
728
|
+
StorageScanRejected: (e) => q.succeed({
|
|
614
729
|
kind: "scan",
|
|
615
730
|
threat: e.threat
|
|
616
731
|
}),
|
|
617
|
-
StorageError: (e) =>
|
|
732
|
+
StorageError: (e) => q.succeed({
|
|
618
733
|
kind: "error",
|
|
619
734
|
message: e.message,
|
|
620
735
|
status: e.status ?? 500
|
|
621
736
|
})
|
|
622
737
|
})));
|
|
623
|
-
return
|
|
738
|
+
return c.kind === "chunk" ? {
|
|
624
739
|
status: 204,
|
|
625
740
|
headers: {
|
|
626
|
-
...
|
|
741
|
+
...t,
|
|
627
742
|
"upload-offset": String(o + 1)
|
|
628
743
|
}
|
|
629
|
-
} :
|
|
744
|
+
} : c.kind === "done" ? {
|
|
630
745
|
status: 201,
|
|
631
746
|
body: JSON.stringify({
|
|
632
|
-
id:
|
|
633
|
-
url:
|
|
634
|
-
contentType:
|
|
635
|
-
size:
|
|
747
|
+
id: c.ref.id,
|
|
748
|
+
url: c.url,
|
|
749
|
+
contentType: c.ref.contentType,
|
|
750
|
+
size: c.ref.size
|
|
636
751
|
}),
|
|
637
752
|
contentType: "application/json",
|
|
638
|
-
headers:
|
|
639
|
-
} :
|
|
640
|
-
status:
|
|
641
|
-
body:
|
|
753
|
+
headers: t
|
|
754
|
+
} : c.kind === "rejected" ? {
|
|
755
|
+
status: c.status,
|
|
756
|
+
body: c.detail,
|
|
642
757
|
contentType: "text/plain",
|
|
643
|
-
headers:
|
|
644
|
-
} :
|
|
758
|
+
headers: t
|
|
759
|
+
} : c.kind === "scan" ? {
|
|
645
760
|
status: 422,
|
|
646
|
-
body: `rejected: ${
|
|
761
|
+
body: `rejected: ${c.threat}`,
|
|
647
762
|
contentType: "text/plain",
|
|
648
|
-
headers:
|
|
763
|
+
headers: t
|
|
649
764
|
} : {
|
|
650
|
-
status:
|
|
651
|
-
body:
|
|
765
|
+
status: c.status,
|
|
766
|
+
body: c.message,
|
|
652
767
|
contentType: "text/plain",
|
|
653
|
-
headers:
|
|
768
|
+
headers: t
|
|
654
769
|
};
|
|
655
770
|
}
|
|
656
|
-
},
|
|
771
|
+
}, U = (e) => ({
|
|
657
772
|
kind: "json",
|
|
658
773
|
data: e
|
|
659
|
-
}),
|
|
774
|
+
}), W = (e, t) => ({
|
|
660
775
|
kind: "json",
|
|
661
776
|
status: e,
|
|
662
777
|
data: { error: t }
|
|
663
|
-
}),
|
|
778
|
+
}), G = (e, t) => {
|
|
664
779
|
try {
|
|
665
780
|
return new URL(e, "http://localhost").searchParams.get(t);
|
|
666
781
|
} catch {
|
|
667
782
|
return null;
|
|
668
783
|
}
|
|
669
|
-
},
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
storageInstance:
|
|
784
|
+
}, K = q.gen(function* () {
|
|
785
|
+
let e = yield* M.catalogueId;
|
|
786
|
+
return p ? {
|
|
787
|
+
catalogueId: e,
|
|
788
|
+
storageInstance: r,
|
|
789
|
+
tenantScoped: !0
|
|
790
|
+
} : {
|
|
791
|
+
catalogueId: e,
|
|
792
|
+
objectNamespace: yield* m.objectNamespace,
|
|
793
|
+
storageInstance: r
|
|
674
794
|
};
|
|
675
|
-
}),
|
|
795
|
+
}), et = [
|
|
676
796
|
{
|
|
677
797
|
method: "POST",
|
|
678
798
|
path: "/upload-ticket",
|
|
679
799
|
description: "Authorize a binary upload with explicit tenant and owner attribution",
|
|
680
|
-
handler: (
|
|
681
|
-
let
|
|
682
|
-
operationId:
|
|
683
|
-
tenantId:
|
|
684
|
-
ownerId:
|
|
685
|
-
key:
|
|
686
|
-
contentType:
|
|
687
|
-
size:
|
|
688
|
-
visibility:
|
|
689
|
-
})))(
|
|
800
|
+
handler: (t) => q.gen(function* () {
|
|
801
|
+
let n = J.String.pipe(J.check(J.makeFilter((e) => e.trim().length > 0))), a = yield* J.decodeUnknownEffect(J.fromJsonString(J.Struct({
|
|
802
|
+
operationId: J.optional(n.pipe(J.check(J.isMaxLength(200)))),
|
|
803
|
+
tenantId: J.NullOr(n),
|
|
804
|
+
ownerId: J.NullOr(n),
|
|
805
|
+
key: n.pipe(J.check(J.isMaxLength(1024))),
|
|
806
|
+
contentType: n.pipe(J.check(J.isMaxLength(255)), J.check(J.makeFilter((e) => !/[\r\n]/.test(e)))),
|
|
807
|
+
size: J.Number.pipe(J.check(J.isInt()), J.check(J.isGreaterThan(0)), J.check(J.makeFilter(Number.isSafeInteger))),
|
|
808
|
+
visibility: J.optional(J.Literals(["public", "private"]))
|
|
809
|
+
})))(t.body).pipe(q.mapError(() => new g({
|
|
690
810
|
provider: "inspect",
|
|
691
811
|
message: "Provide explicit tenantId and ownerId (or null), key, contentType and a positive file size",
|
|
692
812
|
transient: !1,
|
|
693
813
|
status: 400
|
|
694
814
|
})));
|
|
695
|
-
if (a.operationId !== void 0 &&
|
|
696
|
-
if (
|
|
697
|
-
let o = a.operationId ?? (
|
|
815
|
+
if (a.operationId !== void 0 && A.current === void 0) return W(409, "Durable uploads require a bound operation store with default reference and grant stores");
|
|
816
|
+
if (x !== void 0 && a.size > x) return W(413, "File exceeds the configured upload limit");
|
|
817
|
+
let o = yield* _.select(a.tenantId), s = a.operationId ?? (A.current === void 0 ? void 0 : ht()), c = s === void 0 ? void 0 : "inspect-upload:" + mt("sha256").update(JSON.stringify([r, s])).digest("hex"), l = a.visibility !== "public" && Array.isArray(e.uploadAccess) ? yield* J.decodeUnknownEffect(vt)(e.uploadAccess, { onExcessProperty: "error" }).pipe(q.mapError(() => new g({
|
|
698
818
|
provider: "storage",
|
|
699
819
|
message: "Invalid upload access policy",
|
|
700
820
|
transient: !1,
|
|
701
821
|
status: 400
|
|
702
|
-
}))) : void 0, u = yield*
|
|
822
|
+
}))) : void 0, u = yield* F.uploadTicketScope({
|
|
823
|
+
tenantId: a.tenantId,
|
|
824
|
+
destination: o.destination
|
|
825
|
+
}), d = z({
|
|
703
826
|
writeScope: u,
|
|
704
|
-
instance:
|
|
705
|
-
|
|
827
|
+
instance: r,
|
|
828
|
+
destination: o.destination,
|
|
829
|
+
issuerReplicaId: _t().replicaId,
|
|
706
830
|
...l === void 0 ? {} : { access: l },
|
|
707
|
-
...
|
|
831
|
+
...c === void 0 ? {} : { operationId: c },
|
|
708
832
|
sub: a.ownerId,
|
|
709
833
|
tenant: a.tenantId,
|
|
710
834
|
ct: a.contentType,
|
|
@@ -712,33 +836,33 @@ var lt = w.read("VOLTRO_SESSION_COOKIE") ?? "voltro:session", K, ut = (e) => {
|
|
|
712
836
|
vis: a.visibility ?? "private",
|
|
713
837
|
max: a.size
|
|
714
838
|
}, 300);
|
|
715
|
-
return
|
|
716
|
-
uploadPath: `${
|
|
839
|
+
return U({
|
|
840
|
+
uploadPath: `${i}/upload?ticket=${encodeURIComponent(d)}`,
|
|
717
841
|
expiresInSec: 300,
|
|
718
842
|
maxBytes: a.size,
|
|
719
|
-
...
|
|
843
|
+
...s === void 0 ? {} : { operationId: s }
|
|
720
844
|
});
|
|
721
|
-
}).pipe(
|
|
845
|
+
}).pipe(q.catch((e) => q.succeed(W(e.status ?? 500, e.message))))
|
|
722
846
|
},
|
|
723
847
|
{
|
|
724
848
|
method: "GET",
|
|
725
849
|
path: "/download",
|
|
726
850
|
description: "Stream a stored file as an attachment for authorized inspect readers",
|
|
727
|
-
handler: (e) =>
|
|
728
|
-
let t =
|
|
729
|
-
if (!t?.trim()) return
|
|
730
|
-
let { ref: n, stream: r } = yield*
|
|
851
|
+
handler: (e) => q.gen(function* () {
|
|
852
|
+
let t = G(e.url, "refId");
|
|
853
|
+
if (!t?.trim()) return W(400, "A non-empty refId is required");
|
|
854
|
+
let { ref: n, stream: r } = yield* F.getStream(t), i = n.key.split("/").pop() || n.id, a = encodeURIComponent(i).replace(/[!'()*]/g, (e) => `%${e.charCodeAt(0).toString(16).toUpperCase()}`);
|
|
731
855
|
return {
|
|
732
856
|
kind: "bytes",
|
|
733
857
|
contentType: n.contentType,
|
|
734
858
|
byteStream: {
|
|
735
|
-
stream: () =>
|
|
859
|
+
stream: () => pt.toReadableStream(r),
|
|
736
860
|
contentLength: n.size,
|
|
737
861
|
contentDisposition: `attachment; filename="download"; filename*=UTF-8''${a}`
|
|
738
862
|
},
|
|
739
863
|
headers: { "cache-control": "no-store" }
|
|
740
864
|
};
|
|
741
|
-
}).pipe(
|
|
865
|
+
}).pipe(q.catch((e) => q.succeed(W(e.status ?? 500, e.message))))
|
|
742
866
|
},
|
|
743
867
|
{
|
|
744
868
|
method: "GET",
|
|
@@ -746,8 +870,8 @@ var lt = w.read("VOLTRO_SESSION_COOKIE") ?? "voltro:session", K, ut = (e) => {
|
|
|
746
870
|
scope: "process",
|
|
747
871
|
description: "Searchable storage refs, newest first, paginated",
|
|
748
872
|
handler: (e) => {
|
|
749
|
-
let t = Number(
|
|
750
|
-
return
|
|
873
|
+
let t = Number(G(e.url, "offset") ?? 0), n = Number.isSafeInteger(t) && t >= 0 ? t : 0, r = (G(e.url, "search") ?? "").trim().slice(0, 200);
|
|
874
|
+
return M.listRefs({
|
|
751
875
|
tenantId: void 0,
|
|
752
876
|
ownerId: void 0,
|
|
753
877
|
folder: void 0,
|
|
@@ -756,15 +880,15 @@ var lt = w.read("VOLTRO_SESSION_COOKIE") ?? "voltro:session", K, ut = (e) => {
|
|
|
756
880
|
search: r,
|
|
757
881
|
limit: 51,
|
|
758
882
|
offset: n
|
|
759
|
-
}).pipe(
|
|
883
|
+
}).pipe(q.flatMap((e) => K.pipe(q.map((t) => U({
|
|
760
884
|
source: t,
|
|
761
|
-
refs: e.slice(0, 50).map(
|
|
885
|
+
refs: e.slice(0, 50).map(Ft),
|
|
762
886
|
page: {
|
|
763
887
|
search: r,
|
|
764
888
|
offset: n,
|
|
765
889
|
nextOffset: e.length > 50 ? n + 50 : null
|
|
766
890
|
}
|
|
767
|
-
})))),
|
|
891
|
+
})))), q.catch((e) => q.succeed(W(500, e.message))));
|
|
768
892
|
}
|
|
769
893
|
},
|
|
770
894
|
{
|
|
@@ -772,12 +896,12 @@ var lt = w.read("VOLTRO_SESSION_COOKIE") ?? "voltro:session", K, ut = (e) => {
|
|
|
772
896
|
path: "/stats",
|
|
773
897
|
scope: "process",
|
|
774
898
|
description: "Object count + total bytes per tenant + visibility split",
|
|
775
|
-
handler: () =>
|
|
899
|
+
handler: () => M.statistics().pipe(q.flatMap((e) => K.pipe(q.map((t) => U({
|
|
776
900
|
source: t,
|
|
777
|
-
provider:
|
|
778
|
-
bucket:
|
|
901
|
+
provider: p ? "tenant-scoped" : m.name,
|
|
902
|
+
bucket: h,
|
|
779
903
|
...e
|
|
780
|
-
})))),
|
|
904
|
+
})))), q.catch((e) => q.succeed(W(500, e.message))))
|
|
781
905
|
},
|
|
782
906
|
{
|
|
783
907
|
method: "GET",
|
|
@@ -785,196 +909,202 @@ var lt = w.read("VOLTRO_SESSION_COOKIE") ?? "voltro:session", K, ut = (e) => {
|
|
|
785
909
|
scope: "process",
|
|
786
910
|
description: "Grants for a ref (?refId=…)",
|
|
787
911
|
handler: (e) => {
|
|
788
|
-
let t =
|
|
789
|
-
return t ?
|
|
912
|
+
let t = G(e.url, "refId");
|
|
913
|
+
return t ? N.listByRef(t).pipe(q.map((e) => U({ grants: e.map(Bt) })), q.catch((e) => q.succeed(W(500, e.message)))) : q.succeed(W(400, "refId query param required"));
|
|
790
914
|
}
|
|
791
915
|
},
|
|
792
916
|
{
|
|
793
917
|
method: "POST",
|
|
794
918
|
path: "/share",
|
|
795
919
|
description: "Grant a principal access to a ref",
|
|
796
|
-
handler: (e) =>
|
|
797
|
-
let t = yield*
|
|
798
|
-
refId:
|
|
799
|
-
principalType:
|
|
920
|
+
handler: (e) => q.gen(function* () {
|
|
921
|
+
let t = yield* J.decodeUnknownEffect(J.fromJsonString(J.Struct({
|
|
922
|
+
refId: J.String.pipe(J.check(J.makeFilter((e) => e.trim().length > 0))),
|
|
923
|
+
principalType: J.Literals([
|
|
800
924
|
"user",
|
|
801
925
|
"group",
|
|
802
926
|
"apiKey"
|
|
803
927
|
]),
|
|
804
|
-
principalId:
|
|
805
|
-
permission:
|
|
806
|
-
expiresInDays:
|
|
807
|
-
})))(e.body).pipe(
|
|
928
|
+
principalId: J.String.pipe(J.check(J.makeFilter((e) => e.trim().length > 0))),
|
|
929
|
+
permission: J.optional(J.Literals(["read", "write"])),
|
|
930
|
+
expiresInDays: J.optional(J.Number.pipe(J.check(J.isFinite()), J.check(J.isGreaterThan(0))))
|
|
931
|
+
})))(e.body).pipe(q.mapError(() => new g({
|
|
808
932
|
provider: "inspect",
|
|
809
933
|
message: "Invalid share input: provide refId, principalType, principalId, read/write permission and a positive finite expiry if set",
|
|
810
934
|
transient: !1,
|
|
811
935
|
status: 400
|
|
812
936
|
}))), n = t.expiresInDays === void 0 ? null : new Date(Date.now() + t.expiresInDays * 864e5);
|
|
813
|
-
if (n !== null && !Number.isFinite(n.getTime())) return
|
|
814
|
-
let r = yield*
|
|
937
|
+
if (n !== null && !Number.isFinite(n.getTime())) return W(400, "Expiry exceeds the supported date range");
|
|
938
|
+
let r = yield* F.grant({
|
|
815
939
|
refId: t.refId,
|
|
816
940
|
principalType: t.principalType,
|
|
817
941
|
principalId: t.principalId,
|
|
818
942
|
...t.permission ? { permission: t.permission } : {},
|
|
819
943
|
expiresAt: n
|
|
820
944
|
});
|
|
821
|
-
return
|
|
822
|
-
}).pipe(
|
|
945
|
+
return U({ grant: Bt(r) });
|
|
946
|
+
}).pipe(q.catch((e) => q.succeed(W(e.status ?? 500, e.message ?? "share failed"))))
|
|
823
947
|
},
|
|
824
948
|
{
|
|
825
949
|
method: "POST",
|
|
826
950
|
path: "/delete",
|
|
827
951
|
description: "Delete an object reference and its grants; release unreferenced bytes",
|
|
828
|
-
handler: (e) =>
|
|
829
|
-
let t = yield*
|
|
952
|
+
handler: (e) => q.gen(function* () {
|
|
953
|
+
let t = yield* J.decodeUnknownEffect(J.fromJsonString(J.Struct({ refId: J.String.pipe(J.check(J.makeFilter((e) => e.trim().length > 0))) })))(e.body).pipe(q.mapError(() => new g({
|
|
830
954
|
provider: "inspect",
|
|
831
955
|
message: "A non-empty refId is required",
|
|
832
956
|
transient: !1,
|
|
833
957
|
status: 400
|
|
834
958
|
})));
|
|
835
|
-
return yield*
|
|
836
|
-
}).pipe(
|
|
959
|
+
return yield* F.delete(t.refId), U({ ok: !0 });
|
|
960
|
+
}).pipe(q.catch((e) => q.succeed(W(e.status ?? 500, e.message))))
|
|
837
961
|
},
|
|
838
962
|
{
|
|
839
963
|
method: "POST",
|
|
840
964
|
path: "/revoke",
|
|
841
965
|
description: "Revoke a grant by id",
|
|
842
|
-
handler: (e) =>
|
|
843
|
-
let t = yield*
|
|
966
|
+
handler: (e) => q.gen(function* () {
|
|
967
|
+
let t = yield* J.decodeUnknownEffect(J.fromJsonString(J.Struct({ grantId: J.String.pipe(J.check(J.makeFilter((e) => e.trim().length > 0))) })))(e.body).pipe(q.mapError(() => new g({
|
|
844
968
|
provider: "inspect",
|
|
845
969
|
message: "A non-empty grantId is required",
|
|
846
970
|
transient: !1,
|
|
847
971
|
status: 400
|
|
848
972
|
})));
|
|
849
|
-
return yield*
|
|
850
|
-
}).pipe(
|
|
973
|
+
return yield* F.revoke(t.grantId), U({ ok: !0 });
|
|
974
|
+
}).pipe(q.catch((e) => q.succeed(W(e.status ?? 500, e.message ?? "revoke failed"))))
|
|
851
975
|
}
|
|
852
|
-
],
|
|
976
|
+
], tt = [
|
|
853
977
|
{
|
|
854
|
-
...
|
|
978
|
+
...Je,
|
|
855
979
|
execute: (e, t) => {
|
|
856
980
|
let n = e;
|
|
857
|
-
return
|
|
981
|
+
return F.mintUrl(n.id, t.request.subject, {
|
|
858
982
|
...n.password === void 0 ? {} : { password: n.password },
|
|
859
983
|
...n.expiresInSec === void 0 ? {} : { expiresInSec: n.expiresInSec }
|
|
860
|
-
}).pipe(
|
|
984
|
+
}).pipe(q.map((e) => ({ url: e })));
|
|
861
985
|
}
|
|
862
986
|
},
|
|
863
987
|
{
|
|
864
|
-
...
|
|
988
|
+
...qe,
|
|
865
989
|
execute: (e, t) => {
|
|
866
990
|
let n = e;
|
|
867
|
-
return
|
|
991
|
+
return F.mintUploadUrl({
|
|
868
992
|
key: n.key,
|
|
869
993
|
contentType: n.contentType,
|
|
870
994
|
tenantId: t.request.subject.tenantId,
|
|
871
995
|
...n.expiresInSec === void 0 ? {} : { expiresInSec: n.expiresInSec }
|
|
872
|
-
}).pipe(
|
|
996
|
+
}).pipe(q.map((e) => ({ url: e })));
|
|
873
997
|
}
|
|
874
998
|
},
|
|
875
999
|
{
|
|
876
|
-
...
|
|
877
|
-
execute: (e,
|
|
878
|
-
let
|
|
879
|
-
return Z(
|
|
1000
|
+
...Ke,
|
|
1001
|
+
execute: (e, t) => {
|
|
1002
|
+
let n = e;
|
|
1003
|
+
return Z(t, S).pipe(q.flatMap((e) => D(n, t.request.subject).pipe(q.map((t) => ({
|
|
880
1004
|
writer: e,
|
|
881
1005
|
policy: t
|
|
882
|
-
})))),
|
|
1006
|
+
})))), q.flatMap((e) => n.operationId !== void 0 && A.current === void 0 ? q.fail(new g({
|
|
883
1007
|
provider: "storage",
|
|
884
1008
|
message: "Durable uploads require a bound operation store with default reference and grant stores",
|
|
885
1009
|
transient: !1,
|
|
886
1010
|
status: 409
|
|
887
|
-
})) :
|
|
888
|
-
|
|
889
|
-
|
|
1011
|
+
})) : q.succeed(e)), q.flatMap(({ writer: e, policy: t }) => _.select(e.tenantId).pipe(q.flatMap((a) => F.uploadTicketScope({
|
|
1012
|
+
tenantId: e.tenantId,
|
|
1013
|
+
destination: a.destination
|
|
1014
|
+
}).pipe(q.map((o) => {
|
|
1015
|
+
let s = n.expiresInSec ?? 900, c = n.operationId ?? (A.current === void 0 ? void 0 : ht()), l = c === void 0 ? void 0 : "client-upload:" + mt("sha256").update(JSON.stringify([
|
|
1016
|
+
r,
|
|
890
1017
|
e.tenantId,
|
|
891
1018
|
e.id,
|
|
892
|
-
|
|
893
|
-
])).digest("hex"),
|
|
894
|
-
writeScope:
|
|
895
|
-
instance:
|
|
896
|
-
|
|
1019
|
+
c
|
|
1020
|
+
])).digest("hex"), u = z({
|
|
1021
|
+
writeScope: o,
|
|
1022
|
+
instance: r,
|
|
1023
|
+
destination: a.destination,
|
|
1024
|
+
...l === void 0 ? {} : { operationId: l },
|
|
897
1025
|
sub: e.id,
|
|
898
1026
|
tenant: e.tenantId,
|
|
899
|
-
ct:
|
|
900
|
-
vis:
|
|
901
|
-
...
|
|
902
|
-
...
|
|
903
|
-
...
|
|
904
|
-
...
|
|
905
|
-
...
|
|
906
|
-
...
|
|
907
|
-
...
|
|
1027
|
+
ct: n.contentType,
|
|
1028
|
+
vis: n.visibility ?? "private",
|
|
1029
|
+
...t,
|
|
1030
|
+
...n.key === void 0 ? {} : { key: n.key },
|
|
1031
|
+
...n.folder === void 0 ? {} : { folder: n.folder },
|
|
1032
|
+
...n.tags === void 0 ? {} : { tags: n.tags },
|
|
1033
|
+
...n.alt === void 0 ? {} : { alt: n.alt },
|
|
1034
|
+
...n.caption === void 0 ? {} : { caption: n.caption },
|
|
1035
|
+
...x === void 0 ? {} : { max: x }
|
|
908
1036
|
}, s);
|
|
909
1037
|
return {
|
|
910
|
-
uploadUrl: `${
|
|
1038
|
+
uploadUrl: `${y ? y.replace(/\/+$/, "") : ""}${i}/upload?ticket=${encodeURIComponent(u)}`,
|
|
911
1039
|
expiresInSec: s,
|
|
912
|
-
...
|
|
1040
|
+
...c === void 0 ? {} : { operationId: c }
|
|
913
1041
|
};
|
|
914
|
-
}))));
|
|
1042
|
+
}))))));
|
|
915
1043
|
}
|
|
916
1044
|
},
|
|
917
1045
|
{
|
|
918
|
-
...
|
|
919
|
-
execute: (e,
|
|
920
|
-
let
|
|
921
|
-
return Z(
|
|
1046
|
+
...Ge,
|
|
1047
|
+
execute: (e, t) => {
|
|
1048
|
+
let n = e;
|
|
1049
|
+
return Z(t, S).pipe(q.flatMap((e) => D(n, t.request.subject).pipe(q.map((t) => ({
|
|
922
1050
|
writer: e,
|
|
923
1051
|
policy: t
|
|
924
|
-
})))),
|
|
925
|
-
contentType:
|
|
1052
|
+
})))), q.flatMap(({ writer: e, policy: t }) => F.mintPresignedUpload({
|
|
1053
|
+
contentType: n.contentType,
|
|
926
1054
|
tenantId: e.tenantId,
|
|
927
|
-
...
|
|
928
|
-
}).pipe(
|
|
929
|
-
let
|
|
930
|
-
writeScope: i,
|
|
931
|
-
instance:
|
|
932
|
-
|
|
1055
|
+
...n.expiresInSec === void 0 ? {} : { expiresInSec: n.expiresInSec }
|
|
1056
|
+
}).pipe(q.map((i) => {
|
|
1057
|
+
let a = ge({
|
|
1058
|
+
writeScope: i.writeScope,
|
|
1059
|
+
instance: r,
|
|
1060
|
+
destination: i.destination,
|
|
1061
|
+
key: i.key,
|
|
933
1062
|
sub: e.id,
|
|
934
1063
|
tenant: e.tenantId,
|
|
935
|
-
ct:
|
|
936
|
-
vis:
|
|
937
|
-
...
|
|
938
|
-
...
|
|
939
|
-
...
|
|
940
|
-
...
|
|
941
|
-
...
|
|
942
|
-
...
|
|
943
|
-
},
|
|
1064
|
+
ct: n.contentType,
|
|
1065
|
+
vis: n.visibility ?? "private",
|
|
1066
|
+
...t,
|
|
1067
|
+
...n.folder === void 0 ? {} : { folder: n.folder },
|
|
1068
|
+
...n.tags === void 0 ? {} : { tags: n.tags },
|
|
1069
|
+
...n.alt === void 0 ? {} : { alt: n.alt },
|
|
1070
|
+
...n.caption === void 0 ? {} : { caption: n.caption },
|
|
1071
|
+
...x === void 0 ? {} : { max: x }
|
|
1072
|
+
}, i.expiresInSec);
|
|
944
1073
|
return {
|
|
945
|
-
uploadUrl:
|
|
946
|
-
finalizeToken:
|
|
947
|
-
expiresInSec:
|
|
1074
|
+
uploadUrl: i.uploadUrl,
|
|
1075
|
+
finalizeToken: a,
|
|
1076
|
+
expiresInSec: i.expiresInSec
|
|
948
1077
|
};
|
|
949
|
-
}))))
|
|
1078
|
+
}))));
|
|
950
1079
|
}
|
|
951
1080
|
},
|
|
952
1081
|
{
|
|
953
|
-
...
|
|
954
|
-
execute: (e,
|
|
955
|
-
let
|
|
956
|
-
return !
|
|
1082
|
+
...Ve,
|
|
1083
|
+
execute: (e, t) => {
|
|
1084
|
+
let n = ye(e.finalizeToken);
|
|
1085
|
+
return !n || n.instance !== r ? q.fail(new g({
|
|
957
1086
|
provider: "storage",
|
|
958
1087
|
message: "invalid or expired finalize token",
|
|
959
1088
|
transient: !1,
|
|
960
1089
|
status: 401
|
|
961
|
-
})) :
|
|
1090
|
+
})) : zt(n.sub, t.request.subject.id) ? q.fail(new g({
|
|
962
1091
|
provider: "storage",
|
|
963
1092
|
message: "finalize token belongs to another subject",
|
|
964
1093
|
transient: !1,
|
|
965
1094
|
status: 403
|
|
966
|
-
})) :
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
...
|
|
974
|
-
...
|
|
975
|
-
...
|
|
976
|
-
...
|
|
977
|
-
|
|
1095
|
+
})) : I(n).pipe(q.flatMap(() => F.finalizeUpload({
|
|
1096
|
+
destination: n.destination,
|
|
1097
|
+
key: n.key,
|
|
1098
|
+
contentType: n.ct,
|
|
1099
|
+
tenantId: n.tenant,
|
|
1100
|
+
ownerId: n.sub,
|
|
1101
|
+
visibility: n.vis,
|
|
1102
|
+
...n.access === void 0 ? {} : { access: n.access },
|
|
1103
|
+
...n.folder === void 0 ? {} : { folder: n.folder },
|
|
1104
|
+
...n.tags === void 0 ? {} : { tags: n.tags },
|
|
1105
|
+
...n.alt === void 0 ? {} : { alt: n.alt },
|
|
1106
|
+
...n.caption === void 0 ? {} : { caption: n.caption }
|
|
1107
|
+
}).pipe(q.flatMap((e) => F.getUrl(e.id).pipe(q.map((t) => ({
|
|
978
1108
|
id: e.id,
|
|
979
1109
|
url: t,
|
|
980
1110
|
contentType: e.contentType,
|
|
@@ -985,112 +1115,120 @@ var lt = w.read("VOLTRO_SESSION_COOKIE") ?? "voltro:session", K, ut = (e) => {
|
|
|
985
1115
|
}
|
|
986
1116
|
},
|
|
987
1117
|
{
|
|
988
|
-
...
|
|
989
|
-
execute: (e,
|
|
990
|
-
let
|
|
991
|
-
return Z(
|
|
1118
|
+
...ze,
|
|
1119
|
+
execute: (e, t) => {
|
|
1120
|
+
let n = e;
|
|
1121
|
+
return Z(t, S).pipe(q.flatMap((e) => D(n, t.request.subject).pipe(q.map((t) => ({
|
|
992
1122
|
writer: e,
|
|
993
1123
|
policy: t
|
|
994
|
-
})))),
|
|
995
|
-
|
|
1124
|
+
})))), q.flatMap(({ writer: e, policy: t }) => _.select(e.tenantId).pipe(q.flatMap((a) => F.uploadTicketScope({
|
|
1125
|
+
tenantId: e.tenantId,
|
|
1126
|
+
destination: a.destination
|
|
1127
|
+
}).pipe(q.map((o) => {
|
|
1128
|
+
let s = n.expiresInSec ?? ce, c = ht(), l = n.chunkSize && n.chunkSize > 0 ? n.chunkSize : C;
|
|
996
1129
|
return {
|
|
997
|
-
uploadId:
|
|
998
|
-
resumableToken:
|
|
999
|
-
writeScope:
|
|
1000
|
-
instance:
|
|
1001
|
-
|
|
1130
|
+
uploadId: c,
|
|
1131
|
+
resumableToken: ve({
|
|
1132
|
+
writeScope: o,
|
|
1133
|
+
instance: r,
|
|
1134
|
+
destination: a.destination,
|
|
1135
|
+
id: c,
|
|
1002
1136
|
sub: e.id,
|
|
1003
1137
|
tenant: e.tenantId,
|
|
1004
|
-
ct:
|
|
1005
|
-
vis:
|
|
1006
|
-
...
|
|
1007
|
-
size:
|
|
1008
|
-
...
|
|
1009
|
-
...
|
|
1010
|
-
...
|
|
1011
|
-
...
|
|
1012
|
-
...
|
|
1138
|
+
ct: n.contentType,
|
|
1139
|
+
vis: n.visibility ?? "private",
|
|
1140
|
+
...t,
|
|
1141
|
+
size: n.size,
|
|
1142
|
+
...n.folder === void 0 ? {} : { folder: n.folder },
|
|
1143
|
+
...n.tags === void 0 ? {} : { tags: n.tags },
|
|
1144
|
+
...n.alt === void 0 ? {} : { alt: n.alt },
|
|
1145
|
+
...n.caption === void 0 ? {} : { caption: n.caption },
|
|
1146
|
+
...x === void 0 ? {} : { max: x }
|
|
1013
1147
|
}, s),
|
|
1014
|
-
uploadUrl: `${
|
|
1015
|
-
chunkSize:
|
|
1148
|
+
uploadUrl: `${y ? y.replace(/\/+$/, "") : ""}${i}/upload/resumable`,
|
|
1149
|
+
chunkSize: l,
|
|
1016
1150
|
expiresInSec: s
|
|
1017
1151
|
};
|
|
1018
|
-
}))));
|
|
1152
|
+
}))))));
|
|
1019
1153
|
}
|
|
1020
1154
|
},
|
|
1021
1155
|
{
|
|
1022
|
-
...
|
|
1023
|
-
execute: (e,
|
|
1024
|
-
let
|
|
1025
|
-
return Z(
|
|
1156
|
+
...Re,
|
|
1157
|
+
execute: (e, t) => {
|
|
1158
|
+
let n = e, i = n.expiresInSec ?? ce;
|
|
1159
|
+
return Z(t, S).pipe(q.flatMap((e) => D(n, t.request.subject).pipe(q.map((t) => ({
|
|
1026
1160
|
writer: e,
|
|
1027
1161
|
policy: t
|
|
1028
|
-
})))),
|
|
1029
|
-
contentType:
|
|
1162
|
+
})))), q.flatMap(({ writer: e, policy: t }) => F.beginMultipartUpload({
|
|
1163
|
+
contentType: n.contentType,
|
|
1030
1164
|
tenantId: e.tenantId,
|
|
1031
|
-
visibility:
|
|
1165
|
+
visibility: n.visibility ?? "private",
|
|
1032
1166
|
expiresInSec: i
|
|
1033
|
-
}).pipe(
|
|
1034
|
-
multipartToken:
|
|
1035
|
-
writeScope: a,
|
|
1036
|
-
instance:
|
|
1037
|
-
|
|
1038
|
-
|
|
1167
|
+
}).pipe(q.map((a) => ({
|
|
1168
|
+
multipartToken: _e({
|
|
1169
|
+
writeScope: a.writeScope,
|
|
1170
|
+
instance: r,
|
|
1171
|
+
destination: a.destination,
|
|
1172
|
+
key: a.key,
|
|
1173
|
+
uploadId: a.uploadId,
|
|
1039
1174
|
sub: e.id,
|
|
1040
1175
|
tenant: e.tenantId,
|
|
1041
|
-
ct:
|
|
1042
|
-
vis:
|
|
1043
|
-
...
|
|
1044
|
-
size:
|
|
1045
|
-
...
|
|
1046
|
-
...
|
|
1047
|
-
...
|
|
1048
|
-
...
|
|
1176
|
+
ct: n.contentType,
|
|
1177
|
+
vis: n.visibility ?? "private",
|
|
1178
|
+
...t,
|
|
1179
|
+
size: n.size,
|
|
1180
|
+
...n.folder === void 0 ? {} : { folder: n.folder },
|
|
1181
|
+
...n.tags === void 0 ? {} : { tags: n.tags },
|
|
1182
|
+
...n.alt === void 0 ? {} : { alt: n.alt },
|
|
1183
|
+
...n.caption === void 0 ? {} : { caption: n.caption }
|
|
1049
1184
|
}, i),
|
|
1050
|
-
partSize:
|
|
1185
|
+
partSize: n.partSize && n.partSize >= C ? n.partSize : C,
|
|
1051
1186
|
expiresInSec: i
|
|
1052
|
-
})))))
|
|
1187
|
+
})))));
|
|
1053
1188
|
}
|
|
1054
1189
|
},
|
|
1055
1190
|
{
|
|
1056
|
-
...
|
|
1191
|
+
...Ze,
|
|
1057
1192
|
execute: (e) => {
|
|
1058
|
-
let
|
|
1059
|
-
return !
|
|
1193
|
+
let t = e, n = B(t.multipartToken);
|
|
1194
|
+
return !n || n.instance !== r ? q.fail(new g({
|
|
1060
1195
|
provider: "storage",
|
|
1061
1196
|
message: "invalid or expired multipart token",
|
|
1062
1197
|
transient: !1,
|
|
1063
1198
|
status: 401
|
|
1064
|
-
})) : !Number.isInteger(
|
|
1199
|
+
})) : !Number.isInteger(t.partNumber) || t.partNumber < 1 ? q.fail(new g({
|
|
1065
1200
|
provider: "storage",
|
|
1066
1201
|
message: "partNumber must be a positive integer",
|
|
1067
1202
|
transient: !1,
|
|
1068
1203
|
status: 400
|
|
1069
|
-
})) :
|
|
1070
|
-
key:
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1204
|
+
})) : I(n).pipe(q.flatMap(() => F.signMultipartPart({
|
|
1205
|
+
key: n.key,
|
|
1206
|
+
destination: n.destination,
|
|
1207
|
+
tenantId: n.tenant,
|
|
1208
|
+
uploadId: n.uploadId,
|
|
1209
|
+
partNumber: t.partNumber
|
|
1210
|
+
}).pipe(q.map((e) => ({ url: e })))));
|
|
1074
1211
|
}
|
|
1075
1212
|
},
|
|
1076
1213
|
{
|
|
1077
|
-
...
|
|
1078
|
-
execute: (e,
|
|
1079
|
-
let
|
|
1080
|
-
return !i || i.instance !==
|
|
1214
|
+
...Be,
|
|
1215
|
+
execute: (e, t) => {
|
|
1216
|
+
let n = e, i = B(n.multipartToken);
|
|
1217
|
+
return !i || i.instance !== r ? q.fail(new g({
|
|
1081
1218
|
provider: "storage",
|
|
1082
1219
|
message: "invalid or expired multipart token",
|
|
1083
1220
|
transient: !1,
|
|
1084
1221
|
status: 401
|
|
1085
|
-
})) :
|
|
1222
|
+
})) : zt(i.sub, t.request.subject.id) ? q.fail(new g({
|
|
1086
1223
|
provider: "storage",
|
|
1087
1224
|
message: "multipart token belongs to another subject",
|
|
1088
1225
|
transient: !1,
|
|
1089
1226
|
status: 403
|
|
1090
|
-
})) :
|
|
1227
|
+
})) : I(i).pipe(q.flatMap(() => F.completeMultipart({
|
|
1228
|
+
destination: i.destination,
|
|
1091
1229
|
key: i.key,
|
|
1092
1230
|
uploadId: i.uploadId,
|
|
1093
|
-
parts:
|
|
1231
|
+
parts: n.parts,
|
|
1094
1232
|
contentType: i.ct,
|
|
1095
1233
|
tenantId: i.tenant,
|
|
1096
1234
|
ownerId: i.sub,
|
|
@@ -1100,7 +1238,7 @@ var lt = w.read("VOLTRO_SESSION_COOKIE") ?? "voltro:session", K, ut = (e) => {
|
|
|
1100
1238
|
...i.tags === void 0 ? {} : { tags: i.tags },
|
|
1101
1239
|
...i.alt === void 0 ? {} : { alt: i.alt },
|
|
1102
1240
|
...i.caption === void 0 ? {} : { caption: i.caption }
|
|
1103
|
-
}).pipe(
|
|
1241
|
+
}).pipe(q.flatMap((e) => F.getUrl(e.id).pipe(q.map((t) => ({
|
|
1104
1242
|
id: e.id,
|
|
1105
1243
|
url: t,
|
|
1106
1244
|
size: e.size
|
|
@@ -1108,28 +1246,30 @@ var lt = w.read("VOLTRO_SESSION_COOKIE") ?? "voltro:session", K, ut = (e) => {
|
|
|
1108
1246
|
}
|
|
1109
1247
|
},
|
|
1110
1248
|
{
|
|
1111
|
-
...
|
|
1249
|
+
...Le,
|
|
1112
1250
|
execute: (e) => {
|
|
1113
|
-
let
|
|
1114
|
-
return !
|
|
1251
|
+
let t = B(e.multipartToken);
|
|
1252
|
+
return !t || t.instance !== r ? q.fail(new g({
|
|
1115
1253
|
provider: "storage",
|
|
1116
1254
|
message: "invalid or expired multipart token",
|
|
1117
1255
|
transient: !1,
|
|
1118
1256
|
status: 401
|
|
1119
|
-
})) :
|
|
1120
|
-
key:
|
|
1121
|
-
|
|
1122
|
-
|
|
1257
|
+
})) : I(t).pipe(q.flatMap(() => F.abortMultipart({
|
|
1258
|
+
key: t.key,
|
|
1259
|
+
destination: t.destination,
|
|
1260
|
+
tenantId: t.tenant,
|
|
1261
|
+
uploadId: t.uploadId
|
|
1262
|
+
}).pipe(q.as({ ok: !0 }))));
|
|
1123
1263
|
}
|
|
1124
1264
|
},
|
|
1125
1265
|
{
|
|
1126
|
-
|
|
1266
|
+
...$e,
|
|
1127
1267
|
execute: (e, t) => {
|
|
1128
1268
|
let n = e, r = new Uint8Array(Buffer.from(n.bytesBase64, "base64"));
|
|
1129
|
-
return Z(t,
|
|
1269
|
+
return Z(t, S).pipe(q.flatMap((e) => D(n, t.request.subject).pipe(q.map((t) => ({
|
|
1130
1270
|
writer: e,
|
|
1131
1271
|
policy: t
|
|
1132
|
-
})))),
|
|
1272
|
+
})))), q.flatMap(({ writer: e, policy: t }) => F.put({
|
|
1133
1273
|
bytes: r,
|
|
1134
1274
|
...t,
|
|
1135
1275
|
contentType: n.contentType,
|
|
@@ -1138,17 +1278,17 @@ var lt = w.read("VOLTRO_SESSION_COOKIE") ?? "voltro:session", K, ut = (e) => {
|
|
|
1138
1278
|
...n.visibility ? { visibility: n.visibility } : {},
|
|
1139
1279
|
...n.key ? { key: n.key } : {},
|
|
1140
1280
|
...n.password ? { password: n.password } : {}
|
|
1141
|
-
})),
|
|
1281
|
+
})), q.flatMap((e) => F.getUrl(e.id).pipe(q.map((t) => ({
|
|
1142
1282
|
id: e.id,
|
|
1143
1283
|
url: t
|
|
1144
1284
|
})))));
|
|
1145
1285
|
}
|
|
1146
1286
|
},
|
|
1147
1287
|
{
|
|
1148
|
-
...
|
|
1288
|
+
...He,
|
|
1149
1289
|
execute: (e, t) => {
|
|
1150
1290
|
let n = e;
|
|
1151
|
-
return Z(t,
|
|
1291
|
+
return Z(t, S).pipe(q.flatMap((e) => F.ingestUrl(n.url, {
|
|
1152
1292
|
tenantId: e.tenantId,
|
|
1153
1293
|
ownerId: e.id,
|
|
1154
1294
|
...n.visibility ? { visibility: n.visibility } : {},
|
|
@@ -1157,45 +1297,45 @@ var lt = w.read("VOLTRO_SESSION_COOKIE") ?? "voltro:session", K, ut = (e) => {
|
|
|
1157
1297
|
...n.alt === void 0 ? {} : { alt: n.alt },
|
|
1158
1298
|
...n.caption === void 0 ? {} : { caption: n.caption },
|
|
1159
1299
|
...n.key === void 0 ? {} : { key: n.key }
|
|
1160
|
-
})),
|
|
1300
|
+
})), q.flatMap((e) => F.getUrl(e.id).pipe(q.map((t) => ({
|
|
1161
1301
|
id: e.id,
|
|
1162
1302
|
url: t
|
|
1163
1303
|
})))));
|
|
1164
1304
|
}
|
|
1165
1305
|
},
|
|
1166
1306
|
{
|
|
1167
|
-
...
|
|
1307
|
+
...Xe,
|
|
1168
1308
|
execute: (e, t) => {
|
|
1169
1309
|
let n = e, r = n.expiresInDays ? new Date(Date.now() + n.expiresInDays * 864e5) : null;
|
|
1170
|
-
return
|
|
1310
|
+
return Lt(F, n.refId, t).pipe(q.flatMap(() => F.grant({
|
|
1171
1311
|
refId: n.refId,
|
|
1172
1312
|
principalType: n.principalType,
|
|
1173
1313
|
principalId: n.principalId,
|
|
1174
1314
|
...n.permission ? { permission: n.permission } : {},
|
|
1175
1315
|
expiresAt: r,
|
|
1176
1316
|
createdBy: t.request.subject.id
|
|
1177
|
-
})),
|
|
1317
|
+
})), q.map((e) => ({ grantId: e.id })));
|
|
1178
1318
|
}
|
|
1179
1319
|
},
|
|
1180
1320
|
{
|
|
1181
|
-
...
|
|
1321
|
+
...Ye,
|
|
1182
1322
|
execute: (e, t) => {
|
|
1183
1323
|
let n = e;
|
|
1184
|
-
return
|
|
1324
|
+
return F.getGrant(n.grantId).pipe(q.flatMap((e) => e === null ? q.fail(It()) : Lt(F, e.refId, t)), q.flatMap(() => F.revoke(n.grantId)), q.map(() => ({ ok: !0 })));
|
|
1185
1325
|
}
|
|
1186
1326
|
},
|
|
1187
1327
|
{
|
|
1188
|
-
...
|
|
1328
|
+
...Ue,
|
|
1189
1329
|
execute: (e, t) => {
|
|
1190
1330
|
let n = e;
|
|
1191
|
-
return
|
|
1331
|
+
return Lt(F, n.refId, t).pipe(q.flatMap(() => F.listGrants(n.refId)), q.map((e) => ({ grants: e.map(Bt) })));
|
|
1192
1332
|
}
|
|
1193
1333
|
},
|
|
1194
1334
|
{
|
|
1195
|
-
...
|
|
1335
|
+
...We,
|
|
1196
1336
|
execute: (e, t) => {
|
|
1197
1337
|
let n = e;
|
|
1198
|
-
return
|
|
1338
|
+
return F.listRefs({
|
|
1199
1339
|
tenantId: t.request.subject.tenantId,
|
|
1200
1340
|
...n.folder === void 0 ? {} : { folder: n.folder },
|
|
1201
1341
|
...n.tags === void 0 ? {} : { tags: n.tags },
|
|
@@ -1203,121 +1343,153 @@ var lt = w.read("VOLTRO_SESSION_COOKIE") ?? "voltro:session", K, ut = (e) => {
|
|
|
1203
1343
|
...n.includeDerived === void 0 ? {} : { includeDerived: n.includeDerived },
|
|
1204
1344
|
...n.limit === void 0 ? {} : { limit: n.limit },
|
|
1205
1345
|
...n.offset === void 0 ? {} : { offset: n.offset }
|
|
1206
|
-
}).pipe(
|
|
1207
|
-
refs: e.refs.map(
|
|
1346
|
+
}).pipe(q.map((e) => ({
|
|
1347
|
+
refs: e.refs.map(Ft),
|
|
1208
1348
|
nextOffset: e.nextOffset
|
|
1209
1349
|
})));
|
|
1210
1350
|
}
|
|
1211
1351
|
}
|
|
1212
|
-
]
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
base: $,
|
|
1352
|
+
], nt = yt({
|
|
1353
|
+
name: xt({
|
|
1354
|
+
base: Q,
|
|
1216
1355
|
alias: e.alias,
|
|
1217
1356
|
instance: e.name
|
|
1218
1357
|
}),
|
|
1219
|
-
baseName:
|
|
1358
|
+
baseName: Q,
|
|
1220
1359
|
description: "File storage — StorageService over S3 / MinIO / filesystem / memory. Public objects served direct from bucket/CDN; private objects gated by an access policy + per-object grants. Checksums, tenant key-prefixing, _voltro_storage_refs + _voltro_storage_grants, retry.",
|
|
1221
1360
|
permissions: [
|
|
1222
1361
|
"network:outbound:*",
|
|
1223
1362
|
"inspect:read",
|
|
1224
1363
|
"inspect:write"
|
|
1225
1364
|
],
|
|
1226
|
-
declaredEnv:
|
|
1227
|
-
egress:
|
|
1228
|
-
services:
|
|
1229
|
-
inspectEndpoints:
|
|
1365
|
+
declaredEnv: E.declared,
|
|
1366
|
+
egress: Mt(e),
|
|
1367
|
+
services: fe,
|
|
1368
|
+
inspectEndpoints: et,
|
|
1230
1369
|
httpRoutes: [
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1370
|
+
Ne,
|
|
1371
|
+
Pe,
|
|
1372
|
+
Fe
|
|
1234
1373
|
],
|
|
1235
|
-
routes:
|
|
1236
|
-
rpcClientDescriptors:
|
|
1374
|
+
routes: tt,
|
|
1375
|
+
rpcClientDescriptors: Qe,
|
|
1237
1376
|
errorSchemas: [
|
|
1238
1377
|
{
|
|
1239
|
-
schema:
|
|
1378
|
+
schema: g,
|
|
1240
1379
|
import: {
|
|
1241
1380
|
module: "@voltro/plugin-storage/errors",
|
|
1242
1381
|
name: "StorageError"
|
|
1243
1382
|
}
|
|
1244
1383
|
},
|
|
1245
1384
|
{
|
|
1246
|
-
schema:
|
|
1385
|
+
schema: ne,
|
|
1247
1386
|
import: {
|
|
1248
1387
|
module: "@voltro/plugin-storage/errors",
|
|
1249
1388
|
name: "StorageAccessDenied"
|
|
1250
1389
|
}
|
|
1251
1390
|
},
|
|
1252
1391
|
{
|
|
1253
|
-
schema:
|
|
1392
|
+
schema: re,
|
|
1254
1393
|
import: {
|
|
1255
1394
|
module: "@voltro/plugin-storage/errors",
|
|
1256
1395
|
name: "StorageRejected"
|
|
1257
1396
|
}
|
|
1258
1397
|
},
|
|
1259
1398
|
{
|
|
1260
|
-
schema:
|
|
1399
|
+
schema: ie,
|
|
1261
1400
|
import: {
|
|
1262
1401
|
module: "@voltro/plugin-storage/errors",
|
|
1263
1402
|
name: "StorageScanRejected"
|
|
1264
1403
|
}
|
|
1265
1404
|
}
|
|
1266
1405
|
],
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
return {
|
|
1280
|
-
url: await U.runPromise(C.getUrl(s.id, { tenantId: n })),
|
|
1281
|
-
refId: s.id
|
|
1282
|
-
};
|
|
1406
|
+
...s ? { needs: { connections: [{
|
|
1407
|
+
kind: "storage",
|
|
1408
|
+
role: "objects",
|
|
1409
|
+
optional: e.connection === void 0
|
|
1410
|
+
}] } } : {},
|
|
1411
|
+
...e.connection === void 0 ? {} : { connectionBindings: { objects: e.connection } },
|
|
1412
|
+
capabilities: {
|
|
1413
|
+
storageProvider: () => m,
|
|
1414
|
+
storageDestinations: {
|
|
1415
|
+
router: _,
|
|
1416
|
+
directDestination: e.connection === void 0 ? c : void 0,
|
|
1417
|
+
registry: () => f
|
|
1283
1418
|
},
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1419
|
+
mediaPersist: {
|
|
1420
|
+
put: async ({ bytes: e, mediaType: t, tenantId: n, operationId: r, ownerId: i, visibility: a, tags: o }) => {
|
|
1421
|
+
let s = await q.runPromise(F.put({
|
|
1422
|
+
bytes: e,
|
|
1423
|
+
contentType: t,
|
|
1424
|
+
tenantId: n,
|
|
1425
|
+
kind: "media",
|
|
1426
|
+
...i === void 0 ? {} : { ownerId: i },
|
|
1427
|
+
...a === void 0 ? {} : { visibility: a },
|
|
1428
|
+
...o === void 0 ? {} : { tags: o },
|
|
1429
|
+
...A.current === void 0 ? {} : { operationId: r }
|
|
1430
|
+
}));
|
|
1431
|
+
return {
|
|
1432
|
+
url: await q.runPromise(F.getUrl(s.id, { tenantId: n })),
|
|
1433
|
+
refId: s.id
|
|
1434
|
+
};
|
|
1435
|
+
},
|
|
1436
|
+
ingestUrl: async ({ url: e, tenantId: t, operationId: n, ownerId: r, visibility: i, tags: a }) => {
|
|
1437
|
+
let o = await q.runPromise(F.ingestUrl(e, {
|
|
1438
|
+
tenantId: t,
|
|
1439
|
+
...r === void 0 ? {} : { ownerId: r },
|
|
1440
|
+
...i === void 0 ? {} : { visibility: i },
|
|
1441
|
+
...a === void 0 ? {} : { tags: a },
|
|
1442
|
+
...A.current === void 0 ? {} : { operationId: n }
|
|
1443
|
+
}));
|
|
1444
|
+
return {
|
|
1445
|
+
url: await q.runPromise(F.getUrl(o.id, { tenantId: t })),
|
|
1446
|
+
refId: o.id
|
|
1447
|
+
};
|
|
1448
|
+
}
|
|
1296
1449
|
}
|
|
1297
|
-
} },
|
|
1298
|
-
bindDataStore: async (e) => {
|
|
1299
|
-
let r = await U.runPromise(i.objectNamespace);
|
|
1300
|
-
(f || m) && await ee(e), (f || m) && await _(e), f && await n(e), f && (g.current = Ce(e, {
|
|
1301
|
-
storageInstance: t,
|
|
1302
|
-
objectNamespace: r
|
|
1303
|
-
})), m && (v.current = Se(e, {
|
|
1304
|
-
storageInstance: t,
|
|
1305
|
-
objectNamespace: r
|
|
1306
|
-
})), f && m && (y.current = Ee(e, {
|
|
1307
|
-
storageInstance: t,
|
|
1308
|
-
objectNamespace: r
|
|
1309
|
-
})), i.bindDataStore?.(e);
|
|
1310
1450
|
},
|
|
1311
|
-
|
|
1312
|
-
let
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
}
|
|
1451
|
+
bindDataStore: async (t, n) => {
|
|
1452
|
+
let i = s ? n?.connectionReference?.("objects", "storage") || e.connection : void 0;
|
|
1453
|
+
await q.runPromise(oe(n?.connectionRegistry, i)), P = n?.storageReferenceProvider;
|
|
1454
|
+
let a = {
|
|
1455
|
+
storageInstance: r,
|
|
1456
|
+
resolveNamespace: (e) => _.resolve(e).pipe(q.flatMap((e) => e.objectNamespace))
|
|
1457
|
+
};
|
|
1458
|
+
At(m), (w || T) && await te(t), (w || T) && await se(t), (w || !p && m.name === "database") && await o(t), w && (O.current = De(t, a)), T && (k.current = Ee(t, a)), w && T && (A.current = Me(t, a), j.current = t), p || m.bindDataStore?.(t);
|
|
1459
|
+
},
|
|
1460
|
+
onActivate: (t) => q.gen(function* () {
|
|
1461
|
+
let n = s ? t.connectionReference?.("objects", "storage") || e.connection : void 0;
|
|
1462
|
+
if (yield* oe(t.connectionRegistry, n), p) {
|
|
1463
|
+
t.logger.info("storage: tenant-scoped named destination; resolved per request", { destination: h });
|
|
1464
|
+
return;
|
|
1465
|
+
}
|
|
1466
|
+
let r = !!y || !!E.read("STORAGE_CDN_URL", e.cdnBaseUrl);
|
|
1467
|
+
t.logger.info(`storage: provider=${m.name} presign=${m.presigns ? "yes" : "no"} publicUrl=${r ? "yes" : "no"} transforms=yes`, {
|
|
1468
|
+
provider: m.name,
|
|
1469
|
+
bucket: h,
|
|
1470
|
+
refStore: w ? "memory" : "custom"
|
|
1471
|
+
}), m.name === "memory" && process.env.NODE_ENV !== "test" && t.logger.warn("storage: provider=memory — uploads are IN-MEMORY and LOST on restart. Set STORAGE_PROVIDER to filesystem, s3, minio, azure or database and configure a durable destination."), !r && !m.presigns && t.logger.warn("storage: no VOLTRO_PUBLIC_URL / STORAGE_CDN_URL and this provider can't presign — serve URLs are RELATIVE and will not resolve cross-origin (browser <img> / server-to-server AI fetches). Set VOLTRO_PUBLIC_URL to this api's absolute base URL.");
|
|
1318
1472
|
}),
|
|
1319
|
-
onDeactivate: () =>
|
|
1473
|
+
onDeactivate: () => q.void
|
|
1474
|
+
});
|
|
1475
|
+
return $.set(nt, () => A.current === void 0 ? void 0 : {
|
|
1476
|
+
service: F,
|
|
1477
|
+
metadata: A.current,
|
|
1478
|
+
bucket: h
|
|
1479
|
+
}), nt;
|
|
1480
|
+
}, $ = /* @__PURE__ */ new WeakMap(), Wt = (e) => {
|
|
1481
|
+
let t = e.filter((e) => $.has(e));
|
|
1482
|
+
if (t.length !== 1) throw new g({
|
|
1483
|
+
provider: "storage",
|
|
1484
|
+
message: t.length ? "Storage objects are ambiguous; installed instances: " + t.map((e) => e.name).sort().join(", ") : "This app has no Storage plugin",
|
|
1485
|
+
transient: !1
|
|
1486
|
+
});
|
|
1487
|
+
let n = $.get(t[0])();
|
|
1488
|
+
if (n === void 0) throw new g({
|
|
1489
|
+
provider: "storage",
|
|
1490
|
+
message: "Storage objects need a bound data store with the default reference and grant stores",
|
|
1491
|
+
transient: !1
|
|
1320
1492
|
});
|
|
1493
|
+
return n;
|
|
1321
1494
|
};
|
|
1322
|
-
|
|
1323
|
-
export { i as STORAGE_BLOBS_TABLE, a as STORAGE_GRANTS_TABLE, t as STORAGE_REFERENCE_CATALOGUE_TABLE, o as STORAGE_REFS_TABLE, s as STORAGE_USAGE_TABLE, te as StorageAccessDenied, p as StorageError, ne as StorageRejected, re as StorageScanRejected, m as StorageService, c as _voltroStorageBlobsTable, l as _voltroStorageGrantsTable, u as _voltroStorageRefsTable, d as _voltroStorageUsageTable, dt as appStorageProvider, Ye as assetRef, g as assignStorageObjectNamespacesInTransaction, f as assignStorageReferenceInstancesInTransaction, T as azureProvider, xe as buildStorageService, v as bytesToStream, I as checkLimits, Ge as clamavScanner, E as clearStorageBuffer, y as collectStream, b as concatBytes, ft as configuredStorageProvider, L as contentTypeAllowed, Se as dataStoreGrantStore, Ce as dataStoreRefStore, D as databaseProvider, Ze as decodeDataUri, $e as durabilityNotice, j as editImage, Ke as encodeInstream, n as ensureStorageReferenceCatalogue, z as fetchIngestBody, Je as ffmpegTranscoder, O as filesystemProvider, x as fromNodeReadable, S as getObjectStream, M as hashPassword, Ee as makeStorageObjectMetadata, we as memoryGrantStore, k as memoryProvider, B as memoryRefStore, qe as parseClamavResponse, se as parseTransformParams, et as pathDurability, Qe as putAvatar, ie as putObjectStream, ae as readStorageBuffer, V as refMatchesListQuery, _ as requireStorageObjectNamespaces, q as resolveStorageProvider, pe as resolveStorageSecret, A as s3Provider, ut as setActiveStorageProvider, me as signFinalizeTicket, he as signGrant, ge as signMultipartTicket, _e as signResumableTicket, N as signUploadTicket, R as sniffMatches, pt as storageEgressOf, vt as storageInstanceName, h as storageObjectLifecycleTables, e as storageObjectNamespace, bt as storagePlugin, De as storagePutIntentsTable, r as storageReferenceCatalogueTable, Te as storageServiceLayer, C as toNodeReadable, ce as transformCached, le as transformFallbackReason, ue as transformImage, ve as verifyFinalizeTicket, ye as verifyGrant, P as verifyMultipartTicket, fe as verifyPassword, be as verifyResumableTicket, F as verifyUploadTicket, Xe as withStorage };
|
|
1495
|
+
export { c as STORAGE_BLOBS_TABLE, l as STORAGE_GRANTS_TABLE, a as STORAGE_REFERENCE_CATALOGUE_TABLE, u as STORAGE_REFS_TABLE, d as STORAGE_USAGE_TABLE, ne as StorageAccessDenied, ct as StorageAddress, Fe as StorageCustody, g as StorageError, re as StorageRejected, ie as StorageScanRejected, _ as StorageService, ee as _voltroStorageBlobsTable, f as _voltroStorageGrantsTable, p as _voltroStorageRefsTable, m as _voltroStorageUsageTable, Wt as appStorageObjects, jt as appStorageProvider, e as appStorageRouter, et as assetRef, y as assignStorageObjectNamespacesInTransaction, h as assignStorageReferenceInstancesInTransaction, D as azureProvider, Te as buildStorageService, b as bytesToStream, V as checkLimits, U as clamavScanner, O as clearStorageBuffer, x as collectStream, S as concatBytes, kt as configuredStorageProvider, ot as connectStorage, Ce as contentTypeAllowed, Ee as dataStoreGrantStore, De as dataStoreRefStore, k as databaseProvider, nt as decodeDataUri, it as durabilityNotice, ue as editImage, W as encodeInstream, o as ensureStorageReferenceCatalogue, r as existingFilesystemObjectNamespace, H as fetchIngestBody, K as ffmpegTranscoder, A as filesystemProvider, C as fromNodeReadable, ce as getObjectStream, F as hashPassword, ut as isStorageKey, t as makeStorageDestinationRouter, Me as makeStorageObjectMetadata, Oe as memoryGrantStore, j as memoryProvider, ke as memoryRefStore, G as parseClamavResponse, de as parseTransformParams, at as pathDurability, rt as putAvatar, w as putObjectStream, N as readStorageBuffer, Ae as refMatchesListQuery, se as requireStorageObjectNamespaces, X as resolveStorageProvider, L as resolveStorageSecret, Pe as retainedCaptureTables, P as s3Provider, ge as signFinalizeTicket, R as signGrant, _e as signMultipartTicket, ve as signResumableTicket, z as signUploadTicket, we as sniffMatches, dt as storageAddressIdentity, n as storageByteSecurityHeaders, Mt as storageEgressOf, Vt as storageInstanceName, oe as storageObjectLifecycleTables, i as storageObjectNamespace, Ut as storagePlugin, Ne as storagePutIntentsTable, v as storageRefAddress, s as storageReferenceCatalogueTable, je as storageServiceLayer, T as toNodeReadable, fe as transformCached, pe as transformFallbackReason, me as transformImage, ye as verifyFinalizeTicket, be as verifyGrant, B as verifyMultipartTicket, I as verifyPassword, xe as verifyResumableTicket, Se as verifyUploadTicket, tt as withStorage, st as withStorageKeyPrefix };
|