@voltro/plugin-storage 0.85.0 → 0.87.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. package/CHANGELOG.md +5987 -0
  2. package/README.md +77 -0
  3. package/THIRD-PARTY-NOTICES.md +860 -249
  4. package/dist/access.js +47 -0
  5. package/dist/assetRef.js +13 -0
  6. package/dist/avatar.js +39 -0
  7. package/dist/byteSecurity.d.ts +3 -0
  8. package/dist/byteSecurity.js +7 -0
  9. package/dist/connection.js +99 -0
  10. package/dist/constraints.js +93 -0
  11. package/dist/custody.js +132 -0
  12. package/dist/derivatives.js +30 -0
  13. package/dist/env.js +162 -0
  14. package/dist/grant.js +132 -0
  15. package/dist/index.d.ts +525 -203
  16. package/dist/index.js +765 -3196
  17. package/dist/ingest.js +87 -0
  18. package/dist/ingestPolicy.js +1 -0
  19. package/dist/metadataError.js +19 -0
  20. package/dist/objectAbandon.js +16 -0
  21. package/dist/objectLifecycle.js +243 -0
  22. package/dist/objectMetadata.js +308 -0
  23. package/dist/objectWriter.js +87 -0
  24. package/dist/pathDurability.js +16 -0
  25. package/dist/physicalReferences.js +54 -0
  26. package/dist/providers.js +638 -0
  27. package/dist/referenceCatalogue.js +31 -0
  28. package/dist/renditionProof.js +82 -0
  29. package/dist/retainedCapture.js +391 -0
  30. package/dist/retainedObjects.js +190 -0
  31. package/dist/rpc.d.ts +3 -15
  32. package/dist/rpc.js +3 -1
  33. package/dist/scanners.js +46 -0
  34. package/dist/server.d.ts +153 -0
  35. package/dist/server.js +4 -0
  36. package/dist/service.js +1418 -0
  37. package/dist/sourceIdentity.js +14 -0
  38. package/dist/sourcePin.js +35 -0
  39. package/dist/storageNamespaces.js +80 -0
  40. package/dist/storageNumbers.js +13 -0
  41. package/dist/storageObjectNamespaces.js +243 -0
  42. package/dist/storageReferenceInstances.js +52 -0
  43. package/dist/storageRequest.js +10 -0
  44. package/dist/storageRouting.js +46 -0
  45. package/dist/streamBridge.js +33 -0
  46. package/dist/table.js +54 -0
  47. package/dist/transcodeVideo.js +91 -0
  48. package/dist/transform.js +94 -0
  49. package/dist/transformCache.js +31 -0
  50. package/dist/types.d.ts +116 -134
  51. package/dist/types.js +14 -14
  52. package/package.json +17 -6
