@voltro/plugin-storage 0.84.0 → 0.86.0

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