@voltro/plugin-storage 0.81.0 → 0.83.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 +1806 -6
- package/THIRD-PARTY-NOTICES.md +1 -1
- package/dist/index.d.ts +88 -1
- package/dist/index.js +665 -510
- package/dist/types.d.ts +30 -0
- package/package.json +4 -4
package/THIRD-PARTY-NOTICES.md
CHANGED
|
@@ -10789,7 +10789,7 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
|
10789
10789
|
SOFTWARE.
|
|
10790
10790
|
```
|
|
10791
10791
|
|
|
10792
|
-
## undici@8.
|
|
10792
|
+
## undici@8.11.2
|
|
10793
10793
|
|
|
10794
10794
|
License: MIT
|
|
10795
10795
|
|
package/dist/index.d.ts
CHANGED
|
@@ -6,6 +6,7 @@ import { Effect } from 'effect';
|
|
|
6
6
|
import { FieldDefinitions } from '@voltro/database';
|
|
7
7
|
import { Layer } from 'effect';
|
|
8
8
|
import { mixin } from '@voltro/database';
|
|
9
|
+
import { PluginEgressDeclaration } from '@voltro/protocol';
|
|
9
10
|
import { Readable } from 'node:stream';
|
|
10
11
|
import { Schema } from 'effect';
|
|
11
12
|
import { Stream } from 'effect';
|
|
@@ -285,6 +286,16 @@ export declare interface GrantTokenPayload {
|
|
|
285
286
|
/** Hash a file password as `salt:scryptHash` (hex). */
|
|
286
287
|
export declare const hashPassword: (password: string) => string;
|
|
287
288
|
|
|
289
|
+
/** Where `ingestUrl` may fetch from — see `ssrfReason` in `@voltro/runtime`. */
|
|
290
|
+
export declare interface IngestPolicy {
|
|
291
|
+
/** Hosts (or `host:port`, or `*.suffix`) reachable although internal — a
|
|
292
|
+
* deliberate internal source, or a local test server. Everything else that
|
|
293
|
+
* is loopback, private, link-local (cloud metadata) or `.internal` is refused. */
|
|
294
|
+
readonly allowHosts?: ReadonlyArray<string>;
|
|
295
|
+
/** Redirect hops followed, each checked again. Default 5. */
|
|
296
|
+
readonly maxRedirects?: number;
|
|
297
|
+
}
|
|
298
|
+
|
|
288
299
|
/**
|
|
289
300
|
* Filter + page a `StorageService.listRefs` / media-library query. Every
|
|
290
301
|
* filter is optional and ANDed; omit them all to page the whole (tenant-scoped)
|
|
@@ -365,7 +376,7 @@ export declare const makeStorageObjectMetadata: (store: DataStore) => {
|
|
|
365
376
|
readonly id: string;
|
|
366
377
|
readonly fingerprint: string;
|
|
367
378
|
readonly generation: string;
|
|
368
|
-
readonly state: "ready" | "reserved" | "
|
|
379
|
+
readonly state: "ready" | "reserved" | "deleted" | "deleting";
|
|
369
380
|
readonly refId: string;
|
|
370
381
|
readonly objectId: string;
|
|
371
382
|
readonly deleteKey: string | null;
|
|
@@ -574,6 +585,12 @@ export declare interface RefStore {
|
|
|
574
585
|
* newest-first, offset-paged. Backs `StorageService.listRefs`. Fetches
|
|
575
586
|
* `limit + 1` so the service can report whether another page follows. */
|
|
576
587
|
readonly listRefs: (query: ResolvedListQuery) => Effect.Effect<ReadonlyArray<StorageRef>, StorageError>;
|
|
588
|
+
/** Change one ref's visibility; the updated ref, or null when there is none.
|
|
589
|
+
* Optional: a store without it cannot back `StorageService.setVisibility`. */
|
|
590
|
+
readonly setVisibility?: ((id: string, visibility: StorageVisibility) => Effect.Effect<StorageRef | null, StorageError>) | undefined;
|
|
591
|
+
/** How many PUBLIC refs point at this provider key — whether the object must
|
|
592
|
+
* stay publicly readable. */
|
|
593
|
+
readonly countPublicByKey?: ((bucket: string, key: string) => Effect.Effect<number, StorageError>) | undefined;
|
|
577
594
|
}
|
|
578
595
|
|
|
579
596
|
/** One derived output a `Transcoder` produces from a source asset. Each becomes
|
|
@@ -683,6 +700,13 @@ declare const StorageAccessDenied_base: Schema.TaggedErrorClass<StorageAccessDen
|
|
|
683
700
|
reason: typeof Schema.String;
|
|
684
701
|
}>;
|
|
685
702
|
|
|
703
|
+
/**
|
|
704
|
+
* Where the bytes go, read from the same options and env `resolveProvider`
|
|
705
|
+
* reads: an object store is a destination outside the installation; the
|
|
706
|
+
* database, the filesystem and memory keep the bytes inside it.
|
|
707
|
+
*/
|
|
708
|
+
export declare const storageEgressOf: (options: StoragePluginOptions) => ReadonlyArray<PluginEgressDeclaration>;
|
|
709
|
+
|
|
686
710
|
/**
|
|
687
711
|
* Storage failure. `transient` drives retry — `true` for 429 / 5xx /
|
|
688
712
|
* network blips, `false` for 4xx / config / not-found. Surfaced typed so
|
|
@@ -841,8 +865,23 @@ export declare interface StoragePluginOptions {
|
|
|
841
865
|
readonly urlExpiresInSec?: number;
|
|
842
866
|
/** Access engine config — a group resolver + named custom guards. */
|
|
843
867
|
readonly access?: AccessOptions;
|
|
868
|
+
/**
|
|
869
|
+
* The access policy every PRIVATE client upload (an upload ticket) is
|
|
870
|
+
* stored with — declared by the app, never chosen by the client. Without
|
|
871
|
+
* it only the uploader (the implicit owner rule) can read a private upload;
|
|
872
|
+
* `[{ tenant: true }]` lets everyone in the uploader's tenant read it.
|
|
873
|
+
*/
|
|
874
|
+
readonly uploadAccess?: AccessPolicy;
|
|
844
875
|
/** Upload constraints — size cap, content-type allow-list, magic-byte sniff. */
|
|
845
876
|
readonly limits?: UploadLimits;
|
|
877
|
+
/**
|
|
878
|
+
* Where `StorageService.ingestUrl` may fetch from. Every address — the URL
|
|
879
|
+
* and each redirect — is checked: loopback, private, link-local (cloud
|
|
880
|
+
* metadata), `localhost` and `.internal`/`.local` hosts are refused with
|
|
881
|
+
* `StorageRejected` (`blocked-source`). `allowHosts` names deliberate
|
|
882
|
+
* internal sources (or a local test server).
|
|
883
|
+
*/
|
|
884
|
+
readonly ingest?: IngestPolicy;
|
|
846
885
|
/**
|
|
847
886
|
* Let a caller with NO identity mint an upload ticket. Default `false`.
|
|
848
887
|
*
|
|
@@ -933,6 +972,10 @@ export declare interface StorageProvider {
|
|
|
933
972
|
* publicly without the app (filesystem/memory) → the service falls
|
|
934
973
|
* back to the `/_voltro/storage/:id` route. */
|
|
935
974
|
readonly publicUrl?: (key: string) => string | null;
|
|
975
|
+
/** Make an object publicly readable at the provider, or not (s3/minio with
|
|
976
|
+
* per-object ACLs). Absent where the app decides per request (database,
|
|
977
|
+
* filesystem, memory) — there a ref's visibility is the whole answer. */
|
|
978
|
+
readonly setObjectPublic?: (key: string, isPublic: boolean) => Effect.Effect<void, StorageError>;
|
|
936
979
|
/** Presigned PUT for direct-to-bucket uploads (s3/minio). Absent on
|
|
937
980
|
* providers that can't presign uploads. */
|
|
938
981
|
readonly getUploadUrl?: (key: string, expiresInSec: number, contentType: string) => Effect.Effect<string, StorageError>;
|
|
@@ -1099,6 +1142,8 @@ export declare interface StorageServiceOptions {
|
|
|
1099
1142
|
readonly access?: AccessOptions;
|
|
1100
1143
|
/** Upload constraints — size cap, content-type allow-list, magic-byte sniff. */
|
|
1101
1144
|
readonly limits?: UploadLimits;
|
|
1145
|
+
/** Where `ingestUrl` may fetch from (internal addresses are refused). */
|
|
1146
|
+
readonly ingest?: IngestPolicy;
|
|
1102
1147
|
/** Virus scanner run on `put` before the bytes are stored. */
|
|
1103
1148
|
readonly scan?: StorageScanner;
|
|
1104
1149
|
/** App-supplied probe for video/audio uploads (duration + poster frame).
|
|
@@ -1231,6 +1276,30 @@ export declare interface StorageServiceShape {
|
|
|
1231
1276
|
* caller's `tenantId` / `ownerId` for an end-user surface, and deliver any
|
|
1232
1277
|
* listed private object through `mintUrl`. */
|
|
1233
1278
|
readonly listRefs: (input?: ListRefsInput) => Effect.Effect<ListRefsResult, StorageError>;
|
|
1279
|
+
/**
|
|
1280
|
+
* A short-lived URL that delivers the bytes WITHOUT an access check — for
|
|
1281
|
+
* server code that has already decided the reader may see them (a shared
|
|
1282
|
+
* preview whose link was verified). Public: its public URL. Private: a
|
|
1283
|
+
* presigned GET (s3/minio) or the serve URL with a signed grant token. Never
|
|
1284
|
+
* hand one to a caller whose access you have not checked.
|
|
1285
|
+
*/
|
|
1286
|
+
readonly signedUrl: (id: string, opts?: {
|
|
1287
|
+
readonly tenantId?: string | null;
|
|
1288
|
+
readonly expiresInSec?: number;
|
|
1289
|
+
}) => Effect.Effect<string, StorageError>;
|
|
1290
|
+
/**
|
|
1291
|
+
* Make a stored object public or private after the fact — an image that goes
|
|
1292
|
+
* public when its page is published, and private again when it is taken
|
|
1293
|
+
* down. Checks the tenant like `delete`. Where objects are served from a
|
|
1294
|
+
* public base (`cdnBaseUrl`) a public object cannot be taken back: that is
|
|
1295
|
+
* refused (`StorageRejected`, reason `visibility-unsupported`) rather than
|
|
1296
|
+
* left public. On s3 with per-object ACLs the object follows its refs: it
|
|
1297
|
+
* stays public while any ref to the same bytes is. A public object's earlier
|
|
1298
|
+
* responses may remain in browser and CDN caches.
|
|
1299
|
+
*/
|
|
1300
|
+
readonly setVisibility: (id: string, visibility: StorageVisibility, opts?: {
|
|
1301
|
+
readonly tenantId?: string | null;
|
|
1302
|
+
}) => Effect.Effect<StorageRef, StorageError | StorageRejected>;
|
|
1234
1303
|
readonly grant: (input: GrantInput) => Effect.Effect<StorageGrant, StorageError>;
|
|
1235
1304
|
readonly revoke: (grantId: string) => Effect.Effect<void, StorageError>;
|
|
1236
1305
|
/** One grant by id, or null. Server-side read — the RPC layer uses it to
|
|
@@ -1269,6 +1338,8 @@ export declare interface StorageServiceShape {
|
|
|
1269
1338
|
readonly operationId?: string;
|
|
1270
1339
|
readonly ownerId?: string | null;
|
|
1271
1340
|
readonly visibility?: StorageVisibility;
|
|
1341
|
+
/** The access policy of a private object, as on `put`. */
|
|
1342
|
+
readonly access?: AccessPolicy;
|
|
1272
1343
|
readonly key?: string;
|
|
1273
1344
|
readonly folder?: string;
|
|
1274
1345
|
readonly tags?: ReadonlyArray<string>;
|
|
@@ -1447,6 +1518,13 @@ export declare interface Transformed {
|
|
|
1447
1518
|
readonly contentType: string;
|
|
1448
1519
|
}
|
|
1449
1520
|
|
|
1521
|
+
/**
|
|
1522
|
+
* Why a requested transform served the original instead — `null` when it did
|
|
1523
|
+
* not fall back. The storage route sends it as `x-voltro-transform`, so a
|
|
1524
|
+
* resize or format change that did not happen is never silent.
|
|
1525
|
+
*/
|
|
1526
|
+
export declare const transformFallbackReason: (contentType: string, transformed: boolean) => Promise<"not-an-image" | "no-sharp" | "failed" | null>;
|
|
1527
|
+
|
|
1450
1528
|
/**
|
|
1451
1529
|
* Transform image bytes per `params`. Returns null (→ serve original) when
|
|
1452
1530
|
* the content isn't a raster image, `sharp` isn't installed, or processing
|
|
@@ -1460,6 +1538,15 @@ export declare interface TransformParams {
|
|
|
1460
1538
|
readonly format?: string;
|
|
1461
1539
|
readonly q?: number;
|
|
1462
1540
|
readonly fit?: string;
|
|
1541
|
+
/**
|
|
1542
|
+
* The focal point, `fp=x,y` as fractions of the width and height (0–1). With
|
|
1543
|
+
* both `w` and `h` and `fit=cover` (the default), the crop keeps this point
|
|
1544
|
+
* as central as the image allows instead of cutting around the middle.
|
|
1545
|
+
*/
|
|
1546
|
+
readonly fp?: {
|
|
1547
|
+
readonly x: number;
|
|
1548
|
+
readonly y: number;
|
|
1549
|
+
};
|
|
1463
1550
|
}
|
|
1464
1551
|
|
|
1465
1552
|
export declare interface UploadLimits {
|