@@ -0,0 +1,1418 @@
1
+ import { requireStorageReferenceScope as e, storageObjectNamespace as t, storageReferenceScopeFor as n, storageUploadTicketScope as r } from "./storageNamespaces.js";
2
+ import { storageReferenceCatalogueId as i } from "./referenceCatalogue.js";
3
+ import { STORAGE_GRANTS_TABLE as a, STORAGE_REFS_TABLE as o, STORAGE_USAGE_TABLE as s } from "./table.js";
4
+ import "./storageReferenceInstances.js";
5
+ import { StorageAccessDenied as c, StorageError as l, StorageRejected as u, StorageScanRejected as d, StorageService as f, storageRefAddress as p } from "./types.js";
6
+ import { storageInteger as m, storageIntegerSum as h } from "./storageNumbers.js";
7
+ import { getObjectStream as g } from "./streamBridge.js";
8
+ import { storageMetadataError as _ } from "./metadataError.js";
9
+ import { evaluatePolicy as v, grantsAllow as y, hashPassword as ee, resolveSubjectGroups as b } from "./access.js";
10
+ import { declareStorageSigningLifetime as x, signGrant as S } from "./grant.js";
11
+ import { checkLimits as te } from "./constraints.js";
12
+ import { extractImageMetadata as ne } from "./derivatives.js";
13
+ import { assertRenditionOutput as re, makeRenditionProof as C, ownRenditionRef as w, readRenditionProof as T } from "./renditionProof.js";
14
+ import { fetchIngestBody as E, withIngestAbort as D } from "./ingest.js";
15
+ import { makeStorageObjectWriter as ie } from "./objectWriter.js";
16
+ import { protectStorageReferences as ae } from "./physicalReferences.js";
17
+ import { StorageAddress as O, storageKeyProblem as k } from "@voltro/kv/storage";
18
+ import { Effect as A, Exit as oe, Layer as j, Schedule as M, Schema as N, Stream as se } from "effect";
19
+ import { randomUUID as P } from "node:crypto";
20
+ import { and as F, authoredError as I, column as L, contains as R, eq as z, generateId as B, isNull as V, or as H } from "@voltro/database";
21
+ //#region src/service.ts
22
+ var U = async (e) => {
23
+ let { createHash: t } = await import("node:crypto");
24
+ return t("sha256").update(e).digest("hex");
25
+ }, ce = (e, t, n) => `${e?.replace(/\/+$/, "") ?? ""}${n}/${t}`, W = (e) => {
26
+ let t = /* @__PURE__ */ new Map(), n = {
27
+ public: 0,
28
+ private: 0
29
+ };
30
+ for (let r of e) {
31
+ let e = r.tenantId ?? "(global)", i = t.get(e) ?? {
32
+ count: 0,
33
+ bytes: 0
34
+ };
35
+ i.count = h(i.count, r.count, "ref count"), i.bytes = h(i.bytes, r.bytes, "usage bytes"), t.set(e, i), r.visibility === "public" ? n.public = h(n.public, r.count, "public ref count") : n.private = h(n.private, r.count, "private ref count");
36
+ }
37
+ return {
38
+ byTenant: Object.fromEntries(t),
39
+ visibility: n
40
+ };
41
+ }, G = (e, t) => {
42
+ if (t.search && ![
43
+ e.id,
44
+ e.key,
45
+ e.contentType,
46
+ e.ownerId,
47
+ e.tenantId
48
+ ].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;
49
+ if (t.folder !== void 0) {
50
+ let n = t.folder.replace(/\/+$/, ""), r = (e.folder ?? "").replace(/\/+$/, "");
51
+ if (r !== n && !r.startsWith(`${n}/`)) return !1;
52
+ }
53
+ if (t.tags.length > 0) {
54
+ let n = e.tags ?? [];
55
+ if (!t.tags.every((e) => n.includes(e))) return !1;
56
+ }
57
+ return !0;
58
+ }, K = (e) => e === null ? "global" : e === "global" ? "%67lobal" : e.startsWith("%") ? `%${e}` : e, q = () => {
59
+ let e = /* @__PURE__ */ new Map(), n = /* @__PURE__ */ new Map();
60
+ return {
61
+ listObjectReferences: () => A.sync(() => [...e.values()].map((e) => ({
62
+ bucket: e.bucket,
63
+ tenantId: e.tenantId,
64
+ key: e.key,
65
+ visibility: e.visibility
66
+ }))),
67
+ catalogueId: A.succeed(t(["memory-reference-catalogue", P()])),
68
+ statistics: () => A.try({
69
+ try: () => W((function* () {
70
+ for (let t of e.values()) yield {
71
+ tenantId: t.tenantId,
72
+ visibility: t.visibility,
73
+ count: 1,
74
+ bytes: t.size
75
+ };
76
+ })()),
77
+ catch: (e) => _(e, "refstore")
78
+ }),
79
+ insert: (t) => A.try({
80
+ try: () => {
81
+ m(t.size, "ref size"), e.set(t.id, w(t));
82
+ },
83
+ catch: (e) => _(e, "refstore")
84
+ }),
85
+ getById: (t) => A.sync(() => {
86
+ let n = e.get(t);
87
+ return n === void 0 ? null : w(n);
88
+ }),
89
+ delete: (t) => A.sync(() => e.delete(t)),
90
+ listRecent: (t) => A.sync(() => [...e.values()].sort((e, t) => t.createdAt.getTime() - e.createdAt.getTime() || t.id.localeCompare(e.id)).slice(0, t).map(w)),
91
+ countByAddress: (t) => A.sync(() => [...e.values()].filter((e) => e.bucket === t.destination && e.tenantId === t.tenantId && e.key === t.key).length),
92
+ countPublicByAddress: (t) => A.sync(() => [...e.values()].filter((e) => e.bucket === t.destination && e.tenantId === t.tenantId && e.key === t.key && e.visibility === "public").length),
93
+ setVisibility: (t, n) => A.sync(() => {
94
+ let r = e.get(t);
95
+ if (r === void 0) return null;
96
+ let i = {
97
+ ...r,
98
+ visibility: n
99
+ };
100
+ return e.set(t, i), w(i);
101
+ }),
102
+ usageByTenant: (t) => A.try({
103
+ try: () => {
104
+ let n = 0, r = 0;
105
+ for (let i of e.values()) (i.tenantId ?? null) === (t ?? null) && (n = h(n, i.size, "usage bytes"), r++);
106
+ return {
107
+ bytes: n,
108
+ count: r
109
+ };
110
+ },
111
+ catch: (e) => _(e, "refstore")
112
+ }),
113
+ consumeUsage: (e, t, r) => A.try({
114
+ try: () => {
115
+ let i = K(e), a = n.get(i) ?? {
116
+ bytes: 0,
117
+ count: 0
118
+ };
119
+ m(t.bytes, "usage byte delta"), m(t.count, "usage count delta");
120
+ 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);
121
+ return o && n.set(i, {
122
+ bytes: a.bytes + t.bytes,
123
+ count: a.count + t.count
124
+ }), {
125
+ allowed: o,
126
+ bytes: a.bytes,
127
+ count: a.count
128
+ };
129
+ },
130
+ catch: (e) => _(e, "refstore")
131
+ }),
132
+ releaseUsage: (e, t) => A.try({
133
+ try: () => {
134
+ let r = K(e), i = n.get(r);
135
+ m(t.bytes, "usage byte delta"), m(t.count, "usage count delta"), i && n.set(r, {
136
+ bytes: Math.max(0, i.bytes - t.bytes),
137
+ count: Math.max(0, i.count - t.count)
138
+ });
139
+ },
140
+ catch: (e) => _(e, "refstore")
141
+ }),
142
+ listByDerivedFrom: (t) => A.sync(() => [...e.values()].filter((e) => (e.derivedFrom ?? null) === t).map(w)),
143
+ listRefs: (t) => A.sync(() => [...e.values()].filter((e) => G(e, t)).sort((e, t) => t.createdAt.getTime() - e.createdAt.getTime() || t.id.localeCompare(e.id)).slice(t.offset, t.offset + t.limit).map(w))
144
+ };
145
+ }, le = (e) => Array.isArray(e) && e.every((e) => typeof e == "string") ? e : null, J = (e) => {
146
+ let t = {
147
+ id: String(e.id),
148
+ tenantId: e.tenantId ?? null,
149
+ ownerId: e.ownerId ?? null,
150
+ bucket: String(e.bucket),
151
+ key: String(e.key),
152
+ contentType: String(e.contentType),
153
+ size: m(e.size, "ref size"),
154
+ checksum: String(e.checksum),
155
+ visibility: e.visibility === "public" ? "public" : "private",
156
+ accessPolicy: e.accessPolicy ?? null,
157
+ passwordHash: e.passwordHash ?? null,
158
+ createdAt: e.createdAt instanceof Date ? e.createdAt : new Date(String(e.createdAt)),
159
+ width: e.width ?? null,
160
+ height: e.height ?? null,
161
+ duration: e.duration ?? null,
162
+ placeholder: e.placeholder ?? null,
163
+ folder: e.folder ?? null,
164
+ tags: le(e.tags),
165
+ alt: e.alt ?? null,
166
+ caption: e.caption ?? null,
167
+ derivedFrom: e.derivedFrom ?? null,
168
+ kind: e.kind ?? null,
169
+ ...e.renditionProof == null ? {} : { renditionProof: T(e.renditionProof) }
170
+ };
171
+ return t.renditionProof !== void 0 && t.renditionProof !== null && re(t.renditionProof, t), t;
172
+ }, Y = (e) => A.tryPromise({
173
+ try: e,
174
+ catch: (e) => _(e, "refstore", !0)
175
+ }), X = async (e, t) => (await e.query({
176
+ table: "_voltro_storage_usage",
177
+ predicate: {
178
+ column: "tenantId",
179
+ op: "eq",
180
+ value: t
181
+ },
182
+ order: [],
183
+ take: 1,
184
+ skip: void 0,
185
+ projection: void 0
186
+ }))[0] ?? null, Z = (r, a) => {
187
+ let c = Object.freeze({ ...a }), l = "resolveNamespace" in c;
188
+ if (!c.storageInstance.trim()) throw I("Storage requires an explicit plugin instance");
189
+ l || e(c);
190
+ let u = l ? z("storageInstance", c.storageInstance) : F(z("storageInstance", c.storageInstance), z("objectNamespace", c.objectNamespace)), d = async (e) => {
191
+ if (e.storageInstance !== c.storageInstance) return !1;
192
+ let t = N.decodeUnknownSync(O)({
193
+ destination: e.bucket,
194
+ tenantId: e.tenantId,
195
+ key: e.key
196
+ }), r = await A.runPromise(n(c, t));
197
+ return e.objectNamespace === r.objectNamespace;
198
+ }, f = async function* (e) {
199
+ let t = e.take, n = e.skip ?? 0;
200
+ if (!l) {
201
+ yield* await r.query(e);
202
+ return;
203
+ }
204
+ let i = 0;
205
+ for (let a = 0;; a += 256) {
206
+ let o = await r.query({
207
+ ...e,
208
+ take: 256,
209
+ skip: a,
210
+ projection: void 0
211
+ });
212
+ for (let e of o) if (await d(e) && !(i++ < n)) {
213
+ if (t !== void 0 && i > n + t) return;
214
+ yield e;
215
+ }
216
+ if (o.length < 256) return;
217
+ }
218
+ }, g = async (e) => {
219
+ let t = [];
220
+ for await (let n of f(e)) t.push(n);
221
+ return t;
222
+ };
223
+ return {
224
+ catalogueId: Y(() => "resolveNamespace" in c ? i(r).then((e) => t([
225
+ "reference-view",
226
+ e,
227
+ c.storageInstance
228
+ ])) : i(r, c)),
229
+ hasObjectReservation: (e, t) => Y(async () => (await r.query({
230
+ table: "_voltro_storage_object_heads",
231
+ predicate: F(z("objectNamespace", e), z("key", t)),
232
+ order: [],
233
+ take: 1,
234
+ skip: void 0,
235
+ projection: ["id"]
236
+ })).length > 0),
237
+ listObjectReferences: () => Y(async () => (await r.query({
238
+ table: o,
239
+ predicate: void 0,
240
+ order: [],
241
+ take: void 0,
242
+ skip: void 0,
243
+ projection: [
244
+ "bucket",
245
+ "tenantId",
246
+ "key",
247
+ "visibility",
248
+ "storageInstance",
249
+ "objectNamespace"
250
+ ]
251
+ })).map((t) => {
252
+ let n = N.decodeUnknownSync(O)({
253
+ destination: t.bucket,
254
+ tenantId: t.tenantId,
255
+ key: t.key
256
+ }), r = N.decodeUnknownSync(N.Struct({
257
+ storageInstance: N.String,
258
+ objectNamespace: N.String
259
+ }))(t);
260
+ return e(r), {
261
+ ...r,
262
+ bucket: n.destination,
263
+ tenantId: n.tenantId,
264
+ key: n.key,
265
+ visibility: N.decodeUnknownSync(N.Literals(["public", "private"]))(t.visibility)
266
+ };
267
+ })),
268
+ statistics: () => Y(async () => {
269
+ if (l) {
270
+ let e = /* @__PURE__ */ new Map();
271
+ for await (let t of f({
272
+ table: o,
273
+ predicate: u,
274
+ order: [{
275
+ column: "id",
276
+ direction: "asc"
277
+ }],
278
+ take: void 0,
279
+ skip: void 0,
280
+ projection: void 0
281
+ })) {
282
+ let n = J(t), r = JSON.stringify([n.tenantId, n.visibility]), i = e.get(r) ?? {
283
+ tenantId: n.tenantId,
284
+ visibility: n.visibility,
285
+ count: 0,
286
+ bytes: 0
287
+ };
288
+ i.count = h(i.count, 1, "ref count"), i.bytes = h(i.bytes, n.size, "usage bytes"), e.set(r, i);
289
+ }
290
+ return W(e.values());
291
+ }
292
+ return W((await r.query({
293
+ table: o,
294
+ predicate: u,
295
+ order: [],
296
+ take: void 0,
297
+ skip: void 0,
298
+ projection: void 0,
299
+ groupBy: ["tenantId", "visibility"],
300
+ aggregations: [
301
+ L("tenantId"),
302
+ L("visibility"),
303
+ {
304
+ op: "count",
305
+ alias: "count"
306
+ },
307
+ {
308
+ op: "sum",
309
+ column: "size",
310
+ alias: "bytes"
311
+ }
312
+ ]
313
+ })).map((e) => ({
314
+ tenantId: e.tenantId == null ? null : String(e.tenantId),
315
+ visibility: String(e.visibility),
316
+ count: m(e.count, "ref count"),
317
+ bytes: m(e.bytes ?? 0, "usage bytes")
318
+ })));
319
+ }),
320
+ insert: (e) => n(c, p(e)).pipe(A.flatMap((t) => Y(() => r.insert(o, {
321
+ ...w(e),
322
+ ...t,
323
+ size: String(m(e.size, "ref size"))
324
+ })))),
325
+ getById: (e) => Y(async () => {
326
+ let t = await r.query({
327
+ table: o,
328
+ predicate: F(u, z("id", e)),
329
+ order: [],
330
+ take: 1,
331
+ skip: void 0,
332
+ projection: void 0
333
+ });
334
+ return t[0] && await d(t[0]) ? J(t[0]) : null;
335
+ }),
336
+ delete: (e) => Y(l ? () => r.transactional(async (t) => {
337
+ let n = await t.query({
338
+ table: o,
339
+ predicate: F(u, z("id", e)),
340
+ lock: "update",
341
+ order: [],
342
+ take: 1,
343
+ skip: void 0,
344
+ projection: void 0
345
+ });
346
+ return !n[0] || !await d(n[0]) ? !1 : await t.deleteMany(o, { where: F(u, z("objectNamespace", n[0].objectNamespace), z("id", e)) }) > 0;
347
+ }) : async () => await r.deleteMany(o, { where: F(u, z("id", e)) }) > 0),
348
+ listRecent: (e) => Y(async () => (await g({
349
+ table: o,
350
+ predicate: u,
351
+ order: [{
352
+ column: "createdAt",
353
+ direction: "desc"
354
+ }, {
355
+ column: "id",
356
+ direction: "desc"
357
+ }],
358
+ take: e,
359
+ skip: void 0,
360
+ projection: void 0
361
+ })).map(J)),
362
+ countByAddress: (e) => n(c, e).pipe(A.flatMap((t) => Y(async () => {
363
+ let n = await r.query({
364
+ table: o,
365
+ predicate: { and: [
366
+ u,
367
+ z("objectNamespace", t.objectNamespace),
368
+ {
369
+ column: "bucket",
370
+ op: "eq",
371
+ value: e.destination
372
+ },
373
+ {
374
+ column: "tenantId",
375
+ op: "eq",
376
+ value: e.tenantId
377
+ },
378
+ {
379
+ column: "key",
380
+ op: "eq",
381
+ value: e.key
382
+ }
383
+ ] },
384
+ order: [],
385
+ take: void 0,
386
+ skip: void 0,
387
+ projection: void 0,
388
+ aggregations: [{
389
+ op: "count",
390
+ alias: "count"
391
+ }]
392
+ });
393
+ return m(n[0]?.count ?? 0, "ref count");
394
+ }))),
395
+ countPublicByAddress: (e) => n(c, e).pipe(A.flatMap((t) => Y(async () => {
396
+ let n = await r.query({
397
+ table: o,
398
+ predicate: { and: [
399
+ u,
400
+ z("objectNamespace", t.objectNamespace),
401
+ {
402
+ column: "bucket",
403
+ op: "eq",
404
+ value: e.destination
405
+ },
406
+ {
407
+ column: "tenantId",
408
+ op: "eq",
409
+ value: e.tenantId
410
+ },
411
+ {
412
+ column: "key",
413
+ op: "eq",
414
+ value: e.key
415
+ },
416
+ {
417
+ column: "visibility",
418
+ op: "eq",
419
+ value: "public"
420
+ }
421
+ ] },
422
+ order: [],
423
+ take: void 0,
424
+ skip: void 0,
425
+ projection: void 0,
426
+ aggregations: [{
427
+ op: "count",
428
+ alias: "count"
429
+ }]
430
+ });
431
+ return m(n[0]?.count ?? 0, "ref count");
432
+ }))),
433
+ setVisibility: (e, t) => Y(() => r.transactional(async (n) => {
434
+ let r = await n.query({
435
+ table: o,
436
+ predicate: F(u, z("id", e)),
437
+ lock: "update",
438
+ order: [],
439
+ take: 1,
440
+ skip: void 0,
441
+ projection: void 0
442
+ });
443
+ if (!r[0] || !await d(r[0])) return null;
444
+ let i = await n.update(o, e, { visibility: t });
445
+ return i ? J(i) : null;
446
+ })),
447
+ usageByTenant: (e) => Y(async () => {
448
+ let t = await r.query({
449
+ table: o,
450
+ predicate: e === null ? V("tenantId") : z("tenantId", e),
451
+ order: [],
452
+ take: void 0,
453
+ skip: void 0,
454
+ projection: void 0,
455
+ aggregations: [
456
+ {
457
+ op: "count",
458
+ alias: "count"
459
+ },
460
+ {
461
+ op: "sum",
462
+ column: "size",
463
+ alias: "bytes"
464
+ },
465
+ {
466
+ op: "min",
467
+ column: "size",
468
+ alias: "minSize"
469
+ },
470
+ {
471
+ op: "max",
472
+ column: "size",
473
+ alias: "maxSize"
474
+ }
475
+ ]
476
+ });
477
+ return m(t[0]?.count ?? 0, "ref count") > 0 && (m(t[0]?.minSize, "ref size"), m(t[0]?.maxSize, "ref size")), {
478
+ bytes: m(t[0]?.bytes ?? 0, "usage bytes"),
479
+ count: m(t[0]?.count ?? 0, "ref count")
480
+ };
481
+ }),
482
+ consumeUsage: (e, t, n) => Y(async () => {
483
+ let i = K(e);
484
+ m(t.bytes, "usage byte delta"), m(t.count, "usage count delta");
485
+ for (let e = 0; e < 32; e++) {
486
+ e > 0 && await new Promise((t) => setTimeout(t, e));
487
+ let a = await X(r, i), o = a ? m(a.bytes, "usage bytes") : 0, c = a ? m(a.count, "ref count") : 0;
488
+ if (!(Number.isSafeInteger(o + t.bytes) && Number.isSafeInteger(c + t.count) && (n?.maxBytes === void 0 || o + t.bytes <= n.maxBytes) && (n?.maxCount === void 0 || c + t.count <= n.maxCount))) return {
489
+ allowed: !1,
490
+ bytes: o,
491
+ count: c
492
+ };
493
+ if (a) {
494
+ if (await r.updateMany("_voltro_storage_usage", {
495
+ bytes: String(o + t.bytes),
496
+ count: String(c + t.count),
497
+ updatedAt: /* @__PURE__ */ new Date()
498
+ }, { where: F(z("id", String(a.id)), z("bytes", a.bytes), z("count", a.count)) }) === 1) return {
499
+ allowed: !0,
500
+ bytes: o,
501
+ count: c
502
+ };
503
+ } else {
504
+ let e = B({
505
+ kind: "typeid",
506
+ prefix: "susage"
507
+ }, s), n = await r.insertIgnore(s, {
508
+ id: e,
509
+ tenantId: i,
510
+ bytes: String(t.bytes),
511
+ count: String(t.count),
512
+ updatedAt: /* @__PURE__ */ new Date()
513
+ }, { conflictColumns: ["tenantId"] });
514
+ if (String(n.id) === e) return {
515
+ allowed: !0,
516
+ bytes: 0,
517
+ count: 0
518
+ };
519
+ }
520
+ }
521
+ throw I("Storage quota reservation contended after 32 attempts; retry");
522
+ }),
523
+ releaseUsage: (e, t) => Y(async () => {
524
+ let n = K(e);
525
+ m(t.bytes, "usage byte delta"), m(t.count, "usage count delta");
526
+ for (let e = 0; e < 32; e++) {
527
+ e > 0 && await new Promise((t) => setTimeout(t, e));
528
+ let i = await X(r, n);
529
+ if (!i) return;
530
+ let a = m(i.bytes, "usage bytes"), o = m(i.count, "ref count");
531
+ if (await r.updateMany("_voltro_storage_usage", {
532
+ bytes: String(Math.max(0, a - t.bytes)),
533
+ count: String(Math.max(0, o - t.count)),
534
+ updatedAt: /* @__PURE__ */ new Date()
535
+ }, { where: F(z("id", String(i.id)), z("bytes", i.bytes), z("count", i.count)) }) === 1) return;
536
+ }
537
+ throw I("Storage quota release contended after 32 attempts; retry");
538
+ }),
539
+ listByDerivedFrom: (e) => Y(async () => (await g({
540
+ table: o,
541
+ predicate: F(u, z("derivedFrom", e)),
542
+ order: [{
543
+ column: "createdAt",
544
+ direction: "asc"
545
+ }, {
546
+ column: "id",
547
+ direction: "asc"
548
+ }],
549
+ take: void 0,
550
+ skip: void 0,
551
+ projection: void 0
552
+ })).map(J)),
553
+ listRefs: (e) => Y(async () => {
554
+ let t = [u];
555
+ e.tenantId !== void 0 && t.push(e.tenantId === null ? V("tenantId") : z("tenantId", e.tenantId)), e.ownerId !== void 0 && t.push(z("ownerId", e.ownerId)), e.search && t.push(H(...[
556
+ "id",
557
+ "key",
558
+ "contentType",
559
+ "ownerId",
560
+ "tenantId"
561
+ ].map((t) => R(t, e.search)))), e.includeDerived || t.push(V("derivedFrom"));
562
+ let n = e.folder === void 0 && e.tags.length === 0, r = t.length ? F(...t) : void 0, i = await g({
563
+ table: o,
564
+ predicate: r,
565
+ order: [{
566
+ column: "createdAt",
567
+ direction: "desc"
568
+ }, {
569
+ column: "id",
570
+ direction: "desc"
571
+ }],
572
+ take: n ? e.limit : void 0,
573
+ skip: n ? e.offset : void 0,
574
+ projection: void 0
575
+ });
576
+ return n ? i.map(J) : i.map(J).filter((t) => G(t, e)).slice(e.offset, e.offset + e.limit);
577
+ })
578
+ };
579
+ }, Q = () => {
580
+ let e = /* @__PURE__ */ new Map();
581
+ return {
582
+ insert: (t) => A.sync(() => {
583
+ e.set(t.id, t);
584
+ }),
585
+ delete: (t) => A.sync(() => {
586
+ e.delete(t);
587
+ }),
588
+ getById: (t) => A.sync(() => e.get(t) ?? null),
589
+ listByRef: (t) => A.sync(() => [...e.values()].filter((e) => e.refId === t)),
590
+ deleteByRef: (t) => A.sync(() => {
591
+ for (let [n, r] of e) r.refId === t && e.delete(n);
592
+ })
593
+ };
594
+ }, $ = (e) => ({
595
+ id: String(e.id),
596
+ refId: String(e.refId),
597
+ principalType: e.principalType,
598
+ principalId: String(e.principalId),
599
+ permission: e.permission === "write" ? "write" : "read",
600
+ createdAt: e.createdAt instanceof Date ? e.createdAt : new Date(String(e.createdAt)),
601
+ expiresAt: e.expiresAt ? e.expiresAt instanceof Date ? e.expiresAt : new Date(String(e.expiresAt)) : null,
602
+ createdBy: e.createdBy ?? null
603
+ }), ue = (t, n) => {
604
+ let r = Object.freeze({ ...n });
605
+ return e(r), {
606
+ insert: (e) => Y(() => t.insert(a, {
607
+ ...e,
608
+ ...r
609
+ })),
610
+ delete: (e) => Y(() => t.deleteMany(a, { where: F(F(z("storageInstance", r.storageInstance), z("objectNamespace", r.objectNamespace)), z("id", e)) })).pipe(A.asVoid),
611
+ getById: (e) => Y(async () => {
612
+ let n = (await t.query({
613
+ table: a,
614
+ predicate: F(F(z("storageInstance", r.storageInstance), z("objectNamespace", r.objectNamespace)), z("id", e)),
615
+ order: [],
616
+ take: 1,
617
+ skip: void 0,
618
+ projection: void 0
619
+ }))[0];
620
+ return n ? $(n) : null;
621
+ }),
622
+ listByRef: (e) => Y(async () => (await t.query({
623
+ table: a,
624
+ predicate: F(F(z("storageInstance", r.storageInstance), z("objectNamespace", r.objectNamespace)), z("refId", e)),
625
+ order: [{
626
+ column: "createdAt",
627
+ direction: "desc"
628
+ }],
629
+ take: void 0,
630
+ skip: void 0,
631
+ projection: void 0
632
+ })).map($)),
633
+ deleteByRef: (e) => Y(async () => {
634
+ let n = await t.query({
635
+ table: a,
636
+ predicate: F(F(z("storageInstance", r.storageInstance), z("objectNamespace", r.objectNamespace)), z("refId", e)),
637
+ order: [],
638
+ take: void 0,
639
+ skip: void 0,
640
+ projection: void 0
641
+ });
642
+ for (let e of n) await t.delete(a, String(e.id));
643
+ })
644
+ };
645
+ }, de = (e, t) => {
646
+ let r = Object.freeze({ ...t });
647
+ if (!("resolveNamespace" in r)) return ue(e, r);
648
+ let i = Z(e, r), o = (t) => i.getById(t).pipe(A.flatMap((t) => t === null ? A.succeed(void 0) : n(r, p(t)).pipe(A.map((t) => ue(e, t))))), s = (t) => Y(() => e.query({
649
+ table: a,
650
+ predicate: F(z("storageInstance", r.storageInstance), z("id", t)),
651
+ order: [],
652
+ take: 1,
653
+ skip: void 0,
654
+ projection: ["refId"]
655
+ })).pipe(A.flatMap((e) => e[0] === void 0 ? A.succeed(void 0) : o(String(e[0].refId))));
656
+ return {
657
+ insert: (e) => o(e.refId).pipe(A.flatMap((t) => t === void 0 ? A.fail(new l({
658
+ provider: "metadata",
659
+ message: "Storage grant reference is outside the current destination view",
660
+ transient: !1,
661
+ status: 409
662
+ })) : t.insert(e))),
663
+ delete: (e) => s(e).pipe(A.flatMap((t) => t === void 0 ? A.void : t.delete(e))),
664
+ getById: (e) => s(e).pipe(A.flatMap((t) => t === void 0 ? A.succeed(null) : t.getById(e))),
665
+ listByRef: (e) => o(e).pipe(A.flatMap((t) => t === void 0 ? A.succeed([]) : t.listByRef(e))),
666
+ deleteByRef: (e) => o(e).pipe(A.flatMap((t) => t === void 0 ? A.void : t.deleteByRef(e)))
667
+ };
668
+ }, fe = () => B({
669
+ kind: "typeid",
670
+ prefix: "file"
671
+ }, o), pe = () => B({
672
+ kind: "typeid",
673
+ prefix: "grant"
674
+ }, a), me = (e) => {
675
+ let { provider: n, refStore: i, grantStore: a } = e, s = (t) => N.decodeUnknownEffect(O)(p(t)).pipe(A.mapError(() => new l({
676
+ provider: "storage",
677
+ message: "Invalid stored object address",
678
+ transient: !1
679
+ })), A.flatMap((r) => e.destinations === void 0 ? t.bucket === e.bucket ? A.succeed(n) : A.fail(new l({
680
+ provider: "storage",
681
+ message: "Stored object destination is not configured",
682
+ transient: !1
683
+ })) : e.destinations.resolve(r))), f = (t) => ae(t, i, (e) => s({
684
+ bucket: e.destination,
685
+ tenantId: e.tenantId,
686
+ key: e.key
687
+ }), e.resolveObjectReference), m = (e) => s(e).pipe(A.map(f)), h = (t, r, i) => N.decodeUnknownEffect(O)({
688
+ destination: i ?? e.bucket,
689
+ tenantId: t,
690
+ key: r
691
+ }).pipe(A.mapError(() => new l({
692
+ provider: "storage",
693
+ message: "Invalid new object address",
694
+ transient: !1,
695
+ status: 400
696
+ })), A.flatMap(() => i === void 0 ? e.destinations === void 0 ? A.succeed({
697
+ destination: e.bucket,
698
+ provider: n
699
+ }) : e.destinations.select(t) : s({
700
+ bucket: i,
701
+ tenantId: t,
702
+ key: r
703
+ }).pipe(A.map((e) => ({
704
+ destination: i,
705
+ provider: e
706
+ })))), A.map((e) => ({
707
+ ...e,
708
+ provider: f(e.provider)
709
+ }))), T = (t) => A.gen(function* () {
710
+ let n = yield* i.catalogueId, a = yield* t.objectNamespace;
711
+ return yield* A.try({
712
+ try: () => r({
713
+ catalogueId: n,
714
+ objectNamespace: a,
715
+ storageInstance: e.storageInstance ?? "@voltro/plugin-storage"
716
+ }),
717
+ catch: (e) => _(e, "storage", !1)
718
+ });
719
+ }), j = e.access ?? {}, P = e.attempts ?? 3, F = e.urlExpiresInSec ?? 3600;
720
+ x(F);
721
+ let I = (t) => ce(e.publicBaseUrl, t, e.httpPath ?? "/_voltro/storage"), L = M.max([M.recurs(Math.max(0, P - 1)), M.exponential("100 millis")]).pipe(M.while(({ input: e }) => e.transient)), R = (e) => e === null ? "global" : typeof e != "string" || e.length === 0 || /[\uD800-\uDFFF]/u.test(e) ? "\0" : e === "global" ? "%67lobal" : e === "." ? "%2E" : e === ".." ? "%2E%2E" : encodeURIComponent(e), z = (t, n, r) => [
722
+ e.tenantPrefix,
723
+ R(t),
724
+ r ?? n
725
+ ].filter(Boolean).join("/"), V = (e) => {
726
+ if (e === void 0) return A.succeed(void 0);
727
+ let t = k(e);
728
+ return t === void 0 ? A.succeed(e) : A.fail(new l({
729
+ provider: "storage",
730
+ message: `storage key rejected: ${t}`,
731
+ transient: !1,
732
+ status: 400
733
+ }));
734
+ }, H = (t, n, r) => [
735
+ e.tenantPrefix,
736
+ R(t),
737
+ "_incoming",
738
+ n,
739
+ String(r).padStart(6, "0")
740
+ ].filter(Boolean).join("/"), W = (e, t) => t === void 0 || e.tenantId === t, G = (e, t) => t !== void 0 && e.tenantId !== t ? A.fail(new l({
741
+ provider: "storage",
742
+ message: "cross-tenant access denied",
743
+ transient: !1,
744
+ status: 403
745
+ })) : A.succeed(e), K = (t, n, r) => A.gen(function* () {
746
+ let i = e.objects?.(), a = (e) => new l({
747
+ provider: "metadata",
748
+ message: e,
749
+ transient: !1,
750
+ status: 409
751
+ });
752
+ if (i === void 0) return r === void 0 ? !1 : yield* A.fail(a(`claim '${r}' cannot be released: no data store is bound, so ref '${t}' holds no claims`));
753
+ let o = yield* A.tryPromise({
754
+ try: () => i.intent(t),
755
+ catch: (e) => new l({
756
+ provider: "metadata",
757
+ message: String(e?.message ?? e),
758
+ transient: !1
759
+ })
760
+ });
761
+ if (o === void 0) return r === void 0 ? !1 : yield* A.fail(a(`claim '${r}' cannot be released: ref '${t}' was not written through an operation and holds no claims`));
762
+ yield* G(o.ref, n);
763
+ let s = yield* m(o.ref);
764
+ return yield* ie({
765
+ metadata: i,
766
+ provider: {
767
+ ...s,
768
+ delete: (e) => s.delete(e).pipe(A.retry(L))
769
+ }
770
+ }).delete(t, n, r).pipe(A.catchTag("StorageRejected", (e) => A.fail(e.reason === "claim-not-held" ? a(e.detail) : new l({
771
+ provider: "metadata",
772
+ message: e.detail,
773
+ transient: !1
774
+ })))), !0;
775
+ }), q = (e, t) => i.getById(e).pipe(A.flatMap((n) => n ? G(n, t) : A.fail(new l({
776
+ provider: "storage",
777
+ message: `no ref '${e}'`,
778
+ transient: !1,
779
+ status: 404
780
+ })))), le = (t) => A.suspend(() => {
781
+ let n = e.scan(t);
782
+ return A.isEffect(n) ? n : A.tryPromise({
783
+ try: () => Promise.resolve(n),
784
+ catch: (e) => new l({
785
+ provider: "scan",
786
+ message: String(e?.message ?? e),
787
+ transient: !0
788
+ })
789
+ });
790
+ }), J = (t) => A.suspend(() => {
791
+ let n = t.contentType;
792
+ if (!e.videoProbe || !(n.startsWith("video/") || n.startsWith("audio/"))) return A.succeed(null);
793
+ let r;
794
+ try {
795
+ r = e.videoProbe(t);
796
+ } catch {
797
+ return A.succeed(null);
798
+ }
799
+ return A.isEffect(r) ? r.pipe(A.catch(() => A.succeed(null))) : A.tryPromise({
800
+ try: () => Promise.resolve(r),
801
+ catch: () => null
802
+ }).pipe(A.catch(() => A.succeed(null)));
803
+ }), Y = (t, n) => A.gen(function* () {
804
+ let r = te(t.bytes, t.contentType, e.limits);
805
+ if (r) return yield* A.fail(new u(r));
806
+ if (t.claim !== void 0 && t.operationId === void 0) return yield* A.fail(new u({
807
+ reason: "claim-without-operation",
808
+ detail: "a put with a claim needs an operationId; the claim names this caller's hold on that operation's object"
809
+ }));
810
+ if (e.scan) {
811
+ let e = yield* le({
812
+ bytes: t.bytes,
813
+ contentType: t.contentType,
814
+ ...t.key ? { key: t.key } : {}
815
+ });
816
+ if (!e.clean) return yield* A.fail(new d({ threat: e.threat ?? "unknown" }));
817
+ }
818
+ let a = yield* A.promise(() => ne(t.bytes, t.contentType, { normalize: e.normalizeImages ?? !1 })), o = a.bytes, s = yield* J({
819
+ bytes: o,
820
+ contentType: t.contentType
821
+ }), c = a.width ?? s?.width, l = a.height ?? s?.height, f = a.placeholder ?? s?.poster, p = t.duration ?? s?.duration, m = yield* A.promise(() => U(o)), g = t.tenantId ?? null, _ = t.visibility ?? "private", v = yield* V(t.key), y = z(g, m, v), b = yield* h(g, y, t.destination), { provider: x } = b, S = b.destination, C = t.operationId === void 0 ? z(g, m, `i-${yield* A.promise(() => U(new TextEncoder().encode(JSON.stringify([e.storageInstance ?? "@voltro/plugin-storage", S]))))}/plain/${v ?? m}`) : y, T = t.password ? yield* A.sync(() => ee(t.password)) : null, E = {
822
+ id: fe(),
823
+ tenantId: g,
824
+ ownerId: t.ownerId ?? null,
825
+ bucket: S,
826
+ key: C,
827
+ contentType: t.contentType,
828
+ size: o.byteLength,
829
+ checksum: m,
830
+ visibility: _,
831
+ accessPolicy: t.access ?? null,
832
+ passwordHash: T,
833
+ createdAt: /* @__PURE__ */ new Date(),
834
+ ...c === void 0 ? {} : { width: c },
835
+ ...l === void 0 ? {} : { height: l },
836
+ ...f === void 0 ? {} : { placeholder: f },
837
+ ...p === void 0 ? {} : { duration: p },
838
+ ...t.folder === void 0 ? {} : { folder: t.folder },
839
+ ...t.tags === void 0 ? {} : { tags: t.tags },
840
+ ...t.alt === void 0 ? {} : { alt: t.alt },
841
+ ...t.caption === void 0 ? {} : { caption: t.caption },
842
+ ...t.derivedFrom === void 0 ? {} : { derivedFrom: t.derivedFrom },
843
+ ...t.kind === void 0 ? {} : { kind: t.kind }
844
+ }, D = n === void 0 ? E : {
845
+ ...E,
846
+ renditionProof: yield* A.try({
847
+ try: () => re(n, E),
848
+ catch: (e) => e
849
+ })
850
+ }, ae = e.transcode !== void 0 && e.autoTranscode !== !1, O = (e) => ae && e.derivedFrom == null && (t.contentType.startsWith("video/") || t.contentType.startsWith("audio/")) ? A.forkDetach(Z(e).pipe(A.ignore)) : A.void;
851
+ if (t.operationId !== void 0) {
852
+ let n = e.objects?.();
853
+ if (n === void 0) return yield* A.fail(new u({
854
+ reason: "operation-store-unbound",
855
+ detail: "a put with an operationId needs a bound data store; the in-memory ref store cannot hold operation intents"
856
+ }));
857
+ let r = {
858
+ tenantId: g,
859
+ bucket: S,
860
+ operationId: t.operationId,
861
+ checksum: m,
862
+ logicalKey: C,
863
+ fingerprint: yield* A.promise(() => U(new TextEncoder().encode(JSON.stringify([
864
+ m,
865
+ t.contentType,
866
+ _,
867
+ t.access ?? null,
868
+ t.key ?? null,
869
+ t.ownerId ?? null,
870
+ t.folder ?? null,
871
+ t.tags ?? null,
872
+ t.alt ?? null,
873
+ t.caption ?? null,
874
+ t.derivedFrom ?? null,
875
+ t.kind ?? null,
876
+ p ?? null,
877
+ t.password !== void 0
878
+ ]))))
879
+ }, i = yield* ie({
880
+ metadata: n,
881
+ provider: {
882
+ ...x,
883
+ put: (e, t, n) => x.put(e, t, n).pipe(A.retry(L))
884
+ }
885
+ }).put({
886
+ identity: r,
887
+ ref: D,
888
+ bytes: o,
889
+ ...e.quota === void 0 ? {} : { quota: e.quota },
890
+ ...t.claim === void 0 ? {} : { claim: t.claim }
891
+ });
892
+ return yield* O(i.ref), {
893
+ ...i.ref,
894
+ outcome: i.outcome
895
+ };
896
+ }
897
+ let k = {
898
+ bytes: o.byteLength,
899
+ count: 1
900
+ }, j = yield* i.consumeUsage(g, k, e.quota);
901
+ if (!j.allowed) {
902
+ 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} + ${o.byteLength} bytes exceeds max ${t.maxBytes}`;
903
+ return yield* A.fail(new u({
904
+ reason: "quota-exceeded",
905
+ detail: n
906
+ }));
907
+ }
908
+ return yield* ((e) => e.pipe(A.onExit((e) => oe.isSuccess(e) ? A.void : i.delete(D.id).pipe(A.andThen(i.releaseUsage(g, k)), A.ignore))))(i.insert(w(D)).pipe(A.andThen(x.put(C, o, {
909
+ contentType: t.contentType,
910
+ public: _ === "public"
911
+ }).pipe(A.retry(L))))), yield* O(D), {
912
+ ...D,
913
+ outcome: "created"
914
+ };
915
+ }), X = (t) => A.suspend(() => {
916
+ if (!e.transcode) return A.succeed([]);
917
+ let n;
918
+ try {
919
+ n = e.transcode(t);
920
+ } catch {
921
+ return A.succeed([]);
922
+ }
923
+ return A.isEffect(n) ? n.pipe(A.catch(() => A.succeed([]))) : A.tryPromise({
924
+ try: () => Promise.resolve(n),
925
+ catch: () => []
926
+ }).pipe(A.catch(() => A.succeed([])));
927
+ }), Z = (t) => A.gen(function* () {
928
+ if (!e.transcode || t.derivedFrom != null) return [];
929
+ let n = yield* m(t), r = { ...t }, i = r.checksum !== "" && !/^[a-f0-9]{64}$/.test(r.checksum), a = () => n.head(r.key).pipe(A.map((e) => e === null ? null : { ...e })), o = i ? yield* a() : void 0, s = yield* n.get(r.key).pipe(A.retry(L)), c = i ? yield* a() : void 0, l = yield* X({
930
+ bytes: Uint8Array.from(s.bytes),
931
+ contentType: r.contentType,
932
+ ref: { ...r }
933
+ }), u = [];
934
+ for (let e of l) {
935
+ let n = {
936
+ ...e,
937
+ bytes: Uint8Array.from(e.bytes)
938
+ }, i = yield* A.try({
939
+ try: () => C(r, s.bytes, n, {
940
+ before: o,
941
+ after: c
942
+ }),
943
+ catch: (e) => e
944
+ }), a = yield* Y({
945
+ destination: t.bucket,
946
+ bytes: n.bytes,
947
+ contentType: n.contentType,
948
+ tenantId: r.tenantId,
949
+ ownerId: r.ownerId,
950
+ visibility: r.visibility,
951
+ derivedFrom: r.id,
952
+ kind: n.kind,
953
+ ...n.label === void 0 ? {} : { caption: n.label }
954
+ }, i);
955
+ u.push(a);
956
+ }
957
+ return u;
958
+ }), Q = (e, t, n) => A.gen(function* () {
959
+ if (e.derivedFrom != null) {
960
+ let r = yield* i.getById(e.derivedFrom);
961
+ return r === null ? !1 : yield* Q(r, t, n);
962
+ }
963
+ if (e.visibility === "public") return !0;
964
+ if (e.tenantId !== null && !W(e, t.tenantId ?? null)) return !1;
965
+ if (yield* v(e, t, {
966
+ ...j,
967
+ ...n?.password === void 0 ? {} : { password: n.password }
968
+ })) return !0;
969
+ let r = yield* b(t, j), o = yield* a.listByRef(e.id);
970
+ return y(o, t, r, n?.permission ?? "read", Date.now());
971
+ }), $ = (e, t) => {
972
+ if (e.visibility === "public") {
973
+ let n = t.publicUrl?.(e.key);
974
+ if (n != null) return n;
975
+ }
976
+ return I(e.id);
977
+ };
978
+ return {
979
+ operationStatus: (n) => A.gen(function* () {
980
+ if (!n || typeof n.operationId != "string" || n.operationId.length === 0 || n.tenantId !== null && typeof n.tenantId != "string") return yield* A.fail(new l({
981
+ provider: "metadata",
982
+ message: "An exact operation ID and explicit tenant are required",
983
+ transient: !1,
984
+ status: 400
985
+ }));
986
+ let a = e.objects?.();
987
+ if (!a) return yield* A.fail(new l({
988
+ provider: "metadata",
989
+ message: "Durable storage operation metadata is not bound",
990
+ transient: !1,
991
+ status: 409
992
+ }));
993
+ let o = yield* h(n.tenantId, "_namespace", n.destination), s = yield* A.tryPromise({
994
+ try: () => a.operationStatus({
995
+ operationId: n.operationId,
996
+ tenantId: n.tenantId,
997
+ bucket: o.destination
998
+ }),
999
+ catch: (e) => {
1000
+ let t = _(e, "metadata");
1001
+ return new l({
1002
+ provider: "metadata",
1003
+ message: "Storage operation state could not be confirmed; retain its identity for recovery",
1004
+ transient: t.transient,
1005
+ ...t.status === void 0 ? {} : { status: t.status }
1006
+ });
1007
+ }
1008
+ });
1009
+ if ((yield* o.provider.objectNamespace) !== s.scope.objectNamespace || s.scope.storageInstance !== (e.storageInstance ?? "@voltro/plugin-storage")) return yield* A.fail(new l({
1010
+ provider: "metadata",
1011
+ message: "Storage operation metadata belongs to another configured destination",
1012
+ transient: !1,
1013
+ status: 409
1014
+ }));
1015
+ let c = yield* i.catalogueId, u = yield* A.try({
1016
+ try: () => t([
1017
+ "durable-operation-observation",
1018
+ r({
1019
+ ...s.scope,
1020
+ catalogueId: c
1021
+ }),
1022
+ o.destination
1023
+ ]),
1024
+ catch: (e) => _(e, "metadata")
1025
+ });
1026
+ return {
1027
+ ...s.observation,
1028
+ scope: u,
1029
+ destination: o.destination
1030
+ };
1031
+ }),
1032
+ uploadTicketScope: (e) => h(e?.tenantId ?? null, "_namespace", e?.destination).pipe(A.flatMap((e) => T(e.provider))),
1033
+ put: (e) => Y(e),
1034
+ get: (e, t) => q(e, t?.tenantId).pipe(A.flatMap((e) => m(e).pipe(A.flatMap((t) => t.get(e.key).pipe(A.retry(L), A.map((t) => ({
1035
+ bytes: t.bytes,
1036
+ ref: e
1037
+ }))))))),
1038
+ getStream: (e, t) => q(e, t?.tenantId).pipe(A.flatMap((e) => m(e).pipe(A.flatMap((t) => g(t, e.key).pipe(A.retry(L), A.map((t) => ({
1039
+ ref: e,
1040
+ stream: t.stream
1041
+ }))))))),
1042
+ getRange: (e, t, n) => q(e, n?.tenantId).pipe(A.flatMap((e) => m(e).pipe(A.flatMap((n) => {
1043
+ let r = e.size, i = Math.max(0, Math.trunc(t.start));
1044
+ if (r > 0 && i >= r) return A.fail(new l({
1045
+ provider: n.name,
1046
+ message: `range start ${i} past end ${r}`,
1047
+ transient: !1,
1048
+ status: 416
1049
+ }));
1050
+ let a = Math.min(Math.trunc(t.endInclusive), Math.max(0, r - 1));
1051
+ return a < i ? A.fail(new l({
1052
+ provider: n.name,
1053
+ message: `empty range ${i}-${a}`,
1054
+ transient: !1,
1055
+ status: 416
1056
+ })) : (n.getRange ? n.getRange(e.key, i, a).pipe(A.retry(L)) : n.get(e.key).pipe(A.retry(L), A.map((e) => e.bytes.subarray(i, a + 1)))).pipe(A.map((t) => ({
1057
+ bytes: t,
1058
+ ref: e,
1059
+ totalSize: r
1060
+ })));
1061
+ })))),
1062
+ getUrl: (e, t) => q(e, t?.tenantId).pipe(A.flatMap((e) => m(e).pipe(A.flatMap((n) => e.visibility === "public" ? A.succeed($(e, n)) : n.presigns ? n.getUrl(e.key, t?.expiresInSec ?? F) : A.succeed(I(e.id)))))),
1063
+ head: (e, t) => i.getById(e).pipe(A.flatMap((e) => e ? G(e, t?.tenantId).pipe(A.map((e) => e)) : A.succeed(null))),
1064
+ delete: (e, t) => K(e, t?.tenantId, t?.claim).pipe(A.flatMap((n) => n ? A.void : q(e, t?.tenantId).pipe(A.flatMap((t) => m(t).pipe(A.flatMap((n) => a.deleteByRef(e).pipe(A.flatMap(() => i.delete(e)), A.flatMap((e) => e ? n.delete(t.key).pipe(A.retry(L), A.flatMap(() => i.releaseUsage(t.tenantId, {
1065
+ bytes: t.size,
1066
+ count: 1
1067
+ }))) : A.void), A.asVoid))))))),
1068
+ signedUrl: (t, n) => q(t, n?.tenantId).pipe(A.flatMap((t) => m(t).pipe(A.flatMap((r) => {
1069
+ if (t.visibility === "public") return A.succeed($(t, r));
1070
+ let i = n?.expiresInSec ?? F;
1071
+ return r.presigns ? r.getUrl(t.key, i) : A.sync(() => `${I(t.id)}?t=${S(t.id, i, void 0, e.httpPath ?? "/_voltro/storage")}`);
1072
+ })))),
1073
+ setVisibility: (e, t, n) => A.gen(function* () {
1074
+ let r = yield* q(e, n?.tenantId);
1075
+ if (r.visibility === t) return r;
1076
+ let a = i.setVisibility;
1077
+ if (a === void 0) return yield* A.fail(new u({
1078
+ reason: "visibility-unsupported",
1079
+ detail: "the ref store cannot change a stored object visibility"
1080
+ }));
1081
+ let o = r.derivedFrom == null ? yield* i.listByDerivedFrom(r.id) : [], s = [];
1082
+ for (let e of [r, ...o]) {
1083
+ let n = yield* m(e);
1084
+ if (t === "private" && n.publicUrl?.(e.key) != null) return yield* A.fail(new u({
1085
+ reason: "visibility-unsupported",
1086
+ detail: `objects are served from a public base (${n.name} cdnBaseUrl); a public object cannot be made private there`
1087
+ }));
1088
+ if (t === "private" && n.setObjectPublic !== void 0 && i.countPublicByAddress === void 0) return yield* A.fail(new u({
1089
+ reason: "visibility-unsupported",
1090
+ detail: "the ref store cannot tell whether other refs keep these bytes public"
1091
+ }));
1092
+ s.push({
1093
+ ref: e,
1094
+ provider: n
1095
+ });
1096
+ }
1097
+ let c = yield* a(r.id, t);
1098
+ if (c === null) return yield* A.fail(new l({
1099
+ provider: "storage",
1100
+ message: `no ref '${e}'`,
1101
+ transient: !1,
1102
+ status: 404
1103
+ }));
1104
+ for (let e of o) if (e.visibility !== t && (yield* a(e.id, t)) === null) return yield* A.fail(new l({
1105
+ provider: "storage",
1106
+ message: `no ref '${e.id}'`,
1107
+ transient: !1,
1108
+ status: 404
1109
+ }));
1110
+ for (let e of s) if (e.provider.setObjectPublic !== void 0) {
1111
+ let n = i.countPublicByAddress, r = t === "public" || n !== void 0 && (yield* n(p(e.ref))) > 0;
1112
+ yield* e.provider.setObjectPublic(e.ref.key, r);
1113
+ }
1114
+ return c;
1115
+ }),
1116
+ mintUrl: (t, n, r) => A.gen(function* () {
1117
+ let a = yield* i.getById(t).pipe(A.flatMap((e) => e ? A.succeed(e) : A.fail(new l({
1118
+ provider: "storage",
1119
+ message: `no ref '${t}'`,
1120
+ transient: !1,
1121
+ status: 404
1122
+ }))));
1123
+ if (a.visibility === "public" && a.derivedFrom == null) return $(a, yield* m(a));
1124
+ if (!(yield* Q(a, n, r?.password === void 0 ? {} : { password: r.password }))) return yield* A.fail(new c({
1125
+ refId: t,
1126
+ reason: "access denied"
1127
+ }));
1128
+ let o = yield* m(a), s = r?.expiresInSec ?? F;
1129
+ if (o.presigns) return yield* o.getUrl(a.key, s);
1130
+ let u = yield* A.sync(() => S(a.id, s, void 0, e.httpPath ?? "/_voltro/storage"));
1131
+ return `${I(a.id)}?t=${u}`;
1132
+ }),
1133
+ mintUploadUrl: (e) => A.gen(function* () {
1134
+ let { provider: t } = yield* h(e.tenantId ?? null, z(e.tenantId ?? null, "", e.key));
1135
+ if (!t.getUploadUrl) return yield* A.fail(new l({
1136
+ provider: t.name,
1137
+ message: `provider '${t.name}' does not support presigned uploads`,
1138
+ transient: !1,
1139
+ status: 400
1140
+ }));
1141
+ let n = z(e.tenantId ?? null, "", yield* V(e.key));
1142
+ return yield* t.getUploadUrl(n, e.expiresInSec ?? F, e.contentType);
1143
+ }),
1144
+ checkAccess: Q,
1145
+ grant: (e) => A.gen(function* () {
1146
+ yield* q(e.refId);
1147
+ let t = {
1148
+ id: pe(),
1149
+ refId: e.refId,
1150
+ principalType: e.principalType,
1151
+ principalId: e.principalId,
1152
+ permission: e.permission ?? "read",
1153
+ createdAt: /* @__PURE__ */ new Date(),
1154
+ expiresAt: e.expiresAt ?? null,
1155
+ createdBy: e.createdBy ?? null
1156
+ };
1157
+ return yield* a.insert(t), t;
1158
+ }),
1159
+ listRefs: (e) => A.suspend(() => {
1160
+ let t = Math.min(500, Math.max(1, Math.trunc(e?.limit ?? 50))), n = Math.max(0, Math.trunc(e?.offset ?? 0)), r = {
1161
+ tenantId: e && "tenantId" in e ? e.tenantId : void 0,
1162
+ folder: e?.folder,
1163
+ tags: e?.tags ?? [],
1164
+ ownerId: e?.ownerId,
1165
+ includeDerived: e?.includeDerived ?? !1,
1166
+ limit: t + 1,
1167
+ offset: n
1168
+ };
1169
+ return i.listRefs(r).pipe(A.map((e) => {
1170
+ let r = e.length > t;
1171
+ return {
1172
+ refs: r ? e.slice(0, t) : e,
1173
+ nextOffset: r ? n + t : null
1174
+ };
1175
+ }));
1176
+ }),
1177
+ revoke: (e) => a.delete(e),
1178
+ getGrant: (e) => a.getById(e),
1179
+ listGrants: (e) => a.listByRef(e),
1180
+ usage: (e) => i.usageByTenant(e),
1181
+ sweepOrphans: (e) => A.gen(function* () {
1182
+ let t = e?.limit ?? 1e3, n = e?.dryRun ?? !1, r = yield* i.listRecent(t), a = [];
1183
+ for (let e of r) if ((yield* (yield* m(e)).head(e.key)) === null) {
1184
+ if (!n) {
1185
+ if (!(yield* i.delete(e.id))) continue;
1186
+ yield* i.releaseUsage(e.tenantId, {
1187
+ bytes: e.size,
1188
+ count: 1
1189
+ });
1190
+ }
1191
+ a.push(e.id);
1192
+ }
1193
+ return {
1194
+ scanned: r.length,
1195
+ removed: a
1196
+ };
1197
+ }),
1198
+ ingestUrl: (t, n) => D(A.gen(function* () {
1199
+ let r = yield* E(t, e.limits?.maxBytes, e.ingest);
1200
+ return yield* Y({
1201
+ bytes: r.bytes,
1202
+ contentType: n?.contentType ?? r.contentType,
1203
+ ...n?.tenantId === void 0 ? {} : { tenantId: n.tenantId },
1204
+ ...n?.operationId === void 0 ? {} : { operationId: n.operationId },
1205
+ ...n?.ownerId === void 0 ? {} : { ownerId: n.ownerId },
1206
+ ...n?.visibility === void 0 ? {} : { visibility: n.visibility },
1207
+ ...n?.access === void 0 ? {} : { access: n.access },
1208
+ ...n?.key === void 0 ? {} : { key: n.key },
1209
+ ...n?.folder === void 0 ? {} : { folder: n.folder },
1210
+ ...n?.tags === void 0 ? {} : { tags: n.tags },
1211
+ ...n?.alt === void 0 ? {} : { alt: n.alt },
1212
+ ...n?.caption === void 0 ? {} : { caption: n.caption }
1213
+ });
1214
+ }), n?.abortSignal),
1215
+ mintPresignedUpload: (e) => A.gen(function* () {
1216
+ let t = yield* h(e.tenantId ?? null, H(e.tenantId ?? null, "selection", 0)), { provider: n } = t;
1217
+ if (!n.getUploadUrl) return yield* A.fail(new l({
1218
+ provider: n.name,
1219
+ message: `provider '${n.name}' does not support presigned uploads`,
1220
+ transient: !1,
1221
+ status: 400
1222
+ }));
1223
+ let r = e.expiresInSec ?? F, i = `_incoming/${B({
1224
+ kind: "typeid",
1225
+ prefix: "up"
1226
+ }, o)}`, a = z(e.tenantId ?? null, "", i), s = yield* T(n), c = yield* n.getUploadUrl(a, r, e.contentType);
1227
+ return {
1228
+ writeScope: s,
1229
+ destination: t.destination,
1230
+ tenantId: e.tenantId ?? null,
1231
+ uploadUrl: c,
1232
+ key: a,
1233
+ expiresInSec: r
1234
+ };
1235
+ }),
1236
+ finalizeUpload: (e) => m({
1237
+ bucket: e.destination,
1238
+ tenantId: e.tenantId ?? null,
1239
+ key: e.key
1240
+ }).pipe(A.flatMap((t) => t.get(e.key).pipe(A.retry(L), A.flatMap((t) => Y({
1241
+ destination: e.destination,
1242
+ bytes: t.bytes,
1243
+ contentType: e.contentType,
1244
+ ...e.tenantId === void 0 ? {} : { tenantId: e.tenantId },
1245
+ ...e.ownerId === void 0 ? {} : { ownerId: e.ownerId },
1246
+ ...e.visibility === void 0 ? {} : { visibility: e.visibility },
1247
+ ...e.access === void 0 ? {} : { access: e.access },
1248
+ ...e.folder === void 0 ? {} : { folder: e.folder },
1249
+ ...e.tags === void 0 ? {} : { tags: e.tags },
1250
+ ...e.alt === void 0 ? {} : { alt: e.alt },
1251
+ ...e.caption === void 0 ? {} : { caption: e.caption }
1252
+ })), A.ensuring(t.delete(e.key).pipe(A.retry(L), A.ignore))))),
1253
+ putResumableChunk: (e) => m({
1254
+ bucket: e.destination,
1255
+ tenantId: e.tenantId ?? null,
1256
+ key: H(e.tenantId ?? null, e.uploadId, e.index)
1257
+ }).pipe(A.flatMap((t) => t.put(H(e.tenantId ?? null, e.uploadId, e.index), e.bytes, { contentType: "application/octet-stream" }).pipe(A.retry(L), A.asVoid))),
1258
+ resumableStatus: (e) => A.gen(function* () {
1259
+ let t = yield* m({
1260
+ bucket: e.destination,
1261
+ tenantId: e.tenantId ?? null,
1262
+ key: H(e.tenantId ?? null, e.uploadId, 0)
1263
+ }), n = 0, r = 0;
1264
+ for (; n < 1e6;) {
1265
+ let i = yield* t.head(H(e.tenantId ?? null, e.uploadId, n)).pipe(A.retry(L), A.catchIf((e) => e.status === 404, () => A.succeed(null)));
1266
+ if (i === null) break;
1267
+ r += i.size, n += 1;
1268
+ }
1269
+ return {
1270
+ offset: r,
1271
+ nextIndex: n
1272
+ };
1273
+ }),
1274
+ finalizeResumable: (t) => A.gen(function* () {
1275
+ let n = yield* m({
1276
+ bucket: t.destination,
1277
+ tenantId: t.tenantId ?? null,
1278
+ key: H(t.tenantId ?? null, t.uploadId, 0)
1279
+ }), r = e.limits?.maxBytes ?? 2 ** 53 - 1;
1280
+ if (!Number.isSafeInteger(r) || r < 0 || !Number.isSafeInteger(t.count) || t.count < 0) return yield* A.fail(new l({
1281
+ provider: n.name,
1282
+ message: "resumable count and limits.maxBytes must be non-negative safe integers",
1283
+ transient: !1,
1284
+ status: 400
1285
+ }));
1286
+ let i = (e) => H(t.tenantId ?? null, t.uploadId, e), a = A.gen(function* () {
1287
+ for (let e = 0; e < t.count; e++) yield* n.delete(i(e)).pipe(A.retry(L), A.ignore);
1288
+ }), o = () => new u({
1289
+ reason: "too-large",
1290
+ detail: `resumable upload exceeds ${r}-byte limit`
1291
+ }), s = yield* A.gen(function* () {
1292
+ let e = 0;
1293
+ for (let a = 0; a < t.count; a++) {
1294
+ let t = yield* n.head(i(a)).pipe(A.retry(L));
1295
+ if (t === null) return yield* A.fail(new l({
1296
+ provider: n.name,
1297
+ message: `no resumable chunk at '${i(a)}'`,
1298
+ transient: !1,
1299
+ status: 404
1300
+ }));
1301
+ if (!Number.isSafeInteger(t.size) || t.size < 0) return yield* A.fail(new l({
1302
+ provider: n.name,
1303
+ message: "resumable chunk metadata has an invalid size",
1304
+ transient: !1
1305
+ }));
1306
+ if (t.size > r - e) return yield* A.fail(o());
1307
+ e += t.size;
1308
+ }
1309
+ let a = /* @__PURE__ */ new Uint8Array(), s = 0;
1310
+ for (let e = 0; e < t.count; e++) {
1311
+ let t = yield* g(n, i(e)).pipe(A.retry(L));
1312
+ yield* se.runForEach(t.stream, (e) => A.gen(function* () {
1313
+ if (e.byteLength > r - s) return yield* A.fail(o());
1314
+ let t = s + e.byteLength;
1315
+ if (t > a.byteLength) {
1316
+ let e = new Uint8Array(Math.min(r, Math.max(65536, a.byteLength * 2, t)));
1317
+ e.set(a.subarray(0, s)), a = e;
1318
+ }
1319
+ a.set(e, s), s = t;
1320
+ }));
1321
+ }
1322
+ return a.subarray(0, s);
1323
+ }).pipe(A.tapError((e) => e._tag === "StorageRejected" ? a : A.void));
1324
+ return yield* Y({
1325
+ destination: t.destination,
1326
+ bytes: s,
1327
+ contentType: t.contentType,
1328
+ ...t.tenantId === void 0 ? {} : { tenantId: t.tenantId },
1329
+ ...t.ownerId === void 0 ? {} : { ownerId: t.ownerId },
1330
+ ...t.visibility === void 0 ? {} : { visibility: t.visibility },
1331
+ ...t.access === void 0 ? {} : { access: t.access },
1332
+ ...t.folder === void 0 ? {} : { folder: t.folder },
1333
+ ...t.tags === void 0 ? {} : { tags: t.tags },
1334
+ ...t.alt === void 0 ? {} : { alt: t.alt },
1335
+ ...t.caption === void 0 ? {} : { caption: t.caption }
1336
+ }).pipe(A.ensuring(a));
1337
+ }),
1338
+ transcode: (e, t) => q(e, t?.tenantId).pipe(A.flatMap((e) => Z(e))),
1339
+ renditions: (e, t) => q(e, t?.tenantId).pipe(A.flatMap(() => i.listByDerivedFrom(e))),
1340
+ beginMultipartUpload: (e) => A.gen(function* () {
1341
+ let t = yield* h(e.tenantId ?? null, H(e.tenantId ?? null, "selection", 0)), { provider: n } = t;
1342
+ if (!n.createMultipartUpload || !n.presignUploadPart || !n.completeMultipartUpload) return yield* A.fail(new l({
1343
+ provider: n.name,
1344
+ message: `provider '${n.name}' does not support multipart uploads`,
1345
+ transient: !1,
1346
+ status: 400
1347
+ }));
1348
+ let r = z(e.tenantId ?? null, "", `multipart/${B({
1349
+ kind: "typeid",
1350
+ prefix: "mp"
1351
+ }, o)}`), i = yield* T(n), a = yield* n.createMultipartUpload(r, e.contentType, { public: (e.visibility ?? "private") === "public" });
1352
+ return {
1353
+ writeScope: i,
1354
+ destination: t.destination,
1355
+ tenantId: e.tenantId ?? null,
1356
+ uploadId: a.uploadId,
1357
+ key: r
1358
+ };
1359
+ }),
1360
+ signMultipartPart: (e) => m({
1361
+ bucket: e.destination,
1362
+ tenantId: e.tenantId ?? null,
1363
+ key: e.key
1364
+ }).pipe(A.flatMap((t) => A.suspend(() => t.presignUploadPart ? t.presignUploadPart(e.key, e.uploadId, e.partNumber, e.expiresInSec ?? F) : A.fail(new l({
1365
+ provider: t.name,
1366
+ message: "provider does not support multipart uploads",
1367
+ transient: !1,
1368
+ status: 400
1369
+ }))))),
1370
+ completeMultipart: (t) => A.gen(function* () {
1371
+ let n = yield* m({
1372
+ bucket: t.destination,
1373
+ tenantId: t.tenantId ?? null,
1374
+ key: t.key
1375
+ }), r = t.destination;
1376
+ if (!n.completeMultipartUpload) return yield* A.fail(new l({
1377
+ provider: n.name,
1378
+ message: "provider does not support multipart uploads",
1379
+ transient: !1,
1380
+ status: 400
1381
+ }));
1382
+ let a = yield* n.completeMultipartUpload(t.key, t.uploadId, t.parts), o = yield* n.head(t.key).pipe(A.retry(L)), s = o?.size ?? 0, c = (a.etag ?? o?.etag ?? "").replace(/"/g, ""), d = t.tenantId ?? null, f = {
1383
+ bytes: s,
1384
+ count: 1
1385
+ };
1386
+ if (!(yield* i.consumeUsage(d, f, e.quota)).allowed) return yield* n.delete(t.key).pipe(A.retry(L), A.ignore), yield* A.fail(new u({
1387
+ reason: "quota-exceeded",
1388
+ detail: `multipart upload of ${s} bytes exceeds tenant quota`
1389
+ }));
1390
+ let p = {
1391
+ id: fe(),
1392
+ tenantId: t.tenantId ?? null,
1393
+ ownerId: t.ownerId ?? null,
1394
+ bucket: r,
1395
+ key: t.key,
1396
+ contentType: t.contentType,
1397
+ size: s,
1398
+ checksum: c,
1399
+ visibility: t.visibility ?? "private",
1400
+ accessPolicy: t.access ?? null,
1401
+ passwordHash: null,
1402
+ createdAt: /* @__PURE__ */ new Date(),
1403
+ ...t.folder === void 0 ? {} : { folder: t.folder },
1404
+ ...t.tags === void 0 ? {} : { tags: t.tags },
1405
+ ...t.alt === void 0 ? {} : { alt: t.alt },
1406
+ ...t.caption === void 0 ? {} : { caption: t.caption }
1407
+ };
1408
+ return yield* i.insert(p).pipe(A.onExit((e) => oe.isSuccess(e) ? A.void : i.releaseUsage(d, f).pipe(A.ignore))), p;
1409
+ }),
1410
+ abortMultipart: (e) => m({
1411
+ bucket: e.destination,
1412
+ tenantId: e.tenantId ?? null,
1413
+ key: e.key
1414
+ }).pipe(A.flatMap((t) => A.suspend(() => t.abortMultipartUpload ? t.abortMultipartUpload(e.key, e.uploadId).pipe(A.retry(L)) : A.void)))
1415
+ };
1416
+ }, he = (e) => j.succeed(f, me(e));
1417
+ //#endregion
1418
+ export { me as buildStorageService, de as dataStoreGrantStore, Z as dataStoreRefStore, Q as memoryGrantStore, q as memoryRefStore, G as refMatchesListQuery, he as storageServiceLayer, J as toRef };