@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.
@@ -0,0 +1,1084 @@
1
+ import { requireStorageReferenceScope as e, storageObjectNamespace as t, storageUploadTicketScope as n } from "./storageNamespaces.js";
2
+ import { storageReferenceCatalogueId as r } from "./referenceCatalogue.js";
3
+ import { STORAGE_GRANTS_TABLE as i, STORAGE_REFS_TABLE as a, STORAGE_USAGE_TABLE as o } from "./table.js";
4
+ import "./storageReferenceInstances.js";
5
+ import { StorageAccessDenied as s, StorageError as c, StorageRejected as l, StorageScanRejected as u, StorageService as d } from "./types.js";
6
+ import { storageInteger as f, storageIntegerSum as p } from "./storageNumbers.js";
7
+ import { getObjectStream as m } from "./streamBridge.js";
8
+ import { storageMetadataError as h } from "./metadataError.js";
9
+ import { evaluatePolicy as g, grantsAllow as _, hashPassword as v, resolveSubjectGroups as y } from "./access.js";
10
+ import { signGrant as b } from "./grant.js";
11
+ import { checkLimits as ee } from "./constraints.js";
12
+ import { extractImageMetadata as te } from "./derivatives.js";
13
+ import { fetchIngestBody as x, withIngestAbort as S } from "./ingest.js";
14
+ import { makeStorageObjectWriter as C } from "./objectWriter.js";
15
+ import { randomUUID as w } from "node:crypto";
16
+ import { and as T, authoredError as E, column as D, contains as O, eq as k, generateId as A, isNull as j, or as M } from "@voltro/database";
17
+ import { Effect as N, Exit as P, Layer as F, Schedule as I, Stream as L } from "effect";
18
+ //#region src/service.ts
19
+ var R = async (e) => {
20
+ let { createHash: t } = await import("node:crypto");
21
+ return t("sha256").update(e).digest("hex");
22
+ }, z = (e, t, n) => `${e?.replace(/\/+$/, "") ?? ""}${n}/${t}`, B = (e) => {
23
+ let t = /* @__PURE__ */ new Map(), n = {
24
+ public: 0,
25
+ private: 0
26
+ };
27
+ for (let r of e) {
28
+ let e = r.tenantId ?? "(global)", i = t.get(e) ?? {
29
+ count: 0,
30
+ bytes: 0
31
+ };
32
+ i.count = p(i.count, r.count, "ref count"), i.bytes = p(i.bytes, r.bytes, "usage bytes"), t.set(e, i), r.visibility === "public" ? n.public = p(n.public, r.count, "public ref count") : n.private = p(n.private, r.count, "private ref count");
33
+ }
34
+ return {
35
+ byTenant: Object.fromEntries(t),
36
+ visibility: n
37
+ };
38
+ }, V = (e, t) => {
39
+ if (t.search && ![
40
+ e.id,
41
+ e.key,
42
+ e.contentType,
43
+ e.ownerId,
44
+ e.tenantId
45
+ ].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;
46
+ if (t.folder !== void 0) {
47
+ let n = t.folder.replace(/\/+$/, ""), r = (e.folder ?? "").replace(/\/+$/, "");
48
+ if (r !== n && !r.startsWith(`${n}/`)) return !1;
49
+ }
50
+ if (t.tags.length > 0) {
51
+ let n = e.tags ?? [];
52
+ if (!t.tags.every((e) => n.includes(e))) return !1;
53
+ }
54
+ return !0;
55
+ }, H = (e) => e ?? "global", U = () => {
56
+ let e = /* @__PURE__ */ new Map(), n = /* @__PURE__ */ new Map();
57
+ return {
58
+ catalogueId: N.succeed(t(["memory-reference-catalogue", w()])),
59
+ statistics: () => N.try({
60
+ try: () => B((function* () {
61
+ for (let t of e.values()) yield {
62
+ tenantId: t.tenantId,
63
+ visibility: t.visibility,
64
+ count: 1,
65
+ bytes: t.size
66
+ };
67
+ })()),
68
+ catch: (e) => h(e, "refstore")
69
+ }),
70
+ insert: (t) => N.try({
71
+ try: () => {
72
+ f(t.size, "ref size"), e.set(t.id, t);
73
+ },
74
+ catch: (e) => h(e, "refstore")
75
+ }),
76
+ getById: (t) => N.sync(() => e.get(t) ?? null),
77
+ delete: (t) => N.sync(() => e.delete(t)),
78
+ listRecent: (t) => N.sync(() => [...e.values()].sort((e, t) => t.createdAt.getTime() - e.createdAt.getTime() || t.id.localeCompare(e.id)).slice(0, t)),
79
+ countByKey: (t, n) => N.sync(() => [...e.values()].filter((e) => e.bucket === t && e.key === n).length),
80
+ countPublicByKey: (t, n) => N.sync(() => [...e.values()].filter((e) => e.bucket === t && e.key === n && e.visibility === "public").length),
81
+ setVisibility: (t, n) => N.sync(() => {
82
+ let r = e.get(t);
83
+ if (r === void 0) return null;
84
+ let i = {
85
+ ...r,
86
+ visibility: n
87
+ };
88
+ return e.set(t, i), i;
89
+ }),
90
+ usageByTenant: (t) => N.try({
91
+ try: () => {
92
+ let n = 0, r = 0;
93
+ for (let i of e.values()) (i.tenantId ?? null) === (t ?? null) && (n = p(n, i.size, "usage bytes"), r++);
94
+ return {
95
+ bytes: n,
96
+ count: r
97
+ };
98
+ },
99
+ catch: (e) => h(e, "refstore")
100
+ }),
101
+ consumeUsage: (e, t, r) => N.try({
102
+ try: () => {
103
+ let i = H(e), a = n.get(i) ?? {
104
+ bytes: 0,
105
+ count: 0
106
+ };
107
+ f(t.bytes, "usage byte delta"), f(t.count, "usage count delta");
108
+ let o = Number.isSafeInteger(a.bytes + t.bytes) && Number.isSafeInteger(a.count + t.count) && (r?.maxBytes === void 0 || a.bytes + t.bytes <= r.maxBytes) && (r?.maxCount === void 0 || a.count + t.count <= r.maxCount);
109
+ return o && n.set(i, {
110
+ bytes: a.bytes + t.bytes,
111
+ count: a.count + t.count
112
+ }), {
113
+ allowed: o,
114
+ bytes: a.bytes,
115
+ count: a.count
116
+ };
117
+ },
118
+ catch: (e) => h(e, "refstore")
119
+ }),
120
+ releaseUsage: (e, t) => N.try({
121
+ try: () => {
122
+ let r = H(e), i = n.get(r);
123
+ f(t.bytes, "usage byte delta"), f(t.count, "usage count delta"), i && n.set(r, {
124
+ bytes: Math.max(0, i.bytes - t.bytes),
125
+ count: Math.max(0, i.count - t.count)
126
+ });
127
+ },
128
+ catch: (e) => h(e, "refstore")
129
+ }),
130
+ listByDerivedFrom: (t) => N.sync(() => [...e.values()].filter((e) => (e.derivedFrom ?? null) === t)),
131
+ listRefs: (t) => N.sync(() => [...e.values()].filter((e) => V(e, t)).sort((e, t) => t.createdAt.getTime() - e.createdAt.getTime() || t.id.localeCompare(e.id)).slice(t.offset, t.offset + t.limit))
132
+ };
133
+ }, W = (e) => Array.isArray(e) && e.every((e) => typeof e == "string") ? e : null, G = (e) => ({
134
+ id: String(e.id),
135
+ tenantId: e.tenantId ?? null,
136
+ ownerId: e.ownerId ?? null,
137
+ bucket: String(e.bucket),
138
+ key: String(e.key),
139
+ contentType: String(e.contentType),
140
+ size: f(e.size, "ref size"),
141
+ checksum: String(e.checksum),
142
+ visibility: e.visibility === "public" ? "public" : "private",
143
+ accessPolicy: e.accessPolicy ?? null,
144
+ passwordHash: e.passwordHash ?? null,
145
+ createdAt: e.createdAt instanceof Date ? e.createdAt : new Date(String(e.createdAt)),
146
+ width: e.width ?? null,
147
+ height: e.height ?? null,
148
+ duration: e.duration ?? null,
149
+ placeholder: e.placeholder ?? null,
150
+ folder: e.folder ?? null,
151
+ tags: W(e.tags),
152
+ alt: e.alt ?? null,
153
+ caption: e.caption ?? null,
154
+ derivedFrom: e.derivedFrom ?? null,
155
+ kind: e.kind ?? null
156
+ }), K = (e) => N.tryPromise({
157
+ try: e,
158
+ catch: (e) => h(e, "refstore", !0)
159
+ }), q = async (e, t) => (await e.query({
160
+ table: "_voltro_storage_usage",
161
+ predicate: {
162
+ column: "tenantId",
163
+ op: "eq",
164
+ value: t
165
+ },
166
+ order: [],
167
+ take: 1,
168
+ skip: void 0,
169
+ projection: void 0
170
+ }))[0] ?? null, J = (t, n) => {
171
+ let i = Object.freeze({ ...n });
172
+ return e(i), {
173
+ catalogueId: K(() => r(t, i)),
174
+ statistics: () => K(async () => B((await t.query({
175
+ table: a,
176
+ predicate: T(k("storageInstance", i.storageInstance), k("objectNamespace", i.objectNamespace)),
177
+ order: [],
178
+ take: void 0,
179
+ skip: void 0,
180
+ projection: void 0,
181
+ groupBy: ["tenantId", "visibility"],
182
+ aggregations: [
183
+ D("tenantId"),
184
+ D("visibility"),
185
+ {
186
+ op: "count",
187
+ alias: "count"
188
+ },
189
+ {
190
+ op: "sum",
191
+ column: "size",
192
+ alias: "bytes"
193
+ }
194
+ ]
195
+ })).map((e) => ({
196
+ tenantId: e.tenantId == null ? null : String(e.tenantId),
197
+ visibility: String(e.visibility),
198
+ count: f(e.count, "ref count"),
199
+ bytes: f(e.bytes ?? 0, "usage bytes")
200
+ })))),
201
+ insert: (e) => K(() => t.insert(a, {
202
+ ...e,
203
+ storageInstance: i.storageInstance,
204
+ objectNamespace: i.objectNamespace,
205
+ size: String(f(e.size, "ref size"))
206
+ })),
207
+ getById: (e) => K(async () => {
208
+ let n = await t.query({
209
+ table: a,
210
+ predicate: T(T(k("storageInstance", i.storageInstance), k("objectNamespace", i.objectNamespace)), k("id", e)),
211
+ order: [],
212
+ take: 1,
213
+ skip: void 0,
214
+ projection: void 0
215
+ });
216
+ return n[0] ? G(n[0]) : null;
217
+ }),
218
+ delete: (e) => K(async () => await t.deleteMany(a, { where: T(T(k("storageInstance", i.storageInstance), k("objectNamespace", i.objectNamespace)), k("id", e)) }) > 0),
219
+ listRecent: (e) => K(async () => (await t.query({
220
+ table: a,
221
+ predicate: T(k("storageInstance", i.storageInstance), k("objectNamespace", i.objectNamespace)),
222
+ order: [{
223
+ column: "createdAt",
224
+ direction: "desc"
225
+ }],
226
+ take: e,
227
+ skip: void 0,
228
+ projection: void 0
229
+ })).map(G)),
230
+ countByKey: (e, n) => K(async () => {
231
+ let e = await t.query({
232
+ table: a,
233
+ predicate: { and: [k("objectNamespace", i.objectNamespace), {
234
+ column: "key",
235
+ op: "eq",
236
+ value: n
237
+ }] },
238
+ order: [],
239
+ take: void 0,
240
+ skip: void 0,
241
+ projection: void 0,
242
+ aggregations: [{
243
+ op: "count",
244
+ alias: "count"
245
+ }]
246
+ }), r = f(e[0]?.count ?? 0, "ref count");
247
+ return r === 0 ? (await t.query({
248
+ table: "_voltro_storage_object_heads",
249
+ predicate: T(k("objectNamespace", i.objectNamespace), k("key", n)),
250
+ order: [],
251
+ take: 1,
252
+ skip: void 0,
253
+ projection: ["id"]
254
+ })).length : r;
255
+ }),
256
+ countPublicByKey: (e, n) => K(async () => {
257
+ let e = await t.query({
258
+ table: a,
259
+ predicate: { and: [
260
+ k("objectNamespace", i.objectNamespace),
261
+ {
262
+ column: "key",
263
+ op: "eq",
264
+ value: n
265
+ },
266
+ {
267
+ column: "visibility",
268
+ op: "eq",
269
+ value: "public"
270
+ }
271
+ ] },
272
+ order: [],
273
+ take: void 0,
274
+ skip: void 0,
275
+ projection: void 0,
276
+ aggregations: [{
277
+ op: "count",
278
+ alias: "count"
279
+ }]
280
+ });
281
+ return f(e[0]?.count ?? 0, "ref count");
282
+ }),
283
+ setVisibility: (e, n) => K(() => t.transactional(async (t) => {
284
+ if ((await t.query({
285
+ table: "_voltro_storage_refs",
286
+ predicate: T(T(k("storageInstance", i.storageInstance), k("objectNamespace", i.objectNamespace)), k("id", e)),
287
+ lock: "update",
288
+ order: [],
289
+ take: 1,
290
+ skip: void 0,
291
+ projection: ["id"]
292
+ })).length === 0) return null;
293
+ let r = await t.update(a, e, { visibility: n });
294
+ return r ? G(r) : null;
295
+ })),
296
+ usageByTenant: (e) => K(async () => {
297
+ let n = await t.query({
298
+ table: a,
299
+ predicate: e === null ? j("tenantId") : k("tenantId", e),
300
+ order: [],
301
+ take: void 0,
302
+ skip: void 0,
303
+ projection: void 0,
304
+ aggregations: [
305
+ {
306
+ op: "count",
307
+ alias: "count"
308
+ },
309
+ {
310
+ op: "sum",
311
+ column: "size",
312
+ alias: "bytes"
313
+ },
314
+ {
315
+ op: "min",
316
+ column: "size",
317
+ alias: "minSize"
318
+ },
319
+ {
320
+ op: "max",
321
+ column: "size",
322
+ alias: "maxSize"
323
+ }
324
+ ]
325
+ });
326
+ return f(n[0]?.count ?? 0, "ref count") > 0 && (f(n[0]?.minSize, "ref size"), f(n[0]?.maxSize, "ref size")), {
327
+ bytes: f(n[0]?.bytes ?? 0, "usage bytes"),
328
+ count: f(n[0]?.count ?? 0, "ref count")
329
+ };
330
+ }),
331
+ consumeUsage: (e, n, r) => K(async () => {
332
+ let i = H(e);
333
+ f(n.bytes, "usage byte delta"), f(n.count, "usage count delta");
334
+ for (let e = 0; e < 32; e++) {
335
+ e > 0 && await new Promise((t) => setTimeout(t, e));
336
+ let a = await q(t, i), s = a ? f(a.bytes, "usage bytes") : 0, c = a ? f(a.count, "ref count") : 0;
337
+ if (!(Number.isSafeInteger(s + n.bytes) && Number.isSafeInteger(c + n.count) && (r?.maxBytes === void 0 || s + n.bytes <= r.maxBytes) && (r?.maxCount === void 0 || c + n.count <= r.maxCount))) return {
338
+ allowed: !1,
339
+ bytes: s,
340
+ count: c
341
+ };
342
+ if (a) {
343
+ if (await t.updateMany("_voltro_storage_usage", {
344
+ bytes: String(s + n.bytes),
345
+ count: String(c + n.count),
346
+ updatedAt: /* @__PURE__ */ new Date()
347
+ }, { where: T(k("id", String(a.id)), k("bytes", a.bytes), k("count", a.count)) }) === 1) return {
348
+ allowed: !0,
349
+ bytes: s,
350
+ count: c
351
+ };
352
+ } else {
353
+ let e = A({
354
+ kind: "typeid",
355
+ prefix: "susage"
356
+ }, o), r = await t.insertIgnore(o, {
357
+ id: e,
358
+ tenantId: i,
359
+ bytes: String(n.bytes),
360
+ count: String(n.count),
361
+ updatedAt: /* @__PURE__ */ new Date()
362
+ }, { conflictColumns: ["tenantId"] });
363
+ if (String(r.id) === e) return {
364
+ allowed: !0,
365
+ bytes: 0,
366
+ count: 0
367
+ };
368
+ }
369
+ }
370
+ throw E("Storage quota reservation contended after 32 attempts; retry");
371
+ }),
372
+ releaseUsage: (e, n) => K(async () => {
373
+ let r = H(e);
374
+ f(n.bytes, "usage byte delta"), f(n.count, "usage count delta");
375
+ for (let e = 0; e < 32; e++) {
376
+ e > 0 && await new Promise((t) => setTimeout(t, e));
377
+ let i = await q(t, r);
378
+ if (!i) return;
379
+ let a = f(i.bytes, "usage bytes"), o = f(i.count, "ref count");
380
+ if (await t.updateMany("_voltro_storage_usage", {
381
+ bytes: String(Math.max(0, a - n.bytes)),
382
+ count: String(Math.max(0, o - n.count)),
383
+ updatedAt: /* @__PURE__ */ new Date()
384
+ }, { where: T(k("id", String(i.id)), k("bytes", i.bytes), k("count", i.count)) }) === 1) return;
385
+ }
386
+ throw E("Storage quota release contended after 32 attempts; retry");
387
+ }),
388
+ listByDerivedFrom: (e) => K(async () => (await t.query({
389
+ table: a,
390
+ predicate: T(T(k("storageInstance", i.storageInstance), k("objectNamespace", i.objectNamespace)), k("derivedFrom", e)),
391
+ order: [{
392
+ column: "createdAt",
393
+ direction: "asc"
394
+ }],
395
+ take: void 0,
396
+ skip: void 0,
397
+ projection: void 0
398
+ })).map(G)),
399
+ listRefs: (e) => K(async () => {
400
+ let n = [T(k("storageInstance", i.storageInstance), k("objectNamespace", i.objectNamespace))];
401
+ e.tenantId !== void 0 && n.push(e.tenantId === null ? j("tenantId") : k("tenantId", e.tenantId)), e.ownerId !== void 0 && n.push(k("ownerId", e.ownerId)), e.search && n.push(M(...[
402
+ "id",
403
+ "key",
404
+ "contentType",
405
+ "ownerId",
406
+ "tenantId"
407
+ ].map((t) => O(t, e.search)))), e.includeDerived || n.push(j("derivedFrom"));
408
+ let r = e.folder === void 0 && e.tags.length === 0, o = n.length ? T(...n) : void 0, s = await t.query({
409
+ table: a,
410
+ predicate: o,
411
+ order: [{
412
+ column: "createdAt",
413
+ direction: "desc"
414
+ }, {
415
+ column: "id",
416
+ direction: "desc"
417
+ }],
418
+ take: r ? e.limit : void 0,
419
+ skip: r ? e.offset : void 0,
420
+ projection: void 0
421
+ });
422
+ return r ? s.map(G) : s.map(G).filter((t) => V(t, e)).slice(e.offset, e.offset + e.limit);
423
+ })
424
+ };
425
+ }, Y = () => {
426
+ let e = /* @__PURE__ */ new Map();
427
+ return {
428
+ insert: (t) => N.sync(() => {
429
+ e.set(t.id, t);
430
+ }),
431
+ delete: (t) => N.sync(() => {
432
+ e.delete(t);
433
+ }),
434
+ getById: (t) => N.sync(() => e.get(t) ?? null),
435
+ listByRef: (t) => N.sync(() => [...e.values()].filter((e) => e.refId === t)),
436
+ deleteByRef: (t) => N.sync(() => {
437
+ for (let [n, r] of e) r.refId === t && e.delete(n);
438
+ })
439
+ };
440
+ }, X = (e) => ({
441
+ id: String(e.id),
442
+ refId: String(e.refId),
443
+ principalType: e.principalType,
444
+ principalId: String(e.principalId),
445
+ permission: e.permission === "write" ? "write" : "read",
446
+ createdAt: e.createdAt instanceof Date ? e.createdAt : new Date(String(e.createdAt)),
447
+ expiresAt: e.expiresAt ? e.expiresAt instanceof Date ? e.expiresAt : new Date(String(e.expiresAt)) : null,
448
+ createdBy: e.createdBy ?? null
449
+ }), Z = (t, n) => {
450
+ let r = Object.freeze({ ...n });
451
+ return e(r), {
452
+ insert: (e) => K(() => t.insert(i, {
453
+ ...e,
454
+ ...r
455
+ })),
456
+ delete: (e) => K(() => t.deleteMany(i, { where: T(T(k("storageInstance", r.storageInstance), k("objectNamespace", r.objectNamespace)), k("id", e)) })).pipe(N.asVoid),
457
+ getById: (e) => K(async () => {
458
+ let n = (await t.query({
459
+ table: i,
460
+ predicate: T(T(k("storageInstance", r.storageInstance), k("objectNamespace", r.objectNamespace)), k("id", e)),
461
+ order: [],
462
+ take: 1,
463
+ skip: void 0,
464
+ projection: void 0
465
+ }))[0];
466
+ return n ? X(n) : null;
467
+ }),
468
+ listByRef: (e) => K(async () => (await t.query({
469
+ table: i,
470
+ predicate: T(T(k("storageInstance", r.storageInstance), k("objectNamespace", r.objectNamespace)), k("refId", e)),
471
+ order: [{
472
+ column: "createdAt",
473
+ direction: "desc"
474
+ }],
475
+ take: void 0,
476
+ skip: void 0,
477
+ projection: void 0
478
+ })).map(X)),
479
+ deleteByRef: (e) => K(async () => {
480
+ let n = await t.query({
481
+ table: i,
482
+ predicate: T(T(k("storageInstance", r.storageInstance), k("objectNamespace", r.objectNamespace)), k("refId", e)),
483
+ order: [],
484
+ take: void 0,
485
+ skip: void 0,
486
+ projection: void 0
487
+ });
488
+ for (let e of n) await t.delete(i, String(e.id));
489
+ })
490
+ };
491
+ }, Q = () => A({
492
+ kind: "typeid",
493
+ prefix: "file"
494
+ }, a), ne = () => A({
495
+ kind: "typeid",
496
+ prefix: "grant"
497
+ }, i), $ = (e) => {
498
+ let { provider: t, refStore: r, grantStore: i, bucket: o } = e, d = e.access ?? {}, f = e.attempts ?? 3, p = e.urlExpiresInSec ?? 3600, w = (t) => z(e.publicBaseUrl, t, e.httpPath ?? "/_voltro/storage"), T = I.max([I.recurs(Math.max(0, f - 1)), I.exponential("100 millis")]).pipe(I.while(({ input: e }) => e.transient)), E = (t, n, r) => [
499
+ e.tenantPrefix,
500
+ t ?? "global",
501
+ r ?? n
502
+ ].filter(Boolean).join("/"), D = (e) => {
503
+ if (e === void 0) return N.succeed(void 0);
504
+ 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;
505
+ return n === void 0 ? N.succeed(e) : N.fail(new c({
506
+ provider: t.name,
507
+ message: `storage key rejected: ${n}`,
508
+ transient: !1,
509
+ status: 400
510
+ }));
511
+ }, O = (t, n, r) => [
512
+ e.tenantPrefix,
513
+ t ?? "global",
514
+ "_incoming",
515
+ n,
516
+ String(r).padStart(6, "0")
517
+ ].filter(Boolean).join("/"), k = (e, t) => t === void 0 || e.tenantId === t, j = (e, n) => k(e, n) ? N.succeed(e) : N.fail(new c({
518
+ provider: t.name,
519
+ message: "cross-tenant access denied",
520
+ transient: !1,
521
+ status: 403
522
+ })), M = (n, r, i) => N.gen(function* () {
523
+ let a = e.objects?.(), o = (e) => new c({
524
+ provider: "metadata",
525
+ message: e,
526
+ transient: !1,
527
+ status: 409
528
+ });
529
+ if (a === void 0) return i === void 0 ? !1 : yield* N.fail(o(`claim '${i}' cannot be released: no data store is bound, so ref '${n}' holds no claims`));
530
+ let s = yield* N.tryPromise({
531
+ try: () => a.intent(n),
532
+ catch: (e) => new c({
533
+ provider: "metadata",
534
+ message: String(e?.message ?? e),
535
+ transient: !1
536
+ })
537
+ });
538
+ return s === void 0 ? i === void 0 ? !1 : yield* N.fail(o(`claim '${i}' cannot be released: ref '${n}' was not written through an operation and holds no claims`)) : (yield* j(s.ref, r), yield* C({
539
+ metadata: a,
540
+ provider: {
541
+ ...t,
542
+ delete: (e) => t.delete(e).pipe(N.retry(T))
543
+ }
544
+ }).delete(n, r, i).pipe(N.catchTag("StorageRejected", (e) => N.fail(e.reason === "claim-not-held" ? o(e.detail) : new c({
545
+ provider: "metadata",
546
+ message: e.detail,
547
+ transient: !1
548
+ })))), !0);
549
+ }), F = (e, n) => r.getById(e).pipe(N.flatMap((r) => r ? j(r, n) : N.fail(new c({
550
+ provider: t.name,
551
+ message: `no ref '${e}'`,
552
+ transient: !1,
553
+ status: 404
554
+ })))), B = (t) => N.suspend(() => {
555
+ let n = e.scan(t);
556
+ return N.isEffect(n) ? n : N.tryPromise({
557
+ try: () => Promise.resolve(n),
558
+ catch: (e) => new c({
559
+ provider: "scan",
560
+ message: String(e?.message ?? e),
561
+ transient: !0
562
+ })
563
+ });
564
+ }), V = (t) => N.suspend(() => {
565
+ let n = t.contentType;
566
+ if (!e.videoProbe || !(n.startsWith("video/") || n.startsWith("audio/"))) return N.succeed(null);
567
+ let r;
568
+ try {
569
+ r = e.videoProbe(t);
570
+ } catch {
571
+ return N.succeed(null);
572
+ }
573
+ return N.isEffect(r) ? r.pipe(N.catch(() => N.succeed(null))) : N.tryPromise({
574
+ try: () => Promise.resolve(r),
575
+ catch: () => null
576
+ }).pipe(N.catch(() => N.succeed(null)));
577
+ }), H = (n) => N.gen(function* () {
578
+ let i = ee(n.bytes, n.contentType, e.limits);
579
+ if (i) return yield* N.fail(new l(i));
580
+ if (n.claim !== void 0 && n.operationId === void 0) return yield* N.fail(new l({
581
+ reason: "claim-without-operation",
582
+ detail: "a put with a claim needs an operationId; the claim names this caller's hold on that operation's object"
583
+ }));
584
+ if (e.scan) {
585
+ let e = yield* B({
586
+ bytes: n.bytes,
587
+ contentType: n.contentType,
588
+ ...n.key ? { key: n.key } : {}
589
+ });
590
+ if (!e.clean) return yield* N.fail(new u({ threat: e.threat ?? "unknown" }));
591
+ }
592
+ let a = yield* N.promise(() => te(n.bytes, n.contentType, { normalize: e.normalizeImages ?? !1 })), s = a.bytes, c = yield* V({
593
+ bytes: s,
594
+ contentType: n.contentType
595
+ }), d = a.width ?? c?.width, f = a.height ?? c?.height, p = a.placeholder ?? c?.poster, m = n.duration ?? c?.duration, h = yield* N.promise(() => R(s)), g = n.tenantId ?? null, _ = n.visibility ?? "private", y = yield* D(n.key), b = E(g, h, y), x = n.operationId === void 0 ? E(g, h, `i-${yield* N.promise(() => R(new TextEncoder().encode(JSON.stringify([e.storageInstance ?? "@voltro/plugin-storage", o]))))}/plain/${y ?? h}`) : b, S = n.password ? yield* N.sync(() => v(n.password)) : null, w = {
596
+ id: Q(),
597
+ tenantId: g,
598
+ ownerId: n.ownerId ?? null,
599
+ bucket: o,
600
+ key: x,
601
+ contentType: n.contentType,
602
+ size: s.byteLength,
603
+ checksum: h,
604
+ visibility: _,
605
+ accessPolicy: n.access ?? null,
606
+ passwordHash: S,
607
+ createdAt: /* @__PURE__ */ new Date(),
608
+ ...d === void 0 ? {} : { width: d },
609
+ ...f === void 0 ? {} : { height: f },
610
+ ...p === void 0 ? {} : { placeholder: p },
611
+ ...m === void 0 ? {} : { duration: m },
612
+ ...n.folder === void 0 ? {} : { folder: n.folder },
613
+ ...n.tags === void 0 ? {} : { tags: n.tags },
614
+ ...n.alt === void 0 ? {} : { alt: n.alt },
615
+ ...n.caption === void 0 ? {} : { caption: n.caption },
616
+ ...n.derivedFrom === void 0 ? {} : { derivedFrom: n.derivedFrom },
617
+ ...n.kind === void 0 ? {} : { kind: n.kind }
618
+ }, O = e.transcode !== void 0 && e.autoTranscode !== !1, k = (e) => O && e.derivedFrom == null && (n.contentType.startsWith("video/") || n.contentType.startsWith("audio/")) ? N.forkDetach(W(e).pipe(N.ignore)) : N.void;
619
+ if (n.operationId !== void 0) {
620
+ let r = e.objects?.();
621
+ if (r === void 0) return yield* N.fail(new l({
622
+ reason: "operation-store-unbound",
623
+ detail: "a put with an operationId needs a bound data store; the in-memory ref store cannot hold operation intents"
624
+ }));
625
+ let i = {
626
+ tenantId: g,
627
+ bucket: o,
628
+ operationId: n.operationId,
629
+ checksum: h,
630
+ logicalKey: x,
631
+ fingerprint: yield* N.promise(() => R(new TextEncoder().encode(JSON.stringify([
632
+ h,
633
+ n.contentType,
634
+ _,
635
+ n.access ?? null,
636
+ n.key ?? null,
637
+ n.ownerId ?? null,
638
+ n.folder ?? null,
639
+ n.tags ?? null,
640
+ n.alt ?? null,
641
+ n.caption ?? null,
642
+ n.derivedFrom ?? null,
643
+ n.kind ?? null,
644
+ m ?? null,
645
+ n.password !== void 0
646
+ ]))))
647
+ }, a = yield* C({
648
+ metadata: r,
649
+ provider: {
650
+ ...t,
651
+ put: (e, n, r) => t.put(e, n, r).pipe(N.retry(T))
652
+ }
653
+ }).put({
654
+ identity: i,
655
+ ref: w,
656
+ bytes: s,
657
+ ...e.quota === void 0 ? {} : { quota: e.quota },
658
+ ...n.claim === void 0 ? {} : { claim: n.claim }
659
+ });
660
+ return yield* k(a.ref), {
661
+ ...a.ref,
662
+ outcome: a.outcome
663
+ };
664
+ }
665
+ let A = {
666
+ bytes: s.byteLength,
667
+ count: 1
668
+ }, j = yield* r.consumeUsage(g, A, e.quota);
669
+ if (!j.allowed) {
670
+ let t = e.quota ?? {}, n = t.maxCount !== void 0 && j.count + 1 > t.maxCount ? `tenant object count ${j.count} + 1 exceeds max ${t.maxCount}` : `tenant usage ${j.bytes} + ${s.byteLength} bytes exceeds max ${t.maxBytes}`;
671
+ return yield* N.fail(new l({
672
+ reason: "quota-exceeded",
673
+ detail: n
674
+ }));
675
+ }
676
+ return yield* ((e) => e.pipe(N.onExit((e) => P.isSuccess(e) ? N.void : r.delete(w.id).pipe(N.andThen(r.releaseUsage(g, A)), N.ignore))))(r.insert(w).pipe(N.andThen(t.put(x, s, {
677
+ contentType: n.contentType,
678
+ public: _ === "public"
679
+ }).pipe(N.retry(T))))), yield* k(w), {
680
+ ...w,
681
+ outcome: "created"
682
+ };
683
+ }), U = (t) => N.suspend(() => {
684
+ if (!e.transcode) return N.succeed([]);
685
+ let n;
686
+ try {
687
+ n = e.transcode(t);
688
+ } catch {
689
+ return N.succeed([]);
690
+ }
691
+ return N.isEffect(n) ? n.pipe(N.catch(() => N.succeed([]))) : N.tryPromise({
692
+ try: () => Promise.resolve(n),
693
+ catch: () => []
694
+ }).pipe(N.catch(() => N.succeed([])));
695
+ }), W = (n) => N.gen(function* () {
696
+ if (!e.transcode || n.derivedFrom != null) return [];
697
+ let r = yield* t.get(n.key).pipe(N.retry(T)), i = yield* U({
698
+ bytes: r.bytes,
699
+ contentType: n.contentType,
700
+ ref: n
701
+ }), a = [];
702
+ for (let e of i) {
703
+ let t = yield* H({
704
+ bytes: e.bytes,
705
+ contentType: e.contentType,
706
+ tenantId: n.tenantId,
707
+ ownerId: n.ownerId,
708
+ visibility: n.visibility,
709
+ derivedFrom: n.id,
710
+ kind: e.kind,
711
+ ...e.label === void 0 ? {} : { caption: e.label }
712
+ });
713
+ a.push(t);
714
+ }
715
+ return a;
716
+ }), G = (e, t, n) => N.gen(function* () {
717
+ if (e.derivedFrom != null) {
718
+ let i = yield* r.getById(e.derivedFrom);
719
+ return i === null ? !1 : yield* G(i, t, n);
720
+ }
721
+ if (e.visibility === "public") return !0;
722
+ if (e.tenantId !== null && !k(e, t.tenantId ?? null)) return !1;
723
+ if (yield* g(e, t, {
724
+ ...d,
725
+ ...n?.password === void 0 ? {} : { password: n.password }
726
+ })) return !0;
727
+ let a = yield* y(t, d), o = yield* i.listByRef(e.id);
728
+ return _(o, t, a, n?.permission ?? "read", Date.now());
729
+ }), K = (e) => {
730
+ if (e.visibility === "public") {
731
+ let n = t.publicUrl?.(e.key);
732
+ if (n != null) return n;
733
+ }
734
+ return w(e.id);
735
+ };
736
+ return {
737
+ uploadTicketScope: () => N.gen(function* () {
738
+ let i = yield* r.catalogueId, a = yield* t.objectNamespace;
739
+ return yield* N.try({
740
+ try: () => n({
741
+ catalogueId: i,
742
+ objectNamespace: a,
743
+ storageInstance: e.storageInstance ?? "@voltro/plugin-storage"
744
+ }),
745
+ catch: (e) => h(e, "storage", !1)
746
+ });
747
+ }),
748
+ put: H,
749
+ get: (e, n) => F(e, n?.tenantId).pipe(N.flatMap((e) => t.get(e.key).pipe(N.retry(T), N.map((t) => ({
750
+ bytes: t.bytes,
751
+ ref: e
752
+ }))))),
753
+ getStream: (e, n) => F(e, n?.tenantId).pipe(N.flatMap((e) => m(t, e.key).pipe(N.retry(T), N.map((t) => ({
754
+ ref: e,
755
+ stream: t.stream
756
+ }))))),
757
+ getRange: (e, n, r) => F(e, r?.tenantId).pipe(N.flatMap((e) => {
758
+ let r = e.size, i = Math.max(0, Math.trunc(n.start));
759
+ if (r > 0 && i >= r) return N.fail(new c({
760
+ provider: t.name,
761
+ message: `range start ${i} past end ${r}`,
762
+ transient: !1,
763
+ status: 416
764
+ }));
765
+ let a = Math.min(Math.trunc(n.endInclusive), Math.max(0, r - 1));
766
+ return a < i ? N.fail(new c({
767
+ provider: t.name,
768
+ message: `empty range ${i}-${a}`,
769
+ transient: !1,
770
+ status: 416
771
+ })) : (t.getRange ? t.getRange(e.key, i, a).pipe(N.retry(T)) : t.get(e.key).pipe(N.retry(T), N.map((e) => e.bytes.subarray(i, a + 1)))).pipe(N.map((t) => ({
772
+ bytes: t,
773
+ ref: e,
774
+ totalSize: r
775
+ })));
776
+ })),
777
+ getUrl: (e, n) => F(e, n?.tenantId).pipe(N.flatMap((e) => e.visibility === "public" ? N.succeed(K(e)) : t.presigns ? t.getUrl(e.key, n?.expiresInSec ?? p) : N.succeed(w(e.id)))),
778
+ head: (e, t) => r.getById(e).pipe(N.flatMap((e) => e ? j(e, t?.tenantId).pipe(N.map((e) => e)) : N.succeed(null))),
779
+ delete: (e, n) => M(e, n?.tenantId, n?.claim).pipe(N.flatMap((a) => a ? N.void : F(e, n?.tenantId).pipe(N.flatMap((n) => i.deleteByRef(e).pipe(N.flatMap(() => r.delete(e)), N.flatMap((e) => e ? r.countByKey(n.bucket, n.key).pipe(N.flatMap((e) => e === 0 ? t.delete(n.key).pipe(N.retry(T)) : N.void), N.flatMap(() => r.releaseUsage(n.tenantId, {
780
+ bytes: n.size,
781
+ count: 1
782
+ }))) : N.void), N.asVoid))))),
783
+ signedUrl: (n, r) => F(n, r?.tenantId).pipe(N.flatMap((n) => {
784
+ if (n.visibility === "public") return N.succeed(K(n));
785
+ let i = r?.expiresInSec ?? p;
786
+ return t.presigns ? t.getUrl(n.key, i) : N.sync(() => `${w(n.id)}?t=${b(n.id, i, void 0, e.httpPath ?? "/_voltro/storage")}`);
787
+ })),
788
+ setVisibility: (e, n, i) => N.gen(function* () {
789
+ let a = yield* F(e, i?.tenantId);
790
+ if (a.visibility === n) return a;
791
+ let o = r.setVisibility;
792
+ if (o === void 0) return yield* N.fail(new l({
793
+ reason: "visibility-unsupported",
794
+ detail: "the ref store cannot change a stored object's visibility"
795
+ }));
796
+ if (n === "private" && t.publicUrl?.(a.key) != null) return yield* N.fail(new l({
797
+ reason: "visibility-unsupported",
798
+ detail: `objects are served from a public base (${t.name} cdnBaseUrl); a public object cannot be made private there`
799
+ }));
800
+ if (n === "private" && t.setObjectPublic !== void 0 && r.countPublicByKey === void 0) return yield* N.fail(new l({
801
+ reason: "visibility-unsupported",
802
+ detail: "the ref store cannot tell whether other refs keep these bytes public"
803
+ }));
804
+ let s = yield* o(a.id, n);
805
+ if (s === null) return yield* N.fail(new c({
806
+ provider: t.name,
807
+ message: `no ref '${e}'`,
808
+ transient: !1,
809
+ status: 404
810
+ }));
811
+ let u = a.derivedFrom == null ? yield* r.listByDerivedFrom(a.id) : [];
812
+ for (let e of u) e.visibility !== n && (yield* o(e.id, n));
813
+ if (t.setObjectPublic !== void 0) {
814
+ let e = r.countPublicByKey;
815
+ for (let r of [a, ...u]) {
816
+ let i = n === "public" || e !== void 0 && (yield* e(r.bucket, r.key)) > 0;
817
+ yield* t.setObjectPublic(r.key, i);
818
+ }
819
+ }
820
+ return s;
821
+ }),
822
+ mintUrl: (n, i, a) => N.gen(function* () {
823
+ let o = yield* r.getById(n).pipe(N.flatMap((e) => e ? N.succeed(e) : N.fail(new c({
824
+ provider: t.name,
825
+ message: `no ref '${n}'`,
826
+ transient: !1,
827
+ status: 404
828
+ }))));
829
+ if (o.visibility === "public" && o.derivedFrom == null) return K(o);
830
+ if (!(yield* G(o, i, a?.password === void 0 ? {} : { password: a.password }))) return yield* N.fail(new s({
831
+ refId: n,
832
+ reason: "access denied"
833
+ }));
834
+ let l = a?.expiresInSec ?? p;
835
+ if (t.presigns) return yield* t.getUrl(o.key, l);
836
+ let u = yield* N.sync(() => b(o.id, l, void 0, e.httpPath ?? "/_voltro/storage"));
837
+ return `${w(o.id)}?t=${u}`;
838
+ }),
839
+ mintUploadUrl: (e) => N.gen(function* () {
840
+ if (!t.getUploadUrl) return yield* N.fail(new c({
841
+ provider: t.name,
842
+ message: `provider '${t.name}' does not support presigned uploads`,
843
+ transient: !1,
844
+ status: 400
845
+ }));
846
+ let n = E(e.tenantId ?? null, "", yield* D(e.key));
847
+ return yield* t.getUploadUrl(n, e.expiresInSec ?? p, e.contentType);
848
+ }),
849
+ checkAccess: G,
850
+ grant: (e) => N.gen(function* () {
851
+ yield* F(e.refId);
852
+ let t = {
853
+ id: ne(),
854
+ refId: e.refId,
855
+ principalType: e.principalType,
856
+ principalId: e.principalId,
857
+ permission: e.permission ?? "read",
858
+ createdAt: /* @__PURE__ */ new Date(),
859
+ expiresAt: e.expiresAt ?? null,
860
+ createdBy: e.createdBy ?? null
861
+ };
862
+ return yield* i.insert(t), t;
863
+ }),
864
+ listRefs: (e) => N.suspend(() => {
865
+ let t = Math.min(500, Math.max(1, Math.trunc(e?.limit ?? 50))), n = Math.max(0, Math.trunc(e?.offset ?? 0)), i = {
866
+ tenantId: e && "tenantId" in e ? e.tenantId : void 0,
867
+ folder: e?.folder,
868
+ tags: e?.tags ?? [],
869
+ ownerId: e?.ownerId,
870
+ includeDerived: e?.includeDerived ?? !1,
871
+ limit: t + 1,
872
+ offset: n
873
+ };
874
+ return r.listRefs(i).pipe(N.map((e) => {
875
+ let r = e.length > t;
876
+ return {
877
+ refs: r ? e.slice(0, t) : e,
878
+ nextOffset: r ? n + t : null
879
+ };
880
+ }));
881
+ }),
882
+ revoke: (e) => i.delete(e),
883
+ getGrant: (e) => i.getById(e),
884
+ listGrants: (e) => i.listByRef(e),
885
+ usage: (e) => r.usageByTenant(e),
886
+ sweepOrphans: (e) => N.gen(function* () {
887
+ let n = e?.limit ?? 1e3, i = e?.dryRun ?? !1, a = yield* r.listRecent(n), o = [];
888
+ for (let e of a) if ((yield* t.head(e.key)) === null) {
889
+ if (!i) {
890
+ if (!(yield* r.delete(e.id))) continue;
891
+ yield* r.releaseUsage(e.tenantId, {
892
+ bytes: e.size,
893
+ count: 1
894
+ });
895
+ }
896
+ o.push(e.id);
897
+ }
898
+ return {
899
+ scanned: a.length,
900
+ removed: o
901
+ };
902
+ }),
903
+ ingestUrl: (t, n) => S(N.gen(function* () {
904
+ let r = yield* x(t, e.limits?.maxBytes, e.ingest);
905
+ return yield* H({
906
+ bytes: r.bytes,
907
+ contentType: n?.contentType ?? r.contentType,
908
+ ...n?.tenantId === void 0 ? {} : { tenantId: n.tenantId },
909
+ ...n?.operationId === void 0 ? {} : { operationId: n.operationId },
910
+ ...n?.ownerId === void 0 ? {} : { ownerId: n.ownerId },
911
+ ...n?.visibility === void 0 ? {} : { visibility: n.visibility },
912
+ ...n?.access === void 0 ? {} : { access: n.access },
913
+ ...n?.key === void 0 ? {} : { key: n.key },
914
+ ...n?.folder === void 0 ? {} : { folder: n.folder },
915
+ ...n?.tags === void 0 ? {} : { tags: n.tags },
916
+ ...n?.alt === void 0 ? {} : { alt: n.alt },
917
+ ...n?.caption === void 0 ? {} : { caption: n.caption }
918
+ });
919
+ }), n?.abortSignal),
920
+ mintPresignedUpload: (e) => N.gen(function* () {
921
+ if (!t.getUploadUrl) return yield* N.fail(new c({
922
+ provider: t.name,
923
+ message: `provider '${t.name}' does not support presigned uploads`,
924
+ transient: !1,
925
+ status: 400
926
+ }));
927
+ let n = e.expiresInSec ?? p, r = `_incoming/${A({
928
+ kind: "typeid",
929
+ prefix: "up"
930
+ }, a)}`, i = E(e.tenantId ?? null, "", r);
931
+ return {
932
+ uploadUrl: yield* t.getUploadUrl(i, n, e.contentType),
933
+ key: i,
934
+ expiresInSec: n
935
+ };
936
+ }),
937
+ finalizeUpload: (e) => t.get(e.key).pipe(N.retry(T), N.flatMap((t) => H({
938
+ bytes: t.bytes,
939
+ contentType: e.contentType,
940
+ ...e.tenantId === void 0 ? {} : { tenantId: e.tenantId },
941
+ ...e.ownerId === void 0 ? {} : { ownerId: e.ownerId },
942
+ ...e.visibility === void 0 ? {} : { visibility: e.visibility },
943
+ ...e.access === void 0 ? {} : { access: e.access },
944
+ ...e.folder === void 0 ? {} : { folder: e.folder },
945
+ ...e.tags === void 0 ? {} : { tags: e.tags },
946
+ ...e.alt === void 0 ? {} : { alt: e.alt },
947
+ ...e.caption === void 0 ? {} : { caption: e.caption }
948
+ })), N.ensuring(t.delete(e.key).pipe(N.retry(T), N.ignore))),
949
+ putResumableChunk: (e) => t.put(O(e.tenantId ?? null, e.uploadId, e.index), e.bytes, { contentType: "application/octet-stream" }).pipe(N.retry(T), N.asVoid),
950
+ resumableStatus: (e) => N.gen(function* () {
951
+ let n = 0, r = 0;
952
+ for (; n < 1e6;) {
953
+ let i = yield* t.head(O(e.tenantId ?? null, e.uploadId, n)).pipe(N.retry(T), N.catch(() => N.succeed(null)));
954
+ if (i === null) break;
955
+ r += i.size, n += 1;
956
+ }
957
+ return {
958
+ offset: r,
959
+ nextIndex: n
960
+ };
961
+ }),
962
+ finalizeResumable: (n) => N.gen(function* () {
963
+ let r = e.limits?.maxBytes ?? 2 ** 53 - 1;
964
+ if (!Number.isSafeInteger(r) || r < 0 || !Number.isSafeInteger(n.count) || n.count < 0) return yield* N.fail(new c({
965
+ provider: t.name,
966
+ message: "resumable count and limits.maxBytes must be non-negative safe integers",
967
+ transient: !1,
968
+ status: 400
969
+ }));
970
+ let i = (e) => O(n.tenantId ?? null, n.uploadId, e), a = N.gen(function* () {
971
+ for (let e = 0; e < n.count; e++) yield* t.delete(i(e)).pipe(N.retry(T), N.ignore);
972
+ }), o = () => new l({
973
+ reason: "too-large",
974
+ detail: `resumable upload exceeds ${r}-byte limit`
975
+ }), s = yield* N.gen(function* () {
976
+ let e = 0;
977
+ for (let a = 0; a < n.count; a++) {
978
+ let n = yield* t.head(i(a)).pipe(N.retry(T));
979
+ if (n === null) return yield* N.fail(new c({
980
+ provider: t.name,
981
+ message: `no resumable chunk at '${i(a)}'`,
982
+ transient: !1,
983
+ status: 404
984
+ }));
985
+ if (!Number.isSafeInteger(n.size) || n.size < 0) return yield* N.fail(new c({
986
+ provider: t.name,
987
+ message: "resumable chunk metadata has an invalid size",
988
+ transient: !1
989
+ }));
990
+ if (n.size > r - e) return yield* N.fail(o());
991
+ e += n.size;
992
+ }
993
+ let a = /* @__PURE__ */ new Uint8Array(), s = 0;
994
+ for (let e = 0; e < n.count; e++) {
995
+ let n = yield* m(t, i(e)).pipe(N.retry(T));
996
+ yield* L.runForEach(n.stream, (e) => N.gen(function* () {
997
+ if (e.byteLength > r - s) return yield* N.fail(o());
998
+ let t = s + e.byteLength;
999
+ if (t > a.byteLength) {
1000
+ let e = new Uint8Array(Math.min(r, Math.max(65536, a.byteLength * 2, t)));
1001
+ e.set(a.subarray(0, s)), a = e;
1002
+ }
1003
+ a.set(e, s), s = t;
1004
+ }));
1005
+ }
1006
+ return a.subarray(0, s);
1007
+ }).pipe(N.tapError((e) => e._tag === "StorageRejected" ? a : N.void));
1008
+ return yield* H({
1009
+ bytes: s,
1010
+ contentType: n.contentType,
1011
+ ...n.tenantId === void 0 ? {} : { tenantId: n.tenantId },
1012
+ ...n.ownerId === void 0 ? {} : { ownerId: n.ownerId },
1013
+ ...n.visibility === void 0 ? {} : { visibility: n.visibility },
1014
+ ...n.access === void 0 ? {} : { access: n.access },
1015
+ ...n.folder === void 0 ? {} : { folder: n.folder },
1016
+ ...n.tags === void 0 ? {} : { tags: n.tags },
1017
+ ...n.alt === void 0 ? {} : { alt: n.alt },
1018
+ ...n.caption === void 0 ? {} : { caption: n.caption }
1019
+ }).pipe(N.ensuring(a));
1020
+ }),
1021
+ transcode: (e, t) => F(e, t?.tenantId).pipe(N.flatMap((e) => W(e))),
1022
+ renditions: (e, t) => F(e, t?.tenantId).pipe(N.flatMap(() => r.listByDerivedFrom(e))),
1023
+ beginMultipartUpload: (e) => N.gen(function* () {
1024
+ if (!t.createMultipartUpload || !t.presignUploadPart || !t.completeMultipartUpload) return yield* N.fail(new c({
1025
+ provider: t.name,
1026
+ message: `provider '${t.name}' does not support multipart uploads`,
1027
+ transient: !1,
1028
+ status: 400
1029
+ }));
1030
+ let n = E(e.tenantId ?? null, "", `multipart/${A({
1031
+ kind: "typeid",
1032
+ prefix: "mp"
1033
+ }, a)}`);
1034
+ return {
1035
+ uploadId: (yield* t.createMultipartUpload(n, e.contentType, { public: (e.visibility ?? "private") === "public" })).uploadId,
1036
+ key: n
1037
+ };
1038
+ }),
1039
+ signMultipartPart: (e) => N.suspend(() => t.presignUploadPart ? t.presignUploadPart(e.key, e.uploadId, e.partNumber, e.expiresInSec ?? p) : N.fail(new c({
1040
+ provider: t.name,
1041
+ message: "provider does not support multipart uploads",
1042
+ transient: !1,
1043
+ status: 400
1044
+ }))),
1045
+ completeMultipart: (n) => N.gen(function* () {
1046
+ if (!t.completeMultipartUpload) return yield* N.fail(new c({
1047
+ provider: t.name,
1048
+ message: "provider does not support multipart uploads",
1049
+ transient: !1,
1050
+ status: 400
1051
+ }));
1052
+ let i = yield* t.completeMultipartUpload(n.key, n.uploadId, n.parts), a = yield* t.head(n.key).pipe(N.retry(T)), s = a?.size ?? 0, u = (i.etag ?? a?.etag ?? "").replace(/"/g, ""), d = n.tenantId ?? null, f = {
1053
+ bytes: s,
1054
+ count: 1
1055
+ };
1056
+ if (!(yield* r.consumeUsage(d, f, e.quota)).allowed) return yield* t.delete(n.key).pipe(N.retry(T), N.ignore), yield* N.fail(new l({
1057
+ reason: "quota-exceeded",
1058
+ detail: `multipart upload of ${s} bytes exceeds tenant quota`
1059
+ }));
1060
+ let p = {
1061
+ id: Q(),
1062
+ tenantId: n.tenantId ?? null,
1063
+ ownerId: n.ownerId ?? null,
1064
+ bucket: o,
1065
+ key: n.key,
1066
+ contentType: n.contentType,
1067
+ size: s,
1068
+ checksum: u,
1069
+ visibility: n.visibility ?? "private",
1070
+ accessPolicy: n.access ?? null,
1071
+ passwordHash: null,
1072
+ createdAt: /* @__PURE__ */ new Date(),
1073
+ ...n.folder === void 0 ? {} : { folder: n.folder },
1074
+ ...n.tags === void 0 ? {} : { tags: n.tags },
1075
+ ...n.alt === void 0 ? {} : { alt: n.alt },
1076
+ ...n.caption === void 0 ? {} : { caption: n.caption }
1077
+ };
1078
+ return yield* r.insert(p).pipe(N.onExit((e) => P.isSuccess(e) ? N.void : r.releaseUsage(d, f).pipe(N.ignore))), p;
1079
+ }),
1080
+ abortMultipart: (e) => N.suspend(() => t.abortMultipartUpload ? t.abortMultipartUpload(e.key, e.uploadId).pipe(N.retry(T)) : N.void)
1081
+ };
1082
+ }, re = (e) => F.succeed(d, $(e));
1083
+ //#endregion
1084
+ export { $ as buildStorageService, Z as dataStoreGrantStore, J as dataStoreRefStore, Y as memoryGrantStore, U as memoryRefStore, V as refMatchesListQuery, re as storageServiceLayer, G as toRef };