@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.
Files changed (52) hide show
  1. package/CHANGELOG.md +5987 -0
  2. package/README.md +77 -0
  3. package/THIRD-PARTY-NOTICES.md +860 -249
  4. package/dist/access.js +47 -0
  5. package/dist/assetRef.js +13 -0
  6. package/dist/avatar.js +39 -0
  7. package/dist/byteSecurity.d.ts +3 -0
  8. package/dist/byteSecurity.js +7 -0
  9. package/dist/connection.js +99 -0
  10. package/dist/constraints.js +93 -0
  11. package/dist/custody.js +132 -0
  12. package/dist/derivatives.js +30 -0
  13. package/dist/env.js +162 -0
  14. package/dist/grant.js +132 -0
  15. package/dist/index.d.ts +525 -203
  16. package/dist/index.js +765 -3196
  17. package/dist/ingest.js +87 -0
  18. package/dist/ingestPolicy.js +1 -0
  19. package/dist/metadataError.js +19 -0
  20. package/dist/objectAbandon.js +16 -0
  21. package/dist/objectLifecycle.js +243 -0
  22. package/dist/objectMetadata.js +308 -0
  23. package/dist/objectWriter.js +87 -0
  24. package/dist/pathDurability.js +16 -0
  25. package/dist/physicalReferences.js +54 -0
  26. package/dist/providers.js +638 -0
  27. package/dist/referenceCatalogue.js +31 -0
  28. package/dist/renditionProof.js +82 -0
  29. package/dist/retainedCapture.js +391 -0
  30. package/dist/retainedObjects.js +190 -0
  31. package/dist/rpc.d.ts +3 -15
  32. package/dist/rpc.js +3 -1
  33. package/dist/scanners.js +46 -0
  34. package/dist/server.d.ts +153 -0
  35. package/dist/server.js +4 -0
  36. package/dist/service.js +1418 -0
  37. package/dist/sourceIdentity.js +14 -0
  38. package/dist/sourcePin.js +35 -0
  39. package/dist/storageNamespaces.js +80 -0
  40. package/dist/storageNumbers.js +13 -0
  41. package/dist/storageObjectNamespaces.js +243 -0
  42. package/dist/storageReferenceInstances.js +52 -0
  43. package/dist/storageRequest.js +10 -0
  44. package/dist/storageRouting.js +46 -0
  45. package/dist/streamBridge.js +33 -0
  46. package/dist/table.js +54 -0
  47. package/dist/transcodeVideo.js +91 -0
  48. package/dist/transform.js +94 -0
  49. package/dist/transformCache.js +31 -0
  50. package/dist/types.d.ts +116 -134
  51. package/dist/types.js +14 -14
  52. package/package.json +17 -6
