@voltro/plugin-storage 0.84.0 → 0.86.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +1215 -0
- package/README.md +50 -0
- package/THIRD-PARTY-NOTICES.md +91 -365
- package/dist/access.js +47 -0
- package/dist/assetRef.js +13 -0
- package/dist/avatar.js +39 -0
- package/dist/constraints.js +93 -0
- package/dist/derivatives.js +30 -0
- package/dist/env.js +156 -0
- package/dist/grant.js +112 -0
- package/dist/index.d.ts +175 -65
- package/dist/index.js +620 -3072
- package/dist/ingest.js +81 -0
- package/dist/ingestPolicy.js +1 -0
- package/dist/metadataError.js +19 -0
- package/dist/objectLifecycle.js +209 -0
- package/dist/objectMetadata.js +150 -0
- package/dist/objectWriter.js +58 -0
- package/dist/pathDurability.js +16 -0
- package/dist/providers.js +493 -0
- package/dist/referenceCatalogue.js +31 -0
- package/dist/rpc.d.ts +212 -166
- package/dist/rpc.js +63 -40
- package/dist/scanners.js +46 -0
- package/dist/service.js +1084 -0
- package/dist/storageNamespaces.js +56 -0
- package/dist/storageNumbers.js +13 -0
- package/dist/storageObjectNamespaces.js +194 -0
- package/dist/storageReferenceInstances.js +52 -0
- package/dist/streamBridge.js +30 -0
- package/dist/table.js +53 -0
- package/dist/transcodeVideo.js +53 -0
- package/dist/transform.js +90 -0
- package/dist/transformCache.js +31 -0
- package/dist/types.d.ts +31 -45
- package/dist/types.js +5 -1
- package/package.json +6 -6
package/dist/index.d.ts
CHANGED
|
@@ -9,11 +9,14 @@ import { mixin } from '@voltro/database';
|
|
|
9
9
|
import { PluginEgressDeclaration } from '@voltro/protocol';
|
|
10
10
|
import { Readable } from 'node:stream';
|
|
11
11
|
import { Schema } from 'effect';
|
|
12
|
+
import { StorageAccessPolicy } from '@voltro/protocol';
|
|
13
|
+
import { StorageAccessRule } from '@voltro/protocol';
|
|
12
14
|
import { Stream } from 'effect';
|
|
13
15
|
import { Subject } from '@voltro/protocol';
|
|
14
16
|
import { Table } from '@voltro/database';
|
|
15
17
|
import { TableLike } from '@voltro/database';
|
|
16
18
|
import { VoltroPlugin } from '@voltro/protocol';
|
|
19
|
+
import { YieldableError } from 'effect/Cause';
|
|
17
20
|
|
|
18
21
|
export declare interface AccessOptions {
|
|
19
22
|
/** Resolve a subject's group ids. Default: `subject.metadata.groups`. */
|
|
@@ -22,7 +25,7 @@ export declare interface AccessOptions {
|
|
|
22
25
|
readonly guards?: Record<string, StorageGuard>;
|
|
23
26
|
}
|
|
24
27
|
|
|
25
|
-
export declare type AccessPolicy =
|
|
28
|
+
export declare type AccessPolicy = StorageAccessPolicy;
|
|
26
29
|
|
|
27
30
|
/**
|
|
28
31
|
* One access rule. A rule GRANTS when EVERY present condition is satisfied
|
|
@@ -30,24 +33,7 @@ export declare type AccessPolicy = ReadonlyArray<AccessRule>;
|
|
|
30
33
|
* grants (OR). An empty policy on a private object means owner-only (the
|
|
31
34
|
* implicit owner check always applies).
|
|
32
35
|
*/
|
|
33
|
-
export declare
|
|
34
|
-
/** `subject.id === ref.ownerId`. */
|
|
35
|
-
readonly owner?: boolean;
|
|
36
|
-
/** `subject.metadata.roles` intersects these. */
|
|
37
|
-
readonly roles?: ReadonlyArray<string>;
|
|
38
|
-
/** resolved groups (default `subject.metadata.groups`) intersect these. */
|
|
39
|
-
readonly groups?: ReadonlyArray<string>;
|
|
40
|
-
/** `subject.scopes` intersects these. */
|
|
41
|
-
readonly scopes?: ReadonlyArray<string>;
|
|
42
|
-
/** `subject.tenantId === ref.tenantId`. */
|
|
43
|
-
readonly tenant?: boolean;
|
|
44
|
-
/** subject is any authenticated api-key. */
|
|
45
|
-
readonly apiKey?: boolean;
|
|
46
|
-
/** a correct password was supplied (checked at mint, against passwordHash). */
|
|
47
|
-
readonly password?: boolean;
|
|
48
|
-
/** a named custom guard (`options.guards[name]`) returns true. */
|
|
49
|
-
readonly guard?: string;
|
|
50
|
-
}
|
|
36
|
+
export declare type AccessRule = StorageAccessRule;
|
|
51
37
|
|
|
52
38
|
/**
|
|
53
39
|
* The provider the APP configured, falling back to the env-derived default when no
|
|
@@ -72,6 +58,20 @@ export declare interface AssetRefOptions {
|
|
|
72
58
|
readonly nullable?: boolean;
|
|
73
59
|
}
|
|
74
60
|
|
|
61
|
+
/** The caller owns the after-schema transaction, with serving replicas stopped.
|
|
62
|
+
* Assignments preserve reference IDs, keys, grants, raw put identities, claims
|
|
63
|
+
* and quota. No provider I/O or nested transaction occurs. Returned cleanup
|
|
64
|
+
* targets run through their matching service after boot. */
|
|
65
|
+
export declare const assignStorageObjectNamespacesInTransaction: (store: DataStore, scopes: readonly StorageReferenceScope[], assignments: readonly StorageObjectNamespaceAssignment[]) => Promise<StorageObjectNamespaceMigrationResult>;
|
|
66
|
+
|
|
67
|
+
/** Run in an after-schema migration with serving replicas stopped. The mapping
|
|
68
|
+
* comes from the operator, never from provider failures or the default name.
|
|
69
|
+
* The supplied store belongs to the caller’s transaction. No nested transaction
|
|
70
|
+
* is opened. Only ownership columns change: IDs, bytes, claims, quota and replay stay put. */
|
|
71
|
+
export declare const assignStorageReferenceInstancesInTransaction: (store: DataStore, instances: readonly string[], assignments: readonly StorageReferenceInstanceAssignment[]) => Promise<{
|
|
72
|
+
readonly assigned: number;
|
|
73
|
+
}>;
|
|
74
|
+
|
|
75
75
|
export declare const azureProvider: (options: AzureProviderOptions) => StorageProvider;
|
|
76
76
|
|
|
77
77
|
export declare interface AzureProviderOptions {
|
|
@@ -173,10 +173,10 @@ export declare const databaseProvider: () => StorageProvider & {
|
|
|
173
173
|
bindDataStore: (store: unknown) => void;
|
|
174
174
|
};
|
|
175
175
|
|
|
176
|
-
export declare const dataStoreGrantStore: (store: DataStore) => GrantStore;
|
|
176
|
+
export declare const dataStoreGrantStore: (store: DataStore, configuredScope: StorageReferenceScope) => GrantStore;
|
|
177
177
|
|
|
178
178
|
/** Ref store backed by the app's `DataStore` (`_voltro_storage_refs`). */
|
|
179
|
-
export declare const dataStoreRefStore: (store: DataStore) => RefStore;
|
|
179
|
+
export declare const dataStoreRefStore: (store: DataStore, configuredScope: StorageReferenceScope) => RefStore;
|
|
180
180
|
|
|
181
181
|
/** Decode a `data:<mime>;base64,<data>` URI to bytes + content type. */
|
|
182
182
|
export declare const decodeDataUri: (dataUri: string) => {
|
|
@@ -193,10 +193,22 @@ export declare const decodeDataUri: (dataUri: string) => {
|
|
|
193
193
|
*/
|
|
194
194
|
export declare const durabilityNotice: (path: string) => string | undefined;
|
|
195
195
|
|
|
196
|
+
/**
|
|
197
|
+
* Apply a creative edit; null when the input is not an image, `sharp` is not
|
|
198
|
+
* installed, the edit is empty or fails. The format stays the input's.
|
|
199
|
+
*/
|
|
200
|
+
export declare const editImage: (bytes: Uint8Array, contentType: string, edit: ImageEdit) => Promise<Transformed | null>;
|
|
201
|
+
|
|
196
202
|
/** Frame bytes for clamd `INSTREAM`: `zINSTREAM\0` then `<u32 len><data>`
|
|
197
203
|
* chunks, terminated by a zero-length chunk. Exposed for testing. */
|
|
198
204
|
export declare const encodeInstream: (bytes: Uint8Array, chunkSize?: number) => Buffer;
|
|
199
205
|
|
|
206
|
+
/** Boot-time initialization after normal schema reconciliation. This identity
|
|
207
|
+
* describes the persisted reference catalogue, not its provider bytes or host. */
|
|
208
|
+
export declare const ensureStorageReferenceCatalogue: (store: DataStore) => Promise<void>;
|
|
209
|
+
|
|
210
|
+
export declare const fetchIngestBody: (url: string, configuredMaxBytes?: number, policy?: IngestPolicy) => Effect.Effect<StoredObject, StorageError | StorageRejected>;
|
|
211
|
+
|
|
200
212
|
export declare interface FfmpegRenditionSpec {
|
|
201
213
|
/** Derivative class stored on the rendition ref — `'rendition'` / `'poster'`. */
|
|
202
214
|
readonly kind: string;
|
|
@@ -286,6 +298,19 @@ export declare interface GrantTokenPayload {
|
|
|
286
298
|
/** Hash a file password as `salt:scryptHash` (hex). */
|
|
287
299
|
export declare const hashPassword: (password: string) => string;
|
|
288
300
|
|
|
301
|
+
/** A creative edit: the result is new bytes, stored as a new version — unlike a delivery transform. */
|
|
302
|
+
export declare interface ImageEdit {
|
|
303
|
+
/** Clockwise, in degrees. */
|
|
304
|
+
readonly rotate?: 90 | 180 | 270;
|
|
305
|
+
/** Mirror top to bottom. */
|
|
306
|
+
readonly flip?: boolean;
|
|
307
|
+
/** Mirror left to right. */
|
|
308
|
+
readonly flop?: boolean;
|
|
309
|
+
readonly grayscale?: boolean;
|
|
310
|
+
/** Cut this region out, in pixels of the original. */
|
|
311
|
+
readonly crop?: Region;
|
|
312
|
+
}
|
|
313
|
+
|
|
289
314
|
/** Where `ingestUrl` may fetch from — see `ssrfReason` in `@voltro/runtime`. */
|
|
290
315
|
export declare interface IngestPolicy {
|
|
291
316
|
/** Hosts (or `host:port`, or `*.suffix`) reachable although internal — a
|
|
@@ -333,15 +358,21 @@ export declare interface ListRefsResult {
|
|
|
333
358
|
|
|
334
359
|
/** DataStore-backed metadata boundary, intentionally no provider access. The
|
|
335
360
|
* service must use reserve -> provider.put -> confirm and retain failed intents. */
|
|
336
|
-
export declare const makeStorageObjectMetadata: (store: DataStore) => {
|
|
361
|
+
export declare const makeStorageObjectMetadata: (store: DataStore, configuredScope: StorageReferenceScope) => {
|
|
362
|
+
scope: Readonly<{
|
|
363
|
+
storageInstance: string;
|
|
364
|
+
objectNamespace: string;
|
|
365
|
+
}>;
|
|
337
366
|
/** The put intent a reference was written under, if it was written through an operation at all. */
|
|
338
367
|
intent: (refId: string) => Promise<{
|
|
339
368
|
identity: {
|
|
369
|
+
readonly storageInstance: string;
|
|
370
|
+
readonly objectNamespace: string;
|
|
340
371
|
readonly tenantId: string | null;
|
|
341
372
|
readonly bucket: string;
|
|
373
|
+
readonly operationId: string;
|
|
342
374
|
readonly fingerprint: string;
|
|
343
375
|
readonly checksum: string;
|
|
344
|
-
readonly operationId: string;
|
|
345
376
|
readonly logicalKey: string;
|
|
346
377
|
};
|
|
347
378
|
ref: StorageRef;
|
|
@@ -361,32 +392,38 @@ export declare const makeStorageObjectMetadata: (store: DataStore) => {
|
|
|
361
392
|
beginDelete: (refId: string, tenantId?: string | null, claim?: string) => Promise<{
|
|
362
393
|
released: true;
|
|
363
394
|
identity: {
|
|
395
|
+
readonly storageInstance: string;
|
|
396
|
+
readonly objectNamespace: string;
|
|
364
397
|
readonly tenantId: string | null;
|
|
365
398
|
readonly bucket: string;
|
|
399
|
+
readonly operationId: string;
|
|
366
400
|
readonly fingerprint: string;
|
|
367
401
|
readonly checksum: string;
|
|
368
|
-
readonly operationId: string;
|
|
369
402
|
readonly logicalKey: string;
|
|
370
403
|
};
|
|
371
404
|
operation?: never;
|
|
372
405
|
} | {
|
|
373
406
|
released: true;
|
|
374
407
|
operation: {
|
|
375
|
-
readonly key: string;
|
|
376
408
|
readonly id: string;
|
|
409
|
+
readonly storageInstance: string;
|
|
410
|
+
readonly objectNamespace: string;
|
|
411
|
+
readonly objectId: string;
|
|
377
412
|
readonly fingerprint: string;
|
|
378
413
|
readonly generation: string;
|
|
379
|
-
readonly
|
|
414
|
+
readonly key: string;
|
|
380
415
|
readonly refId: string;
|
|
381
|
-
readonly
|
|
416
|
+
readonly state: "ready" | "reserved" | "deleting" | "deleted";
|
|
382
417
|
readonly deleteKey: string | null;
|
|
383
418
|
};
|
|
384
419
|
identity: {
|
|
420
|
+
readonly storageInstance: string;
|
|
421
|
+
readonly objectNamespace: string;
|
|
385
422
|
readonly tenantId: string | null;
|
|
386
423
|
readonly bucket: string;
|
|
424
|
+
readonly operationId: string;
|
|
387
425
|
readonly fingerprint: string;
|
|
388
426
|
readonly checksum: string;
|
|
389
|
-
readonly operationId: string;
|
|
390
427
|
readonly logicalKey: string;
|
|
391
428
|
};
|
|
392
429
|
}>;
|
|
@@ -541,6 +578,9 @@ export declare interface RefStatistics {
|
|
|
541
578
|
}
|
|
542
579
|
|
|
543
580
|
export declare interface RefStore {
|
|
581
|
+
/** Stable identity of this actual reference view. Shared catalogues expose
|
|
582
|
+
* the same identity; independent/process-local stores must expose their own. */
|
|
583
|
+
readonly catalogueId: Effect.Effect<string, StorageError>;
|
|
544
584
|
/** Aggregate the complete reference index without a recent-object limit. */
|
|
545
585
|
readonly statistics: () => Effect.Effect<RefStatistics, StorageError>;
|
|
546
586
|
readonly insert: (ref: StorageRef) => Effect.Effect<void, StorageError>;
|
|
@@ -593,6 +633,14 @@ export declare interface RefStore {
|
|
|
593
633
|
readonly countPublicByKey?: ((bucket: string, key: string) => Effect.Effect<number, StorageError>) | undefined;
|
|
594
634
|
}
|
|
595
635
|
|
|
636
|
+
/** A region of an image in pixels. */
|
|
637
|
+
declare interface Region {
|
|
638
|
+
readonly left: number;
|
|
639
|
+
readonly top: number;
|
|
640
|
+
readonly width: number;
|
|
641
|
+
readonly height: number;
|
|
642
|
+
}
|
|
643
|
+
|
|
596
644
|
/** One derived output a `Transcoder` produces from a source asset. Each becomes
|
|
597
645
|
* a normal storage ref linked back to the original via `derivedFrom`. */
|
|
598
646
|
export declare interface Rendition {
|
|
@@ -604,6 +652,9 @@ export declare interface Rendition {
|
|
|
604
652
|
readonly label?: string;
|
|
605
653
|
}
|
|
606
654
|
|
|
655
|
+
/** Nullable additions deliberately fail closed until the explicit upgrade. */
|
|
656
|
+
export declare const requireStorageObjectNamespaces: (store: DataStore) => Promise<void>;
|
|
657
|
+
|
|
607
658
|
/** A `ListRefsInput` after the service normalizes its defaults / clamps — what
|
|
608
659
|
* a `RefStore.listRefs` impl receives. `limit` is already the `+1` probe. */
|
|
609
660
|
export declare interface ResolvedListQuery {
|
|
@@ -655,23 +706,25 @@ export declare interface S3ProviderOptions {
|
|
|
655
706
|
readonly publicAcl?: boolean;
|
|
656
707
|
}
|
|
657
708
|
|
|
709
|
+
declare type ScopedStorageObjectIdentity = StorageObjectIdentity & StorageReferenceScope;
|
|
710
|
+
|
|
658
711
|
/** Register the app's storage provider (or clear with `undefined`). */
|
|
659
712
|
export declare const setActiveStorageProvider: (provider: StorageProvider | undefined) => void;
|
|
660
713
|
|
|
661
714
|
/** Sign a finalize token valid for `ttlSeconds`. */
|
|
662
|
-
export declare const signFinalizeTicket: (fields: Omit<FinalizeTicketPayload, "exp">, ttlSeconds: number, secret?: string) => string;
|
|
715
|
+
export declare const signFinalizeTicket: (fields: Omit<FinalizeTicketPayload, "exp" | "version">, ttlSeconds: number, secret?: string) => string;
|
|
663
716
|
|
|
664
717
|
/** Mint a token granting read access to `refId` for `ttlSeconds`. */
|
|
665
718
|
export declare const signGrant: (refId: string, ttlSeconds: number, secret?: string, audience?: string) => string;
|
|
666
719
|
|
|
667
720
|
/** Sign a multipart ticket valid for `ttlSeconds`. */
|
|
668
|
-
export declare const signMultipartTicket: (fields: Omit<MultipartTicketPayload, "exp">, ttlSeconds: number, secret?: string) => string;
|
|
721
|
+
export declare const signMultipartTicket: (fields: Omit<MultipartTicketPayload, "exp" | "version">, ttlSeconds: number, secret?: string) => string;
|
|
669
722
|
|
|
670
723
|
/** Sign a resumable ticket valid for `ttlSeconds`. */
|
|
671
|
-
export declare const signResumableTicket: (fields: Omit<ResumableTicketPayload, "exp">, ttlSeconds: number, secret?: string) => string;
|
|
724
|
+
export declare const signResumableTicket: (fields: Omit<ResumableTicketPayload, "exp" | "version">, ttlSeconds: number, secret?: string) => string;
|
|
672
725
|
|
|
673
726
|
/** Sign an upload ticket valid for `ttlSeconds`. */
|
|
674
|
-
export declare const signUploadTicket: (fields: Omit<UploadTicketPayload, "exp">, ttlSeconds: number, secret?: string) => string;
|
|
727
|
+
export declare const signUploadTicket: (fields: Omit<UploadTicketPayload, "exp" | "version">, ttlSeconds: number, secret?: string) => string;
|
|
675
728
|
|
|
676
729
|
/** True if the bytes match the declared content type's magic number, OR we
|
|
677
730
|
* have no signature for that type (can't verify → don't block). */
|
|
@@ -681,6 +734,8 @@ export declare const STORAGE_BLOBS_TABLE = "_voltro_storage_blobs";
|
|
|
681
734
|
|
|
682
735
|
export declare const STORAGE_GRANTS_TABLE = "_voltro_storage_grants";
|
|
683
736
|
|
|
737
|
+
export declare const STORAGE_REFERENCE_CATALOGUE_TABLE = "_voltro_storage_reference_catalogue";
|
|
738
|
+
|
|
684
739
|
export declare const STORAGE_REFS_TABLE = "_voltro_storage_refs";
|
|
685
740
|
|
|
686
741
|
export declare const STORAGE_USAGE_TABLE = "_voltro_storage_usage";
|
|
@@ -693,12 +748,10 @@ export declare const STORAGE_USAGE_TABLE = "_voltro_storage_usage";
|
|
|
693
748
|
export declare class StorageAccessDenied extends StorageAccessDenied_base {
|
|
694
749
|
}
|
|
695
750
|
|
|
696
|
-
declare const StorageAccessDenied_base: Schema.
|
|
697
|
-
readonly
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
reason: typeof Schema.String;
|
|
701
|
-
}>;
|
|
751
|
+
declare const StorageAccessDenied_base: Schema.Class<StorageAccessDenied, Schema.TaggedStruct<"StorageAccessDenied", {
|
|
752
|
+
readonly refId: Schema.String;
|
|
753
|
+
readonly reason: Schema.String;
|
|
754
|
+
}>, YieldableError>;
|
|
702
755
|
|
|
703
756
|
/**
|
|
704
757
|
* Where the bytes go, read from the same options and env `resolveProvider`
|
|
@@ -715,14 +768,12 @@ export declare const storageEgressOf: (options: StoragePluginOptions) => Readonl
|
|
|
715
768
|
export declare class StorageError extends StorageError_base {
|
|
716
769
|
}
|
|
717
770
|
|
|
718
|
-
declare const StorageError_base: Schema.
|
|
719
|
-
readonly
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
status: Schema.optional<typeof Schema.Number>;
|
|
725
|
-
}>;
|
|
771
|
+
declare const StorageError_base: Schema.Class<StorageError, Schema.TaggedStruct<"StorageError", {
|
|
772
|
+
readonly provider: Schema.String;
|
|
773
|
+
readonly message: Schema.String;
|
|
774
|
+
readonly transient: Schema.Boolean;
|
|
775
|
+
readonly status: Schema.optional<Schema.Number>;
|
|
776
|
+
}>, YieldableError>;
|
|
726
777
|
|
|
727
778
|
/** A persisted, explicit share of one object with one principal. */
|
|
728
779
|
export declare interface StorageGrant {
|
|
@@ -752,8 +803,9 @@ export declare type StorageGuard = (ctx: {
|
|
|
752
803
|
* and `BASE_NAME` is not exported, so a caller minting a ticket outside the
|
|
753
804
|
* plugin had to guess it. Guessing is exactly what a `string` parameter invites.
|
|
754
805
|
*
|
|
806
|
+
* const writeScope = await Effect.runPromise(service.uploadTicketScope())
|
|
755
807
|
* const ticket = signUploadTicket(
|
|
756
|
-
* { instance: storageInstanceName(), key, contentType },
|
|
808
|
+
* { writeScope, instance: storageInstanceName(options), key, ct: contentType, sub: ownerId, tenant: tenantId, vis: 'private' },
|
|
757
809
|
* 300,
|
|
758
810
|
* )
|
|
759
811
|
*
|
|
@@ -782,11 +834,14 @@ export declare const storageObjectLifecycleTables: ( Table<"_voltro_storage_oper
|
|
|
782
834
|
readonly nonce: ColumnBuilder<string, "text", boolean>;
|
|
783
835
|
}>, false, never> | Table<"_voltro_storage_object_heads", FieldDefinitions<{
|
|
784
836
|
readonly id: ColumnBuilder<string, "text", boolean>;
|
|
837
|
+
readonly objectNamespace: ColumnBuilder<string | null, "text", boolean>;
|
|
785
838
|
readonly generation: ColumnBuilder<string, "text", boolean>;
|
|
786
839
|
readonly key: ColumnBuilder<string, "text", boolean>;
|
|
787
840
|
readonly reservations: ColumnBuilder<string, "bigint", boolean>;
|
|
788
841
|
}>, false, never> | Table<"_voltro_storage_operations", FieldDefinitions<{
|
|
789
842
|
readonly id: ColumnBuilder<string, "text", boolean>;
|
|
843
|
+
readonly storageInstance: ColumnBuilder<string | null, "text", boolean>;
|
|
844
|
+
readonly objectNamespace: ColumnBuilder<string | null, "text", boolean>;
|
|
790
845
|
readonly objectId: ColumnBuilder<string, "text", boolean>;
|
|
791
846
|
readonly fingerprint: ColumnBuilder<string, "text", boolean>;
|
|
792
847
|
readonly generation: ColumnBuilder<string, "text", boolean>;
|
|
@@ -802,6 +857,19 @@ export declare const storageObjectLifecycleTables: ( Table<"_voltro_storage_oper
|
|
|
802
857
|
|
|
803
858
|
export declare type StorageObjectMetadata = ReturnType<typeof makeStorageObjectMetadata>;
|
|
804
859
|
|
|
860
|
+
/** Credential-independent identity of a physical object-key namespace.
|
|
861
|
+
* Equal identities mean an equal key addresses the same provider bytes. */
|
|
862
|
+
export declare const storageObjectNamespace: (parts: readonly string[]) => string;
|
|
863
|
+
|
|
864
|
+
export declare interface StorageObjectNamespaceAssignment extends StorageReferenceScope {
|
|
865
|
+
readonly refId: string;
|
|
866
|
+
}
|
|
867
|
+
|
|
868
|
+
export declare interface StorageObjectNamespaceMigrationResult {
|
|
869
|
+
readonly assigned: number;
|
|
870
|
+
readonly pendingDeletes: readonly StorageObjectNamespaceAssignment[];
|
|
871
|
+
}
|
|
872
|
+
|
|
805
873
|
export declare const storagePlugin: (options?: StoragePluginOptions) => VoltroPlugin;
|
|
806
874
|
|
|
807
875
|
export declare interface StoragePluginOptions {
|
|
@@ -866,12 +934,25 @@ export declare interface StoragePluginOptions {
|
|
|
866
934
|
/** Access engine config — a group resolver + named custom guards. */
|
|
867
935
|
readonly access?: AccessOptions;
|
|
868
936
|
/**
|
|
869
|
-
* The
|
|
870
|
-
*
|
|
937
|
+
* The default policy for PRIVATE client uploads, or an Effect function
|
|
938
|
+
* authorizing self-service upload visibility and requested policies before the server signs a ticket. Without
|
|
871
939
|
* it only the uploader (the implicit owner rule) can read a private upload;
|
|
872
940
|
* `[{ tenant: true }]` lets everyone in the uploader's tenant read it.
|
|
873
941
|
*/
|
|
874
|
-
readonly uploadAccess?: AccessPolicy
|
|
942
|
+
readonly uploadAccess?: AccessPolicy | ((request: {
|
|
943
|
+
readonly subject: Subject;
|
|
944
|
+
readonly requested: AccessPolicy | undefined;
|
|
945
|
+
readonly visibility: 'public' | 'private';
|
|
946
|
+
readonly contentType: string;
|
|
947
|
+
}) => Effect.Effect<AccessPolicy, StorageError>);
|
|
948
|
+
/**
|
|
949
|
+
* How long a browser or shared cache may keep a PUBLIC object the serve
|
|
950
|
+
* route delivers itself (and each transform of it). Default: a year,
|
|
951
|
+
* `immutable`. An object can turn private later; a copy cached before then
|
|
952
|
+
* keeps opening until this runs out — set it to bound that window (the
|
|
953
|
+
* bucket's own caching, behind a direct URL, is the provider's).
|
|
954
|
+
*/
|
|
955
|
+
readonly publicCacheSeconds?: number;
|
|
875
956
|
/** Upload constraints — size cap, content-type allow-list, magic-byte sniff. */
|
|
876
957
|
readonly limits?: UploadLimits;
|
|
877
958
|
/**
|
|
@@ -943,6 +1024,8 @@ export declare interface StoragePluginOptions {
|
|
|
943
1024
|
* access policy.
|
|
944
1025
|
*/
|
|
945
1026
|
export declare interface StorageProvider {
|
|
1027
|
+
/** Stable physical object-key namespace; exclude credentials and plugin aliases. */
|
|
1028
|
+
readonly objectNamespace: Effect.Effect<string, StorageError>;
|
|
946
1029
|
/**
|
|
947
1030
|
* Where a FILESYSTEM provider writes. Absent for every other provider.
|
|
948
1031
|
*
|
|
@@ -1033,7 +1116,9 @@ export declare type StorageProviderName = 's3' | 'minio' | 'azure' | 'filesystem
|
|
|
1033
1116
|
export declare const storagePutIntentsTable: Table<"_voltro_storage_put_intents", FieldDefinitions<{
|
|
1034
1117
|
readonly id: ColumnBuilder<string, "text", boolean>;
|
|
1035
1118
|
readonly refId: ColumnBuilder<string, "text", boolean>;
|
|
1036
|
-
readonly
|
|
1119
|
+
readonly storageInstance: ColumnBuilder<string | null, "text", boolean>;
|
|
1120
|
+
readonly objectNamespace: ColumnBuilder<string | null, "text", boolean>;
|
|
1121
|
+
readonly identity: ColumnBuilder<ScopedStorageObjectIdentity, "json", boolean>;
|
|
1037
1122
|
readonly ref: ColumnBuilder<StorageRef, "json", boolean>;
|
|
1038
1123
|
}>, false, never>;
|
|
1039
1124
|
|
|
@@ -1083,18 +1168,32 @@ export declare interface StorageRef {
|
|
|
1083
1168
|
readonly kind?: string | null;
|
|
1084
1169
|
}
|
|
1085
1170
|
|
|
1171
|
+
export declare const storageReferenceCatalogueTable: Table<"_voltro_storage_reference_catalogue", FieldDefinitions<{
|
|
1172
|
+
readonly id: ColumnBuilder<string, "text", boolean>;
|
|
1173
|
+
readonly namespace: ColumnBuilder<string, "text", boolean>;
|
|
1174
|
+
}>, false, never>;
|
|
1175
|
+
|
|
1176
|
+
export declare interface StorageReferenceInstanceAssignment {
|
|
1177
|
+
readonly refId: string;
|
|
1178
|
+
readonly storageInstance: string;
|
|
1179
|
+
}
|
|
1180
|
+
|
|
1181
|
+
export declare interface StorageReferenceScope {
|
|
1182
|
+
readonly storageInstance: string;
|
|
1183
|
+
readonly objectNamespace: string;
|
|
1184
|
+
}
|
|
1185
|
+
|
|
1086
1186
|
/** An upload was rejected by a constraint (size / content-type / magic-byte
|
|
1087
1187
|
* mismatch). `reason` is a stable code; `detail` is human-readable. */
|
|
1088
1188
|
export declare class StorageRejected extends StorageRejected_base {
|
|
1189
|
+
get message(): string;
|
|
1089
1190
|
}
|
|
1090
1191
|
|
|
1091
|
-
declare const StorageRejected_base: Schema.
|
|
1092
|
-
readonly _tag: Schema.tag<"StorageRejected">;
|
|
1093
|
-
} & {
|
|
1192
|
+
declare const StorageRejected_base: Schema.Class<StorageRejected, Schema.TaggedStruct<"StorageRejected", {
|
|
1094
1193
|
/** `'too-large' | 'content-type-not-allowed' | 'content-mismatch'` */
|
|
1095
|
-
reason:
|
|
1096
|
-
detail:
|
|
1097
|
-
}>;
|
|
1194
|
+
readonly reason: Schema.String;
|
|
1195
|
+
readonly detail: Schema.String;
|
|
1196
|
+
}>, YieldableError>;
|
|
1098
1197
|
|
|
1099
1198
|
/** Scans bytes before they're stored. Return `{ clean:false, threat }` to
|
|
1100
1199
|
* reject the upload (fails with `StorageScanRejected`, nothing is stored). */
|
|
@@ -1108,11 +1207,9 @@ export declare type StorageScanner = (input: {
|
|
|
1108
1207
|
export declare class StorageScanRejected extends StorageScanRejected_base {
|
|
1109
1208
|
}
|
|
1110
1209
|
|
|
1111
|
-
declare const StorageScanRejected_base: Schema.
|
|
1112
|
-
readonly
|
|
1113
|
-
}
|
|
1114
|
-
threat: typeof Schema.String;
|
|
1115
|
-
}>;
|
|
1210
|
+
declare const StorageScanRejected_base: Schema.Class<StorageScanRejected, Schema.TaggedStruct<"StorageScanRejected", {
|
|
1211
|
+
readonly threat: Schema.String;
|
|
1212
|
+
}>, YieldableError>;
|
|
1116
1213
|
|
|
1117
1214
|
export declare interface StorageScanResult {
|
|
1118
1215
|
readonly clean: boolean;
|
|
@@ -1123,7 +1220,7 @@ export declare interface StorageScanResult {
|
|
|
1123
1220
|
export declare class StorageService extends StorageService_base {
|
|
1124
1221
|
}
|
|
1125
1222
|
|
|
1126
|
-
declare const StorageService_base: Context.
|
|
1223
|
+
declare const StorageService_base: Context.ServiceClass<StorageService, "@voltro/plugin-storage/StorageService", StorageServiceShape>;
|
|
1127
1224
|
|
|
1128
1225
|
export declare const storageServiceLayer: (options: StorageServiceOptions) => Layer.Layer<StorageService>;
|
|
1129
1226
|
|
|
@@ -1132,6 +1229,8 @@ export declare interface StorageServiceOptions {
|
|
|
1132
1229
|
readonly refStore: RefStore;
|
|
1133
1230
|
readonly grantStore: GrantStore;
|
|
1134
1231
|
readonly bucket: string;
|
|
1232
|
+
/** Canonical plugin instance; separates new plain keys on a shared provider. */
|
|
1233
|
+
readonly storageInstance?: string;
|
|
1135
1234
|
/** Static prefix prepended to every key (e.g. an app/env namespace). */
|
|
1136
1235
|
readonly tenantPrefix?: string;
|
|
1137
1236
|
/** Transient-failure retries (429 / 5xx / network). Default 3. */
|
|
@@ -1184,6 +1283,8 @@ export declare interface StorageServiceOptions {
|
|
|
1184
1283
|
|
|
1185
1284
|
/** The service handlers consume: `const storage = yield* StorageService`. */
|
|
1186
1285
|
export declare interface StorageServiceShape {
|
|
1286
|
+
/** Opaque destination binding for manually signed upload-family credentials. */
|
|
1287
|
+
readonly uploadTicketScope: () => Effect.Effect<string, StorageError>;
|
|
1187
1288
|
/** Store bytes. The result is the ref plus this call's `outcome`. */
|
|
1188
1289
|
readonly put: (input: PutInput) => Effect.Effect<StoredRef, StorageError | StorageRejected | StorageScanRejected>;
|
|
1189
1290
|
/** Fetch an object's bytes by id. Enforces the tenant guard ONLY — it does
|
|
@@ -1370,6 +1471,7 @@ export declare interface StorageServiceShape {
|
|
|
1370
1471
|
readonly tenantId?: string | null;
|
|
1371
1472
|
readonly ownerId?: string | null;
|
|
1372
1473
|
readonly visibility?: StorageVisibility;
|
|
1474
|
+
readonly access?: AccessPolicy;
|
|
1373
1475
|
readonly folder?: string;
|
|
1374
1476
|
readonly tags?: ReadonlyArray<string>;
|
|
1375
1477
|
readonly alt?: string;
|
|
@@ -1403,6 +1505,7 @@ export declare interface StorageServiceShape {
|
|
|
1403
1505
|
readonly tenantId?: string | null;
|
|
1404
1506
|
readonly ownerId?: string | null;
|
|
1405
1507
|
readonly visibility?: StorageVisibility;
|
|
1508
|
+
readonly access?: AccessPolicy;
|
|
1406
1509
|
readonly folder?: string;
|
|
1407
1510
|
readonly tags?: ReadonlyArray<string>;
|
|
1408
1511
|
readonly alt?: string;
|
|
@@ -1452,6 +1555,7 @@ export declare interface StorageServiceShape {
|
|
|
1452
1555
|
readonly tenantId?: string | null;
|
|
1453
1556
|
readonly ownerId?: string | null;
|
|
1454
1557
|
readonly visibility?: StorageVisibility;
|
|
1558
|
+
readonly access?: AccessPolicy;
|
|
1455
1559
|
readonly folder?: string;
|
|
1456
1560
|
readonly tags?: ReadonlyArray<string>;
|
|
1457
1561
|
readonly alt?: string;
|
|
@@ -1564,10 +1668,14 @@ export declare interface UploadLimits {
|
|
|
1564
1668
|
/** What an upload ticket authorizes: a single through-app upload bound to an
|
|
1565
1669
|
* owner/tenant/content-type/visibility, until `exp`. */
|
|
1566
1670
|
export declare interface UploadTicketPayload {
|
|
1671
|
+
/** Frozen-policy ticket contract. Previous tickets must be minted again. */
|
|
1672
|
+
readonly version: 2;
|
|
1567
1673
|
/** Optional durable write identity, preserved across ticket renewal. */
|
|
1568
1674
|
readonly operationId?: string;
|
|
1569
|
-
/**
|
|
1570
|
-
readonly
|
|
1675
|
+
/** Exact reference catalogue and physical byte destination authorized by the issuer. */
|
|
1676
|
+
readonly writeScope: string;
|
|
1677
|
+
/** Optional signed routing hint for the binary relay; destination authorization still uses writeScope. */
|
|
1678
|
+
readonly issuerReplicaId?: string;
|
|
1571
1679
|
/** Exact storage plugin instance authorized to accept the bytes. */
|
|
1572
1680
|
readonly instance: string;
|
|
1573
1681
|
/** ownerId (subject id) the stored object is attributed to. */
|
|
@@ -1577,6 +1685,8 @@ export declare interface UploadTicketPayload {
|
|
|
1577
1685
|
/** Authorized content-type — the stored object uses this. */
|
|
1578
1686
|
readonly ct: string;
|
|
1579
1687
|
readonly vis: 'public' | 'private';
|
|
1688
|
+
/** Server-authorized policy, frozen into the signed ticket. */
|
|
1689
|
+
readonly access?: AccessPolicy;
|
|
1580
1690
|
/** Optional fixed logical key (else content-addressed). */
|
|
1581
1691
|
readonly key?: string;
|
|
1582
1692
|
/** Max bytes the route will accept for this ticket (0/undefined = no cap). */
|