package/dist/index.js CHANGED
@@ -1,2737 +1,128 @@
1
- import { StorageAccessDenied as e, StorageError as t, StorageRejected as n, StorageScanRejected as r, StorageService as i } from "./types.js";
2
- import { abortMultipartUploadDescriptor as a, beginMultipartUploadDescriptor as o, beginResumableUploadDescriptor as s, completeMultipartUploadDescriptor as c, finalizeUploadDescriptor as l, ingestUrlDescriptor as u, listGrantsDescriptor as d, listRefsDescriptor as f, mintPresignedUploadDescriptor as p, mintUploadTicketDescriptor as m, mintUploadUrlDescriptor as ee, mintUrlDescriptor as te, revokeDescriptor as ne, shareDescriptor as h, signMultipartPartDescriptor as g, storageRpcClientImports as _, uploadDescriptor as re } from "./rpc.js";
3
- import { processIdentity as ie } from "@voltro/protocol/identity";
4
- import { Effect as v, Exit as y, Layer as b, Schedule as x, Schema as S, Stream as C } from "effect";
5
- import { StorageAccessPolicySchema as ae, definePlugin as oe, pluginInstanceName as w } from "@voltro/protocol";
6
- import { readCookie as se, resolveSessionSecret as ce, verifySession as le } from "@voltro/protocol/session";
7
- import { and as ue, authoredError as T, bigint as E, bytes as D, causeBranches as O, column as de, contains as fe, eq as k, extractDbCause as pe, generateId as A, id as j, integer as M, isNull as me, isTransientContention as he, json as ge, mixin as _e, neq as ve, or as N, reference as ye, table as P, text as F, timestamp as be, wireSafeCause as xe } from "@voltro/database";
8
- import { pluginEnv as Se } from "@voltro/env";
9
- import { createHash as Ce, createHmac as I, randomBytes as we, randomUUID as Te, scryptSync as Ee, timingSafeEqual as L } from "node:crypto";
10
- import { ssrfReason as De } from "@voltro/runtime";
11
- import { spawn as Oe } from "node:child_process";
12
- import { mkdtemp as R, readFile as z, rm as ke, writeFile as Ae } from "node:fs/promises";
13
- import { tmpdir as je } from "node:os";
14
- import { join as Me } from "node:path";
15
- import { statSync as Ne } from "node:fs";
16
- //#region src/streamBridge.ts
17
- var Pe = 1 << 20, Fe = (e, n, r = !1) => new t({
18
- provider: e,
19
- message: n,
20
- transient: r
21
- }), Ie = (e) => {
22
- let t = 0;
23
- for (let n of e) t += n.byteLength;
24
- let n = new Uint8Array(t), r = 0;
25
- for (let t of e) n.set(t, r), r += t.byteLength;
26
- return n;
27
- }, Le = (e, t = Pe) => {
28
- let n = [];
29
- for (let r = 0; r < e.byteLength; r += t) n.push(e.subarray(r, Math.min(r + t, e.byteLength)));
30
- return C.fromIterable(n);
31
- }, Re = (e) => e.pipe(C.runCollect, v.map((e) => Ie(e))), ze = (e, t) => C.suspend(() => C.fromAsyncIterable(t(), (t) => Fe(e, `read stream failed: ${String(t?.message ?? t)}`, !0))).pipe(C.map((e) => e instanceof Uint8Array ? e : new Uint8Array(e))), Be = async (e) => {
32
- let { Readable: t } = await import("node:stream");
33
- return t.fromWeb(C.toReadableStream(e));
34
- }, Ve = (e, t) => e.getStream ? e.getStream(t) : e.get(t).pipe(v.map((e) => ({
35
- stream: Le(e.bytes),
36
- contentType: e.contentType,
37
- size: e.bytes.byteLength
38
- }))), He = (e, t, n, r) => e.putStream ? e.putStream(t, n, r) : Re(n).pipe(v.flatMap((n) => e.put(t, n, {
39
- contentType: r.contentType,
40
- ...r.public === void 0 ? {} : { public: r.public }
41
- }))), B = "_voltro_storage_refs", V = "_voltro_storage_grants", H = "_voltro_storage_blobs", Ue = "_voltro_storage_usage", We = P(B, {
42
- id: j({ prefix: "file" }),
43
- tenantId: F().nullable(),
44
- ownerId: F().nullable(),
45
- bucket: F(),
46
- key: F(),
47
- contentType: F(),
48
- size: E(),
49
- checksum: F(),
50
- visibility: F(),
51
- accessPolicy: ge().nullable(),
52
- passwordHash: F().nullable(),
53
- width: M().nullable(),
54
- height: M().nullable(),
55
- duration: M().nullable(),
56
- placeholder: F().nullable(),
57
- folder: F().nullable(),
58
- tags: ge().nullable(),
59
- alt: F().nullable(),
60
- caption: F().nullable(),
61
- derivedFrom: F().nullable(),
62
- kind: F().nullable(),
63
- createdAt: be()
64
- }).index(["key"]).index(["tenantId"]).index(["ownerId"]).index(["folder"]).index(["derivedFrom"]), Ge = P(V, {
65
- id: j({ prefix: "sgrant" }),
66
- refId: F(),
67
- principalType: F(),
68
- principalId: F(),
69
- permission: F(),
70
- createdAt: be(),
71
- expiresAt: be().nullable(),
72
- createdBy: F().nullable()
73
- }).index(["refId"]).index(["principalId"]), Ke = P(Ue, {
74
- id: j({ prefix: "susage" }),
75
- tenantId: F().maxLength(191),
76
- bytes: E().default("0"),
77
- count: E().default("0"),
78
- updatedAt: be()
79
- }).unique("byStorageUsageTenant", ["tenantId"]), qe = P(H, {
80
- id: j({ prefix: "blob" }),
81
- key: F(),
82
- data: D(),
83
- contentType: F(),
84
- size: E()
85
- }).index(["key"]), U = Se([
86
- {
87
- name: "STORAGE_PROVIDER",
88
- required: !1,
89
- secret: !1,
90
- description: "Provider name: 's3' | 'minio' | 'azure' | 'database' | 'filesystem' | 'memory'. Default 'memory'."
91
- },
92
- {
93
- name: "S3_BUCKET",
94
- required: !1,
95
- secret: !1,
96
- description: "S3/MinIO bucket name. Default STORAGE_BUCKET, else \"voltro\"."
97
- },
98
- {
99
- name: "STORAGE_BUCKET",
100
- required: !1,
101
- secret: !1,
102
- description: "Fallback bucket name when S3_BUCKET is unset."
103
- },
104
- {
105
- name: "S3_REGION",
106
- required: !1,
107
- secret: !1,
108
- description: "S3 region. Falls back to AWS_REGION."
109
- },
110
- {
111
- name: "AWS_REGION",
112
- required: !1,
113
- secret: !1,
114
- description: "AWS region fallback for the S3 provider."
115
- },
116
- {
117
- name: "S3_ENDPOINT",
118
- required: !1,
119
- secret: !1,
120
- description: "Custom S3 endpoint URL. Falls back to MINIO_ENDPOINT."
121
- },
122
- {
123
- name: "MINIO_ENDPOINT",
124
- required: !1,
125
- secret: !1,
126
- description: "MinIO endpoint URL fallback for the S3 provider."
127
- },
128
- {
129
- name: "S3_ACCESS_KEY_ID",
130
- required: !1,
131
- secret: !0,
132
- description: "S3 access key id. Falls back to AWS_ACCESS_KEY_ID."
133
- },
134
- {
135
- name: "AWS_ACCESS_KEY_ID",
136
- required: !1,
137
- secret: !0,
138
- description: "AWS access key id fallback for the S3 provider."
139
- },
140
- {
141
- name: "S3_SECRET_ACCESS_KEY",
142
- required: !1,
143
- secret: !0,
144
- description: "S3 secret access key. Falls back to AWS_SECRET_ACCESS_KEY."
145
- },
146
- {
147
- name: "AWS_SECRET_ACCESS_KEY",
148
- required: !1,
149
- secret: !0,
150
- description: "AWS secret access key fallback for the S3 provider."
151
- },
152
- {
153
- name: "S3_FORCE_PATH_STYLE",
154
- required: !1,
155
- secret: !1,
156
- description: "Set to \"1\" to force path-style S3 addressing."
157
- },
158
- {
159
- name: "STORAGE_CDN_URL",
160
- required: !1,
161
- secret: !1,
162
- description: "Public base URL (CDN) served in front of the bucket for public objects."
163
- },
164
- {
165
- name: "VOLTRO_PUBLIC_URL",
166
- required: !1,
167
- secret: !1,
168
- description: "Absolute public base URL of THIS api (scheme://host[:port]) — prepended to the /_voltro/storage/:id serve URL so getUrl/mintUrl/the upload route emit ABSOLUTE URLs. Required when the api is a different origin than the app."
169
- },
170
- {
171
- name: "STORAGE_ALLOWED_ORIGINS",
172
- required: !1,
173
- secret: !1,
174
- description: "Comma-separated origins allowed to read the serve route + POST the upload route cross-origin (CORS). Use '*' for any. Omit for same-origin only."
175
- },
176
- {
177
- name: "AZURE_STORAGE_ACCOUNT",
178
- required: !1,
179
- secret: !1,
180
- description: "Azure storage account name (provider \"azure\")."
181
- },
182
- {
183
- name: "AZURE_STORAGE_KEY",
184
- required: !1,
185
- secret: !0,
186
- description: "Azure account key — needed to mint SAS URLs."
187
- },
188
- {
189
- name: "AZURE_STORAGE_CONNECTION_STRING",
190
- required: !1,
191
- secret: !0,
192
- description: "Azure connection string (carries the account key)."
193
- },
194
- {
195
- name: "AZURE_STORAGE_ENDPOINT",
196
- required: !1,
197
- secret: !1,
198
- description: "Custom Azure blob endpoint (e.g. Azurite)."
199
- },
200
- {
201
- name: "AZURE_STORAGE_CONTAINER",
202
- required: !1,
203
- secret: !1,
204
- description: "Azure blob container name (the \"bucket\")."
205
- },
206
- {
207
- name: "STORAGE_ROOT",
208
- required: !1,
209
- secret: !1,
210
- description: "Filesystem provider root directory. Default \".voltro-storage\"."
211
- },
212
- {
213
- name: "VOLTRO_STORAGE_SECRET",
214
- required: !1,
215
- secret: !0,
216
- description: "HMAC secret for signed grant tokens. Falls back to the session secret."
217
- },
218
- {
219
- name: "VOLTRO_SESSION_COOKIE",
220
- required: !1,
221
- secret: !1,
222
- description: "Session cookie name used to resolve private-object access. Default \"voltro:session\"."
223
- },
224
- {
225
- name: "CLAMAV_HOST",
226
- required: !1,
227
- secret: !1,
228
- description: "clamd host for the optional clamav virus scanner. Default 127.0.0.1."
229
- },
230
- {
231
- name: "CLAMAV_PORT",
232
- required: !1,
233
- secret: !1,
234
- description: "clamd port for the optional clamav virus scanner. Default 3310."
235
- }
236
- ]), W = (e, n) => {
237
- let r = typeof e == "number" ? e : typeof e == "bigint" || typeof e == "string" && /^\d+$/.test(e) ? Number(e) : NaN;
238
- if (!Number.isSafeInteger(r) || r < 0) throw new t({
239
- provider: "metadata",
240
- message: `Storage ${n} must be a non-negative safe integer at most Number.MAX_SAFE_INTEGER`,
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
+ //#region 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(", "),
241
44
  transient: !1
242
45
  });
243
- return r;
244
- }, Je = (e, t, n) => W(e + t, n), G = (e, n, r = !1) => {
245
- let i = O(e).find(S.is(t));
246
- if (i !== void 0) return i;
247
- let a = pe(e), o = a.dbCode === "22003" || a.dbSqlState === "22003" || a.dbCode === "ER_WARN_DATA_OUT_OF_RANGE" || a.dbErrno === 1264 || a.dbNumber === 8115 || a.dbNumber === 248, s = new t({
248
- provider: n,
249
- message: `${o ? "Storage metadata numeric value out of range: " : ""}${xe(e)}`,
250
- transient: o ? !1 : he(e) || r
251
- });
252
- return Object.defineProperty(s, "cause", {
253
- value: e,
254
- configurable: !0
255
- }), s;
256
- }, Ye = (e) => O(e).find(S.is(n)), K = (e, n, r, i) => new t({
257
- provider: e,
258
- message: n,
259
- transient: r,
260
- ...i === void 0 ? {} : { status: i }
261
- }), Xe = (e) => e === void 0 || e === 408 || e === 429 || e >= 500, Ze = /* @__PURE__ */ new Map(), Qe = (e, t) => Ze.get(e)?.get(t)?.bytes, $e = (e) => {
262
- Ze.get(e)?.clear();
263
- }, et = (e = "default") => {
264
- let t = Ze.get(e) ?? /* @__PURE__ */ new Map();
265
- return Ze.set(e, t), {
266
- name: "memory",
267
- presigns: !1,
268
- put: (e, n, r) => v.sync(() => (t.set(e, {
269
- bytes: n,
270
- contentType: r.contentType
271
- }), { size: n.byteLength })),
272
- get: (e) => v.suspend(() => {
273
- let n = t.get(e);
274
- return n ? v.succeed({
275
- bytes: n.bytes,
276
- contentType: n.contentType
277
- }) : v.fail(K("memory", `no object at key '${e}'`, !1, 404));
278
- }),
279
- delete: (e) => v.sync(() => {
280
- t.delete(e);
281
- }),
282
- publicUrl: () => null,
283
- getUrl: () => v.succeed(""),
284
- head: (e) => v.sync(() => {
285
- let n = t.get(e);
286
- return n ? { size: n.bytes.byteLength } : null;
287
- })
288
- };
289
- }, tt = (e) => {
290
- let t = e.root, n = async (e) => {
291
- let { join: n, resolve: r, sep: i } = await import("node:path"), a = r(t), o = r(a, e);
292
- if (o !== a && !o.startsWith(a + i)) throw Error(`key '${e}' escapes the storage root`);
293
- return n(o);
294
- }, r = (e, t, n = !1) => v.tryPromise({
295
- try: e,
296
- catch: (e) => e?.code === "ENOENT" ? K("filesystem", `no object at key '${t}'`, !1, 404) : K("filesystem", String(e?.message ?? e), n)
297
- });
298
- return {
299
- root: t,
300
- name: "filesystem",
301
- presigns: !1,
302
- put: (e, t, i) => r(async () => {
303
- let r = await import("node:fs/promises"), { dirname: i } = await import("node:path"), { randomUUID: a } = await import("node:crypto"), o = await n(e), s = i(o);
304
- await r.mkdir(s, { recursive: !0 });
305
- let c = `${o}.tmp-${a()}`;
306
- try {
307
- await r.writeFile(c, t), await r.rename(c, o);
308
- } catch (e) {
309
- throw await r.rm(c, { force: !0 }).catch(() => {}), e;
310
- }
311
- return { size: t.byteLength };
312
- }, e, !0),
313
- get: (e) => r(async () => {
314
- let t = await (await import("node:fs/promises")).readFile(await n(e));
315
- return {
316
- bytes: new Uint8Array(t),
317
- contentType: "application/octet-stream"
318
- };
319
- }, e),
320
- delete: (e) => r(async () => {
321
- await (await import("node:fs/promises")).rm(await n(e), { force: !0 });
322
- }, e),
323
- publicUrl: () => null,
324
- getUrl: () => v.succeed(""),
325
- head: (e) => v.tryPromise({
326
- try: async () => {
327
- let t = await import("node:fs/promises");
328
- try {
329
- return { size: (await t.stat(await n(e))).size };
330
- } catch (e) {
331
- if (e?.code === "ENOENT") return null;
332
- throw e;
333
- }
334
- },
335
- catch: (e) => K("filesystem", String(e?.message ?? e), !1)
336
- }),
337
- getStream: (e) => r(async () => {
338
- let t = await import("node:fs/promises"), { createReadStream: r } = await import("node:fs"), i = await n(e), a = await t.stat(i);
339
- return {
340
- stream: ze("filesystem", () => r(i)),
341
- contentType: "application/octet-stream",
342
- size: a.size
343
- };
344
- }, e),
345
- putStream: (e, t, i) => r(async () => {
346
- let r = await import("node:fs/promises"), { dirname: i } = await import("node:path"), { randomUUID: a } = await import("node:crypto"), { createWriteStream: o } = await import("node:fs"), { pipeline: s } = await import("node:stream/promises"), c = await n(e);
347
- await r.mkdir(i(c), { recursive: !0 });
348
- let l = `${c}.tmp-${a()}`;
349
- try {
350
- await s(await Be(t), o(l));
351
- let e = await r.stat(l);
352
- return await r.rename(l, c), { size: e.size };
353
- } catch (e) {
354
- throw await r.rm(l, { force: !0 }).catch(() => {}), e;
355
- }
356
- }, e, !0),
357
- getRange: (e, t, i) => r(async () => {
358
- let { createReadStream: r } = await import("node:fs"), a = await n(e), o = [];
359
- return await new Promise((e, n) => {
360
- let s = r(a, {
361
- start: t,
362
- end: i
363
- });
364
- s.on("data", (e) => o.push(e)), s.on("end", () => e()), s.on("error", n);
365
- }), Ie(o);
366
- }, e)
367
- };
368
- }, nt = (e) => {
369
- let t = e.name ?? "s3", n = e.publicAcl ?? !0, r = null, i = () => r || (r = (async () => {
370
- let t, n;
371
- try {
372
- t = await import("@aws-sdk/client-s3"), n = await import("@aws-sdk/s3-request-presigner");
373
- } catch (e) {
374
- throw Error("the 's3'/'minio' storage provider requires the '@aws-sdk/client-s3' + '@aws-sdk/s3-request-presigner' optional dependencies. Install them to enable it.", { cause: e });
375
- }
376
- return {
377
- client: new t.S3Client({
378
- ...e.region ? { region: e.region } : { region: "us-east-1" },
379
- ...e.endpoint ? { endpoint: e.endpoint } : {},
380
- ...e.forcePathStyle ? { forcePathStyle: !0 } : {},
381
- ...e.accessKeyId && e.secretAccessKey ? { credentials: {
382
- accessKeyId: e.accessKeyId,
383
- secretAccessKey: e.secretAccessKey
384
- } } : {}
385
- }),
386
- cmds: t,
387
- presign: n.getSignedUrl
388
- };
389
- })(), r), a = (e) => v.tryPromise({
390
- try: e,
391
- catch: (e) => {
392
- let n = e?.$metadata?.httpStatusCode;
393
- return K(t, String(e?.message ?? e), Xe(n), n);
394
- }
395
- }), o = async (e) => {
396
- let t = e;
397
- if (typeof t.transformToByteArray == "function") return t.transformToByteArray();
398
- let n = [];
399
- for await (let e of t) n.push(e);
400
- let r = n.reduce((e, t) => e + t.byteLength, 0), i = new Uint8Array(r), a = 0;
401
- for (let e of n) i.set(e, a), a += e.byteLength;
402
- return i;
403
- };
404
- return {
405
- name: t,
406
- presigns: !0,
407
- put: (t, r, o) => a(async () => {
408
- let { client: a, cmds: s } = await i();
409
- return await a.send(new s.PutObjectCommand({
410
- Bucket: e.bucket,
411
- Key: t,
412
- Body: r,
413
- ContentType: o.contentType,
414
- ...o.public && n ? { ACL: "public-read" } : {}
415
- })), { size: r.byteLength };
416
- }),
417
- get: (t) => a(async () => {
418
- let { client: n, cmds: r } = await i(), a = await n.send(new r.GetObjectCommand({
419
- Bucket: e.bucket,
420
- Key: t
421
- }));
422
- return {
423
- bytes: await o(a.Body),
424
- contentType: a.ContentType ?? "application/octet-stream"
425
- };
426
- }),
427
- delete: (t) => a(async () => {
428
- let { client: n, cmds: r } = await i();
429
- await n.send(new r.DeleteObjectCommand({
430
- Bucket: e.bucket,
431
- Key: t
432
- }));
433
- }),
434
- publicUrl: (t) => e.cdnBaseUrl ? `${e.cdnBaseUrl.replace(/\/$/, "")}/${t}` : null,
435
- ...n ? { setObjectPublic: (t, n) => a(async () => {
436
- let { client: r, cmds: a } = await i();
437
- await r.send(new a.PutObjectAclCommand({
438
- Bucket: e.bucket,
439
- Key: t,
440
- ACL: n ? "public-read" : "private"
441
- }));
442
- }) } : {},
443
- getUrl: (t, n) => a(async () => {
444
- let { client: r, cmds: a, presign: o } = await i();
445
- return o(r, new a.GetObjectCommand({
446
- Bucket: e.bucket,
447
- Key: t
448
- }), { expiresIn: n });
449
- }),
450
- getUploadUrl: (t, n, r) => a(async () => {
451
- let { client: a, cmds: o, presign: s } = await i();
452
- return s(a, new o.PutObjectCommand({
453
- Bucket: e.bucket,
454
- Key: t,
455
- ContentType: r
456
- }), { expiresIn: n });
457
- }),
458
- createMultipartUpload: (t, r, o) => a(async () => {
459
- let { client: a, cmds: s } = await i(), c = await a.send(new s.CreateMultipartUploadCommand({
460
- Bucket: e.bucket,
461
- Key: t,
462
- ContentType: r,
463
- ...o?.public && n ? { ACL: "public-read" } : {}
464
- }));
465
- if (!c.UploadId) throw Error("s3 createMultipartUpload returned no UploadId");
466
- return { uploadId: c.UploadId };
467
- }),
468
- presignUploadPart: (t, n, r, o) => a(async () => {
469
- let { client: a, cmds: s, presign: c } = await i();
470
- return c(a, new s.UploadPartCommand({
471
- Bucket: e.bucket,
472
- Key: t,
473
- UploadId: n,
474
- PartNumber: r
475
- }), { expiresIn: o });
476
- }),
477
- completeMultipartUpload: (t, n, r) => a(async () => {
478
- let { client: a, cmds: o } = await i(), s = await a.send(new o.CompleteMultipartUploadCommand({
479
- Bucket: e.bucket,
480
- Key: t,
481
- UploadId: n,
482
- MultipartUpload: { Parts: r.map((e) => ({
483
- PartNumber: e.partNumber,
484
- ETag: e.etag
485
- })) }
486
- }));
487
- return s.ETag === void 0 ? {} : { etag: s.ETag };
488
- }),
489
- abortMultipartUpload: (t, n) => a(async () => {
490
- let { client: r, cmds: a } = await i();
491
- await r.send(new a.AbortMultipartUploadCommand({
492
- Bucket: e.bucket,
493
- Key: t,
494
- UploadId: n
495
- }));
496
- }),
497
- head: (n) => v.tryPromise({
498
- try: async () => {
499
- let { client: t, cmds: r } = await i();
500
- try {
501
- let i = await t.send(new r.HeadObjectCommand({
502
- Bucket: e.bucket,
503
- Key: n
504
- }));
505
- return {
506
- size: i.ContentLength ?? 0,
507
- ...i.ETag === void 0 ? {} : { etag: i.ETag }
508
- };
509
- } catch (e) {
510
- if (e?.$metadata?.httpStatusCode === 404) return null;
511
- throw e;
512
- }
513
- },
514
- catch: (e) => {
515
- let n = e?.$metadata?.httpStatusCode;
516
- return K(t, String(e?.message ?? e), Xe(n), n);
517
- }
518
- }),
519
- getStream: (n) => a(async () => {
520
- let { client: r, cmds: a } = await i(), o = await r.send(new a.GetObjectCommand({
521
- Bucket: e.bucket,
522
- Key: n
523
- })), s = o.Body;
524
- return {
525
- stream: ze(t, () => s),
526
- contentType: o.ContentType ?? "application/octet-stream",
527
- ...o.ContentLength === void 0 ? {} : { size: o.ContentLength }
528
- };
529
- }),
530
- putStream: (t, r, o) => a(async () => {
531
- let { client: a, cmds: s } = await i(), c;
532
- try {
533
- c = await import("@aws-sdk/lib-storage");
534
- } catch (e) {
535
- throw Error("s3/minio `putStream` requires the '@aws-sdk/lib-storage' optional dependency (multipart upload). Install it to enable streamed uploads.", { cause: e });
536
- }
537
- let l = await Be(r);
538
- return await new c.Upload({
539
- client: a,
540
- params: {
541
- Bucket: e.bucket,
542
- Key: t,
543
- Body: l,
544
- ContentType: o.contentType,
545
- ...o.public && n ? { ACL: "public-read" } : {}
546
- }
547
- }).done(), { size: o.totalSize ?? (await a.send(new s.HeadObjectCommand({
548
- Bucket: e.bucket,
549
- Key: t
550
- }))).ContentLength ?? 0 };
551
- }),
552
- getRange: (t, n, r) => a(async () => {
553
- let { client: a, cmds: s } = await i(), c = await a.send(new s.GetObjectCommand({
554
- Bucket: e.bucket,
555
- Key: t,
556
- Range: `bytes=${n}-${r}`
557
- }));
558
- return o(c.Body);
559
- })
560
- };
561
- }, rt = (e) => e instanceof Uint8Array ? e : typeof e == "string" ? new Uint8Array(Buffer.from(e, "base64")) : new Uint8Array(e), it = () => {
562
- let e = null, t = () => {
563
- if (!e) throw T("the 'database' storage provider isn't bound to a DataStore yet");
564
- return e;
565
- }, n = (e) => v.tryPromise({
566
- try: e,
567
- catch: (e) => G(e, "database", !0)
568
- }), r = async (e, n) => (await t().query({
569
- table: H,
570
- predicate: {
571
- column: "key",
572
- op: "eq",
573
- value: e
574
- },
575
- order: [],
576
- take: 1,
577
- skip: void 0,
578
- projection: n
579
- }))[0];
580
- return {
581
- name: "database",
582
- presigns: !1,
583
- bindDataStore: (t) => {
584
- e = t;
585
- },
586
- put: (e, i, a) => n(async () => {
587
- let n = await r(e);
588
- return n ? await t().update(H, String(n.id), {
589
- data: i,
590
- contentType: a.contentType,
591
- size: String(i.byteLength)
592
- }) : await t().insert(H, {
593
- id: A({
594
- kind: "typeid",
595
- prefix: "blob"
596
- }, H),
597
- key: e,
598
- data: i,
599
- contentType: a.contentType,
600
- size: String(i.byteLength)
601
- }), { size: i.byteLength };
602
- }),
603
- get: (e) => v.suspend(() => n(() => r(e)).pipe(v.flatMap((t) => t ? v.succeed({
604
- bytes: rt(t.data),
605
- contentType: String(t.contentType)
606
- }) : v.fail(K("database", `no object at key '${e}'`, !1, 404))))),
607
- delete: (e) => n(async () => {
608
- let n = await r(e, ["id"]);
609
- n && await t().delete(H, String(n.id));
610
- }),
611
- publicUrl: () => null,
612
- getUrl: () => v.succeed(""),
613
- head: (e) => n(async () => {
614
- let t = await r(e, ["size"]);
615
- return t ? { size: W(t.size, "blob size") } : null;
616
- })
617
- };
618
- }, at = (e) => {
619
- let t = null, n = () => t || (t = (async () => {
620
- let t;
621
- try {
622
- t = await import("@azure/storage-blob");
623
- } catch (e) {
624
- throw Error("the 'azure' storage provider requires the '@azure/storage-blob' optional dependency. Install it to enable it.", { cause: e });
625
- }
626
- let n = U.read("AZURE_STORAGE_ACCOUNT", e.accountName), r = U.read("AZURE_STORAGE_KEY", e.accountKey), i = n && r ? new t.StorageSharedKeyCredential(n, r) : null, a = U.read("AZURE_STORAGE_CONNECTION_STRING", e.connectionString);
627
- return {
628
- container: (a ? t.BlobServiceClient.fromConnectionString(a) : new t.BlobServiceClient(e.endpoint ?? `https://${n}.blob.core.windows.net`, i ?? void 0)).getContainerClient(e.container),
629
- sdk: t,
630
- cred: i
631
- };
632
- })(), t), r = (e) => v.tryPromise({
633
- try: e,
634
- catch: (e) => {
635
- let t = e?.statusCode;
636
- return K("azure", String(e?.message ?? e), Xe(t), t);
637
- }
638
- }), i = async (e) => {
639
- if (!e) return /* @__PURE__ */ new Uint8Array();
640
- let t = [];
641
- for await (let n of e) t.push(typeof n == "string" ? new TextEncoder().encode(n) : new Uint8Array(n));
642
- let n = t.reduce((e, t) => e + t.byteLength, 0), r = new Uint8Array(n), i = 0;
643
- for (let e of t) r.set(e, i), i += e.byteLength;
644
- return r;
645
- }, a = async (t, r, i) => {
646
- let { container: a, sdk: o, cred: s } = await n();
647
- if (!s) throw Error("azure SAS requires accountName + accountKey (set them or AZURE_STORAGE_ACCOUNT/AZURE_STORAGE_KEY)");
648
- let c = a.getBlockBlobClient(t), l = o.generateBlobSASQueryParameters({
649
- containerName: e.container,
650
- blobName: t,
651
- permissions: o.BlobSASPermissions.parse(r),
652
- startsOn: /* @__PURE__ */ new Date(Date.now() - 6e4),
653
- expiresOn: new Date(Date.now() + i * 1e3)
654
- }, s).toString();
655
- return `${c.url}?${l}`;
656
- };
657
- return {
658
- name: "azure",
659
- presigns: !0,
660
- put: (e, t, i) => r(async () => {
661
- let { container: r } = await n();
662
- return await r.getBlockBlobClient(e).uploadData(Buffer.from(t), { blobHTTPHeaders: { blobContentType: i.contentType } }), { size: t.byteLength };
663
- }),
664
- get: (e) => r(async () => {
665
- let { container: t } = await n(), r = await t.getBlockBlobClient(e).download();
666
- return {
667
- bytes: await i(r.readableStreamBody),
668
- contentType: r.contentType ?? "application/octet-stream"
669
- };
670
- }),
671
- delete: (e) => r(async () => {
672
- let { container: t } = await n();
673
- await t.getBlockBlobClient(e).deleteIfExists();
674
- }),
675
- publicUrl: (t) => e.cdnBaseUrl ? `${e.cdnBaseUrl.replace(/\/$/, "")}/${t}` : null,
676
- getUrl: (e, t) => r(() => a(e, "r", t)),
677
- getUploadUrl: (e, t, n) => r(() => a(e, "cw", t)),
678
- head: (e) => v.tryPromise({
679
- try: async () => {
680
- let { container: t } = await n();
681
- try {
682
- let n = await t.getBlockBlobClient(e).getProperties();
683
- return {
684
- size: n.contentLength ?? 0,
685
- ...n.etag === void 0 ? {} : { etag: n.etag }
686
- };
687
- } catch (e) {
688
- if (e?.statusCode === 404) return null;
689
- throw e;
690
- }
691
- },
692
- catch: (e) => {
693
- let t = e?.statusCode;
694
- return K("azure", String(e?.message ?? e), Xe(t), t);
695
- }
696
- }),
697
- getStream: (e) => r(async () => {
698
- let { container: t } = await n(), r = await t.getBlockBlobClient(e).download();
699
- return {
700
- stream: ze("azure", () => r.readableStreamBody),
701
- contentType: r.contentType ?? "application/octet-stream",
702
- ...r.contentLength === void 0 ? {} : { size: r.contentLength }
703
- };
704
- }),
705
- putStream: (e, t, i) => r(async () => {
706
- let { container: r } = await n(), a = await Be(t);
707
- return await r.getBlockBlobClient(e).uploadStream(a, 4194304, 5, { blobHTTPHeaders: { blobContentType: i.contentType } }), { size: i.totalSize ?? (await r.getBlockBlobClient(e).getProperties()).contentLength ?? 0 };
708
- }),
709
- getRange: (e, t, a) => r(async () => {
710
- let { container: r } = await n(), o = await r.getBlockBlobClient(e).download(t, a - t + 1);
711
- return i(o.readableStreamBody);
712
- })
713
- };
714
- }, ot = (e = {
715
- entries: 200,
716
- bytes: 67108864,
717
- pending: 32
718
- }) => {
719
- let t = /* @__PURE__ */ new Map(), n = /* @__PURE__ */ new Map(), r = 0;
720
- return { getOrCreate: (i, a) => {
721
- let o = t.get(i);
722
- if (o) return Promise.resolve(o);
723
- let s = n.get(i);
724
- if (s) return s;
725
- if (n.size >= e.pending) return Promise.resolve(null);
726
- let c = Promise.resolve().then(a).then((n) => {
727
- if (n && e.entries > 0 && n.bytes.byteLength <= e.bytes) {
728
- for (; t.size >= e.entries || r + n.bytes.byteLength > e.bytes;) {
729
- let e = t.keys().next().value;
730
- if (e === void 0) break;
731
- r -= t.get(e).bytes.byteLength, t.delete(e);
732
- }
733
- t.set(i, n), r += n.bytes.byteLength;
734
- }
735
- return n;
736
- }).finally(() => {
737
- n.delete(i);
738
- });
739
- return n.set(i, c), c;
740
- } };
741
- }, st = (e, t, n, r, i, a) => {
742
- let o = n / r, s = Math.min(e, Math.round(t * o)), c = Math.min(t, Math.round(s / o)), l = (e, t) => Math.max(0, Math.min(t, e));
743
- return {
744
- left: l(Math.round(i * e - s / 2), e - s),
745
- top: l(Math.round(a * t - c / 2), t - c),
746
- width: s,
747
- height: c
748
- };
749
- }, ct = {
750
- webp: "image/webp",
751
- avif: "image/avif",
752
- jpeg: "image/jpeg",
753
- jpg: "image/jpeg",
754
- png: "image/png"
755
- }, lt = (e) => {
756
- if (!e) return null;
757
- let t = new URLSearchParams(e), n = (e) => {
758
- let n = t.get(e);
759
- if (n == null) return;
760
- let r = Number(n);
761
- return Number.isFinite(r) && r > 0 ? Math.floor(r) : void 0;
762
- }, r = n("w"), i = n("h"), a = n("q"), o = (t.get("format") ?? t.get("fm") ?? void 0)?.toLowerCase(), s = t.get("fit") ?? void 0, c = (t.get("fp") ?? "").split(",").map(Number), l = c.length === 2 && c.every((e) => Number.isFinite(e) && e >= 0 && e <= 1) ? {
763
- x: c[0],
764
- y: c[1]
765
- } : void 0;
766
- return r === void 0 && i === void 0 && !o && a === void 0 ? null : {
767
- ...r === void 0 ? {} : { w: r },
768
- ...i === void 0 ? {} : { h: i },
769
- ...o ? { format: o } : {},
770
- ...a === void 0 ? {} : { q: a },
771
- ...s ? { fit: s } : {},
772
- ...l ? { fp: l } : {}
773
- };
774
- }, ut = (e) => e.startsWith("image/") && !e.includes("svg"), dt, ft = async () => (dt ??= import("sharp").then((e) => e.default ?? e, () => null), dt), pt = async (e, t) => t ? null : ut(e) ? await ft() === null ? "no-sharp" : "failed" : "not-an-image", mt = async (e, t, n) => {
775
- if (!ut(t)) return null;
776
- let r = await ft();
777
- if (!r) return null;
778
- try {
779
- let i = r(Buffer.from(e), { failOn: "none" }), a = n.fit ?? "cover";
780
- if (n.fp !== void 0 && n.w !== void 0 && n.h !== void 0 && a === "cover") {
781
- let e = await i.metadata();
782
- e.width !== void 0 && e.height !== void 0 && (i = i.extract(st(e.width, e.height, n.w, n.h, n.fp.x, n.fp.y)));
783
- }
784
- (n.w !== void 0 || n.h !== void 0) && (i = i.resize({
785
- ...n.w === void 0 ? {} : { width: n.w },
786
- ...n.h === void 0 ? {} : { height: n.h },
787
- fit: n.fit ?? "cover",
788
- withoutEnlargement: !0
789
- }));
790
- let o = n.format && ct[n.format] ? n.format : void 0, s = t;
791
- if (o) {
792
- let e = o === "jpg" ? "jpeg" : o;
793
- i = i.toFormat(e, n.q === void 0 ? {} : { quality: n.q }), s = ct[o];
794
- } else n.q !== void 0 && (t === "image/jpeg" || t === "image/webp") && (i = i.toFormat(t === "image/webp" ? "webp" : "jpeg", { quality: n.q }));
795
- let c = await i.toBuffer();
796
- return {
797
- bytes: new Uint8Array(c),
798
- contentType: s
799
- };
800
- } catch {
801
- return null;
802
- }
803
- }, ht = async (e, t, n) => {
804
- if (!ut(t) || n.rotate === void 0 && n.flip !== !0 && n.flop !== !0 && n.grayscale !== !0 && n.crop === void 0) return null;
805
- let r = await ft();
806
- if (!r) return null;
807
- try {
808
- let i = r(Buffer.from(e), { failOn: "none" });
809
- return n.crop !== void 0 && (i = i.extract(n.crop)), n.rotate !== void 0 && (i = i.rotate(n.rotate)), n.flip === !0 && (i = i.flip()), n.flop === !0 && (i = i.flop()), n.grayscale === !0 && (i = i.grayscale()), {
810
- bytes: new Uint8Array(await i.toBuffer()),
811
- contentType: t
812
- };
813
- } catch {
814
- return null;
815
- }
816
- }, gt = ot(), _t = (e, t, n) => JSON.stringify([
817
- e,
818
- t,
819
- n.w,
820
- n.h,
821
- n.format,
822
- n.q,
823
- n.fit,
824
- n.fp?.x,
825
- n.fp?.y
826
- ]), vt = async (e, t, n, r) => gt.getOrCreate(_t(e, n, r), () => mt(t, n, r)), yt = (e) => {
827
- let t = we(16).toString("hex");
828
- return `${t}:${Ee(e, t, 32).toString("hex")}`;
829
- }, bt = (e, t) => {
830
- if (!e || !t) return !1;
831
- let [n, r] = t.split(":");
832
- if (!n || !r) return !1;
833
- let i = Buffer.from(r, "hex"), a = Ee(e, n, i.length);
834
- return a.length === i.length && L(a, i);
835
- }, xt = (e) => Array.isArray(e) ? e.filter((e) => typeof e == "string") : [], St = (e) => xt(e.metadata?.roles), Ct = (e) => xt(e.scopes), wt = (e, t) => e.some((e) => t.includes(e)), Tt = (e) => xt(e.metadata?.groups), Et = (e) => typeof e == "boolean" ? v.succeed(e) : v.isEffect(e) ? e : v.promise(() => e), Dt = (e, t, n = {}) => v.gen(function* () {
836
- if (t.id && e.ownerId && t.id === e.ownerId) return !0;
837
- let r = e.accessPolicy ?? [];
838
- if (r.length === 0) return !1;
839
- let i = n.resolveGroups ? yield* v.promise(async () => await n.resolveGroups(t)) : Tt(t);
840
- for (let a of r) if (yield* Ot(a, e, t, i, n)) return !0;
841
- return !1;
842
- }), Ot = (e, t, n, r, i) => v.gen(function* () {
843
- let a = !1, o = (e) => (a = !0, e);
844
- if (e.owner !== void 0 && e.owner && !o(!!n.id && !!t.ownerId && n.id === t.ownerId) || e.tenant !== void 0 && e.tenant && !o(!!n.tenantId && n.tenantId === t.tenantId) || e.apiKey !== void 0 && e.apiKey && !o(n.type === "apiKey") || e.roles && e.roles.length > 0 && !o(wt(St(n), e.roles)) || e.groups && e.groups.length > 0 && !o(wt(r, e.groups)) || e.scopes && e.scopes.length > 0 && !o(wt(Ct(n), e.scopes)) || e.password !== void 0 && e.password && !o(bt(i.password, t.passwordHash))) return !1;
845
- if (e.guard) {
846
- let r = i.guards?.[e.guard];
847
- if (!o(r ? yield* Et(r({
848
- subject: n,
849
- ref: t
850
- })) : !1)) return !1;
851
- }
852
- return a;
853
- }), kt = (e, t) => {
854
- let n = [];
855
- e.id && n.push({
856
- type: e.type === "apiKey" ? "apiKey" : "user",
857
- id: e.id
858
- });
859
- for (let e of t) n.push({
860
- type: "group",
861
- id: e
862
- });
863
- return n;
864
- }, At = (e, t, n, r, i) => {
865
- let a = kt(t, n);
866
- return e.some((e) => e.expiresAt && e.expiresAt.getTime() < i || r === "write" && e.permission !== "write" ? !1 : a.some((t) => t.type === e.principalType && t.id === e.principalId));
867
- }, jt = (e, t) => t.resolveGroups ? v.promise(async () => await t.resolveGroups(e)) : v.succeed(Tt(e)), q = () => U.read("VOLTRO_STORAGE_SECRET") ?? ce(), J = (e) => (typeof e == "string" ? Buffer.from(e, "utf8") : e).toString("base64").replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, ""), Y = (e) => {
868
- let t = e.replace(/-/g, "+").replace(/_/g, "/") + "=".repeat((4 - e.length % 4) % 4);
869
- return Buffer.from(t, "base64");
870
- }, Mt = (e, t, n = q(), r = "/_voltro/storage") => {
871
- if (!n) throw Error("signGrant: secret must be a non-empty string");
872
- let i = {
873
- refId: e,
874
- audience: r,
875
- exp: Math.floor(Date.now() / 1e3) + Math.floor(t)
876
- }, a = J(JSON.stringify(i));
877
- return `${a}.${J(I("sha256", n).update(a).digest())}`;
878
- }, Nt = (e, t = q()) => {
879
- if (!e || !t) return null;
880
- let n = e.indexOf(".");
881
- if (n <= 0 || n === e.length - 1) return null;
882
- let r = e.slice(0, n), i = e.slice(n + 1), a = I("sha256", t).update(r).digest(), o = Y(i);
883
- if (o.length !== a.length || !L(o, a)) return null;
884
- try {
885
- let e = JSON.parse(Y(r).toString("utf8"));
886
- return typeof e.audience != "string" || !e.audience || typeof e.refId != "string" || typeof e.exp != "number" || e.exp < Math.floor(Date.now() / 1e3) ? null : e;
887
- } catch {
888
- return null;
889
- }
890
- }, Pt = (e) => e.version === 1 ? e.access === void 0 || e.vis === "private" && y.isSuccess(S.decodeUnknownExit(ae, { onExcessProperty: "error" })(e.access)) : !1, Ft = (e, t, n = q()) => {
891
- if (!n) throw Error("signUploadTicket: secret must be a non-empty string");
892
- let r = {
893
- ...e,
894
- version: 1,
895
- exp: Math.floor(Date.now() / 1e3) + Math.floor(t)
896
- }, i = J(JSON.stringify(r));
897
- return `${i}.${J(I("sha256", n).update(`u:${i}`).digest())}`;
898
- }, It = (e, t = q()) => {
899
- if (!e || !t) return null;
900
- let n = e.indexOf(".");
901
- if (n <= 0 || n === e.length - 1) return null;
902
- let r = e.slice(0, n), i = e.slice(n + 1), a = I("sha256", t).update(`u:${r}`).digest(), o = Y(i);
903
- if (o.length !== a.length || !L(o, a)) return null;
904
- try {
905
- let e = JSON.parse(Y(r).toString("utf8"));
906
- return !Pt(e) || e.operationId !== void 0 && (typeof e.operationId != "string" || !e.operationId.trim() || e.operationId.length > 200) || typeof e.instance != "string" || !e.instance || typeof e.ct != "string" || typeof e.exp != "number" || e.vis !== "public" && e.vis !== "private" || e.replicaId !== void 0 && (typeof e.replicaId != "string" || !e.replicaId.trim()) || e.exp < Math.floor(Date.now() / 1e3) ? null : e;
907
- } catch {
908
- return null;
909
- }
910
- }, Lt = (e, t, n = q()) => {
911
- if (!n) throw Error("signFinalizeTicket: secret must be a non-empty string");
912
- let r = {
913
- ...e,
914
- version: 1,
915
- exp: Math.floor(Date.now() / 1e3) + Math.floor(t)
916
- }, i = J(JSON.stringify(r));
917
- return `${i}.${J(I("sha256", n).update(`f:${i}`).digest())}`;
918
- }, Rt = (e, t = q()) => {
919
- if (!e || !t) return null;
920
- let n = e.indexOf(".");
921
- if (n <= 0 || n === e.length - 1) return null;
922
- let r = e.slice(0, n), i = e.slice(n + 1), a = I("sha256", t).update(`f:${r}`).digest(), o = Y(i);
923
- if (o.length !== a.length || !L(o, a)) return null;
924
- try {
925
- let e = JSON.parse(Y(r).toString("utf8"));
926
- return !Pt(e) || typeof e.key != "string" || e.key.length === 0 || typeof e.instance != "string" || !e.instance || typeof e.ct != "string" || typeof e.exp != "number" || e.vis !== "public" && e.vis !== "private" || e.exp < Math.floor(Date.now() / 1e3) ? null : e;
927
- } catch {
928
- return null;
929
- }
930
- }, zt = (e, t, n = q()) => {
931
- if (!n) throw Error("signResumableTicket: secret must be a non-empty string");
932
- let r = {
933
- ...e,
934
- version: 1,
935
- exp: Math.floor(Date.now() / 1e3) + Math.floor(t)
936
- }, i = J(JSON.stringify(r));
937
- return `${i}.${J(I("sha256", n).update(`r:${i}`).digest())}`;
938
- }, Bt = (e, t = q()) => {
939
- if (!e || !t) return null;
940
- let n = e.indexOf(".");
941
- if (n <= 0 || n === e.length - 1) return null;
942
- let r = e.slice(0, n), i = e.slice(n + 1), a = I("sha256", t).update(`r:${r}`).digest(), o = Y(i);
943
- if (o.length !== a.length || !L(o, a)) return null;
944
- try {
945
- let e = JSON.parse(Y(r).toString("utf8"));
946
- return !Pt(e) || typeof e.id != "string" || e.id.length === 0 || typeof e.size != "number" || e.size < 0 || typeof e.instance != "string" || !e.instance || typeof e.ct != "string" || typeof e.exp != "number" || e.vis !== "public" && e.vis !== "private" || e.exp < Math.floor(Date.now() / 1e3) ? null : e;
947
- } catch {
948
- return null;
949
- }
950
- }, Vt = (e, t, n = q()) => {
951
- if (!n) throw Error("signMultipartTicket: secret must be a non-empty string");
952
- let r = {
953
- ...e,
954
- version: 1,
955
- exp: Math.floor(Date.now() / 1e3) + Math.floor(t)
956
- }, i = J(JSON.stringify(r));
957
- return `${i}.${J(I("sha256", n).update(`m:${i}`).digest())}`;
958
- }, Ht = (e, t = q()) => {
959
- if (!e || !t) return null;
960
- let n = e.indexOf(".");
961
- if (n <= 0 || n === e.length - 1) return null;
962
- let r = e.slice(0, n), i = e.slice(n + 1), a = I("sha256", t).update(`m:${r}`).digest(), o = Y(i);
963
- if (o.length !== a.length || !L(o, a)) return null;
964
- try {
965
- let e = JSON.parse(Y(r).toString("utf8"));
966
- return !Pt(e) || typeof e.key != "string" || e.key.length === 0 || typeof e.uploadId != "string" || e.uploadId.length === 0 || typeof e.instance != "string" || !e.instance || typeof e.ct != "string" || typeof e.exp != "number" || e.vis !== "public" && e.vis !== "private" || e.exp < Math.floor(Date.now() / 1e3) ? null : e;
967
- } catch {
968
- return null;
969
- }
970
- }, Ut = (e, t) => {
971
- if (!t || t.length === 0) return !0;
972
- let n = e.toLowerCase();
973
- return t.some((e) => {
974
- let t = e.toLowerCase();
975
- return t.endsWith("/*") ? n.startsWith(t.slice(0, -1)) : n === t;
976
- });
977
- }, Wt = [
978
- {
979
- ct: /^image\/png$/,
980
- offset: 0,
981
- magic: [
982
- 137,
983
- 80,
984
- 78,
985
- 71
986
- ]
987
- },
988
- {
989
- ct: /^image\/jpe?g$/,
990
- offset: 0,
991
- magic: [
992
- 255,
993
- 216,
994
- 255
995
- ]
996
- },
997
- {
998
- ct: /^image\/gif$/,
999
- offset: 0,
1000
- magic: [
1001
- 71,
1002
- 73,
1003
- 70,
1004
- 56
1005
- ]
1006
- },
1007
- {
1008
- ct: /^image\/webp$/,
1009
- offset: 0,
1010
- magic: [
1011
- 82,
1012
- 73,
1013
- 70,
1014
- 70
1015
- ]
1016
- },
1017
- {
1018
- ct: /^image\/bmp$/,
1019
- offset: 0,
1020
- magic: [66, 77]
1021
- },
1022
- {
1023
- ct: /^application\/pdf$/,
1024
- offset: 0,
1025
- magic: [
1026
- 37,
1027
- 80,
1028
- 68,
1029
- 70
1030
- ]
1031
- },
1032
- {
1033
- ct: /^application\/zip$/,
1034
- offset: 0,
1035
- magic: [
1036
- 80,
1037
- 75,
1038
- 3,
1039
- 4
1040
- ]
1041
- },
1042
- {
1043
- ct: /^application\/gzip$/,
1044
- offset: 0,
1045
- magic: [31, 139]
1046
- }
1047
- ], Gt = (e, t) => {
1048
- let n = t.toLowerCase(), r = Wt.find((e) => e.ct.test(n));
1049
- return r ? e.length < r.offset + r.magic.length ? !1 : r.magic.every((t, n) => e[r.offset + n] === t) : !0;
1050
- }, Kt = (e, t, n) => n ? n.maxBytes !== void 0 && e.byteLength > n.maxBytes ? {
1051
- reason: "too-large",
1052
- detail: `${e.byteLength} bytes exceeds the ${n.maxBytes}-byte limit`
1053
- } : Ut(t, n.allowedContentTypes) ? n.sniff && !Gt(e, t) ? {
1054
- reason: "content-mismatch",
1055
- detail: `bytes do not match the declared content type '${t}'`
1056
- } : null : {
1057
- reason: "content-type-not-allowed",
1058
- detail: `content type '${t}' is not in the allow-list`
1059
- } : null, qt = async (e, t, n) => {
1060
- if (!ut(t)) return { bytes: e };
1061
- let r = await ft();
1062
- if (!r) return { bytes: e };
1063
- try {
1064
- let t = e;
1065
- if (n?.normalize) {
1066
- let n = await r(Buffer.from(e), { failOn: "none" }).rotate().toBuffer();
1067
- t = new Uint8Array(n);
1068
- }
1069
- let i = await r(Buffer.from(t), { failOn: "none" }).metadata(), a = await r(Buffer.from(t), { failOn: "none" }).resize({
1070
- width: 24,
1071
- height: 24,
1072
- fit: "inside",
1073
- withoutEnlargement: !0
1074
- }).webp({ quality: 40 }).toBuffer().catch(() => null);
1075
- return {
1076
- bytes: t,
1077
- ...typeof i.width == "number" ? { width: i.width } : {},
1078
- ...typeof i.height == "number" ? { height: i.height } : {},
1079
- ...a ? { placeholder: `data:image/webp;base64,${a.toString("base64")}` } : {}
1080
- };
1081
- } catch {
1082
- return { bytes: e };
1083
- }
1084
- }, Jt = 67108864, Yt = (e) => new n({
1085
- reason: "too-large",
1086
- detail: `remote body exceeds the ${e}-byte ingest limit`
1087
- }), Xt = (e, t) => new n({
1088
- reason: "blocked-source",
1089
- detail: `will not fetch ${e}: ${t}`
1090
- }), Zt = (e, r, i = {}) => v.suspend(() => {
1091
- let a = r ?? Jt;
1092
- return !Number.isSafeInteger(a) || a < 0 ? v.fail(new t({
1093
- provider: "ingest",
1094
- message: "limits.maxBytes must be a non-negative safe integer",
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",
1095
58
  transient: !1
1096
- })) : v.tryPromise({
1097
- try: async (n) => {
1098
- let r = e, o;
1099
- for (let e = 0;; e++) {
1100
- let t = De(r, { ...i.allowHosts === void 0 ? {} : { allowHosts: i.allowHosts } });
1101
- if (t !== null) throw Xt(r, t);
1102
- o = await fetch(r, {
1103
- signal: n,
1104
- redirect: "manual"
1105
- });
1106
- let a = o.headers.get("location");
1107
- if (o.status < 300 || o.status >= 400 || a === null) break;
1108
- if (await o.body?.cancel().catch(() => {}), e >= (i.maxRedirects ?? 5)) throw Xt(r, "too many redirects");
1109
- r = new URL(a, r).toString();
1110
- }
1111
- let s;
1112
- try {
1113
- if (!o.ok) throw new t({
1114
- provider: "ingest",
1115
- message: `remote server returned HTTP ${o.status}`,
1116
- transient: o.status === 429 || o.status >= 500,
1117
- status: o.status
1118
- });
1119
- let e = o.headers.get("content-length"), n = o.headers.get("content-encoding")?.trim().toLowerCase();
1120
- if ((!n || n === "identity") && e !== null && /^\d+$/.test(e) && BigInt(e) > BigInt(a)) throw Yt(a);
1121
- let r = /* @__PURE__ */ new Uint8Array(), i = 0;
1122
- if (o.body !== null) for (s = o.body.getReader();;) {
1123
- let e = await s.read();
1124
- if (e.done) break;
1125
- if (e.value.byteLength > a - i) throw Yt(a);
1126
- if (e.value.byteLength !== 0) {
1127
- let t = i + e.value.byteLength;
1128
- if (t > r.byteLength) {
1129
- let e = Math.min(a, Math.max(65536, r.byteLength * 2, t)), n = new Uint8Array(e);
1130
- n.set(r), r = n;
1131
- }
1132
- r.set(e.value, i), i = t;
1133
- }
1134
- }
1135
- return {
1136
- bytes: i === r.byteLength ? r : r.slice(0, i),
1137
- contentType: o.headers.get("content-type")?.split(";")[0]?.trim() || "application/octet-stream"
1138
- };
1139
- } finally {
1140
- s === void 0 ? await o.body?.cancel().catch(() => {}) : (await s.cancel().catch(() => {}), s.releaseLock());
1141
- }
1142
- },
1143
- catch: (e) => e instanceof n || e instanceof t ? e : new t({
1144
- provider: "ingest",
1145
- message: "remote fetch or body read failed",
1146
- transient: !0
1147
- })
1148
- });
1149
- }), Qt = (e, t) => v.suspend(() => {
1150
- if (t === void 0) return e;
1151
- if (t.aborted) return v.interrupt;
1152
- let n = v.callback((e) => {
1153
- let n = () => e(v.interrupt);
1154
- return t.addEventListener("abort", n, { once: !0 }), t.aborted && n(), v.sync(() => t.removeEventListener("abort", n));
1155
59
  });
1156
- return v.raceFirst(e, n);
1157
- }), $t = (e) => {
1158
- let r = (e, n) => v.tryPromise({
1159
- try: n,
1160
- catch: (n) => {
1161
- let r = Ye(n);
1162
- if (r !== void 0) return r;
1163
- let i = G(n, "metadata"), a = new t({
1164
- provider: "metadata",
1165
- message: `Storage ${e} was not confirmed: ${i.message}; retain the operation identity for recovery`,
1166
- transient: i.transient,
1167
- ...i.status === void 0 ? {} : { status: i.status }
1168
- });
1169
- return Object.defineProperty(a, "cause", {
1170
- value: n,
1171
- configurable: !0
1172
- }), a;
1173
- }
1174
- });
1175
- return {
1176
- put: (t) => v.gen(function* () {
1177
- if (t.bytes.byteLength !== t.ref.size || Ce("sha256").update(t.bytes).digest("hex") !== t.identity.checksum) return yield* v.fail(new n({
1178
- reason: "operation-content-mismatch",
1179
- detail: "Storage operation bytes do not match their reserved identity"
1180
- }));
1181
- let i = yield* r("put reservation", () => e.metadata.reserve(t.identity, t.ref, t.quota, t.claim)), a = i.outcome;
1182
- return i.ready ? {
1183
- ref: i.ref,
1184
- outcome: a
1185
- } : (yield* e.provider.put(i.ref.key, t.bytes, {
1186
- contentType: i.ref.contentType,
1187
- public: i.ref.visibility === "public"
1188
- }), {
1189
- ref: yield* r("put confirmation", () => e.metadata.confirm(t.identity, t.claim)),
1190
- outcome: a
1191
- });
1192
- }),
1193
- delete: (t, n, i) => v.gen(function* () {
1194
- let a = yield* r("delete acceptance", () => e.metadata.beginDelete(t, n, i));
1195
- "operation" in a && (a.operation.deleteKey !== null && (yield* e.provider.delete(a.operation.deleteKey)), yield* r("delete confirmation", () => e.metadata.confirmDelete(a.identity)));
1196
- })
1197
- };
1198
- }, en = async (e) => {
1199
- let { createHash: t } = await import("node:crypto");
1200
- return t("sha256").update(e).digest("hex");
1201
- }, tn = (e, t, n) => `${e?.replace(/\/+$/, "") ?? ""}${n}/${t}`, nn = (e) => {
1202
- let t = /* @__PURE__ */ new Map(), n = {
1203
- public: 0,
1204
- private: 0
1205
- };
1206
- for (let r of e) {
1207
- let e = r.tenantId ?? "(global)", i = t.get(e) ?? {
1208
- count: 0,
1209
- bytes: 0
1210
- };
1211
- i.count = Je(i.count, r.count, "ref count"), i.bytes = Je(i.bytes, r.bytes, "usage bytes"), t.set(e, i), r.visibility === "public" ? n.public = Je(n.public, r.count, "public ref count") : n.private = Je(n.private, r.count, "private ref count");
1212
- }
1213
- return {
1214
- byTenant: Object.fromEntries(t),
1215
- visibility: n
1216
- };
1217
- }, rn = (e, t) => {
1218
- if (t.search && ![
1219
- e.id,
1220
- e.key,
1221
- e.contentType,
1222
- e.ownerId,
1223
- e.tenantId
1224
- ].some((e) => e?.toLowerCase().includes(t.search.toLowerCase())) || t.tenantId !== void 0 && (e.tenantId ?? null) !== (t.tenantId ?? null) || t.ownerId !== void 0 && e.ownerId !== t.ownerId || !t.includeDerived && e.derivedFrom != null) return !1;
1225
- if (t.folder !== void 0) {
1226
- let n = t.folder.replace(/\/+$/, ""), r = (e.folder ?? "").replace(/\/+$/, "");
1227
- if (r !== n && !r.startsWith(`${n}/`)) return !1;
1228
- }
1229
- if (t.tags.length > 0) {
1230
- let n = e.tags ?? [];
1231
- if (!t.tags.every((e) => n.includes(e))) return !1;
1232
- }
1233
- return !0;
1234
- }, an = (e) => e ?? "global", on = () => {
1235
- let e = /* @__PURE__ */ new Map(), t = /* @__PURE__ */ new Map();
1236
- return {
1237
- statistics: () => v.try({
1238
- try: () => nn((function* () {
1239
- for (let t of e.values()) yield {
1240
- tenantId: t.tenantId,
1241
- visibility: t.visibility,
1242
- count: 1,
1243
- bytes: t.size
1244
- };
1245
- })()),
1246
- catch: (e) => G(e, "refstore")
1247
- }),
1248
- insert: (t) => v.try({
1249
- try: () => {
1250
- W(t.size, "ref size"), e.set(t.id, t);
1251
- },
1252
- catch: (e) => G(e, "refstore")
1253
- }),
1254
- getById: (t) => v.sync(() => e.get(t) ?? null),
1255
- delete: (t) => v.sync(() => e.delete(t)),
1256
- listRecent: (t) => v.sync(() => [...e.values()].sort((e, t) => t.createdAt.getTime() - e.createdAt.getTime() || t.id.localeCompare(e.id)).slice(0, t)),
1257
- countByKey: (t, n) => v.sync(() => [...e.values()].filter((e) => e.bucket === t && e.key === n).length),
1258
- countPublicByKey: (t, n) => v.sync(() => [...e.values()].filter((e) => e.bucket === t && e.key === n && e.visibility === "public").length),
1259
- setVisibility: (t, n) => v.sync(() => {
1260
- let r = e.get(t);
1261
- if (r === void 0) return null;
1262
- let i = {
1263
- ...r,
1264
- visibility: n
1265
- };
1266
- return e.set(t, i), i;
1267
- }),
1268
- usageByTenant: (t) => v.try({
1269
- try: () => {
1270
- let n = 0, r = 0;
1271
- for (let i of e.values()) (i.tenantId ?? null) === (t ?? null) && (n = Je(n, i.size, "usage bytes"), r++);
1272
- return {
1273
- bytes: n,
1274
- count: r
1275
- };
1276
- },
1277
- catch: (e) => G(e, "refstore")
1278
- }),
1279
- consumeUsage: (e, n, r) => v.try({
1280
- try: () => {
1281
- let i = an(e), a = t.get(i) ?? {
1282
- bytes: 0,
1283
- count: 0
1284
- };
1285
- W(n.bytes, "usage byte delta"), W(n.count, "usage count delta");
1286
- let o = Number.isSafeInteger(a.bytes + n.bytes) && Number.isSafeInteger(a.count + n.count) && (r?.maxBytes === void 0 || a.bytes + n.bytes <= r.maxBytes) && (r?.maxCount === void 0 || a.count + n.count <= r.maxCount);
1287
- return o && t.set(i, {
1288
- bytes: a.bytes + n.bytes,
1289
- count: a.count + n.count
1290
- }), {
1291
- allowed: o,
1292
- bytes: a.bytes,
1293
- count: a.count
1294
- };
1295
- },
1296
- catch: (e) => G(e, "refstore")
1297
- }),
1298
- releaseUsage: (e, n) => v.try({
1299
- try: () => {
1300
- let r = an(e), i = t.get(r);
1301
- W(n.bytes, "usage byte delta"), W(n.count, "usage count delta"), i && t.set(r, {
1302
- bytes: Math.max(0, i.bytes - n.bytes),
1303
- count: Math.max(0, i.count - n.count)
1304
- });
1305
- },
1306
- catch: (e) => G(e, "refstore")
1307
- }),
1308
- listByDerivedFrom: (t) => v.sync(() => [...e.values()].filter((e) => (e.derivedFrom ?? null) === t)),
1309
- listRefs: (t) => v.sync(() => [...e.values()].filter((e) => rn(e, t)).sort((e, t) => t.createdAt.getTime() - e.createdAt.getTime() || t.id.localeCompare(e.id)).slice(t.offset, t.offset + t.limit))
1310
- };
1311
- }, sn = (e) => Array.isArray(e) && e.every((e) => typeof e == "string") ? e : null, X = (e) => ({
1312
- id: String(e.id),
1313
- tenantId: e.tenantId ?? null,
1314
- ownerId: e.ownerId ?? null,
1315
- bucket: String(e.bucket),
1316
- key: String(e.key),
1317
- contentType: String(e.contentType),
1318
- size: W(e.size, "ref size"),
1319
- checksum: String(e.checksum),
1320
- visibility: e.visibility === "public" ? "public" : "private",
1321
- accessPolicy: e.accessPolicy ?? null,
1322
- passwordHash: e.passwordHash ?? null,
1323
- createdAt: e.createdAt instanceof Date ? e.createdAt : new Date(String(e.createdAt)),
1324
- width: e.width ?? null,
1325
- height: e.height ?? null,
1326
- duration: e.duration ?? null,
1327
- placeholder: e.placeholder ?? null,
1328
- folder: e.folder ?? null,
1329
- tags: sn(e.tags),
1330
- alt: e.alt ?? null,
1331
- caption: e.caption ?? null,
1332
- derivedFrom: e.derivedFrom ?? null,
1333
- kind: e.kind ?? null
1334
- }), Z = (e) => v.tryPromise({
1335
- try: e,
1336
- catch: (e) => G(e, "refstore", !0)
1337
- }), cn = async (e, t) => (await e.query({
1338
- table: "_voltro_storage_usage",
1339
- predicate: {
1340
- column: "tenantId",
1341
- op: "eq",
1342
- value: t
1343
- },
1344
- order: [],
1345
- take: 1,
1346
- skip: void 0,
1347
- projection: void 0
1348
- }))[0] ?? null, ln = (e) => ({
1349
- statistics: () => Z(async () => nn((await e.query({
1350
- table: B,
1351
- predicate: void 0,
1352
- order: [],
1353
- take: void 0,
1354
- skip: void 0,
1355
- projection: void 0,
1356
- groupBy: ["tenantId", "visibility"],
1357
- aggregations: [
1358
- de("tenantId"),
1359
- de("visibility"),
1360
- {
1361
- op: "count",
1362
- alias: "count"
1363
- },
1364
- {
1365
- op: "sum",
1366
- column: "size",
1367
- alias: "bytes"
1368
- }
1369
- ]
1370
- })).map((e) => ({
1371
- tenantId: e.tenantId == null ? null : String(e.tenantId),
1372
- visibility: String(e.visibility),
1373
- count: W(e.count, "ref count"),
1374
- bytes: W(e.bytes ?? 0, "usage bytes")
1375
- })))),
1376
- insert: (t) => Z(() => e.insert(B, {
1377
- ...t,
1378
- size: String(W(t.size, "ref size"))
1379
- })),
1380
- getById: (t) => Z(async () => {
1381
- let n = await e.query({
1382
- table: B,
1383
- predicate: {
1384
- column: "id",
1385
- op: "eq",
1386
- value: t
1387
- },
1388
- order: [],
1389
- take: 1,
1390
- skip: void 0,
1391
- projection: void 0
1392
- });
1393
- return n[0] ? X(n[0]) : null;
1394
- }),
1395
- delete: (t) => Z(() => e.delete(B, t)),
1396
- listRecent: (t) => Z(async () => (await e.query({
1397
- table: B,
1398
- predicate: void 0,
1399
- order: [{
1400
- column: "createdAt",
1401
- direction: "desc"
1402
- }],
1403
- take: t,
1404
- skip: void 0,
1405
- projection: void 0
1406
- })).map(X)),
1407
- countByKey: (t, n) => Z(async () => W((await e.query({
1408
- table: B,
1409
- predicate: { and: [{
1410
- column: "bucket",
1411
- op: "eq",
1412
- value: t
1413
- }, {
1414
- column: "key",
1415
- op: "eq",
1416
- value: n
1417
- }] },
1418
- order: [],
1419
- take: void 0,
1420
- skip: void 0,
1421
- projection: void 0,
1422
- aggregations: [{
1423
- op: "count",
1424
- alias: "count"
1425
- }]
1426
- }))[0]?.count ?? 0, "ref count")),
1427
- countPublicByKey: (t, n) => Z(async () => W((await e.query({
1428
- table: B,
1429
- predicate: { and: [
1430
- {
1431
- column: "bucket",
1432
- op: "eq",
1433
- value: t
1434
- },
1435
- {
1436
- column: "key",
1437
- op: "eq",
1438
- value: n
1439
- },
1440
- {
1441
- column: "visibility",
1442
- op: "eq",
1443
- value: "public"
1444
- }
1445
- ] },
1446
- order: [],
1447
- take: void 0,
1448
- skip: void 0,
1449
- projection: void 0,
1450
- aggregations: [{
1451
- op: "count",
1452
- alias: "count"
1453
- }]
1454
- }))[0]?.count ?? 0, "ref count")),
1455
- setVisibility: (t, n) => Z(async () => {
1456
- let r = await e.update(B, t, { visibility: n });
1457
- return r ? X(r) : null;
1458
- }),
1459
- usageByTenant: (t) => Z(async () => {
1460
- let n = await e.query({
1461
- table: B,
1462
- predicate: {
1463
- column: "tenantId",
1464
- op: "eq",
1465
- value: t
1466
- },
1467
- order: [],
1468
- take: void 0,
1469
- skip: void 0,
1470
- projection: void 0,
1471
- aggregations: [
1472
- {
1473
- op: "count",
1474
- alias: "count"
1475
- },
1476
- {
1477
- op: "sum",
1478
- column: "size",
1479
- alias: "bytes"
1480
- },
1481
- {
1482
- op: "min",
1483
- column: "size",
1484
- alias: "minSize"
1485
- },
1486
- {
1487
- op: "max",
1488
- column: "size",
1489
- alias: "maxSize"
1490
- }
1491
- ]
1492
- });
1493
- return W(n[0]?.count ?? 0, "ref count") > 0 && (W(n[0]?.minSize, "ref size"), W(n[0]?.maxSize, "ref size")), {
1494
- bytes: W(n[0]?.bytes ?? 0, "usage bytes"),
1495
- count: W(n[0]?.count ?? 0, "ref count")
1496
- };
1497
- }),
1498
- consumeUsage: (t, n, r) => Z(async () => {
1499
- let i = an(t);
1500
- W(n.bytes, "usage byte delta"), W(n.count, "usage count delta");
1501
- for (let t = 0; t < 32; t++) {
1502
- t > 0 && await new Promise((e) => setTimeout(e, t));
1503
- let a = await cn(e, i), o = a ? W(a.bytes, "usage bytes") : 0, s = a ? W(a.count, "ref count") : 0;
1504
- if (!(Number.isSafeInteger(o + n.bytes) && Number.isSafeInteger(s + n.count) && (r?.maxBytes === void 0 || o + n.bytes <= r.maxBytes) && (r?.maxCount === void 0 || s + n.count <= r.maxCount))) return {
1505
- allowed: !1,
1506
- bytes: o,
1507
- count: s
1508
- };
1509
- if (a) {
1510
- if (await e.updateMany("_voltro_storage_usage", {
1511
- bytes: String(o + n.bytes),
1512
- count: String(s + n.count),
1513
- updatedAt: /* @__PURE__ */ new Date()
1514
- }, { where: ue(k("id", String(a.id)), k("bytes", a.bytes), k("count", a.count)) }) === 1) return {
1515
- allowed: !0,
1516
- bytes: o,
1517
- count: s
1518
- };
1519
- } else {
1520
- let t = A({
1521
- kind: "typeid",
1522
- prefix: "susage"
1523
- }, Ue), r = await e.insertIgnore(Ue, {
1524
- id: t,
1525
- tenantId: i,
1526
- bytes: String(n.bytes),
1527
- count: String(n.count),
1528
- updatedAt: /* @__PURE__ */ new Date()
1529
- }, { conflictColumns: ["tenantId"] });
1530
- if (String(r.id) === t) return {
1531
- allowed: !0,
1532
- bytes: 0,
1533
- count: 0
1534
- };
1535
- }
1536
- }
1537
- throw T("Storage quota reservation contended after 32 attempts; retry");
1538
- }),
1539
- releaseUsage: (t, n) => Z(async () => {
1540
- let r = an(t);
1541
- W(n.bytes, "usage byte delta"), W(n.count, "usage count delta");
1542
- for (let t = 0; t < 32; t++) {
1543
- t > 0 && await new Promise((e) => setTimeout(e, t));
1544
- let i = await cn(e, r);
1545
- if (!i) return;
1546
- let a = W(i.bytes, "usage bytes"), o = W(i.count, "ref count");
1547
- if (await e.updateMany("_voltro_storage_usage", {
1548
- bytes: String(Math.max(0, a - n.bytes)),
1549
- count: String(Math.max(0, o - n.count)),
1550
- updatedAt: /* @__PURE__ */ new Date()
1551
- }, { where: ue(k("id", String(i.id)), k("bytes", i.bytes), k("count", i.count)) }) === 1) return;
1552
- }
1553
- throw T("Storage quota release contended after 32 attempts; retry");
1554
- }),
1555
- listByDerivedFrom: (t) => Z(async () => (await e.query({
1556
- table: B,
1557
- predicate: {
1558
- column: "derivedFrom",
1559
- op: "eq",
1560
- value: t
1561
- },
1562
- order: [{
1563
- column: "createdAt",
1564
- direction: "asc"
1565
- }],
1566
- take: void 0,
1567
- skip: void 0,
1568
- projection: void 0
1569
- })).map(X)),
1570
- listRefs: (t) => Z(async () => {
1571
- let n = [];
1572
- t.tenantId !== void 0 && n.push(k("tenantId", t.tenantId)), t.ownerId !== void 0 && n.push(k("ownerId", t.ownerId)), t.search && n.push(N(...[
1573
- "id",
1574
- "key",
1575
- "contentType",
1576
- "ownerId",
1577
- "tenantId"
1578
- ].map((e) => fe(e, t.search)))), t.includeDerived || n.push(me("derivedFrom"));
1579
- let r = t.folder === void 0 && t.tags.length === 0, i = n.length ? ue(...n) : void 0, a = await e.query({
1580
- table: B,
1581
- predicate: i,
1582
- order: [{
1583
- column: "createdAt",
1584
- direction: "desc"
1585
- }, {
1586
- column: "id",
1587
- direction: "desc"
1588
- }],
1589
- take: r ? t.limit : void 0,
1590
- skip: r ? t.offset : void 0,
1591
- projection: void 0
1592
- });
1593
- return r ? a.map(X) : a.map(X).filter((e) => rn(e, t)).slice(t.offset, t.offset + t.limit);
1594
- })
1595
- }), un = () => {
1596
- let e = /* @__PURE__ */ new Map();
1597
- return {
1598
- insert: (t) => v.sync(() => {
1599
- e.set(t.id, t);
1600
- }),
1601
- delete: (t) => v.sync(() => {
1602
- e.delete(t);
1603
- }),
1604
- getById: (t) => v.sync(() => e.get(t) ?? null),
1605
- listByRef: (t) => v.sync(() => [...e.values()].filter((e) => e.refId === t)),
1606
- deleteByRef: (t) => v.sync(() => {
1607
- for (let [n, r] of e) r.refId === t && e.delete(n);
1608
- })
1609
- };
1610
- }, dn = (e) => ({
1611
- id: String(e.id),
1612
- refId: String(e.refId),
1613
- principalType: e.principalType,
1614
- principalId: String(e.principalId),
1615
- permission: e.permission === "write" ? "write" : "read",
1616
- createdAt: e.createdAt instanceof Date ? e.createdAt : new Date(String(e.createdAt)),
1617
- expiresAt: e.expiresAt ? e.expiresAt instanceof Date ? e.expiresAt : new Date(String(e.expiresAt)) : null,
1618
- createdBy: e.createdBy ?? null
1619
- }), fn = (e) => ({
1620
- insert: (t) => Z(() => e.insert(V, { ...t })),
1621
- delete: (t) => Z(() => e.delete(V, t)),
1622
- getById: (t) => Z(async () => {
1623
- let n = (await e.query({
1624
- table: V,
1625
- predicate: {
1626
- column: "id",
1627
- op: "eq",
1628
- value: t
1629
- },
1630
- order: [],
1631
- take: 1,
1632
- skip: void 0,
1633
- projection: void 0
1634
- }))[0];
1635
- return n ? dn(n) : null;
1636
- }),
1637
- listByRef: (t) => Z(async () => (await e.query({
1638
- table: V,
1639
- predicate: {
1640
- column: "refId",
1641
- op: "eq",
1642
- value: t
1643
- },
1644
- order: [{
1645
- column: "createdAt",
1646
- direction: "desc"
1647
- }],
1648
- take: void 0,
1649
- skip: void 0,
1650
- projection: void 0
1651
- })).map(dn)),
1652
- deleteByRef: (t) => Z(async () => {
1653
- let n = await e.query({
1654
- table: V,
1655
- predicate: {
1656
- column: "refId",
1657
- op: "eq",
1658
- value: t
1659
- },
1660
- order: [],
1661
- take: void 0,
1662
- skip: void 0,
1663
- projection: void 0
1664
- });
1665
- for (let t of n) await e.delete(V, String(t.id));
1666
- })
1667
- }), pn = () => A({
1668
- kind: "typeid",
1669
- prefix: "file"
1670
- }, B), mn = () => A({
1671
- kind: "typeid",
1672
- prefix: "grant"
1673
- }, V), hn = (i) => {
1674
- let { provider: a, refStore: o, grantStore: s, bucket: c } = i, l = i.access ?? {}, u = i.attempts ?? 3, d = i.urlExpiresInSec ?? 3600, f = (e) => tn(i.publicBaseUrl, e, i.httpPath ?? "/_voltro/storage"), p = x.max([x.recurs(Math.max(0, u - 1)), x.exponential("100 millis")]).pipe(x.while(({ input: e }) => e.transient)), m = (e, t, n) => [
1675
- i.tenantPrefix,
1676
- e ?? "global",
1677
- n ?? t
1678
- ].filter(Boolean).join("/"), ee = (e) => {
1679
- if (e === void 0) return v.succeed(void 0);
1680
- let n = e.length === 0 ? "empty" : e.includes("\0") ? "contains NUL" : e.startsWith("/") || e.startsWith("\\") ? "starts with a path separator" : e.includes("\\") ? "contains a backslash" : e.split("/").some((e) => e === "" || e === "." || e === "..") ? "contains an empty, \".\" or \"..\" segment" : void 0;
1681
- return n === void 0 ? v.succeed(e) : v.fail(new t({
1682
- provider: a.name,
1683
- message: `storage key rejected: ${n}`,
1684
- transient: !1,
1685
- status: 400
1686
- }));
1687
- }, te = (e, t, n) => [
1688
- i.tenantPrefix,
1689
- e ?? "global",
1690
- "_incoming",
1691
- t,
1692
- String(n).padStart(6, "0")
1693
- ].filter(Boolean).join("/"), ne = (e, t) => t === void 0 || e.tenantId === t, h = (e, n) => ne(e, n) ? v.succeed(e) : v.fail(new t({
1694
- provider: a.name,
1695
- message: "cross-tenant access denied",
1696
- transient: !1,
1697
- status: 403
1698
- })), g = (e, n, r) => v.gen(function* () {
1699
- let o = i.objects?.(), s = (e) => new t({
1700
- provider: "metadata",
1701
- message: e,
1702
- transient: !1,
1703
- status: 409
1704
- });
1705
- if (o === void 0) return r === void 0 ? !1 : yield* v.fail(s(`claim '${r}' cannot be released: no data store is bound, so ref '${e}' holds no claims`));
1706
- let c = yield* v.tryPromise({
1707
- try: () => o.intent(e),
1708
- catch: (e) => new t({
1709
- provider: "metadata",
1710
- message: String(e?.message ?? e),
1711
- transient: !1
1712
- })
1713
- });
1714
- return c === void 0 ? r === void 0 ? !1 : yield* v.fail(s(`claim '${r}' cannot be released: ref '${e}' was not written through an operation and holds no claims`)) : (yield* h(c.ref, n), yield* $t({
1715
- metadata: o,
1716
- provider: {
1717
- ...a,
1718
- delete: (e) => a.delete(e).pipe(v.retry(p))
1719
- }
1720
- }).delete(e, n, r).pipe(v.catchTag("StorageRejected", (e) => v.fail(e.reason === "claim-not-held" ? s(e.detail) : new t({
1721
- provider: "metadata",
1722
- message: e.detail,
1723
- transient: !1
1724
- })))), !0);
1725
- }), _ = (e, n) => o.getById(e).pipe(v.flatMap((r) => r ? h(r, n) : v.fail(new t({
1726
- provider: a.name,
1727
- message: `no ref '${e}'`,
1728
- transient: !1,
1729
- status: 404
1730
- })))), re = (e) => v.suspend(() => {
1731
- let n = i.scan(e);
1732
- return v.isEffect(n) ? n : v.tryPromise({
1733
- try: () => Promise.resolve(n),
1734
- catch: (e) => new t({
1735
- provider: "scan",
1736
- message: String(e?.message ?? e),
1737
- transient: !0
1738
- })
1739
- });
1740
- }), ie = (e) => v.suspend(() => {
1741
- let t = e.contentType;
1742
- if (!i.videoProbe || !(t.startsWith("video/") || t.startsWith("audio/"))) return v.succeed(null);
1743
- let n;
1744
- try {
1745
- n = i.videoProbe(e);
1746
- } catch {
1747
- return v.succeed(null);
1748
- }
1749
- return v.isEffect(n) ? n.pipe(v.catch(() => v.succeed(null))) : v.tryPromise({
1750
- try: () => Promise.resolve(n),
1751
- catch: () => null
1752
- }).pipe(v.catch(() => v.succeed(null)));
1753
- }), b = (e) => v.gen(function* () {
1754
- let t = Kt(e.bytes, e.contentType, i.limits);
1755
- if (t) return yield* v.fail(new n(t));
1756
- if (e.claim !== void 0 && e.operationId === void 0) return yield* v.fail(new n({
1757
- reason: "claim-without-operation",
1758
- detail: "a put with a claim needs an operationId; the claim names this caller's hold on that operation's object"
1759
- }));
1760
- if (i.scan) {
1761
- let t = yield* re({
1762
- bytes: e.bytes,
1763
- contentType: e.contentType,
1764
- ...e.key ? { key: e.key } : {}
1765
- });
1766
- if (!t.clean) return yield* v.fail(new r({ threat: t.threat ?? "unknown" }));
1767
- }
1768
- let s = yield* v.promise(() => qt(e.bytes, e.contentType, { normalize: i.normalizeImages ?? !1 })), l = s.bytes, u = yield* ie({
1769
- bytes: l,
1770
- contentType: e.contentType
1771
- }), d = s.width ?? u?.width, f = s.height ?? u?.height, te = s.placeholder ?? u?.poster, ne = e.duration ?? u?.duration, h = yield* v.promise(() => en(l)), g = e.tenantId ?? null, _ = e.visibility ?? "private", b = m(g, h, yield* ee(e.key)), x = e.password ? yield* v.sync(() => yt(e.password)) : null, S = {
1772
- id: pn(),
1773
- tenantId: g,
1774
- ownerId: e.ownerId ?? null,
1775
- bucket: c,
1776
- key: b,
1777
- contentType: e.contentType,
1778
- size: l.byteLength,
1779
- checksum: h,
1780
- visibility: _,
1781
- accessPolicy: e.access ?? null,
1782
- passwordHash: x,
1783
- createdAt: /* @__PURE__ */ new Date(),
1784
- ...d === void 0 ? {} : { width: d },
1785
- ...f === void 0 ? {} : { height: f },
1786
- ...te === void 0 ? {} : { placeholder: te },
1787
- ...ne === void 0 ? {} : { duration: ne },
1788
- ...e.folder === void 0 ? {} : { folder: e.folder },
1789
- ...e.tags === void 0 ? {} : { tags: e.tags },
1790
- ...e.alt === void 0 ? {} : { alt: e.alt },
1791
- ...e.caption === void 0 ? {} : { caption: e.caption },
1792
- ...e.derivedFrom === void 0 ? {} : { derivedFrom: e.derivedFrom },
1793
- ...e.kind === void 0 ? {} : { kind: e.kind }
1794
- }, C = i.transcode !== void 0 && i.autoTranscode !== !1, oe = (t) => C && t.derivedFrom == null && (e.contentType.startsWith("video/") || e.contentType.startsWith("audio/")) ? v.forkDetach(ae(t).pipe(v.ignore)) : v.void;
1795
- if (e.operationId !== void 0) {
1796
- let t = i.objects?.();
1797
- if (t === void 0) return yield* v.fail(new n({
1798
- reason: "operation-store-unbound",
1799
- detail: "a put with an operationId needs a bound data store; the in-memory ref store cannot hold operation intents"
1800
- }));
1801
- let r = {
1802
- tenantId: g,
1803
- bucket: c,
1804
- operationId: e.operationId,
1805
- checksum: h,
1806
- logicalKey: b,
1807
- fingerprint: yield* v.promise(() => en(new TextEncoder().encode(JSON.stringify([
1808
- h,
1809
- e.contentType,
1810
- _,
1811
- e.access ?? null,
1812
- e.key ?? null,
1813
- e.ownerId ?? null,
1814
- e.folder ?? null,
1815
- e.tags ?? null,
1816
- e.alt ?? null,
1817
- e.caption ?? null,
1818
- e.derivedFrom ?? null,
1819
- e.kind ?? null,
1820
- ne ?? null,
1821
- e.password !== void 0
1822
- ]))))
1823
- }, o = yield* $t({
1824
- metadata: t,
1825
- provider: {
1826
- ...a,
1827
- put: (e, t, n) => a.put(e, t, n).pipe(v.retry(p))
1828
- }
1829
- }).put({
1830
- identity: r,
1831
- ref: S,
1832
- bytes: l,
1833
- ...i.quota === void 0 ? {} : { quota: i.quota },
1834
- ...e.claim === void 0 ? {} : { claim: e.claim }
1835
- });
1836
- return yield* oe(o.ref), {
1837
- ...o.ref,
1838
- outcome: o.outcome
1839
- };
1840
- }
1841
- let w = {
1842
- bytes: l.byteLength,
1843
- count: 1
1844
- }, se = yield* o.consumeUsage(g, w, i.quota);
1845
- if (!se.allowed) {
1846
- let e = i.quota ?? {}, t = e.maxCount !== void 0 && se.count + 1 > e.maxCount ? `tenant object count ${se.count} + 1 exceeds max ${e.maxCount}` : `tenant usage ${se.bytes} + ${l.byteLength} bytes exceeds max ${e.maxBytes}`;
1847
- return yield* v.fail(new n({
1848
- reason: "quota-exceeded",
1849
- detail: t
1850
- }));
1851
- }
1852
- return yield* ((e) => e.pipe(v.onExit((e) => y.isSuccess(e) ? v.void : o.delete(S.id).pipe(v.andThen(o.releaseUsage(g, w)), v.ignore))))(o.insert(S).pipe(v.andThen(a.put(b, l, {
1853
- contentType: e.contentType,
1854
- public: _ === "public"
1855
- }).pipe(v.retry(p))))), yield* oe(S), {
1856
- ...S,
1857
- outcome: "created"
1858
- };
1859
- }), S = (e) => v.suspend(() => {
1860
- if (!i.transcode) return v.succeed([]);
1861
- let t;
1862
- try {
1863
- t = i.transcode(e);
1864
- } catch {
1865
- return v.succeed([]);
1866
- }
1867
- return v.isEffect(t) ? t.pipe(v.catch(() => v.succeed([]))) : v.tryPromise({
1868
- try: () => Promise.resolve(t),
1869
- catch: () => []
1870
- }).pipe(v.catch(() => v.succeed([])));
1871
- }), ae = (e) => v.gen(function* () {
1872
- if (!i.transcode || e.derivedFrom != null) return [];
1873
- let t = yield* a.get(e.key).pipe(v.retry(p)), n = yield* S({
1874
- bytes: t.bytes,
1875
- contentType: e.contentType,
1876
- ref: e
1877
- }), r = [];
1878
- for (let t of n) {
1879
- let n = yield* b({
1880
- bytes: t.bytes,
1881
- contentType: t.contentType,
1882
- tenantId: e.tenantId,
1883
- ownerId: e.ownerId,
1884
- visibility: e.visibility,
1885
- derivedFrom: e.id,
1886
- kind: t.kind,
1887
- ...t.label === void 0 ? {} : { caption: t.label }
1888
- });
1889
- r.push(n);
1890
- }
1891
- return r;
1892
- }), oe = (e, t, n) => v.gen(function* () {
1893
- if (e.derivedFrom != null) {
1894
- let r = yield* o.getById(e.derivedFrom);
1895
- return r === null ? !1 : yield* oe(r, t, n);
1896
- }
1897
- if (e.visibility === "public") return !0;
1898
- if (e.tenantId !== null && !ne(e, t.tenantId ?? null)) return !1;
1899
- if (yield* Dt(e, t, {
1900
- ...l,
1901
- ...n?.password === void 0 ? {} : { password: n.password }
1902
- })) return !0;
1903
- let r = yield* jt(t, l);
1904
- return At(yield* s.listByRef(e.id), t, r, n?.permission ?? "read", Date.now());
1905
- }), w = (e) => {
1906
- if (e.visibility === "public") {
1907
- let t = a.publicUrl?.(e.key);
1908
- if (t != null) return t;
1909
- }
1910
- return f(e.id);
1911
- };
1912
- return {
1913
- put: b,
1914
- get: (e, t) => _(e, t?.tenantId).pipe(v.flatMap((e) => a.get(e.key).pipe(v.retry(p), v.map((t) => ({
1915
- bytes: t.bytes,
1916
- ref: e
1917
- }))))),
1918
- getStream: (e, t) => _(e, t?.tenantId).pipe(v.map((e) => ({
1919
- ref: e,
1920
- stream: C.unwrap(v.suspend(() => a.getStream ? a.getStream(e.key).pipe(v.retry(p), v.map((e) => e.stream)) : a.get(e.key).pipe(v.retry(p), v.map((e) => C.make(e.bytes)))))
1921
- }))),
1922
- getRange: (e, n, r) => _(e, r?.tenantId).pipe(v.flatMap((e) => {
1923
- let r = e.size, i = Math.max(0, Math.trunc(n.start));
1924
- if (r > 0 && i >= r) return v.fail(new t({
1925
- provider: a.name,
1926
- message: `range start ${i} past end ${r}`,
1927
- transient: !1,
1928
- status: 416
1929
- }));
1930
- let o = Math.min(Math.trunc(n.endInclusive), Math.max(0, r - 1));
1931
- return o < i ? v.fail(new t({
1932
- provider: a.name,
1933
- message: `empty range ${i}-${o}`,
1934
- transient: !1,
1935
- status: 416
1936
- })) : (a.getRange ? a.getRange(e.key, i, o).pipe(v.retry(p)) : a.get(e.key).pipe(v.retry(p), v.map((e) => e.bytes.subarray(i, o + 1)))).pipe(v.map((t) => ({
1937
- bytes: t,
1938
- ref: e,
1939
- totalSize: r
1940
- })));
1941
- })),
1942
- getUrl: (e, t) => _(e, t?.tenantId).pipe(v.flatMap((e) => e.visibility === "public" ? v.succeed(w(e)) : a.presigns ? a.getUrl(e.key, t?.expiresInSec ?? d) : v.succeed(f(e.id)))),
1943
- head: (e, t) => o.getById(e).pipe(v.flatMap((e) => e ? h(e, t?.tenantId).pipe(v.map((e) => e)) : v.succeed(null))),
1944
- delete: (e, t) => g(e, t?.tenantId, t?.claim).pipe(v.flatMap((n) => n ? v.void : _(e, t?.tenantId).pipe(v.flatMap((t) => s.deleteByRef(e).pipe(v.flatMap(() => o.delete(e)), v.flatMap((e) => e ? o.countByKey(t.bucket, t.key).pipe(v.flatMap((e) => e === 0 ? a.delete(t.key).pipe(v.retry(p)) : v.void), v.flatMap(() => o.releaseUsage(t.tenantId, {
1945
- bytes: t.size,
1946
- count: 1
1947
- }))) : v.void), v.asVoid))))),
1948
- signedUrl: (e, t) => _(e, t?.tenantId).pipe(v.flatMap((e) => {
1949
- if (e.visibility === "public") return v.succeed(w(e));
1950
- let n = t?.expiresInSec ?? d;
1951
- return a.presigns ? a.getUrl(e.key, n) : v.sync(() => `${f(e.id)}?t=${Mt(e.id, n, void 0, i.httpPath ?? "/_voltro/storage")}`);
1952
- })),
1953
- setVisibility: (e, r, i) => v.gen(function* () {
1954
- let s = yield* _(e, i?.tenantId);
1955
- if (s.visibility === r) return s;
1956
- let c = o.setVisibility;
1957
- if (c === void 0) return yield* v.fail(new n({
1958
- reason: "visibility-unsupported",
1959
- detail: "the ref store cannot change a stored object's visibility"
1960
- }));
1961
- if (r === "private" && a.publicUrl?.(s.key) != null) return yield* v.fail(new n({
1962
- reason: "visibility-unsupported",
1963
- detail: `objects are served from a public base (${a.name} cdnBaseUrl); a public object cannot be made private there`
1964
- }));
1965
- if (r === "private" && a.setObjectPublic !== void 0 && o.countPublicByKey === void 0) return yield* v.fail(new n({
1966
- reason: "visibility-unsupported",
1967
- detail: "the ref store cannot tell whether other refs keep these bytes public"
1968
- }));
1969
- let l = yield* c(s.id, r);
1970
- if (l === null) return yield* v.fail(new t({
1971
- provider: a.name,
1972
- message: `no ref '${e}'`,
1973
- transient: !1,
1974
- status: 404
1975
- }));
1976
- let u = s.derivedFrom == null ? yield* o.listByDerivedFrom(s.id) : [];
1977
- for (let e of u) e.visibility !== r && (yield* c(e.id, r));
1978
- if (a.setObjectPublic !== void 0) {
1979
- let e = o.countPublicByKey;
1980
- for (let t of [s, ...u]) {
1981
- let n = r === "public" || e !== void 0 && (yield* e(t.bucket, t.key)) > 0;
1982
- yield* a.setObjectPublic(t.key, n);
1983
- }
1984
- }
1985
- return l;
1986
- }),
1987
- mintUrl: (n, r, s) => v.gen(function* () {
1988
- let c = yield* o.getById(n).pipe(v.flatMap((e) => e ? v.succeed(e) : v.fail(new t({
1989
- provider: a.name,
1990
- message: `no ref '${n}'`,
1991
- transient: !1,
1992
- status: 404
1993
- }))));
1994
- if (c.visibility === "public" && c.derivedFrom == null) return w(c);
1995
- if (!(yield* oe(c, r, s?.password === void 0 ? {} : { password: s.password }))) return yield* v.fail(new e({
1996
- refId: n,
1997
- reason: "access denied"
1998
- }));
1999
- let l = s?.expiresInSec ?? d;
2000
- if (a.presigns) return yield* a.getUrl(c.key, l);
2001
- let u = yield* v.sync(() => Mt(c.id, l, void 0, i.httpPath ?? "/_voltro/storage"));
2002
- return `${f(c.id)}?t=${u}`;
2003
- }),
2004
- mintUploadUrl: (e) => v.gen(function* () {
2005
- if (!a.getUploadUrl) return yield* v.fail(new t({
2006
- provider: a.name,
2007
- message: `provider '${a.name}' does not support presigned uploads`,
2008
- transient: !1,
2009
- status: 400
2010
- }));
2011
- let n = m(e.tenantId ?? null, "", yield* ee(e.key));
2012
- return yield* a.getUploadUrl(n, e.expiresInSec ?? d, e.contentType);
2013
- }),
2014
- checkAccess: oe,
2015
- grant: (e) => v.gen(function* () {
2016
- let t = {
2017
- id: mn(),
2018
- refId: e.refId,
2019
- principalType: e.principalType,
2020
- principalId: e.principalId,
2021
- permission: e.permission ?? "read",
2022
- createdAt: /* @__PURE__ */ new Date(),
2023
- expiresAt: e.expiresAt ?? null,
2024
- createdBy: e.createdBy ?? null
2025
- };
2026
- return yield* s.insert(t), t;
2027
- }),
2028
- listRefs: (e) => v.suspend(() => {
2029
- let t = Math.min(500, Math.max(1, Math.trunc(e?.limit ?? 50))), n = Math.max(0, Math.trunc(e?.offset ?? 0)), r = {
2030
- tenantId: e && "tenantId" in e ? e.tenantId : void 0,
2031
- folder: e?.folder,
2032
- tags: e?.tags ?? [],
2033
- ownerId: e?.ownerId,
2034
- includeDerived: e?.includeDerived ?? !1,
2035
- limit: t + 1,
2036
- offset: n
2037
- };
2038
- return o.listRefs(r).pipe(v.map((e) => {
2039
- let r = e.length > t;
2040
- return {
2041
- refs: r ? e.slice(0, t) : e,
2042
- nextOffset: r ? n + t : null
2043
- };
2044
- }));
2045
- }),
2046
- revoke: (e) => s.delete(e),
2047
- getGrant: (e) => s.getById(e),
2048
- listGrants: (e) => s.listByRef(e),
2049
- usage: (e) => o.usageByTenant(e),
2050
- sweepOrphans: (e) => v.gen(function* () {
2051
- let t = e?.limit ?? 1e3, n = e?.dryRun ?? !1, r = yield* o.listRecent(t), i = [];
2052
- for (let e of r) if ((yield* a.head(e.key)) === null) {
2053
- if (!n) {
2054
- if (!(yield* o.delete(e.id))) continue;
2055
- yield* o.releaseUsage(e.tenantId, {
2056
- bytes: e.size,
2057
- count: 1
2058
- });
2059
- }
2060
- i.push(e.id);
2061
- }
2062
- return {
2063
- scanned: r.length,
2064
- removed: i
2065
- };
2066
- }),
2067
- ingestUrl: (e, t) => Qt(v.gen(function* () {
2068
- let n = yield* Zt(e, i.limits?.maxBytes, i.ingest);
2069
- return yield* b({
2070
- bytes: n.bytes,
2071
- contentType: t?.contentType ?? n.contentType,
2072
- ...t?.tenantId === void 0 ? {} : { tenantId: t.tenantId },
2073
- ...t?.operationId === void 0 ? {} : { operationId: t.operationId },
2074
- ...t?.ownerId === void 0 ? {} : { ownerId: t.ownerId },
2075
- ...t?.visibility === void 0 ? {} : { visibility: t.visibility },
2076
- ...t?.access === void 0 ? {} : { access: t.access },
2077
- ...t?.key === void 0 ? {} : { key: t.key },
2078
- ...t?.folder === void 0 ? {} : { folder: t.folder },
2079
- ...t?.tags === void 0 ? {} : { tags: t.tags },
2080
- ...t?.alt === void 0 ? {} : { alt: t.alt },
2081
- ...t?.caption === void 0 ? {} : { caption: t.caption }
2082
- });
2083
- }), t?.abortSignal),
2084
- mintPresignedUpload: (e) => v.gen(function* () {
2085
- if (!a.getUploadUrl) return yield* v.fail(new t({
2086
- provider: a.name,
2087
- message: `provider '${a.name}' does not support presigned uploads`,
2088
- transient: !1,
2089
- status: 400
2090
- }));
2091
- let n = e.expiresInSec ?? d, r = `_incoming/${A({
2092
- kind: "typeid",
2093
- prefix: "up"
2094
- }, B)}`, i = m(e.tenantId ?? null, "", r);
2095
- return {
2096
- uploadUrl: yield* a.getUploadUrl(i, n, e.contentType),
2097
- key: i,
2098
- expiresInSec: n
2099
- };
2100
- }),
2101
- finalizeUpload: (e) => a.get(e.key).pipe(v.retry(p), v.flatMap((t) => b({
2102
- bytes: t.bytes,
2103
- contentType: e.contentType,
2104
- ...e.tenantId === void 0 ? {} : { tenantId: e.tenantId },
2105
- ...e.ownerId === void 0 ? {} : { ownerId: e.ownerId },
2106
- ...e.visibility === void 0 ? {} : { visibility: e.visibility },
2107
- ...e.access === void 0 ? {} : { access: e.access },
2108
- ...e.folder === void 0 ? {} : { folder: e.folder },
2109
- ...e.tags === void 0 ? {} : { tags: e.tags },
2110
- ...e.alt === void 0 ? {} : { alt: e.alt },
2111
- ...e.caption === void 0 ? {} : { caption: e.caption }
2112
- })), v.ensuring(a.delete(e.key).pipe(v.retry(p), v.ignore))),
2113
- putResumableChunk: (e) => a.put(te(e.tenantId ?? null, e.uploadId, e.index), e.bytes, { contentType: "application/octet-stream" }).pipe(v.retry(p), v.asVoid),
2114
- resumableStatus: (e) => v.gen(function* () {
2115
- let t = 0, n = 0;
2116
- for (; t < 1e6;) {
2117
- let r = yield* a.head(te(e.tenantId ?? null, e.uploadId, t)).pipe(v.retry(p), v.catch(() => v.succeed(null)));
2118
- if (r === null) break;
2119
- n += r.size, t += 1;
2120
- }
2121
- return {
2122
- offset: n,
2123
- nextIndex: t
2124
- };
2125
- }),
2126
- finalizeResumable: (e) => v.gen(function* () {
2127
- let r = i.limits?.maxBytes ?? 2 ** 53 - 1;
2128
- if (!Number.isSafeInteger(r) || r < 0 || !Number.isSafeInteger(e.count) || e.count < 0) return yield* v.fail(new t({
2129
- provider: a.name,
2130
- message: "resumable count and limits.maxBytes must be non-negative safe integers",
2131
- transient: !1,
2132
- status: 400
2133
- }));
2134
- let o = (t) => te(e.tenantId ?? null, e.uploadId, t), s = v.gen(function* () {
2135
- for (let t = 0; t < e.count; t++) yield* a.delete(o(t)).pipe(v.retry(p), v.ignore);
2136
- }), c = () => new n({
2137
- reason: "too-large",
2138
- detail: `resumable upload exceeds ${r}-byte limit`
2139
- }), l = yield* v.gen(function* () {
2140
- let n = 0;
2141
- for (let i = 0; i < e.count; i++) {
2142
- let e = yield* a.head(o(i)).pipe(v.retry(p));
2143
- if (e === null) return yield* v.fail(new t({
2144
- provider: a.name,
2145
- message: `no resumable chunk at '${o(i)}'`,
2146
- transient: !1,
2147
- status: 404
2148
- }));
2149
- if (!Number.isSafeInteger(e.size) || e.size < 0) return yield* v.fail(new t({
2150
- provider: a.name,
2151
- message: "resumable chunk metadata has an invalid size",
2152
- transient: !1
2153
- }));
2154
- if (e.size > r - n) return yield* v.fail(c());
2155
- n += e.size;
2156
- }
2157
- let i = /* @__PURE__ */ new Uint8Array(), s = 0;
2158
- for (let t = 0; t < e.count; t++) {
2159
- let e = yield* Ve(a, o(t)).pipe(v.retry(p));
2160
- yield* C.runForEach(e.stream, (e) => v.gen(function* () {
2161
- if (e.byteLength > r - s) return yield* v.fail(c());
2162
- let t = s + e.byteLength;
2163
- if (t > i.byteLength) {
2164
- let e = new Uint8Array(Math.min(r, Math.max(65536, i.byteLength * 2, t)));
2165
- e.set(i.subarray(0, s)), i = e;
2166
- }
2167
- i.set(e, s), s = t;
2168
- }));
2169
- }
2170
- return i.subarray(0, s);
2171
- }).pipe(v.tapError((e) => e._tag === "StorageRejected" ? s : v.void));
2172
- return yield* b({
2173
- bytes: l,
2174
- contentType: e.contentType,
2175
- ...e.tenantId === void 0 ? {} : { tenantId: e.tenantId },
2176
- ...e.ownerId === void 0 ? {} : { ownerId: e.ownerId },
2177
- ...e.visibility === void 0 ? {} : { visibility: e.visibility },
2178
- ...e.access === void 0 ? {} : { access: e.access },
2179
- ...e.folder === void 0 ? {} : { folder: e.folder },
2180
- ...e.tags === void 0 ? {} : { tags: e.tags },
2181
- ...e.alt === void 0 ? {} : { alt: e.alt },
2182
- ...e.caption === void 0 ? {} : { caption: e.caption }
2183
- }).pipe(v.ensuring(s));
2184
- }),
2185
- transcode: (e, t) => _(e, t?.tenantId).pipe(v.flatMap((e) => ae(e))),
2186
- renditions: (e, t) => _(e, t?.tenantId).pipe(v.flatMap(() => o.listByDerivedFrom(e))),
2187
- beginMultipartUpload: (e) => v.gen(function* () {
2188
- if (!a.createMultipartUpload || !a.presignUploadPart || !a.completeMultipartUpload) return yield* v.fail(new t({
2189
- provider: a.name,
2190
- message: `provider '${a.name}' does not support multipart uploads`,
2191
- transient: !1,
2192
- status: 400
2193
- }));
2194
- let n = m(e.tenantId ?? null, "", `multipart/${A({
2195
- kind: "typeid",
2196
- prefix: "mp"
2197
- }, B)}`);
2198
- return {
2199
- uploadId: (yield* a.createMultipartUpload(n, e.contentType, { public: (e.visibility ?? "private") === "public" })).uploadId,
2200
- key: n
2201
- };
2202
- }),
2203
- signMultipartPart: (e) => v.suspend(() => a.presignUploadPart ? a.presignUploadPart(e.key, e.uploadId, e.partNumber, e.expiresInSec ?? d) : v.fail(new t({
2204
- provider: a.name,
2205
- message: "provider does not support multipart uploads",
2206
- transient: !1,
2207
- status: 400
2208
- }))),
2209
- completeMultipart: (e) => v.gen(function* () {
2210
- if (!a.completeMultipartUpload) return yield* v.fail(new t({
2211
- provider: a.name,
2212
- message: "provider does not support multipart uploads",
2213
- transient: !1,
2214
- status: 400
2215
- }));
2216
- let r = yield* a.completeMultipartUpload(e.key, e.uploadId, e.parts), s = yield* a.head(e.key).pipe(v.retry(p)), l = s?.size ?? 0, u = (r.etag ?? s?.etag ?? "").replace(/"/g, ""), d = e.tenantId ?? null, f = {
2217
- bytes: l,
2218
- count: 1
2219
- };
2220
- if (!(yield* o.consumeUsage(d, f, i.quota)).allowed) return yield* a.delete(e.key).pipe(v.retry(p), v.ignore), yield* v.fail(new n({
2221
- reason: "quota-exceeded",
2222
- detail: `multipart upload of ${l} bytes exceeds tenant quota`
2223
- }));
2224
- let m = {
2225
- id: pn(),
2226
- tenantId: e.tenantId ?? null,
2227
- ownerId: e.ownerId ?? null,
2228
- bucket: c,
2229
- key: e.key,
2230
- contentType: e.contentType,
2231
- size: l,
2232
- checksum: u,
2233
- visibility: e.visibility ?? "private",
2234
- accessPolicy: e.access ?? null,
2235
- passwordHash: null,
2236
- createdAt: /* @__PURE__ */ new Date(),
2237
- ...e.folder === void 0 ? {} : { folder: e.folder },
2238
- ...e.tags === void 0 ? {} : { tags: e.tags },
2239
- ...e.alt === void 0 ? {} : { alt: e.alt },
2240
- ...e.caption === void 0 ? {} : { caption: e.caption }
2241
- };
2242
- return yield* o.insert(m).pipe(v.onExit((e) => y.isSuccess(e) ? v.void : o.releaseUsage(d, f).pipe(v.ignore))), m;
2243
- }),
2244
- abortMultipart: (e) => v.suspend(() => a.abortMultipartUpload ? a.abortMultipartUpload(e.key, e.uploadId).pipe(v.retry(p)) : v.void)
2245
- };
2246
- }, gn = (e) => b.succeed(i, hn(e)), _n = "_voltro_storage_operation_locks", Q = "_voltro_storage_object_heads", vn = "_voltro_storage_operations", yn = "_voltro_storage_object_claims", bn = [
2247
- P(_n, {
2248
- id: F().maxLength(64),
2249
- nonce: F()
2250
- }).primaryKey(["id"]).nonReactive(),
2251
- P(Q, {
2252
- id: F().maxLength(64),
2253
- generation: F(),
2254
- key: F(),
2255
- reservations: E()
2256
- }).primaryKey(["id"]).nonReactive(),
2257
- P(vn, {
2258
- id: F().maxLength(64),
2259
- objectId: F().maxLength(64),
2260
- fingerprint: F().maxLength(64),
2261
- generation: F(),
2262
- key: F(),
2263
- refId: F(),
2264
- state: F(),
2265
- deleteKey: F().nullable()
2266
- }).primaryKey(["id"]).nonReactive(),
2267
- P(yn, {
2268
- id: F().maxLength(64),
2269
- operationId: F().maxLength(64),
2270
- claim: F()
2271
- }).primaryKey(["id"]).nonReactive()
2272
- ], xn = S.Struct({
2273
- id: S.String,
2274
- objectId: S.String,
2275
- fingerprint: S.String,
2276
- generation: S.String,
2277
- key: S.String,
2278
- refId: S.String,
2279
- state: S.Literals([
2280
- "reserved",
2281
- "ready",
2282
- "deleting",
2283
- "deleted"
2284
- ]),
2285
- deleteKey: S.NullOr(S.String)
2286
- }), Sn = S.Struct({
2287
- id: S.String,
2288
- generation: S.String,
2289
- key: S.String,
2290
- reservations: S.Int.pipe(S.check(S.isGreaterThanOrEqualTo(0)))
2291
- }), Cn = (e) => S.decodeUnknownSync(Sn)({
2292
- ...e,
2293
- reservations: W(e.reservations, "shared-object reservation count")
2294
- }), wn = (e) => Ce("sha256").update(JSON.stringify(e)).digest("hex"), Tn = (e, t) => wn([e, t]), En = (e) => {
2295
- if (!e.bucket || !e.operationId || !e.logicalKey || !/^[a-f0-9]{64}$/.test(e.fingerprint) || !/^[a-f0-9]{64}$/.test(e.checksum)) throw Error("Storage operation requires a bucket, operation identity, key and SHA-256 fingerprint");
2296
- return {
2297
- id: wn([
2298
- e.bucket,
2299
- e.tenantId,
2300
- e.operationId
2301
- ]),
2302
- objectId: wn([
2303
- e.bucket,
2304
- e.tenantId,
2305
- e.logicalKey,
2306
- e.checksum
2307
- ]),
2308
- lockId: wn([e.tenantId])
2309
- };
2310
- }, Dn = async (e, t, n) => {
2311
- let { lockId: r } = En(t);
2312
- return await e.insertIgnoreWithOutcome(_n, {
2313
- id: r,
2314
- nonce: Te()
2315
- }, { conflictColumns: ["id"] }), e.transactional(async (e) => {
2316
- if ((await e.query({
2317
- table: _n,
2318
- predicate: k("id", r),
2319
- lock: "update",
2320
- order: [],
2321
- take: 1,
2322
- skip: void 0,
2323
- projection: void 0
2324
- })).length !== 1 || await e.update(_n, r, { nonce: Te() }) === null) throw Error("Storage operation lock is unavailable");
2325
- return n(e);
2326
- });
2327
- }, $ = async (e, t) => {
2328
- let r = En(t), i = await e.query({
2329
- table: vn,
2330
- predicate: k("id", r.id),
2331
- order: [],
2332
- take: 1,
2333
- skip: void 0,
2334
- projection: void 0
2335
- });
2336
- if (!i[0]) return;
2337
- let a = S.decodeUnknownSync(xn)(i[0]);
2338
- if (a.fingerprint !== t.fingerprint || a.objectId !== r.objectId) throw new n({
2339
- reason: "operation-identity-reused",
2340
- detail: `storage operation '${t.operationId}' was already used with different inputs`
2341
- });
2342
- return a;
2343
- }, On = async (e, t) => {
2344
- let n = await $(e, t);
2345
- if (n) return n;
2346
- let { id: r, objectId: i } = En(t), a = await e.query({
2347
- table: Q,
2348
- predicate: k("id", i),
2349
- order: [],
2350
- take: 1,
2351
- skip: void 0,
2352
- projection: void 0
2353
- }), o = a[0] ? Cn(a[0]) : void 0, s = o?.generation ?? Te(), c = o?.key ?? `${t.logicalKey}/g-${s}`;
2354
- o ? await e.update(Q, i, { reservations: String(Je(o.reservations, 1, "shared-object reservation count")) }) : await e.insert(Q, {
2355
- id: i,
2356
- generation: s,
2357
- key: c,
2358
- reservations: "1"
2359
- });
2360
- let l = {
2361
- id: r,
2362
- objectId: i,
2363
- fingerprint: t.fingerprint,
2364
- generation: s,
2365
- key: c,
2366
- refId: `file_${Te()}`,
2367
- state: "reserved",
2368
- deleteKey: null
2369
- };
2370
- return await e.insert(vn, l), l;
2371
- }, kn = async (e, t) => {
2372
- let n = await $(e, t);
2373
- if (!n) throw Error("Storage operation is missing");
2374
- if (n.state === "deleting" || n.state === "deleted") throw Error("Deleted storage operation cannot be confirmed by a late put");
2375
- return await e.update(vn, n.id, { state: "ready" }), {
2376
- ...n,
2377
- state: "ready"
2378
- };
2379
- }, An = async (e, t) => {
2380
- let n = await $(e, t);
2381
- if (!n) throw Error("Storage operation is missing");
2382
- if (n.state === "deleting" || n.state === "deleted") return n;
2383
- if (n.state !== "ready") throw Error("An unconfirmed put cannot be deleted");
2384
- let r = await e.query({
2385
- table: Q,
2386
- predicate: k("id", n.objectId),
2387
- order: [],
2388
- take: 1,
2389
- skip: void 0,
2390
- projection: void 0
2391
- }), i = r[0] ? Cn(r[0]) : void 0;
2392
- if (!i || i.generation !== n.generation || i.reservations < 1) throw Error("Storage object generation does not own its reservation");
2393
- let a = i.reservations === 1 ? i.key : null;
2394
- return a === null ? await e.update(Q, i.id, { reservations: String(i.reservations - 1) }) : await e.delete(Q, i.id), await e.update(vn, n.id, {
2395
- state: "deleting",
2396
- deleteKey: a
2397
- }), {
2398
- ...n,
2399
- state: "deleting",
2400
- deleteKey: a
2401
- };
2402
- }, jn = async (e, t) => {
2403
- let n = await $(e, t);
2404
- if (!n || n.state !== "deleting" && n.state !== "deleted") throw Error("Storage deletion has not been accepted");
2405
- return n.state !== "deleted" && (await e.update(vn, n.id, { state: "deleted" }), !0);
2406
- }, Mn = async (e, t, n) => {
2407
- if (!n) throw Error("Storage object claim must be a non-empty string");
2408
- await e.insertIgnoreWithOutcome(yn, {
2409
- id: Tn(t, n),
2410
- operationId: t,
2411
- claim: n
2412
- }, { conflictColumns: ["id"] });
2413
- }, Nn = async (e, t, n) => {
2414
- let r = Tn(t, n);
2415
- return {
2416
- held: await e.delete(yn, r),
2417
- others: (await e.query({
2418
- table: yn,
2419
- predicate: ue(k("operationId", t), ve("claim", n)),
2420
- order: [],
2421
- take: 1,
2422
- skip: void 0,
2423
- projection: void 0
2424
- })).length > 0
2425
- };
2426
- }, Pn = (e, t) => e.deleteMany(yn, { where: k("operationId", t) }), Fn = "_voltro_storage_put_intents", In = P(Fn, {
2427
- id: F().maxLength(64),
2428
- refId: F().maxLength(64),
2429
- identity: ge(),
2430
- ref: ge()
2431
- }).primaryKey(["id"]).unique("storagePutRef", ["refId"]).nonReactive(), Ln = S.Struct({
2432
- tenantId: S.NullOr(S.String),
2433
- bucket: S.String,
2434
- operationId: S.String,
2435
- fingerprint: S.String,
2436
- checksum: S.String,
2437
- logicalKey: S.String
2438
- }), Rn = async (e, t) => {
2439
- let n = await e.query({
2440
- table: Fn,
2441
- predicate: k("refId", t),
2442
- order: [],
2443
- take: 2,
2444
- skip: void 0,
2445
- projection: void 0
2446
- });
2447
- if (n.length === 0) return;
2448
- if (n.length !== 1) throw Error("Storage reference has ambiguous operation ownership");
2449
- let r = n[0], i = S.decodeUnknownSync(Ln)(r.identity);
2450
- if (typeof r.ref != "object" || r.ref === null || Array.isArray(r.ref)) throw Error("Storage operation reference is unreadable");
2451
- let a = X(r.ref);
2452
- if (a.id !== t || a.bucket !== i.bucket || a.tenantId !== i.tenantId || a.checksum !== i.checksum || !Number.isSafeInteger(a.size) || a.size < 0 || !Number.isFinite(a.createdAt.getTime())) throw Error("Storage operation reference does not match its identity");
2453
- return {
2454
- identity: i,
2455
- ref: a
2456
- };
2457
- }, zn = (e) => ({
2458
- intent: (t) => Rn(e, t),
2459
- reserve: (t, r, i, a) => Dn(e, t, async (e) => {
2460
- if (r.tenantId !== t.tenantId || r.bucket !== t.bucket || r.checksum !== t.checksum || !Number.isSafeInteger(r.size) || r.size < 0) throw Error("Storage put metadata does not match its identity");
2461
- let o = await $(e, t);
2462
- if (o) {
2463
- if (o.state === "deleting" || o.state === "deleted") throw Error("Storage put identity has already been deleted");
2464
- let t = await Rn(e, o.refId);
2465
- if (!t) throw Error("Storage operation lost its put intent");
2466
- let n = o.state === "ready";
2467
- return n && a !== void 0 && await Mn(e, o.id, a), {
2468
- ref: t.ref,
2469
- ready: n,
2470
- outcome: n ? "joined" : "resumed"
2471
- };
2472
- }
2473
- let s = await On(e, t), c = ln(e);
2474
- if (!(await v.runPromise(c.consumeUsage(t.tenantId, {
2475
- bytes: r.size,
2476
- count: 1
2477
- }, i))).allowed) throw new n({
2478
- reason: "quota-exceeded",
2479
- detail: "Storage operation exceeds tenant quota"
2480
- });
2481
- let l = X({
2482
- ...r,
2483
- id: s.refId,
2484
- key: s.key
2485
- });
2486
- return await e.insert(Fn, {
2487
- id: s.id,
2488
- refId: l.id,
2489
- identity: t,
2490
- ref: l
2491
- }), {
2492
- ref: l,
2493
- ready: !1,
2494
- outcome: "created"
2495
- };
2496
- }),
2497
- confirm: (t, n) => Dn(e, t, async (e) => {
2498
- let r = await $(e, t);
2499
- if (!r) throw Error("Storage put operation is missing");
2500
- let i = await Rn(e, r.refId);
2501
- if (!i) throw Error("Storage put intent is missing");
2502
- if (n !== void 0 && await Mn(e, r.id, n), r.state === "ready") {
2503
- let n = await v.runPromise(ln(e).getById(r.refId));
2504
- if (!n || n.key !== r.key || n.checksum !== t.checksum) throw Error("Confirmed storage operation lost its reference");
2505
- return n;
2506
- }
2507
- return await kn(e, t), await v.runPromise(ln(e).insert(i.ref)), i.ref;
2508
- }),
2509
- beginDelete: async (t, r, i) => {
2510
- let a = await Rn(e, t);
2511
- if (!a) throw Error("Storage delete operation is missing");
2512
- if (r !== void 0 && a.identity.tenantId !== r) throw Error("Storage delete tenant mismatch");
2513
- return Dn(e, a.identity, async (e) => {
2514
- let r = await Rn(e, t);
2515
- if (!r) throw Error("Storage delete intent disappeared");
2516
- let a = await $(e, r.identity);
2517
- if (!a) throw Error("Storage delete lost its operation");
2518
- let o = a.state !== "deleting" && a.state !== "deleted";
2519
- if (i === void 0) o && await Pn(e, a.id);
2520
- else if (o) {
2521
- let o = await Nn(e, a.id, i);
2522
- if (o.others) return {
2523
- released: !0,
2524
- identity: r.identity
2525
- };
2526
- if (!o.held) throw new n({
2527
- reason: "claim-not-held",
2528
- detail: `claim '${i}' is not held on storage reference '${t}'; a reference put without a claim is deleted as a whole by a delete that names none`
2529
- });
2530
- }
2531
- let s = await An(e, r.identity);
2532
- if (a.state === "ready") {
2533
- let n = ln(e);
2534
- if (await v.runPromise(fn(e).deleteByRef(t)), !await v.runPromise(n.delete(t))) throw Error("Storage deletion lost its confirmed reference");
2535
- await v.runPromise(n.releaseUsage(r.identity.tenantId, {
2536
- bytes: r.ref.size,
2537
- count: 1
2538
- }));
2539
- }
2540
- return {
2541
- released: !0,
2542
- operation: s,
2543
- identity: r.identity
2544
- };
2545
- });
2546
- },
2547
- confirmDelete: (t) => Dn(e, t, (e) => jn(e, t))
2548
- }), Bn = (e, t = 65536) => {
2549
- let n = [Buffer.from("zINSTREAM\0", "utf8")];
2550
- for (let r = 0; r < e.length; r += t) {
2551
- let i = e.subarray(r, Math.min(r + t, e.length)), a = Buffer.alloc(4);
2552
- a.writeUInt32BE(i.length, 0), n.push(a, Buffer.from(i));
2553
- }
2554
- let r = Buffer.alloc(4);
2555
- return r.writeUInt32BE(0, 0), n.push(r), Buffer.concat(n);
2556
- }, Vn = (e) => {
2557
- let t = e.replace(/\0+$/, "").trim();
2558
- if (/\bOK$/.test(t)) return { clean: !0 };
2559
- let n = /:\s*(.+?)\s+FOUND$/.exec(t);
2560
- if (n) return {
2561
- clean: !1,
2562
- threat: n[1] ?? "unknown"
2563
- };
2564
- throw Error(`clamav: unexpected response: ${t}`);
2565
- }, Hn = async (e, t) => {
2566
- let n = await import("node:net"), r = U.read("CLAMAV_HOST", t.host) ?? "127.0.0.1", i = U.read("CLAMAV_PORT"), a = t.port ?? (i ? Number(i) : 3310), o = t.timeoutMs ?? 3e4;
2567
- return new Promise((i, s) => {
2568
- let c = n.createConnection({
2569
- host: r,
2570
- port: a
2571
- }), l = "", u = setTimeout(() => {
2572
- c.destroy(), s(/* @__PURE__ */ Error("clamav scan timed out"));
2573
- }, o);
2574
- c.on("error", (e) => {
2575
- clearTimeout(u), s(e);
2576
- }), c.on("connect", () => {
2577
- c.end(Bn(e, t.chunkSize));
2578
- }), c.on("data", (e) => {
2579
- l += e.toString("utf8");
2580
- }), c.on("close", () => {
2581
- clearTimeout(u);
2582
- try {
2583
- i(Vn(l));
2584
- } catch (e) {
2585
- s(e);
2586
- }
60
+ return At(t);
61
+ }, X = (e) => {
62
+ if (e.provider && typeof e.provider == "object") return e.provider;
63
+ let t = e.provider ?? E.read("STORAGE_PROVIDER");
64
+ if (t === void 0) {
65
+ let t = X({
66
+ ...e,
67
+ provider: "memory"
2587
68
  });
2588
- });
2589
- }, Un = (e = {}) => (t) => Hn(t.bytes, e), Wn = (e, t, n) => new Promise((r, i) => {
2590
- let a = Oe(e, [...t], { stdio: [
2591
- "ignore",
2592
- "ignore",
2593
- "pipe"
2594
- ] }), o = "", s = setTimeout(() => {
2595
- a.kill("SIGKILL"), i(/* @__PURE__ */ Error("ffmpeg timed out"));
2596
- }, n);
2597
- a.stderr?.on("data", (e) => {
2598
- o += String(e);
2599
- }), a.on("error", (e) => {
2600
- clearTimeout(s), i(e);
2601
- }), a.on("close", (e) => {
2602
- clearTimeout(s), e === 0 ? r() : i(/* @__PURE__ */ Error(`ffmpeg exited ${String(e)}: ${o.slice(-400)}`));
2603
- });
2604
- }), Gn = (e) => async ({ bytes: t }) => {
2605
- let n = e.ffmpegPath ?? "ffmpeg", r = e.timeoutMs ?? 3e5, i = await R(Me(je(), "voltro-tc-")), a = Me(i, "in"), o = [];
2606
- try {
2607
- await Ae(a, t);
2608
- for (let t of e.renditions) {
2609
- let e = Me(i, `out.${t.ext}`);
2610
- try {
2611
- await Wn(n, [
2612
- "-y",
2613
- "-i",
2614
- a,
2615
- ...t.args,
2616
- e
2617
- ], r);
2618
- let i = await z(e);
2619
- o.push({
2620
- bytes: new Uint8Array(i),
2621
- contentType: t.contentType,
2622
- kind: t.kind,
2623
- ...t.label === void 0 ? {} : { label: t.label }
2624
- }), await ke(e, { force: !0 });
2625
- } catch {}
2626
- }
2627
- } finally {
2628
- await ke(i, {
2629
- recursive: !0,
2630
- force: !0
2631
- }).catch(() => void 0);
2632
- }
2633
- return o;
2634
- };
2635
- //#endregion
2636
- //#region src/assetRef.ts
2637
- function Kn(e = {}) {
2638
- let t = e.nullable ?? !0, n = e.fk === !1 ? F().externalId() : ye(() => We, { onDelete: e.onDelete ?? "setNull" });
2639
- return t ? n.nullable() : n;
2640
- }
2641
- var qn = () => _e({
2642
- id: "@voltro/plugin-storage/withStorage",
2643
- fields: { asset: Kn() }
2644
- }), Jn = {
2645
- "image/png": "png",
2646
- "image/jpeg": "jpg",
2647
- "image/jpg": "jpg",
2648
- "image/gif": "gif",
2649
- "image/webp": "webp",
2650
- "image/svg+xml": "svg"
2651
- }, Yn = (e) => {
2652
- let t = /^data:([^;,]+)(;base64)?,(.*)$/s.exec(e);
2653
- if (!t) throw Error("not a data URI");
2654
- let n = t[1] || "application/octet-stream", r = !!t[2], i = t[3] ?? "";
2655
- return {
2656
- bytes: r ? new Uint8Array(Buffer.from(i, "base64")) : new Uint8Array(Buffer.from(decodeURIComponent(i), "utf8")),
2657
- contentType: n
2658
- };
2659
- }, Xn = (e, n) => v.gen(function* () {
2660
- let r = yield* v.try({
2661
- try: () => Yn(n.dataUri),
2662
- catch: (e) => new t({
2663
- provider: "avatar",
2664
- message: String(e?.message ?? e),
2665
- transient: !1,
2666
- status: 400
2667
- })
2668
- }), i = Jn[r.contentType] ?? "bin";
2669
- return yield* e.put({
2670
- bytes: r.bytes,
2671
- contentType: r.contentType,
2672
- tenantId: n.tenantId,
2673
- ownerId: n.userId,
2674
- visibility: "public",
2675
- key: `avatars/${n.userId}/avatar.${i}`
2676
- });
2677
- }), Zn = (e) => {
2678
- try {
2679
- let t = Ne(e), n = Ne("/");
2680
- return typeof t.dev != "number" || typeof n.dev != "number" ? "unknown" : t.dev === n.dev ? "same-device-as-root" : "separate-mount";
2681
- } catch {
2682
- return "unknown";
69
+ return Y.add(t), t;
2683
70
  }
2684
- }, Qn = (e) => {
2685
- if (Zn(e) === "same-device-as-root") return `the capture is going to ${e}, which is on the SAME filesystem as \`/\`.\n A mounted volume would be a separate one. If this process is a container, that means the capture
2686
- dies with it — which is the exact failure it exists for. On a development machine this is normal
2687
- and can be ignored.`;
2688
- }, $n = U.read("VOLTRO_SESSION_COOKIE") ?? "voltro:session", er, tr = (e) => {
2689
- er = e;
2690
- }, nr = () => er ?? ir({}), rr = () => er === void 0 ? U.read("STORAGE_PROVIDER") === void 0 ? void 0 : ir({}) : er, ir = (e) => {
2691
- if (e.provider && typeof e.provider == "object") return e.provider;
2692
- let t = (e.provider ?? U.read("STORAGE_PROVIDER") ?? "memory").toLowerCase(), n = U.read("S3_BUCKET", e.bucket) ?? U.read("STORAGE_BUCKET") ?? "voltro";
2693
- switch (t) {
71
+ let n = t.toLowerCase(), r = E.read("S3_BUCKET", e.bucket) ?? E.read("STORAGE_BUCKET") ?? "voltro";
72
+ switch (n) {
2694
73
  case "s3":
2695
74
  case "minio": {
2696
- let r = U.read("S3_REGION", e.region) ?? U.read("AWS_REGION"), i = U.read("S3_ENDPOINT", e.endpoint) ?? U.read("MINIO_ENDPOINT"), a = U.read("S3_ACCESS_KEY_ID", e.accessKeyId) ?? U.read("AWS_ACCESS_KEY_ID"), o = U.read("S3_SECRET_ACCESS_KEY", e.secretAccessKey) ?? U.read("AWS_SECRET_ACCESS_KEY"), s = U.read("STORAGE_CDN_URL", e.cdnBaseUrl);
2697
- return nt({
2698
- bucket: n,
2699
- name: t,
2700
- ...r ? { region: r } : {},
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 } : {},
2701
79
  ...i ? { endpoint: i } : {},
2702
80
  ...a ? { accessKeyId: a } : {},
2703
81
  ...o ? { secretAccessKey: o } : {},
2704
82
  ...s ? { cdnBaseUrl: s } : {},
2705
83
  ...e.publicAcl === void 0 ? {} : { publicAcl: e.publicAcl },
2706
- ...t === "minio" || U.read("S3_FORCE_PATH_STYLE") === "1" ? { forcePathStyle: !0 } : {}
2707
- });
84
+ ...n === "minio" || E.read("S3_FORCE_PATH_STYLE") === "1" ? { forcePathStyle: !0 } : {}
85
+ };
86
+ return P(c);
2708
87
  }
2709
88
  case "azure": {
2710
- let t = U.read("AZURE_STORAGE_ACCOUNT", e.accountName), r = U.read("AZURE_STORAGE_KEY", e.accountKey), i = U.read("AZURE_STORAGE_CONNECTION_STRING", e.connectionString), a = U.read("AZURE_STORAGE_ENDPOINT", e.endpoint), o = U.read("STORAGE_CDN_URL", e.cdnBaseUrl);
2711
- return at({
2712
- container: U.read("AZURE_STORAGE_CONTAINER", e.bucket) ?? n,
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,
2713
91
  ...t ? { accountName: t } : {},
2714
- ...r ? { accountKey: r } : {},
92
+ ...n ? { accountKey: n } : {},
2715
93
  ...i ? { connectionString: i } : {},
2716
94
  ...a ? { endpoint: a } : {},
2717
95
  ...o ? { cdnBaseUrl: o } : {}
2718
- });
96
+ };
97
+ return D(s);
2719
98
  }
2720
- case "database": return it();
2721
- case "filesystem": return tt({ root: U.read("STORAGE_ROOT", e.root) ?? ".voltro-storage" });
2722
- default: return et(e.name ?? "default");
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
+ });
2723
107
  }
2724
- }, ar = (e) => {
2725
- let t = "stored files (uploads, renditions) and their reads", n = "provider 'database' or 'filesystem' keeps the bytes inside the installation";
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";
2726
117
  if (e.provider && typeof e.provider == "object") return [{
2727
118
  destination: `runtime:the '${e.provider.name}' storage provider`,
2728
119
  purpose: t,
2729
120
  data: ["files"],
2730
121
  disable: n
2731
122
  }];
2732
- let r = (e.provider ?? U.read("STORAGE_PROVIDER") ?? "memory").toLowerCase();
123
+ let r = (e.provider ?? E.read("STORAGE_PROVIDER") ?? "memory").toLowerCase();
2733
124
  if (r === "s3" || r === "minio") {
2734
- let r = U.read("S3_ENDPOINT", e.endpoint) ?? U.read("MINIO_ENDPOINT"), i = U.read("S3_REGION", e.region) ?? U.read("AWS_REGION") ?? "us-east-1";
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";
2735
126
  return [{
2736
127
  destination: r ?? `s3.${i}.amazonaws.com`,
2737
128
  purpose: t,
@@ -2740,7 +131,7 @@ var qn = () => _e({
2740
131
  }];
2741
132
  }
2742
133
  if (r === "azure") {
2743
- let r = U.read("AZURE_STORAGE_ENDPOINT", e.endpoint), i = U.read("AZURE_STORAGE_ACCOUNT", e.accountName);
134
+ let r = E.read("AZURE_STORAGE_ENDPOINT", e.endpoint), i = E.read("AZURE_STORAGE_ACCOUNT", e.accountName);
2744
135
  return [{
2745
136
  destination: r ?? (i === void 0 ? "runtime:the Azure storage connection string" : `${i}.blob.core.windows.net`),
2746
137
  purpose: t,
@@ -2749,11 +140,11 @@ var qn = () => _e({
2749
140
  }];
2750
141
  }
2751
142
  return [];
2752
- }, or = (e) => {
143
+ }, Nt = (e) => {
2753
144
  if (e !== void 0) return e;
2754
- let t = U.read("STORAGE_ALLOWED_ORIGINS");
145
+ let t = E.read("STORAGE_ALLOWED_ORIGINS");
2755
146
  return t ? t.trim() === "*" ? "*" : t.split(",").map((e) => e.trim()).filter(Boolean) : [];
2756
- }, sr = (e, t) => {
147
+ }, Pt = (e, t) => {
2757
148
  if (!e || t !== "*" && !t.includes(e)) return {};
2758
149
  let n = {
2759
150
  "access-control-allow-origin": t === "*" ? "*" : e,
@@ -2763,7 +154,7 @@ var qn = () => _e({
2763
154
  vary: "Origin"
2764
155
  };
2765
156
  return t !== "*" && (n["access-control-allow-credentials"] = "true"), n;
2766
- }, cr = (e) => ({
157
+ }, Ft = (e) => ({
2767
158
  id: e.id,
2768
159
  tenantId: e.tenantId,
2769
160
  ownerId: e.ownerId,
@@ -2786,29 +177,29 @@ var qn = () => _e({
2786
177
  caption: e.caption ?? null,
2787
178
  derivedFrom: e.derivedFrom ?? null,
2788
179
  kind: e.kind ?? null
2789
- }), lr = () => new t({
180
+ }), It = () => new g({
2790
181
  provider: "storage",
2791
182
  message: "not permitted to administer sharing for this object",
2792
183
  transient: !1,
2793
184
  status: 403
2794
- }), ur = (e, t, n) => {
185
+ }), Lt = (e, t, n) => {
2795
186
  let r = n.request.subject;
2796
- return (r.scopes ?? []).includes("admin:full") ? v.void : e.head(t, { tenantId: r.tenantId ?? null }).pipe(v.catch(() => v.fail(lr())), v.flatMap((e) => {
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) => {
2797
188
  let t = e?.ownerId;
2798
- return t != null && t === r.id ? v.void : v.fail(lr());
189
+ return t != null && t === r.id ? q.void : q.fail(It());
2799
190
  }));
2800
- }, dr = () => new t({
191
+ }, Rt = () => new g({
2801
192
  provider: "storage",
2802
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.",
2803
194
  transient: !1,
2804
195
  status: 401
2805
- }), fr = (e, t) => {
196
+ }), Z = (e, t) => {
2806
197
  let n = e.request.subject.id ?? null, r = e.request.subject.tenantId ?? null;
2807
- return n === null && !t ? v.fail(dr()) : v.succeed({
198
+ return n === null && !t ? q.fail(Rt()) : q.succeed({
2808
199
  id: n,
2809
200
  tenantId: r
2810
201
  });
2811
- }, pr = (e, t) => e !== null && e !== (t ?? null), mr = (e) => ({
202
+ }, zt = (e, t) => e !== null && e !== (t ?? null), Bt = (e) => ({
2812
203
  id: e.id,
2813
204
  refId: e.refId,
2814
205
  principalType: e.principalType,
@@ -2817,143 +208,208 @@ var qn = () => _e({
2817
208
  createdAt: e.createdAt.toISOString(),
2818
209
  expiresAt: e.expiresAt ? e.expiresAt.toISOString() : null,
2819
210
  createdBy: e.createdBy
2820
- }), hr = "@voltro/plugin-storage", gr = (e = {}) => w({
2821
- base: hr,
211
+ }), Q = "@voltro/plugin-storage", Vt = (e = {}) => xt({
212
+ base: Q,
2822
213
  alias: e.alias,
2823
214
  instance: e.name
2824
- }), _r = (i = {}) => {
2825
- let y = w({
2826
- base: hr,
2827
- alias: i.alias,
2828
- instance: i.name
2829
- }), b = y === hr ? "/_voltro/storage" : `/_voltro/storage/i/${Buffer.from(y).toString("hex")}`, x = ir(i);
2830
- tr(x);
2831
- let ue = U.read("S3_BUCKET", i.bucket) ?? U.read("STORAGE_BUCKET") ?? "voltro", T = U.read("VOLTRO_PUBLIC_URL", i.publicBaseUrl), E = or(i.allowedOrigins), D = i.limits?.maxBytes, O = i.anonymousUploads === !0, de = 5242880, fe = 21600, k = i.refStore === void 0 || i.refStore === "memory", pe = i.grantStore === void 0 || i.grantStore === "memory", A = (e, n) => v.gen(function* () {
2832
- let r = (e) => S.decodeUnknownEffect(ae)(e, { onExcessProperty: "error" }).pipe(v.mapError(() => new t({
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,
218
+ alias: e.alias,
219
+ instance: e.name
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({
2833
271
  provider: "storage",
2834
272
  message: "Invalid upload access policy",
2835
273
  transient: !1,
2836
274
  status: 400
2837
- }))), a = e.access === void 0 ? void 0 : yield* r(e.access), o = e.visibility ?? "private";
2838
- if (a !== void 0 && o === "public") return yield* v.fail(new t({
275
+ }))), i = t.access === void 0 ? void 0 : yield* r(t.access), a = t.visibility ?? "private";
276
+ if (i !== void 0 && a === "public") return yield* q.fail(new g({
2839
277
  provider: "storage",
2840
278
  message: "An access policy requires a private upload",
2841
279
  transient: !1,
2842
280
  status: 400
2843
281
  }));
2844
- let s = i.uploadAccess;
2845
- if (a !== void 0 && typeof s != "function") return yield* v.fail(new t({
282
+ let o = e.uploadAccess;
283
+ if (i !== void 0 && typeof o != "function") return yield* q.fail(new g({
2846
284
  provider: "storage",
2847
285
  message: "Requested upload access requires an uploadAccess authorization function on storagePlugin",
2848
286
  transient: !1,
2849
287
  status: 403
2850
288
  }));
2851
- let c = typeof s == "function" ? yield* s({
289
+ let s = typeof o == "function" ? yield* o({
2852
290
  subject: n,
2853
- requested: a,
2854
- visibility: o,
2855
- contentType: e.contentType
2856
- }) : o === "private" ? s : void 0, l = c === void 0 ? void 0 : yield* r(c);
2857
- return o === "public" ? l !== void 0 && l.length > 0 ? yield* v.fail(new t({
291
+ requested: i,
292
+ visibility: a,
293
+ contentType: t.contentType
294
+ }) : a === "private" ? o : void 0, c = s === void 0 ? void 0 : yield* r(s);
295
+ return a === "public" ? c !== void 0 && c.length > 0 ? yield* q.fail(new g({
2858
296
  provider: "storage",
2859
297
  message: "A public upload cannot carry an access policy",
2860
298
  transient: !1,
2861
299
  status: 400
2862
- })) : {} : l === void 0 ? {} : { access: l };
2863
- }), j = { current: k ? on() : i.refStore }, M = { current: pe ? un() : i.grantStore }, me = { current: void 0 }, he = {
2864
- insert: (e) => j.current.insert(e),
2865
- getById: (e) => j.current.getById(e),
2866
- delete: (e) => j.current.delete(e),
2867
- statistics: () => j.current.statistics(),
2868
- listRecent: (e) => j.current.listRecent(e),
2869
- countByKey: (e, t) => j.current.countByKey(e, t),
2870
- usageByTenant: (e) => j.current.usageByTenant(e),
2871
- consumeUsage: (e, t, n) => j.current.consumeUsage(e, t, n),
2872
- releaseUsage: (e, t) => j.current.releaseUsage(e, t),
2873
- listByDerivedFrom: (e) => j.current.listByDerivedFrom(e),
2874
- listRefs: (e) => j.current.listRefs(e),
300
+ })) : {} : c === void 0 ? {} : { access: c };
301
+ }), O = { current: w ? ke() : e.refStore }, k = { current: T ? Oe() : e.grantStore }, A = { current: void 0 }, j = { current: void 0 }, M = {
302
+ get catalogueId() {
303
+ return O.current.catalogueId;
304
+ },
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),
2875
318
  get setVisibility() {
2876
- return j.current.setVisibility;
319
+ return O.current.setVisibility;
2877
320
  },
2878
- get countPublicByKey() {
2879
- return j.current.countPublicByKey;
321
+ get countPublicByAddress() {
322
+ return O.current.countPublicByAddress;
2880
323
  }
2881
- }, ge = {
2882
- insert: (e) => M.current.insert(e),
2883
- delete: (e) => M.current.delete(e),
2884
- getById: (e) => M.current.getById(e),
2885
- listByRef: (e) => M.current.listByRef(e),
2886
- deleteByRef: (e) => M.current.deleteByRef(e)
2887
- }, _e = {
2888
- httpPath: b,
2889
- provider: x,
2890
- refStore: he,
2891
- grantStore: ge,
2892
- bucket: ue,
2893
- ...i.tenantPrefix === void 0 ? {} : { tenantPrefix: i.tenantPrefix },
2894
- ...i.attempts === void 0 ? {} : { attempts: i.attempts },
2895
- ...i.urlExpiresInSec === void 0 ? {} : { urlExpiresInSec: i.urlExpiresInSec },
2896
- ...i.access === void 0 ? {} : { access: i.access },
2897
- ...i.limits === void 0 ? {} : { limits: i.limits },
2898
- ...i.ingest === void 0 ? {} : { ingest: i.ingest },
2899
- ...i.scan === void 0 ? {} : { scan: i.scan },
2900
- ...i.videoProbe === void 0 ? {} : { videoProbe: i.videoProbe },
2901
- ...i.transcode === void 0 ? {} : { transcode: i.transcode },
2902
- ...i.autoTranscode === void 0 ? {} : { autoTranscode: i.autoTranscode },
2903
- ...T ? { publicBaseUrl: T } : {},
2904
- ...i.normalizeImages === void 0 ? {} : { normalizeImages: i.normalizeImages },
2905
- ...i.quota === void 0 ? {} : { quota: i.quota },
2906
- objects: () => me.current
2907
- }, ve = gn(_e), N = hn(_e), ye = `${b}/`, P = (e) => v.runPromise(e.pipe(v.catch(() => v.succeed(null)))), F = (e, t) => {
2908
- if (!e) return "invalid";
2909
- let n = /^bytes=(\d*)-(\d*)$/.exec(e.trim());
2910
- if (!n) return "invalid";
2911
- let r = n[1] ?? "", i = n[2] ?? "";
2912
- if (r === "" && i === "") return "invalid";
2913
- if (r === "") {
2914
- let e = Number(i);
2915
- return !Number.isFinite(e) || e <= 0 ? "invalid" : t === 0 ? "unsatisfiable" : {
2916
- start: Math.max(0, t - e),
2917
- endInclusive: t - 1
2918
- };
2919
- }
2920
- let a = Number(r);
2921
- if (!Number.isFinite(a)) return "invalid";
2922
- if (t > 0 && a >= t) return "unsatisfiable";
2923
- let o = i === "" ? Math.max(0, t - 1) : Math.min(Number(i), Math.max(0, t - 1));
2924
- return !Number.isFinite(o) || o < a ? "invalid" : {
2925
- start: a,
2926
- endInclusive: o
2927
- };
2928
- }, be = i.publicCacheSeconds === void 0 ? "public, max-age=31536000, immutable" : `public, max-age=${Math.max(0, Math.floor(i.publicCacheSeconds))}`, xe = /^(?:image\/(?!svg)|video\/|audio\/|application\/pdf(?:;|$)|text\/plain(?:;|$))/i, Se = (e) => ({
2929
- "x-content-type-options": "nosniff",
2930
- "content-disposition": xe.test(e) ? "inline" : "attachment"
2931
- }), I = ot(), we = async (e, t, n, r) => {
2932
- if (n) {
2933
- let r, i = await I.getOrCreate(_t(JSON.stringify([e.id, e.checksum]), e.contentType, n), async () => {
2934
- let t = await P(N.get(e.id));
2935
- return t ? (r = t.bytes, mt(t.bytes, e.contentType, n)) : null;
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)),
344
+ ...e.tenantPrefix === void 0 ? {} : { tenantPrefix: e.tenantPrefix },
345
+ ...e.attempts === void 0 ? {} : { attempts: e.attempts },
346
+ ...e.urlExpiresInSec === void 0 ? {} : { urlExpiresInSec: e.urlExpiresInSec },
347
+ ...e.access === void 0 ? {} : { access: e.access },
348
+ ...e.limits === void 0 ? {} : { limits: e.limits },
349
+ ...e.ingest === void 0 ? {} : { ingest: e.ingest },
350
+ ...e.scan === void 0 ? {} : { scan: e.scan },
351
+ ...e.videoProbe === void 0 ? {} : { videoProbe: e.videoProbe },
352
+ ...e.transcode === void 0 ? {} : { transcode: e.transcode },
353
+ ...e.autoTranscode === void 0 ? {} : { autoTranscode: e.autoTranscode },
354
+ ...y ? { publicBaseUrl: y } : {},
355
+ ...e.normalizeImages === void 0 ? {} : { normalizeImages: e.normalizeImages },
356
+ ...e.quota === void 0 ? {} : { quota: e.quota },
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({
371
+ provider: "storage",
372
+ message: "Upload ticket belongs to another storage destination",
373
+ transient: !1,
374
+ status: 409
375
+ })))), L = (e, t) => q.runPromise(I(e).pipe(q.match({
376
+ onSuccess: () => null,
377
+ onFailure: (e) => ({
378
+ status: e.status ?? 503,
379
+ body: e.status === 409 ? e.message : "Storage upload destination could not be checked",
380
+ contentType: "text/plain",
381
+ headers: t
382
+ })
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;
2936
392
  }).catch(() => null);
2937
- if (!i && r === void 0 && (r = (await P(N.get(e.id)))?.bytes), !i && r === void 0) return {
393
+ if (!a && i === void 0 && (i = (await V(F.get(e.id)))?.bytes), !a && i === void 0) return {
2938
394
  status: 404,
2939
395
  body: "not found",
2940
396
  contentType: "text/plain"
2941
397
  };
2942
- let a = i ? i.bytes : r, o = i ? i.contentType : e.contentType, s = await pt(e.contentType, i !== null);
398
+ let o = a ? a.bytes : i, s = a ? a.contentType : e.contentType, c = await pe(e.contentType, a !== null);
2943
399
  return {
2944
400
  status: 200,
2945
- body: a,
2946
- contentType: o,
401
+ body: o,
402
+ contentType: s,
2947
403
  headers: {
2948
- ...Se(o),
404
+ ...n(s),
2949
405
  "cache-control": t,
2950
406
  "accept-ranges": "none",
2951
- ...s === null ? {} : { "x-voltro-transform": `original; reason=${s}` }
407
+ ...c === null ? {} : { "x-voltro-transform": `original; reason=${c}` }
2952
408
  }
2953
409
  };
2954
410
  }
2955
- let i = r === void 0 ? "invalid" : F(r, e.size);
2956
- if (i === "unsatisfiable") return {
411
+ let o = Tt(a, {}) ? Et(i, e.size) : { _tag: "ignored" };
412
+ if (o._tag === "unsatisfiable") return {
2957
413
  status: 416,
2958
414
  body: "range not satisfiable",
2959
415
  contentType: "text/plain",
@@ -2962,17 +418,20 @@ var qn = () => _e({
2962
418
  "accept-ranges": "bytes"
2963
419
  }
2964
420
  };
2965
- if (i !== "invalid") {
2966
- let n = await P(N.getRange(e.id, i));
2967
- return n ? {
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 ? {
2968
427
  status: 206,
2969
- body: n.bytes,
428
+ body: r.bytes,
2970
429
  contentType: e.contentType,
2971
430
  headers: {
2972
- ...Se(e.contentType),
431
+ ...n(e.contentType),
2973
432
  "cache-control": t,
2974
433
  "accept-ranges": "bytes",
2975
- "content-range": `bytes ${i.start}-${i.endInclusive}/${n.totalSize}`
434
+ "content-range": `bytes ${o.start}-${o.end}/${r.totalSize}`
2976
435
  }
2977
436
  } : {
2978
437
  status: 404,
@@ -2980,69 +439,81 @@ var qn = () => _e({
2980
439
  contentType: "text/plain"
2981
440
  };
2982
441
  }
2983
- let a = await P(N.getStream(e.id));
2984
- return a ? {
442
+ let s = await V(F.getStream(e.id));
443
+ return s ? {
2985
444
  status: 200,
2986
445
  contentType: e.contentType,
2987
446
  headers: {
2988
- ...Se(e.contentType),
447
+ ...n(e.contentType),
2989
448
  "cache-control": t,
2990
449
  "accept-ranges": "bytes"
2991
450
  },
2992
451
  byteStream: {
2993
452
  contentLength: e.size,
2994
- stream: () => C.toReadableStream(a.stream)
453
+ stream: () => pt.toReadableStream(s.stream)
2995
454
  }
2996
455
  } : {
2997
456
  status: 404,
2998
457
  body: "not found",
2999
458
  contentType: "text/plain"
3000
459
  };
3001
- }, Ee = async (e) => {
3002
- let t = e.path.startsWith(ye) ? e.path.slice(ye.length).split("/")[0] ?? "" : "";
460
+ }, Ae = async (e) => {
461
+ let t = e.path.startsWith(R) ? e.path.slice(R.length).split("/")[0] ?? "" : "";
3003
462
  if (!t) return {
3004
463
  status: 404,
3005
464
  body: "not found",
3006
465
  contentType: "text/plain"
3007
466
  };
3008
- let n = await P(N.head(t));
467
+ let n = await V(F.head(t));
3009
468
  if (!n) return {
3010
469
  status: 404,
3011
470
  body: "not found",
3012
471
  contentType: "text/plain"
3013
472
  };
3014
- let r = lt(e.query), i = e.headers.range, a = n.derivedFrom == null ? null : await P(N.head(n.derivedFrom));
3015
- if (n.derivedFrom != null && a === null) return {
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));
474
+ if (n.derivedFrom != null && s === null) return {
3016
475
  status: 404,
3017
476
  body: "not found",
3018
477
  contentType: "text/plain"
3019
478
  };
3020
- if (n.visibility === "public" && (a === null || a.visibility === "public")) {
3021
- let e = x.publicUrl?.(n.key) ?? null;
3022
- return e && !r ? {
479
+ if (n.visibility === "public" && (s === null || s.visibility === "public")) {
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 ? {
3023
488
  status: 302,
3024
489
  headers: {
3025
- location: e,
490
+ location: t,
3026
491
  "cache-control": "public, max-age=300"
3027
492
  }
3028
- } : we(n, be, r, i);
493
+ } : H(n, Ce, r, a, o);
3029
494
  }
3030
- let o = !1, s = e.query ? new URLSearchParams(e.query).get("t") : null;
3031
- if (s) {
3032
- let e = Nt(s);
3033
- o = !!e && (e.refId === t || a !== null && e.refId === a.id) && e.audience === b;
495
+ let c = !1, l = e.query ? new URLSearchParams(e.query).get("t") : null;
496
+ if (l) {
497
+ let e = be(l);
498
+ c = !!e && (e.refId === t || s !== null && e.refId === s.id) && e.audience === i;
3034
499
  }
3035
- if (!o) {
3036
- let t = se(e.headers.cookie, $n), r = t ? le(t, ce()) : null;
3037
- r && (o = await P(N.checkAccess(n, r)) === !0);
500
+ if (!c) {
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);
3038
503
  }
3039
- if (!o) return {
504
+ if (!c) return {
3040
505
  status: 403,
3041
506
  body: "forbidden",
3042
507
  contentType: "text/plain"
3043
508
  };
3044
- if (x.presigns && !r) {
3045
- let e = await P(x.getUrl(n.key, 300));
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));
3046
517
  if (e && /^https?:/.test(e)) return {
3047
518
  status: 302,
3048
519
  headers: {
@@ -3051,12 +522,12 @@ var qn = () => _e({
3051
522
  }
3052
523
  };
3053
524
  }
3054
- return we(n, "private, no-store", r, i);
3055
- }, L = {
525
+ return H(n, "private, no-store", r, a, o);
526
+ }, Ne = {
3056
527
  method: "GET",
3057
- path: b,
528
+ path: i,
3058
529
  handle: async (e) => {
3059
- let t = await Ee(e), n = sr(e.headers.origin, E);
530
+ let t = await Ae(e), n = Pt(e.headers.origin, b);
3060
531
  return Object.keys(n).length === 0 ? t : {
3061
532
  ...t,
3062
533
  headers: {
@@ -3065,12 +536,12 @@ var qn = () => _e({
3065
536
  }
3066
537
  };
3067
538
  }
3068
- }, De = {
539
+ }, Pe = {
3069
540
  method: "*",
3070
- path: `${b}/upload`,
541
+ path: `${i}/upload`,
3071
542
  originGuard: "exempt",
3072
543
  handle: async (e) => {
3073
- let t = sr(e.headers.origin, E);
544
+ let t = Pt(e.headers.origin, b);
3074
545
  if (e.method === "OPTIONS") return {
3075
546
  status: 204,
3076
547
  headers: t
@@ -3081,112 +552,113 @@ var qn = () => _e({
3081
552
  contentType: "text/plain",
3082
553
  headers: t
3083
554
  };
3084
- let n = e.query ? new URLSearchParams(e.query).get("ticket") : null, r = n ? It(n) : null;
3085
- if (!r || r.instance !== y) return {
555
+ let n = e.query ? new URLSearchParams(e.query).get("ticket") : null, i = n ? Se(n) : null;
556
+ if (!i || i.instance !== r) return {
3086
557
  status: 401,
3087
558
  body: "invalid or expired upload ticket",
3088
559
  contentType: "text/plain",
3089
560
  headers: t
3090
561
  };
3091
- if (r.replicaId !== void 0 && r.replicaId !== ie().replicaId) return {
3092
- status: 409,
3093
- body: "upload ticket belongs to another replica",
3094
- contentType: "text/plain",
3095
- headers: t
3096
- };
562
+ let a = await L(i, t);
563
+ if (a) return a;
3097
564
  if (e.rawBody.length === 0) return {
3098
565
  status: 400,
3099
566
  body: "empty body",
3100
567
  contentType: "text/plain",
3101
568
  headers: t
3102
569
  };
3103
- if (r.max && e.rawBody.length > r.max) return {
570
+ if (i.max && e.rawBody.length > i.max) return {
3104
571
  status: 413,
3105
572
  body: "payload too large",
3106
573
  contentType: "text/plain",
3107
574
  headers: t
3108
575
  };
3109
- let i = await v.runPromise(N.put({
576
+ let o = await q.runPromise(F.put({
3110
577
  bytes: e.rawBody,
3111
- contentType: r.ct,
3112
- tenantId: r.tenant,
3113
- ownerId: r.sub,
3114
- visibility: r.vis,
3115
- ...r.access === void 0 ? {} : { access: r.access },
3116
- ...r.operationId === void 0 ? {} : { operationId: r.operationId },
3117
- ...r.key === void 0 ? {} : { key: r.key },
3118
- ...r.folder === void 0 ? {} : { folder: r.folder },
3119
- ...r.tags === void 0 ? {} : { tags: r.tags },
3120
- ...r.alt === void 0 ? {} : { alt: r.alt },
3121
- ...r.caption === void 0 ? {} : { caption: r.caption }
3122
- }).pipe(v.flatMap((e) => N.getUrl(e.id).pipe(v.map((t) => ({
578
+ contentType: i.ct,
579
+ tenantId: i.tenant,
580
+ destination: i.destination,
581
+ ownerId: i.sub,
582
+ visibility: i.vis,
583
+ ...i.access === void 0 ? {} : { access: i.access },
584
+ ...i.operationId === void 0 ? {} : { operationId: i.operationId },
585
+ ...i.key === void 0 ? {} : { key: i.key },
586
+ ...i.folder === void 0 ? {} : { folder: i.folder },
587
+ ...i.tags === void 0 ? {} : { tags: i.tags },
588
+ ...i.alt === void 0 ? {} : { alt: i.alt },
589
+ ...i.caption === void 0 ? {} : { caption: i.caption }
590
+ }).pipe(q.flatMap((e) => F.getUrl(e.id).pipe(q.map((t) => ({
3123
591
  kind: "ok",
3124
592
  ref: e,
3125
593
  url: t
3126
- })))), v.catchTags({
3127
- StorageRejected: (e) => v.succeed({
594
+ })))), q.catchTags({
595
+ StorageRejected: (e) => q.succeed({
3128
596
  kind: "rejected",
3129
- status: e.reason === "too-large" ? 413 : 415,
597
+ status: Ht(e),
3130
598
  detail: e.detail
3131
599
  }),
3132
- StorageScanRejected: (e) => v.succeed({
600
+ StorageScanRejected: (e) => q.succeed({
3133
601
  kind: "scan",
3134
602
  threat: e.threat
3135
603
  }),
3136
- StorageError: (e) => v.succeed({
604
+ StorageError: (e) => q.succeed({
3137
605
  kind: "error",
3138
- message: e.message
606
+ message: e.message,
607
+ status: e.status ?? 500
3139
608
  })
3140
609
  })));
3141
- return i.kind === "ok" ? {
610
+ return o.kind === "ok" ? {
3142
611
  status: 201,
3143
612
  body: JSON.stringify({
3144
- id: i.ref.id,
3145
- url: i.url,
3146
- contentType: i.ref.contentType,
3147
- size: i.ref.size
613
+ id: o.ref.id,
614
+ url: o.url,
615
+ contentType: o.ref.contentType,
616
+ size: o.ref.size
3148
617
  }),
3149
618
  contentType: "application/json",
3150
619
  headers: t
3151
- } : i.kind === "rejected" ? {
3152
- status: i.status,
3153
- body: i.detail,
620
+ } : o.kind === "rejected" ? {
621
+ status: o.status,
622
+ body: o.detail,
3154
623
  contentType: "text/plain",
3155
624
  headers: t
3156
- } : i.kind === "scan" ? {
625
+ } : o.kind === "scan" ? {
3157
626
  status: 422,
3158
- body: `rejected: ${i.threat}`,
627
+ body: `rejected: ${o.threat}`,
3159
628
  contentType: "text/plain",
3160
629
  headers: t
3161
630
  } : {
3162
- status: 500,
3163
- body: i.message,
631
+ status: o.status,
632
+ body: o.message,
3164
633
  contentType: "text/plain",
3165
634
  headers: t
3166
635
  };
3167
636
  }
3168
- }, Oe = {
637
+ }, Fe = {
3169
638
  method: "*",
3170
- path: `${b}/upload/resumable`,
639
+ path: `${i}/upload/resumable`,
3171
640
  originGuard: "exempt",
3172
641
  handle: async (e) => {
3173
- let t = sr(e.headers.origin, E);
642
+ let t = Pt(e.headers.origin, b);
3174
643
  if (e.method === "OPTIONS") return {
3175
644
  status: 204,
3176
645
  headers: t
3177
646
  };
3178
- let n = new URLSearchParams(e.query || ""), r = Bt(n.get("token") ?? "");
3179
- if (!r || r.instance !== y) return {
647
+ let n = new URLSearchParams(e.query || ""), i = xe(n.get("token") ?? "");
648
+ if (!i || i.instance !== r) return {
3180
649
  status: 401,
3181
650
  body: "invalid or expired resumable token",
3182
651
  contentType: "text/plain",
3183
652
  headers: t
3184
653
  };
654
+ let a = await L(i, t);
655
+ if (a) return a;
3185
656
  if (e.method === "GET" || e.method === "HEAD") {
3186
- let e = await v.runPromise(N.resumableStatus({
3187
- uploadId: r.id,
3188
- tenantId: r.tenant
3189
- }).pipe(v.match({
657
+ let e = await q.runPromise(F.resumableStatus({
658
+ uploadId: i.id,
659
+ tenantId: i.tenant,
660
+ destination: i.destination
661
+ }).pipe(q.match({
3190
662
  onFailure: (e) => ({ error: e.message }),
3191
663
  onSuccess: (e) => e
3192
664
  })));
@@ -3211,8 +683,8 @@ var qn = () => _e({
3211
683
  contentType: "text/plain",
3212
684
  headers: t
3213
685
  };
3214
- let i = Number(n.get("index"));
3215
- if (!Number.isInteger(i) || i < 0) return {
686
+ let o = Number(n.get("index"));
687
+ if (!Number.isInteger(o) || o < 0) return {
3216
688
  status: 400,
3217
689
  body: "missing/invalid chunk index",
3218
690
  contentType: "text/plain",
@@ -3224,153 +696,173 @@ var qn = () => _e({
3224
696
  contentType: "text/plain",
3225
697
  headers: t
3226
698
  };
3227
- let a = n.get("final") === "1", o = await v.runPromise(N.putResumableChunk({
3228
- uploadId: r.id,
3229
- tenantId: r.tenant,
3230
- index: i,
699
+ let s = n.get("final") === "1", c = await q.runPromise(F.putResumableChunk({
700
+ uploadId: i.id,
701
+ tenantId: i.tenant,
702
+ destination: i.destination,
703
+ index: o,
3231
704
  bytes: e.rawBody
3232
- }).pipe(v.flatMap(() => a ? N.finalizeResumable({
3233
- uploadId: r.id,
3234
- count: i + 1,
3235
- contentType: r.ct,
3236
- tenantId: r.tenant,
3237
- ownerId: r.sub,
3238
- visibility: r.vis,
3239
- ...r.access === void 0 ? {} : { access: r.access },
3240
- ...r.folder === void 0 ? {} : { folder: r.folder },
3241
- ...r.tags === void 0 ? {} : { tags: r.tags },
3242
- ...r.alt === void 0 ? {} : { alt: r.alt },
3243
- ...r.caption === void 0 ? {} : { caption: r.caption }
3244
- }).pipe(v.flatMap((e) => N.getUrl(e.id).pipe(v.map((t) => ({
705
+ }).pipe(q.flatMap(() => s ? F.finalizeResumable({
706
+ uploadId: i.id,
707
+ destination: i.destination,
708
+ count: o + 1,
709
+ contentType: i.ct,
710
+ tenantId: i.tenant,
711
+ ownerId: i.sub,
712
+ visibility: i.vis,
713
+ ...i.access === void 0 ? {} : { access: i.access },
714
+ ...i.folder === void 0 ? {} : { folder: i.folder },
715
+ ...i.tags === void 0 ? {} : { tags: i.tags },
716
+ ...i.alt === void 0 ? {} : { alt: i.alt },
717
+ ...i.caption === void 0 ? {} : { caption: i.caption }
718
+ }).pipe(q.flatMap((e) => F.getUrl(e.id).pipe(q.map((t) => ({
3245
719
  kind: "done",
3246
720
  ref: e,
3247
721
  url: t
3248
- }))))) : v.succeed({ kind: "chunk" })), v.catchTags({
3249
- StorageRejected: (e) => v.succeed({
722
+ }))))) : q.succeed({ kind: "chunk" })), q.catchTags({
723
+ StorageRejected: (e) => q.succeed({
3250
724
  kind: "rejected",
3251
- status: e.reason === "too-large" ? 413 : 415,
725
+ status: Ht(e),
3252
726
  detail: e.detail
3253
727
  }),
3254
- StorageScanRejected: (e) => v.succeed({
728
+ StorageScanRejected: (e) => q.succeed({
3255
729
  kind: "scan",
3256
730
  threat: e.threat
3257
731
  }),
3258
- StorageError: (e) => v.succeed({
732
+ StorageError: (e) => q.succeed({
3259
733
  kind: "error",
3260
- message: e.message
734
+ message: e.message,
735
+ status: e.status ?? 500
3261
736
  })
3262
737
  })));
3263
- return o.kind === "chunk" ? {
738
+ return c.kind === "chunk" ? {
3264
739
  status: 204,
3265
740
  headers: {
3266
741
  ...t,
3267
- "upload-offset": String(i + 1)
742
+ "upload-offset": String(o + 1)
3268
743
  }
3269
- } : o.kind === "done" ? {
744
+ } : c.kind === "done" ? {
3270
745
  status: 201,
3271
746
  body: JSON.stringify({
3272
- id: o.ref.id,
3273
- url: o.url,
3274
- contentType: o.ref.contentType,
3275
- size: o.ref.size
747
+ id: c.ref.id,
748
+ url: c.url,
749
+ contentType: c.ref.contentType,
750
+ size: c.ref.size
3276
751
  }),
3277
752
  contentType: "application/json",
3278
753
  headers: t
3279
- } : o.kind === "rejected" ? {
3280
- status: o.status,
3281
- body: o.detail,
754
+ } : c.kind === "rejected" ? {
755
+ status: c.status,
756
+ body: c.detail,
3282
757
  contentType: "text/plain",
3283
758
  headers: t
3284
- } : o.kind === "scan" ? {
759
+ } : c.kind === "scan" ? {
3285
760
  status: 422,
3286
- body: `rejected: ${o.threat}`,
761
+ body: `rejected: ${c.threat}`,
3287
762
  contentType: "text/plain",
3288
763
  headers: t
3289
764
  } : {
3290
- status: 500,
3291
- body: o.message,
765
+ status: c.status,
766
+ body: c.message,
3292
767
  contentType: "text/plain",
3293
768
  headers: t
3294
769
  };
3295
770
  }
3296
- }, R = (e) => ({
771
+ }, U = (e) => ({
3297
772
  kind: "json",
3298
773
  data: e
3299
- }), z = (e, t) => ({
774
+ }), W = (e, t) => ({
3300
775
  kind: "json",
3301
776
  status: e,
3302
777
  data: { error: t }
3303
- }), ke = (e, t) => {
778
+ }), G = (e, t) => {
3304
779
  try {
3305
780
  return new URL(e, "http://localhost").searchParams.get(t);
3306
781
  } catch {
3307
782
  return null;
3308
783
  }
3309
- }, Ae = [
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
794
+ };
795
+ }), et = [
3310
796
  {
3311
797
  method: "POST",
3312
798
  path: "/upload-ticket",
3313
799
  description: "Authorize a binary upload with explicit tenant and owner attribution",
3314
- handler: (e) => v.gen(function* () {
3315
- let n = S.String.pipe(S.check(S.makeFilter((e) => e.trim().length > 0))), r = yield* S.decodeUnknownEffect(S.fromJsonString(S.Struct({
3316
- operationId: S.optional(n.pipe(S.check(S.isMaxLength(200)))),
3317
- tenantId: S.NullOr(n),
3318
- ownerId: S.NullOr(n),
3319
- key: n.pipe(S.check(S.isMaxLength(1024))),
3320
- contentType: n.pipe(S.check(S.isMaxLength(255)), S.check(S.makeFilter((e) => !/[\r\n]/.test(e)))),
3321
- size: S.Number.pipe(S.check(S.isInt()), S.check(S.isGreaterThan(0)), S.check(S.makeFilter(Number.isSafeInteger))),
3322
- visibility: S.optional(S.Literals(["public", "private"]))
3323
- })))(e.body).pipe(v.mapError(() => new t({
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({
3324
810
  provider: "inspect",
3325
811
  message: "Provide explicit tenantId and ownerId (or null), key, contentType and a positive file size",
3326
812
  transient: !1,
3327
813
  status: 400
3328
814
  })));
3329
- if (r.operationId !== void 0 && me.current === void 0) return z(409, "Durable uploads require a bound operation store with default reference and grant stores");
3330
- if (D !== void 0 && r.size > D) return z(413, "File exceeds the configured upload limit");
3331
- let a = r.visibility !== "public" && Array.isArray(i.uploadAccess) ? yield* S.decodeUnknownEffect(ae)(i.uploadAccess, { onExcessProperty: "error" }).pipe(v.mapError(() => new t({
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({
3332
818
  provider: "storage",
3333
819
  message: "Invalid upload access policy",
3334
820
  transient: !1,
3335
821
  status: 400
3336
- }))) : void 0, o = Ft({
3337
- instance: y,
3338
- ...a === void 0 ? {} : { access: a },
3339
- ...r.operationId === void 0 ? {} : { operationId: `inspect-upload:${Ce("sha256").update(JSON.stringify([y, r.operationId])).digest("hex")}` },
3340
- replicaId: ie().replicaId,
3341
- sub: r.ownerId,
3342
- tenant: r.tenantId,
3343
- ct: r.contentType,
3344
- key: r.key,
3345
- vis: r.visibility ?? "private",
3346
- max: r.size
822
+ }))) : void 0, u = yield* F.uploadTicketScope({
823
+ tenantId: a.tenantId,
824
+ destination: o.destination
825
+ }), d = z({
826
+ writeScope: u,
827
+ instance: r,
828
+ destination: o.destination,
829
+ issuerReplicaId: _t().replicaId,
830
+ ...l === void 0 ? {} : { access: l },
831
+ ...c === void 0 ? {} : { operationId: c },
832
+ sub: a.ownerId,
833
+ tenant: a.tenantId,
834
+ ct: a.contentType,
835
+ key: a.key,
836
+ vis: a.visibility ?? "private",
837
+ max: a.size
3347
838
  }, 300);
3348
- return R({
3349
- uploadPath: `${b}/upload?ticket=${encodeURIComponent(o)}`,
839
+ return U({
840
+ uploadPath: `${i}/upload?ticket=${encodeURIComponent(d)}`,
3350
841
  expiresInSec: 300,
3351
- maxBytes: r.size
842
+ maxBytes: a.size,
843
+ ...s === void 0 ? {} : { operationId: s }
3352
844
  });
3353
- }).pipe(v.catch((e) => v.succeed(z(e.status ?? 500, e.message))))
845
+ }).pipe(q.catch((e) => q.succeed(W(e.status ?? 500, e.message))))
3354
846
  },
3355
847
  {
3356
848
  method: "GET",
3357
849
  path: "/download",
3358
850
  description: "Stream a stored file as an attachment for authorized inspect readers",
3359
- handler: (e) => v.gen(function* () {
3360
- let t = ke(e.url, "refId");
3361
- if (!t?.trim()) return z(400, "A non-empty refId is required");
3362
- let { ref: n, stream: r } = yield* N.getStream(t), i = n.key.split("/").pop() || n.id, a = encodeURIComponent(i).replace(/[!'()*]/g, (e) => `%${e.charCodeAt(0).toString(16).toUpperCase()}`);
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()}`);
3363
855
  return {
3364
856
  kind: "bytes",
3365
857
  contentType: n.contentType,
3366
858
  byteStream: {
3367
- stream: () => C.toReadableStream(r),
859
+ stream: () => pt.toReadableStream(r),
3368
860
  contentLength: n.size,
3369
861
  contentDisposition: `attachment; filename="download"; filename*=UTF-8''${a}`
3370
862
  },
3371
863
  headers: { "cache-control": "no-store" }
3372
864
  };
3373
- }).pipe(v.catch((e) => v.succeed(z(e.status ?? 500, e.message))))
865
+ }).pipe(q.catch((e) => q.succeed(W(e.status ?? 500, e.message))))
3374
866
  },
3375
867
  {
3376
868
  method: "GET",
@@ -3378,8 +870,8 @@ var qn = () => _e({
3378
870
  scope: "process",
3379
871
  description: "Searchable storage refs, newest first, paginated",
3380
872
  handler: (e) => {
3381
- let t = Number(ke(e.url, "offset") ?? 0), n = Number.isSafeInteger(t) && t >= 0 ? t : 0, r = (ke(e.url, "search") ?? "").trim().slice(0, 200);
3382
- return he.listRefs({
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({
3383
875
  tenantId: void 0,
3384
876
  ownerId: void 0,
3385
877
  folder: void 0,
@@ -3388,14 +880,15 @@ var qn = () => _e({
3388
880
  search: r,
3389
881
  limit: 51,
3390
882
  offset: n
3391
- }).pipe(v.map((e) => R({
3392
- refs: e.slice(0, 50).map(cr),
883
+ }).pipe(q.flatMap((e) => K.pipe(q.map((t) => U({
884
+ source: t,
885
+ refs: e.slice(0, 50).map(Ft),
3393
886
  page: {
3394
887
  search: r,
3395
888
  offset: n,
3396
889
  nextOffset: e.length > 50 ? n + 50 : null
3397
890
  }
3398
- })), v.catch((e) => v.succeed(z(500, e.message))));
891
+ })))), q.catch((e) => q.succeed(W(500, e.message))));
3399
892
  }
3400
893
  },
3401
894
  {
@@ -3403,11 +896,12 @@ var qn = () => _e({
3403
896
  path: "/stats",
3404
897
  scope: "process",
3405
898
  description: "Object count + total bytes per tenant + visibility split",
3406
- handler: () => he.statistics().pipe(v.map((e) => R({
3407
- provider: x.name,
3408
- bucket: ue,
899
+ handler: () => M.statistics().pipe(q.flatMap((e) => K.pipe(q.map((t) => U({
900
+ source: t,
901
+ provider: p ? "tenant-scoped" : m.name,
902
+ bucket: h,
3409
903
  ...e
3410
- })), v.catch((e) => v.succeed(z(500, e.message))))
904
+ })))), q.catch((e) => q.succeed(W(500, e.message))))
3411
905
  },
3412
906
  {
3413
907
  method: "GET",
@@ -3415,103 +909,119 @@ var qn = () => _e({
3415
909
  scope: "process",
3416
910
  description: "Grants for a ref (?refId=…)",
3417
911
  handler: (e) => {
3418
- let t = ke(e.url, "refId");
3419
- return t ? ge.listByRef(t).pipe(v.map((e) => R({ grants: e.map(mr) })), v.catch((e) => v.succeed(z(500, e.message)))) : v.succeed(z(400, "refId query param required"));
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"));
3420
914
  }
3421
915
  },
3422
916
  {
3423
917
  method: "POST",
3424
918
  path: "/share",
3425
919
  description: "Grant a principal access to a ref",
3426
- handler: (e) => v.gen(function* () {
3427
- let n = yield* S.decodeUnknownEffect(S.fromJsonString(S.Struct({
3428
- refId: S.String.pipe(S.check(S.makeFilter((e) => e.trim().length > 0))),
3429
- principalType: S.Literals([
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([
3430
924
  "user",
3431
925
  "group",
3432
926
  "apiKey"
3433
927
  ]),
3434
- principalId: S.String.pipe(S.check(S.makeFilter((e) => e.trim().length > 0))),
3435
- permission: S.optional(S.Literals(["read", "write"])),
3436
- expiresInDays: S.optional(S.Number.pipe(S.check(S.isFinite()), S.check(S.isGreaterThan(0))))
3437
- })))(e.body).pipe(v.mapError(() => new t({
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({
3438
932
  provider: "inspect",
3439
933
  message: "Invalid share input: provide refId, principalType, principalId, read/write permission and a positive finite expiry if set",
3440
934
  transient: !1,
3441
935
  status: 400
3442
- }))), r = n.expiresInDays === void 0 ? null : new Date(Date.now() + n.expiresInDays * 864e5);
3443
- if (r !== null && !Number.isFinite(r.getTime())) return z(400, "Expiry exceeds the supported date range");
3444
- let i = yield* N.grant({
3445
- refId: n.refId,
3446
- principalType: n.principalType,
3447
- principalId: n.principalId,
3448
- ...n.permission ? { permission: n.permission } : {},
3449
- expiresAt: r
936
+ }))), n = t.expiresInDays === void 0 ? null : new Date(Date.now() + t.expiresInDays * 864e5);
937
+ if (n !== null && !Number.isFinite(n.getTime())) return W(400, "Expiry exceeds the supported date range");
938
+ let r = yield* F.grant({
939
+ refId: t.refId,
940
+ principalType: t.principalType,
941
+ principalId: t.principalId,
942
+ ...t.permission ? { permission: t.permission } : {},
943
+ expiresAt: n
3450
944
  });
3451
- return R({ grant: mr(i) });
3452
- }).pipe(v.catch((e) => v.succeed(z(e.status ?? 500, e.message ?? "share failed"))))
945
+ return U({ grant: Bt(r) });
946
+ }).pipe(q.catch((e) => q.succeed(W(e.status ?? 500, e.message ?? "share failed"))))
3453
947
  },
3454
948
  {
3455
949
  method: "POST",
3456
950
  path: "/delete",
3457
951
  description: "Delete an object reference and its grants; release unreferenced bytes",
3458
- handler: (e) => v.gen(function* () {
3459
- let n = yield* S.decodeUnknownEffect(S.fromJsonString(S.Struct({ refId: S.String.pipe(S.check(S.makeFilter((e) => e.trim().length > 0))) })))(e.body).pipe(v.mapError(() => new t({
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({
3460
954
  provider: "inspect",
3461
955
  message: "A non-empty refId is required",
3462
956
  transient: !1,
3463
957
  status: 400
3464
958
  })));
3465
- return yield* N.delete(n.refId), R({ ok: !0 });
3466
- }).pipe(v.catch((e) => v.succeed(z(e.status ?? 500, e.message))))
959
+ return yield* F.delete(t.refId), U({ ok: !0 });
960
+ }).pipe(q.catch((e) => q.succeed(W(e.status ?? 500, e.message))))
3467
961
  },
3468
962
  {
3469
963
  method: "POST",
3470
964
  path: "/revoke",
3471
965
  description: "Revoke a grant by id",
3472
- handler: (e) => v.gen(function* () {
3473
- let n = yield* S.decodeUnknownEffect(S.fromJsonString(S.Struct({ grantId: S.String.pipe(S.check(S.makeFilter((e) => e.trim().length > 0))) })))(e.body).pipe(v.mapError(() => new t({
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({
3474
968
  provider: "inspect",
3475
969
  message: "A non-empty grantId is required",
3476
970
  transient: !1,
3477
971
  status: 400
3478
972
  })));
3479
- return yield* N.revoke(n.grantId), R({ ok: !0 });
3480
- }).pipe(v.catch((e) => v.succeed(z(e.status ?? 500, e.message ?? "revoke failed"))))
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"))))
3481
975
  }
3482
- ], je = [
976
+ ], tt = [
3483
977
  {
3484
- ...te,
978
+ ...Je,
3485
979
  execute: (e, t) => {
3486
980
  let n = e;
3487
- return N.mintUrl(n.id, t.request.subject, {
981
+ return F.mintUrl(n.id, t.request.subject, {
3488
982
  ...n.password === void 0 ? {} : { password: n.password },
3489
983
  ...n.expiresInSec === void 0 ? {} : { expiresInSec: n.expiresInSec }
3490
- }).pipe(v.map((e) => ({ url: e })));
984
+ }).pipe(q.map((e) => ({ url: e })));
3491
985
  }
3492
986
  },
3493
987
  {
3494
- ...ee,
988
+ ...qe,
3495
989
  execute: (e, t) => {
3496
990
  let n = e;
3497
- return N.mintUploadUrl({
991
+ return F.mintUploadUrl({
3498
992
  key: n.key,
3499
993
  contentType: n.contentType,
3500
994
  tenantId: t.request.subject.tenantId,
3501
995
  ...n.expiresInSec === void 0 ? {} : { expiresInSec: n.expiresInSec }
3502
- }).pipe(v.map((e) => ({ url: e })));
996
+ }).pipe(q.map((e) => ({ url: e })));
3503
997
  }
3504
998
  },
3505
999
  {
3506
- ...m,
1000
+ ...Ke,
3507
1001
  execute: (e, t) => {
3508
1002
  let n = e;
3509
- return fr(t, O).pipe(v.flatMap((e) => A(n, t.request.subject).pipe(v.map((t) => ({
1003
+ return Z(t, S).pipe(q.flatMap((e) => D(n, t.request.subject).pipe(q.map((t) => ({
3510
1004
  writer: e,
3511
1005
  policy: t
3512
- })))), v.map(({ writer: e, policy: t }) => {
3513
- let r = n.expiresInSec ?? 900, i = Ft({
3514
- instance: y,
1006
+ })))), q.flatMap((e) => n.operationId !== void 0 && A.current === void 0 ? q.fail(new g({
1007
+ provider: "storage",
1008
+ message: "Durable uploads require a bound operation store with default reference and grant stores",
1009
+ transient: !1,
1010
+ status: 409
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,
1017
+ e.tenantId,
1018
+ e.id,
1019
+ c
1020
+ ])).digest("hex"), u = z({
1021
+ writeScope: o,
1022
+ instance: r,
1023
+ destination: a.destination,
1024
+ ...l === void 0 ? {} : { operationId: l },
3515
1025
  sub: e.id,
3516
1026
  tenant: e.tenantId,
3517
1027
  ct: n.contentType,
@@ -3522,30 +1032,33 @@ var qn = () => _e({
3522
1032
  ...n.tags === void 0 ? {} : { tags: n.tags },
3523
1033
  ...n.alt === void 0 ? {} : { alt: n.alt },
3524
1034
  ...n.caption === void 0 ? {} : { caption: n.caption },
3525
- ...D === void 0 ? {} : { max: D }
3526
- }, r);
1035
+ ...x === void 0 ? {} : { max: x }
1036
+ }, s);
3527
1037
  return {
3528
- uploadUrl: `${T ? T.replace(/\/+$/, "") : ""}${b}/upload?ticket=${encodeURIComponent(i)}`,
3529
- expiresInSec: r
1038
+ uploadUrl: `${y ? y.replace(/\/+$/, "") : ""}${i}/upload?ticket=${encodeURIComponent(u)}`,
1039
+ expiresInSec: s,
1040
+ ...c === void 0 ? {} : { operationId: c }
3530
1041
  };
3531
- }));
1042
+ }))))));
3532
1043
  }
3533
1044
  },
3534
1045
  {
3535
- ...p,
1046
+ ...Ge,
3536
1047
  execute: (e, t) => {
3537
1048
  let n = e;
3538
- return fr(t, O).pipe(v.flatMap((e) => A(n, t.request.subject).pipe(v.map((t) => ({
1049
+ return Z(t, S).pipe(q.flatMap((e) => D(n, t.request.subject).pipe(q.map((t) => ({
3539
1050
  writer: e,
3540
1051
  policy: t
3541
- })))), v.flatMap(({ writer: e, policy: t }) => N.mintPresignedUpload({
1052
+ })))), q.flatMap(({ writer: e, policy: t }) => F.mintPresignedUpload({
3542
1053
  contentType: n.contentType,
3543
1054
  tenantId: e.tenantId,
3544
1055
  ...n.expiresInSec === void 0 ? {} : { expiresInSec: n.expiresInSec }
3545
- }).pipe(v.map((r) => {
3546
- let i = Lt({
3547
- instance: y,
3548
- key: r.key,
1056
+ }).pipe(q.map((i) => {
1057
+ let a = ge({
1058
+ writeScope: i.writeScope,
1059
+ instance: r,
1060
+ destination: i.destination,
1061
+ key: i.key,
3549
1062
  sub: e.id,
3550
1063
  tenant: e.tenantId,
3551
1064
  ct: n.contentType,
@@ -3555,65 +1068,71 @@ var qn = () => _e({
3555
1068
  ...n.tags === void 0 ? {} : { tags: n.tags },
3556
1069
  ...n.alt === void 0 ? {} : { alt: n.alt },
3557
1070
  ...n.caption === void 0 ? {} : { caption: n.caption },
3558
- ...D === void 0 ? {} : { max: D }
3559
- }, r.expiresInSec);
1071
+ ...x === void 0 ? {} : { max: x }
1072
+ }, i.expiresInSec);
3560
1073
  return {
3561
- uploadUrl: r.uploadUrl,
3562
- finalizeToken: i,
3563
- expiresInSec: r.expiresInSec
1074
+ uploadUrl: i.uploadUrl,
1075
+ finalizeToken: a,
1076
+ expiresInSec: i.expiresInSec
3564
1077
  };
3565
1078
  }))));
3566
1079
  }
3567
1080
  },
3568
1081
  {
3569
- ...l,
3570
- execute: (e, n) => {
3571
- let r = Rt(e.finalizeToken);
3572
- return !r || r.instance !== y ? v.fail(new t({
1082
+ ...Ve,
1083
+ execute: (e, t) => {
1084
+ let n = ye(e.finalizeToken);
1085
+ return !n || n.instance !== r ? q.fail(new g({
3573
1086
  provider: "storage",
3574
1087
  message: "invalid or expired finalize token",
3575
1088
  transient: !1,
3576
1089
  status: 401
3577
- })) : pr(r.sub, n.request.subject.id) ? v.fail(new t({
1090
+ })) : zt(n.sub, t.request.subject.id) ? q.fail(new g({
3578
1091
  provider: "storage",
3579
1092
  message: "finalize token belongs to another subject",
3580
1093
  transient: !1,
3581
1094
  status: 403
3582
- })) : N.finalizeUpload({
3583
- key: r.key,
3584
- contentType: r.ct,
3585
- tenantId: r.tenant,
3586
- ownerId: r.sub,
3587
- visibility: r.vis,
3588
- ...r.access === void 0 ? {} : { access: r.access },
3589
- ...r.folder === void 0 ? {} : { folder: r.folder },
3590
- ...r.tags === void 0 ? {} : { tags: r.tags },
3591
- ...r.alt === void 0 ? {} : { alt: r.alt },
3592
- ...r.caption === void 0 ? {} : { caption: r.caption }
3593
- }).pipe(v.flatMap((e) => N.getUrl(e.id).pipe(v.map((t) => ({
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) => ({
3594
1108
  id: e.id,
3595
1109
  url: t,
3596
1110
  contentType: e.contentType,
3597
1111
  size: e.size,
3598
1112
  ...e.width == null ? {} : { width: e.width },
3599
1113
  ...e.height == null ? {} : { height: e.height }
3600
- })))));
1114
+ })))))));
3601
1115
  }
3602
1116
  },
3603
1117
  {
3604
- ...s,
1118
+ ...ze,
3605
1119
  execute: (e, t) => {
3606
1120
  let n = e;
3607
- return fr(t, O).pipe(v.flatMap((e) => A(n, t.request.subject).pipe(v.map((t) => ({
1121
+ return Z(t, S).pipe(q.flatMap((e) => D(n, t.request.subject).pipe(q.map((t) => ({
3608
1122
  writer: e,
3609
1123
  policy: t
3610
- })))), v.map(({ writer: e, policy: t }) => {
3611
- let r = n.expiresInSec ?? fe, i = Te(), a = n.chunkSize && n.chunkSize > 0 ? n.chunkSize : de;
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;
3612
1129
  return {
3613
- uploadId: i,
3614
- resumableToken: zt({
3615
- instance: y,
3616
- id: i,
1130
+ uploadId: c,
1131
+ resumableToken: ve({
1132
+ writeScope: o,
1133
+ instance: r,
1134
+ destination: a.destination,
1135
+ id: c,
3617
1136
  sub: e.id,
3618
1137
  tenant: e.tenantId,
3619
1138
  ct: n.contentType,
@@ -3624,32 +1143,34 @@ var qn = () => _e({
3624
1143
  ...n.tags === void 0 ? {} : { tags: n.tags },
3625
1144
  ...n.alt === void 0 ? {} : { alt: n.alt },
3626
1145
  ...n.caption === void 0 ? {} : { caption: n.caption },
3627
- ...D === void 0 ? {} : { max: D }
3628
- }, r),
3629
- uploadUrl: `${T ? T.replace(/\/+$/, "") : ""}${b}/upload/resumable`,
3630
- chunkSize: a,
3631
- expiresInSec: r
1146
+ ...x === void 0 ? {} : { max: x }
1147
+ }, s),
1148
+ uploadUrl: `${y ? y.replace(/\/+$/, "") : ""}${i}/upload/resumable`,
1149
+ chunkSize: l,
1150
+ expiresInSec: s
3632
1151
  };
3633
- }));
1152
+ }))))));
3634
1153
  }
3635
1154
  },
3636
1155
  {
3637
- ...o,
1156
+ ...Re,
3638
1157
  execute: (e, t) => {
3639
- let n = e, r = n.expiresInSec ?? fe;
3640
- return fr(t, O).pipe(v.flatMap((e) => A(n, t.request.subject).pipe(v.map((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) => ({
3641
1160
  writer: e,
3642
1161
  policy: t
3643
- })))), v.flatMap(({ writer: e, policy: t }) => N.beginMultipartUpload({
1162
+ })))), q.flatMap(({ writer: e, policy: t }) => F.beginMultipartUpload({
3644
1163
  contentType: n.contentType,
3645
1164
  tenantId: e.tenantId,
3646
1165
  visibility: n.visibility ?? "private",
3647
- expiresInSec: r
3648
- }).pipe(v.map((i) => ({
3649
- multipartToken: Vt({
3650
- instance: y,
3651
- key: i.key,
3652
- uploadId: i.uploadId,
1166
+ expiresInSec: i
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,
3653
1174
  sub: e.id,
3654
1175
  tenant: e.tenantId,
3655
1176
  ct: n.contentType,
@@ -3660,51 +1181,54 @@ var qn = () => _e({
3660
1181
  ...n.tags === void 0 ? {} : { tags: n.tags },
3661
1182
  ...n.alt === void 0 ? {} : { alt: n.alt },
3662
1183
  ...n.caption === void 0 ? {} : { caption: n.caption }
3663
- }, r),
3664
- partSize: n.partSize && n.partSize >= de ? n.partSize : de,
3665
- expiresInSec: r
1184
+ }, i),
1185
+ partSize: n.partSize && n.partSize >= C ? n.partSize : C,
1186
+ expiresInSec: i
3666
1187
  })))));
3667
1188
  }
3668
1189
  },
3669
1190
  {
3670
- ...g,
1191
+ ...Ze,
3671
1192
  execute: (e) => {
3672
- let n = e, r = Ht(n.multipartToken);
3673
- return !r || r.instance !== y ? v.fail(new t({
1193
+ let t = e, n = B(t.multipartToken);
1194
+ return !n || n.instance !== r ? q.fail(new g({
3674
1195
  provider: "storage",
3675
1196
  message: "invalid or expired multipart token",
3676
1197
  transient: !1,
3677
1198
  status: 401
3678
- })) : !Number.isInteger(n.partNumber) || n.partNumber < 1 ? v.fail(new t({
1199
+ })) : !Number.isInteger(t.partNumber) || t.partNumber < 1 ? q.fail(new g({
3679
1200
  provider: "storage",
3680
1201
  message: "partNumber must be a positive integer",
3681
1202
  transient: !1,
3682
1203
  status: 400
3683
- })) : N.signMultipartPart({
3684
- key: r.key,
3685
- uploadId: r.uploadId,
3686
- partNumber: n.partNumber
3687
- }).pipe(v.map((e) => ({ url: e })));
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 })))));
3688
1211
  }
3689
1212
  },
3690
1213
  {
3691
- ...c,
3692
- execute: (e, n) => {
3693
- let r = e, i = Ht(r.multipartToken);
3694
- return !i || i.instance !== y ? v.fail(new t({
1214
+ ...Be,
1215
+ execute: (e, t) => {
1216
+ let n = e, i = B(n.multipartToken);
1217
+ return !i || i.instance !== r ? q.fail(new g({
3695
1218
  provider: "storage",
3696
1219
  message: "invalid or expired multipart token",
3697
1220
  transient: !1,
3698
1221
  status: 401
3699
- })) : pr(i.sub, n.request.subject.id) ? v.fail(new t({
1222
+ })) : zt(i.sub, t.request.subject.id) ? q.fail(new g({
3700
1223
  provider: "storage",
3701
1224
  message: "multipart token belongs to another subject",
3702
1225
  transient: !1,
3703
1226
  status: 403
3704
- })) : N.completeMultipart({
1227
+ })) : I(i).pipe(q.flatMap(() => F.completeMultipart({
1228
+ destination: i.destination,
3705
1229
  key: i.key,
3706
1230
  uploadId: i.uploadId,
3707
- parts: r.parts,
1231
+ parts: n.parts,
3708
1232
  contentType: i.ct,
3709
1233
  tenantId: i.tenant,
3710
1234
  ownerId: i.sub,
@@ -3714,36 +1238,38 @@ var qn = () => _e({
3714
1238
  ...i.tags === void 0 ? {} : { tags: i.tags },
3715
1239
  ...i.alt === void 0 ? {} : { alt: i.alt },
3716
1240
  ...i.caption === void 0 ? {} : { caption: i.caption }
3717
- }).pipe(v.flatMap((e) => N.getUrl(e.id).pipe(v.map((t) => ({
1241
+ }).pipe(q.flatMap((e) => F.getUrl(e.id).pipe(q.map((t) => ({
3718
1242
  id: e.id,
3719
1243
  url: t,
3720
1244
  size: e.size
3721
- })))));
1245
+ })))))));
3722
1246
  }
3723
1247
  },
3724
1248
  {
3725
- ...a,
1249
+ ...Le,
3726
1250
  execute: (e) => {
3727
- let n = Ht(e.multipartToken);
3728
- return !n || n.instance !== y ? v.fail(new t({
1251
+ let t = B(e.multipartToken);
1252
+ return !t || t.instance !== r ? q.fail(new g({
3729
1253
  provider: "storage",
3730
1254
  message: "invalid or expired multipart token",
3731
1255
  transient: !1,
3732
1256
  status: 401
3733
- })) : N.abortMultipart({
3734
- key: n.key,
3735
- uploadId: n.uploadId
3736
- }).pipe(v.as({ ok: !0 }));
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 }))));
3737
1263
  }
3738
1264
  },
3739
1265
  {
3740
- ...re,
1266
+ ...$e,
3741
1267
  execute: (e, t) => {
3742
1268
  let n = e, r = new Uint8Array(Buffer.from(n.bytesBase64, "base64"));
3743
- return fr(t, O).pipe(v.flatMap((e) => A(n, t.request.subject).pipe(v.map((t) => ({
1269
+ return Z(t, S).pipe(q.flatMap((e) => D(n, t.request.subject).pipe(q.map((t) => ({
3744
1270
  writer: e,
3745
1271
  policy: t
3746
- })))), v.flatMap(({ writer: e, policy: t }) => N.put({
1272
+ })))), q.flatMap(({ writer: e, policy: t }) => F.put({
3747
1273
  bytes: r,
3748
1274
  ...t,
3749
1275
  contentType: n.contentType,
@@ -3752,17 +1278,17 @@ var qn = () => _e({
3752
1278
  ...n.visibility ? { visibility: n.visibility } : {},
3753
1279
  ...n.key ? { key: n.key } : {},
3754
1280
  ...n.password ? { password: n.password } : {}
3755
- })), v.flatMap((e) => N.getUrl(e.id).pipe(v.map((t) => ({
1281
+ })), q.flatMap((e) => F.getUrl(e.id).pipe(q.map((t) => ({
3756
1282
  id: e.id,
3757
1283
  url: t
3758
1284
  })))));
3759
1285
  }
3760
1286
  },
3761
1287
  {
3762
- ...u,
1288
+ ...He,
3763
1289
  execute: (e, t) => {
3764
1290
  let n = e;
3765
- return fr(t, O).pipe(v.flatMap((e) => N.ingestUrl(n.url, {
1291
+ return Z(t, S).pipe(q.flatMap((e) => F.ingestUrl(n.url, {
3766
1292
  tenantId: e.tenantId,
3767
1293
  ownerId: e.id,
3768
1294
  ...n.visibility ? { visibility: n.visibility } : {},
@@ -3771,45 +1297,45 @@ var qn = () => _e({
3771
1297
  ...n.alt === void 0 ? {} : { alt: n.alt },
3772
1298
  ...n.caption === void 0 ? {} : { caption: n.caption },
3773
1299
  ...n.key === void 0 ? {} : { key: n.key }
3774
- })), v.flatMap((e) => N.getUrl(e.id).pipe(v.map((t) => ({
1300
+ })), q.flatMap((e) => F.getUrl(e.id).pipe(q.map((t) => ({
3775
1301
  id: e.id,
3776
1302
  url: t
3777
1303
  })))));
3778
1304
  }
3779
1305
  },
3780
1306
  {
3781
- ...h,
1307
+ ...Xe,
3782
1308
  execute: (e, t) => {
3783
1309
  let n = e, r = n.expiresInDays ? new Date(Date.now() + n.expiresInDays * 864e5) : null;
3784
- return ur(N, n.refId, t).pipe(v.flatMap(() => N.grant({
1310
+ return Lt(F, n.refId, t).pipe(q.flatMap(() => F.grant({
3785
1311
  refId: n.refId,
3786
1312
  principalType: n.principalType,
3787
1313
  principalId: n.principalId,
3788
1314
  ...n.permission ? { permission: n.permission } : {},
3789
1315
  expiresAt: r,
3790
1316
  createdBy: t.request.subject.id
3791
- })), v.map((e) => ({ grantId: e.id })));
1317
+ })), q.map((e) => ({ grantId: e.id })));
3792
1318
  }
3793
1319
  },
3794
1320
  {
3795
- ...ne,
1321
+ ...Ye,
3796
1322
  execute: (e, t) => {
3797
1323
  let n = e;
3798
- return N.getGrant(n.grantId).pipe(v.flatMap((e) => e === null ? v.fail(lr()) : ur(N, e.refId, t)), v.flatMap(() => N.revoke(n.grantId)), v.map(() => ({ ok: !0 })));
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 })));
3799
1325
  }
3800
1326
  },
3801
1327
  {
3802
- ...d,
1328
+ ...Ue,
3803
1329
  execute: (e, t) => {
3804
1330
  let n = e;
3805
- return ur(N, n.refId, t).pipe(v.flatMap(() => N.listGrants(n.refId)), v.map((e) => ({ grants: e.map(mr) })));
1331
+ return Lt(F, n.refId, t).pipe(q.flatMap(() => F.listGrants(n.refId)), q.map((e) => ({ grants: e.map(Bt) })));
3806
1332
  }
3807
1333
  },
3808
1334
  {
3809
- ...f,
1335
+ ...We,
3810
1336
  execute: (e, t) => {
3811
1337
  let n = e;
3812
- return N.listRefs({
1338
+ return F.listRefs({
3813
1339
  tenantId: t.request.subject.tenantId,
3814
1340
  ...n.folder === void 0 ? {} : { folder: n.folder },
3815
1341
  ...n.tags === void 0 ? {} : { tags: n.tags },
@@ -3817,111 +1343,154 @@ var qn = () => _e({
3817
1343
  ...n.includeDerived === void 0 ? {} : { includeDerived: n.includeDerived },
3818
1344
  ...n.limit === void 0 ? {} : { limit: n.limit },
3819
1345
  ...n.offset === void 0 ? {} : { offset: n.offset }
3820
- }).pipe(v.map((e) => ({
3821
- refs: e.refs.map(cr),
1346
+ }).pipe(q.map((e) => ({
1347
+ refs: e.refs.map(Ft),
3822
1348
  nextOffset: e.nextOffset
3823
1349
  })));
3824
1350
  }
3825
1351
  }
3826
- ];
3827
- return oe({
3828
- name: w({
3829
- base: hr,
3830
- alias: i.alias,
3831
- instance: i.name
1352
+ ], nt = yt({
1353
+ name: xt({
1354
+ base: Q,
1355
+ alias: e.alias,
1356
+ instance: e.name
3832
1357
  }),
3833
- baseName: hr,
1358
+ baseName: Q,
3834
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.",
3835
1360
  permissions: [
3836
1361
  "network:outbound:*",
3837
1362
  "inspect:read",
3838
1363
  "inspect:write"
3839
1364
  ],
3840
- declaredEnv: U.declared,
3841
- egress: ar(i),
3842
- services: ve,
3843
- inspectEndpoints: Ae,
1365
+ declaredEnv: E.declared,
1366
+ egress: Mt(e),
1367
+ services: fe,
1368
+ inspectEndpoints: et,
3844
1369
  httpRoutes: [
3845
- L,
3846
- De,
3847
- Oe
1370
+ Ne,
1371
+ Pe,
1372
+ Fe
3848
1373
  ],
3849
- routes: je,
3850
- rpcClientDescriptors: _,
1374
+ routes: tt,
1375
+ rpcClientDescriptors: Qe,
3851
1376
  errorSchemas: [
3852
1377
  {
3853
- schema: t,
1378
+ schema: g,
3854
1379
  import: {
3855
1380
  module: "@voltro/plugin-storage/errors",
3856
1381
  name: "StorageError"
3857
1382
  }
3858
1383
  },
3859
1384
  {
3860
- schema: e,
1385
+ schema: ne,
3861
1386
  import: {
3862
1387
  module: "@voltro/plugin-storage/errors",
3863
1388
  name: "StorageAccessDenied"
3864
1389
  }
3865
1390
  },
3866
1391
  {
3867
- schema: n,
1392
+ schema: re,
3868
1393
  import: {
3869
1394
  module: "@voltro/plugin-storage/errors",
3870
1395
  name: "StorageRejected"
3871
1396
  }
3872
1397
  },
3873
1398
  {
3874
- schema: r,
1399
+ schema: ie,
3875
1400
  import: {
3876
1401
  module: "@voltro/plugin-storage/errors",
3877
1402
  name: "StorageScanRejected"
3878
1403
  }
3879
1404
  }
3880
1405
  ],
3881
- capabilities: { mediaPersist: {
3882
- put: async ({ bytes: e, mediaType: t, tenantId: n, operationId: r, ownerId: i, visibility: a, tags: o }) => {
3883
- let s = await v.runPromise(N.put({
3884
- bytes: e,
3885
- contentType: t,
3886
- tenantId: n,
3887
- kind: "media",
3888
- ...i === void 0 ? {} : { ownerId: i },
3889
- ...a === void 0 ? {} : { visibility: a },
3890
- ...o === void 0 ? {} : { tags: o },
3891
- ...me.current === void 0 ? {} : { operationId: r }
3892
- }));
3893
- return {
3894
- url: await v.runPromise(N.getUrl(s.id, { tenantId: n })),
3895
- refId: s.id
3896
- };
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
3897
1418
  },
3898
- ingestUrl: async ({ url: e, tenantId: t, operationId: n, ownerId: r, visibility: i, tags: a }) => {
3899
- let o = await v.runPromise(N.ingestUrl(e, {
3900
- tenantId: t,
3901
- ...r === void 0 ? {} : { ownerId: r },
3902
- ...i === void 0 ? {} : { visibility: i },
3903
- ...a === void 0 ? {} : { tags: a },
3904
- ...me.current === void 0 ? {} : { operationId: n }
3905
- }));
3906
- return {
3907
- url: await v.runPromise(N.getUrl(o.id, { tenantId: t })),
3908
- refId: o.id
3909
- };
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
+ }
3910
1449
  }
3911
- } },
3912
- bindDataStore: (e) => {
3913
- k && (j.current = ln(e)), pe && (M.current = fn(e)), k && pe && (me.current = zn(e)), x.bindDataStore?.(e);
3914
1450
  },
3915
- onActivate: (e) => v.sync(() => {
3916
- let t = !!T || !!U.read("STORAGE_CDN_URL", i.cdnBaseUrl);
3917
- e.logger.info(`storage: provider=${x.name} presign=${x.presigns ? "yes" : "no"} publicUrl=${t ? "yes" : "no"} transforms=yes`, {
3918
- provider: x.name,
3919
- bucket: ue,
3920
- refStore: k ? "memory" : "custom"
3921
- }), x.name === "memory" && process.env.NODE_ENV !== "test" && e.logger.warn("storage: provider=memory — uploads are IN-MEMORY and LOST on restart. Set STORAGE_PROVIDER (filesystem / s3 / r2 / azure / gcs) for anything but throwaway dev. (Empty/placeholder storage env silently falls back to memory.)"), !t && !x.presigns && e.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.");
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.");
3922
1472
  }),
3923
- onDeactivate: () => v.void
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
3924
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
1492
+ });
1493
+ return n;
3925
1494
  };
3926
1495
  //#endregion
3927
- export { H as STORAGE_BLOBS_TABLE, V as STORAGE_GRANTS_TABLE, B as STORAGE_REFS_TABLE, Ue as STORAGE_USAGE_TABLE, e as StorageAccessDenied, t as StorageError, n as StorageRejected, r as StorageScanRejected, i as StorageService, qe as _voltroStorageBlobsTable, Ge as _voltroStorageGrantsTable, We as _voltroStorageRefsTable, Ke as _voltroStorageUsageTable, nr as appStorageProvider, Kn as assetRef, at as azureProvider, hn as buildStorageService, Le as bytesToStream, Kt as checkLimits, Un as clamavScanner, $e as clearStorageBuffer, Re as collectStream, Ie as concatBytes, rr as configuredStorageProvider, Ut as contentTypeAllowed, fn as dataStoreGrantStore, ln as dataStoreRefStore, it as databaseProvider, Yn as decodeDataUri, Qn as durabilityNotice, ht as editImage, Bn as encodeInstream, Gn as ffmpegTranscoder, tt as filesystemProvider, ze as fromNodeReadable, Ve as getObjectStream, yt as hashPassword, zn as makeStorageObjectMetadata, un as memoryGrantStore, et as memoryProvider, on as memoryRefStore, Vn as parseClamavResponse, lt as parseTransformParams, Zn as pathDurability, Xn as putAvatar, He as putObjectStream, Qe as readStorageBuffer, rn as refMatchesListQuery, ir as resolveStorageProvider, q as resolveStorageSecret, nt as s3Provider, tr as setActiveStorageProvider, Lt as signFinalizeTicket, Mt as signGrant, Vt as signMultipartTicket, zt as signResumableTicket, Ft as signUploadTicket, Gt as sniffMatches, ar as storageEgressOf, gr as storageInstanceName, bn as storageObjectLifecycleTables, _r as storagePlugin, In as storagePutIntentsTable, gn as storageServiceLayer, Be as toNodeReadable, vt as transformCached, pt as transformFallbackReason, mt as transformImage, Rt as verifyFinalizeTicket, Nt as verifyGrant, Ht as verifyMultipartTicket, bt as verifyPassword, Bt as verifyResumableTicket, It as verifyUploadTicket, qn as withStorage };
1496
+ 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 };