@panorama-industries/effect-vercel-blob 0.0.0-stage → 0.2.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/LICENSE +21 -0
- package/README.md +13 -2
- package/dist/client.d.ts +8 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +8 -0
- package/dist/client.js.map +1 -0
- package/dist/contracts/blob-client.d.ts +67 -0
- package/dist/contracts/blob-client.d.ts.map +1 -0
- package/dist/contracts/blob-client.js +11 -0
- package/dist/contracts/blob-client.js.map +1 -0
- package/dist/contracts/blob-config.d.ts +114 -0
- package/dist/contracts/blob-config.d.ts.map +1 -0
- package/dist/contracts/blob-config.js +7 -0
- package/dist/contracts/blob-config.js.map +1 -0
- package/dist/contracts/blob-domain.d.ts +336 -0
- package/dist/contracts/blob-domain.d.ts.map +1 -0
- package/dist/contracts/blob-domain.js +152 -0
- package/dist/contracts/blob-domain.js.map +1 -0
- package/dist/contracts/blob-errors.d.ts +125 -0
- package/dist/contracts/blob-errors.d.ts.map +1 -0
- package/dist/contracts/blob-errors.js +114 -0
- package/dist/contracts/blob-errors.js.map +1 -0
- package/dist/contracts/blob-signed-urls.d.ts +83 -0
- package/dist/contracts/blob-signed-urls.d.ts.map +1 -0
- package/dist/contracts/blob-signed-urls.js +10 -0
- package/dist/contracts/blob-signed-urls.js.map +1 -0
- package/dist/contracts/blob-store.d.ts +153 -0
- package/dist/contracts/blob-store.d.ts.map +1 -0
- package/dist/contracts/blob-store.js +15 -0
- package/dist/contracts/blob-store.js.map +1 -0
- package/dist/contracts/blob-uploads.d.ts +101 -0
- package/dist/contracts/blob-uploads.d.ts.map +1 -0
- package/dist/contracts/blob-uploads.js +17 -0
- package/dist/contracts/blob-uploads.js.map +1 -0
- package/dist/implementation/blob-client-live.d.ts +37 -0
- package/dist/implementation/blob-client-live.d.ts.map +1 -0
- package/dist/implementation/blob-client-live.js +213 -0
- package/dist/implementation/blob-client-live.js.map +1 -0
- package/dist/implementation/blob-config-live.d.ts +49 -0
- package/dist/implementation/blob-config-live.d.ts.map +1 -0
- package/dist/implementation/blob-config-live.js +82 -0
- package/dist/implementation/blob-config-live.js.map +1 -0
- package/dist/implementation/blob-live.d.ts +16 -0
- package/dist/implementation/blob-live.d.ts.map +1 -0
- package/dist/implementation/blob-live.js +16 -0
- package/dist/implementation/blob-live.js.map +1 -0
- package/dist/implementation/blob-signed-urls-live.d.ts +12 -0
- package/dist/implementation/blob-signed-urls-live.d.ts.map +1 -0
- package/dist/implementation/blob-signed-urls-live.js +92 -0
- package/dist/implementation/blob-signed-urls-live.js.map +1 -0
- package/dist/implementation/blob-store-live.d.ts +18 -0
- package/dist/implementation/blob-store-live.d.ts.map +1 -0
- package/dist/implementation/blob-store-live.js +364 -0
- package/dist/implementation/blob-store-live.js.map +1 -0
- package/dist/implementation/blob-uploads-live.d.ts +11 -0
- package/dist/implementation/blob-uploads-live.d.ts.map +1 -0
- package/dist/implementation/blob-uploads-live.js +218 -0
- package/dist/implementation/blob-uploads-live.js.map +1 -0
- package/dist/index.d.ts +15 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +15 -0
- package/dist/index.js.map +1 -0
- package/dist/internal/blob-errors.d.ts +79 -0
- package/dist/internal/blob-errors.d.ts.map +1 -0
- package/dist/internal/blob-errors.js +196 -0
- package/dist/internal/blob-errors.js.map +1 -0
- package/dist/internal/blob-request.d.ts +255 -0
- package/dist/internal/blob-request.d.ts.map +1 -0
- package/dist/internal/blob-request.js +291 -0
- package/dist/internal/blob-request.js.map +1 -0
- package/dist/internal/callback.d.ts +70 -0
- package/dist/internal/callback.d.ts.map +1 -0
- package/dist/internal/callback.js +141 -0
- package/dist/internal/callback.js.map +1 -0
- package/dist/internal/client-token.d.ts +65 -0
- package/dist/internal/client-token.d.ts.map +1 -0
- package/dist/internal/client-token.js +80 -0
- package/dist/internal/client-token.js.map +1 -0
- package/dist/internal/env.d.ts +34 -0
- package/dist/internal/env.d.ts.map +1 -0
- package/dist/internal/env.js +61 -0
- package/dist/internal/env.js.map +1 -0
- package/dist/internal/multipart.d.ts +110 -0
- package/dist/internal/multipart.d.ts.map +1 -0
- package/dist/internal/multipart.js +290 -0
- package/dist/internal/multipart.js.map +1 -0
- package/dist/internal/presign.d.ts +123 -0
- package/dist/internal/presign.d.ts.map +1 -0
- package/dist/internal/presign.js +345 -0
- package/dist/internal/presign.js.map +1 -0
- package/dist/internal/store-id.d.ts +38 -0
- package/dist/internal/store-id.d.ts.map +1 -0
- package/dist/internal/store-id.js +54 -0
- package/dist/internal/store-id.js.map +1 -0
- package/dist/internal/urls.d.ts +26 -0
- package/dist/internal/urls.d.ts.map +1 -0
- package/dist/internal/urls.js +33 -0
- package/dist/internal/urls.js.map +1 -0
- package/dist/internal/wire.d.ts +55 -0
- package/dist/internal/wire.d.ts.map +1 -0
- package/dist/internal/wire.js +64 -0
- package/dist/internal/wire.js.map +1 -0
- package/dist/internal/write-headers.d.ts +56 -0
- package/dist/internal/write-headers.d.ts.map +1 -0
- package/dist/internal/write-headers.js +82 -0
- package/dist/internal/write-headers.js.map +1 -0
- package/dist/testing/index.d.ts +2 -0
- package/dist/testing/index.d.ts.map +1 -0
- package/dist/testing/index.js +2 -0
- package/dist/testing/index.js.map +1 -0
- package/dist/testing/test-blob-store.d.ts +134 -0
- package/dist/testing/test-blob-store.d.ts.map +1 -0
- package/dist/testing/test-blob-store.js +718 -0
- package/dist/testing/test-blob-store.js.map +1 -0
- package/package.json +65 -3
- package/src/client.ts +11 -0
- package/src/contracts/blob-client.ts +121 -0
- package/src/contracts/blob-config.ts +64 -0
- package/src/contracts/blob-domain.ts +304 -0
- package/src/contracts/blob-errors.ts +161 -0
- package/src/contracts/blob-signed-urls.ts +112 -0
- package/src/contracts/blob-store.ts +258 -0
- package/src/contracts/blob-uploads.ts +151 -0
- package/src/implementation/blob-client-live.ts +387 -0
- package/src/implementation/blob-config-live.ts +145 -0
- package/src/implementation/blob-live.ts +30 -0
- package/src/implementation/blob-signed-urls-live.ts +121 -0
- package/src/implementation/blob-store-live.ts +528 -0
- package/src/implementation/blob-uploads-live.ts +326 -0
- package/src/index.ts +18 -0
- package/src/internal/blob-errors.ts +325 -0
- package/src/internal/blob-request.ts +617 -0
- package/src/internal/callback.ts +200 -0
- package/src/internal/client-token.ts +132 -0
- package/src/internal/env.ts +128 -0
- package/src/internal/multipart.ts +526 -0
- package/src/internal/presign.ts +477 -0
- package/src/internal/store-id.ts +69 -0
- package/src/internal/urls.ts +42 -0
- package/src/internal/wire.ts +80 -0
- package/src/internal/write-headers.ts +118 -0
- package/src/testing/index.ts +1 -0
- package/src/testing/test-blob-store.ts +1136 -0
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
import type { OidcTokenUnavailable, VercelApiError } from "@panorama-industries/effect-vercel-core";
|
|
2
|
+
import type { Array, Duration, Effect, Stream } from "effect";
|
|
3
|
+
import { Context, Schema } from "effect";
|
|
4
|
+
import type { BlobAccess, BlobBody, BlobLocator, BlobMetadata, BlobPathname, CreateBlobOptions, CreateFolderResult, ETag, GetBlobResult, ListedBlob, ListPage, MultipartUpload, OnUploadProgress, OverwriteOptions, PartNumber, PutBlobResult, UploadedPart } from "./blob-domain.ts";
|
|
5
|
+
import type { BlobNotFound, BlobOidcEnvironmentNotAllowed, BlobPreconditionFailed, BlobStoreUnavailable, BlobUploadRejected } from "./blob-errors.ts";
|
|
6
|
+
/** Failures every Blob API call can report. */
|
|
7
|
+
export type BlobRequestError = VercelApiError | BlobStoreUnavailable | BlobOidcEnvironmentNotAllowed | OidcTokenUnavailable;
|
|
8
|
+
/** Failures of creating or replacing a blob. */
|
|
9
|
+
export type BlobWriteError = BlobRequestError | BlobPreconditionFailed | BlobUploadRejected;
|
|
10
|
+
/** Options for {@link BlobStore} `put`. */
|
|
11
|
+
export type PutOptions = CreateBlobOptions & {
|
|
12
|
+
/**
|
|
13
|
+
* Upload in 8 MiB parts, eight at a time, instead of one request. Use it for large bodies; parts
|
|
14
|
+
* are produced from the body as it streams, so memory stays bounded.
|
|
15
|
+
*/
|
|
16
|
+
readonly multipart?: boolean | undefined;
|
|
17
|
+
/**
|
|
18
|
+
* Refuse a multipart upload whose known size exceeds this many bytes before sending anything.
|
|
19
|
+
* Streams of unknown size are not checked.
|
|
20
|
+
*/
|
|
21
|
+
readonly maximumSizeInBytes?: number | undefined;
|
|
22
|
+
readonly onUploadProgress?: OnUploadProgress | undefined;
|
|
23
|
+
};
|
|
24
|
+
/** Width of an optimized image in pixels: an integer from 1 to 8192. */
|
|
25
|
+
export declare const ImageWidth: Schema.brand<Schema.Int, "ImageWidth">;
|
|
26
|
+
/** Width of an optimized image in pixels. */
|
|
27
|
+
export type ImageWidth = typeof ImageWidth.Type;
|
|
28
|
+
/** Quality of an optimized image: an integer from 1 to 100. */
|
|
29
|
+
export declare const ImageQuality: Schema.brand<Schema.Int, "ImageQuality">;
|
|
30
|
+
/** Quality of an optimized image: an integer from 1 to 100. */
|
|
31
|
+
export type ImageQuality = typeof ImageQuality.Type;
|
|
32
|
+
/** Output format of an optimized image. */
|
|
33
|
+
export declare const ImageFormat: Schema.Literals<readonly ["jpeg", "png", "webp", "avif"]>;
|
|
34
|
+
/** Output format of an optimized image. */
|
|
35
|
+
export type ImageFormat = typeof ImageFormat.Type;
|
|
36
|
+
/** How Vercel Image Optimization transforms an image before it is stored. */
|
|
37
|
+
export interface ImageOptimization {
|
|
38
|
+
readonly width: ImageWidth;
|
|
39
|
+
/** Defaults to 75. */
|
|
40
|
+
readonly quality?: ImageQuality | undefined;
|
|
41
|
+
/** Defaults to the source format. */
|
|
42
|
+
readonly format?: ImageFormat | undefined;
|
|
43
|
+
}
|
|
44
|
+
/** Options for {@link BlobStore} `putImage`; the stored media type comes from the optimizer. */
|
|
45
|
+
export type PutImageOptions = OverwriteOptions & {
|
|
46
|
+
readonly access: BlobAccess;
|
|
47
|
+
readonly addRandomSuffix?: boolean | undefined;
|
|
48
|
+
readonly cacheControlMaxAge?: Duration.Input | undefined;
|
|
49
|
+
readonly optimizeImage: ImageOptimization;
|
|
50
|
+
readonly onUploadProgress?: OnUploadProgress | undefined;
|
|
51
|
+
};
|
|
52
|
+
/** Options for {@link BlobStore} `get`. */
|
|
53
|
+
export interface GetOptions {
|
|
54
|
+
readonly access: BlobAccess;
|
|
55
|
+
/**
|
|
56
|
+
* When false, read a private blob from origin storage instead of the CDN cache: always the latest
|
|
57
|
+
* content, but slower. Ignored for public blobs.
|
|
58
|
+
*/
|
|
59
|
+
readonly useCache?: boolean | undefined;
|
|
60
|
+
/** Return `NotModified` instead of the content when the blob still has this ETag. */
|
|
61
|
+
readonly ifNoneMatch?: string | undefined;
|
|
62
|
+
/** Extra request headers; they override the defaults, including `authorization`. */
|
|
63
|
+
readonly headers?: Readonly<Record<string, string>> | undefined;
|
|
64
|
+
}
|
|
65
|
+
/** Options for {@link BlobStore} `list` and `listAll`. */
|
|
66
|
+
export interface ListOptions {
|
|
67
|
+
/** Entries per page; the store's default and maximum is 1000. */
|
|
68
|
+
readonly limit?: number | undefined;
|
|
69
|
+
/** Only blobs whose pathname starts with this. */
|
|
70
|
+
readonly prefix?: string | undefined;
|
|
71
|
+
/**
|
|
72
|
+
* `folded` returns the folders directly under `prefix` in `folders` and only the blobs at that
|
|
73
|
+
* level in `blobs`.
|
|
74
|
+
*/
|
|
75
|
+
readonly mode?: "expanded" | "folded" | undefined;
|
|
76
|
+
}
|
|
77
|
+
/** Options for {@link BlobStore} `createMultipartUpload`. */
|
|
78
|
+
export type CreateMultipartUploadOptions = CreateBlobOptions;
|
|
79
|
+
declare const BlobStore_base: Context.ServiceClass<BlobStore, "@effect-vercel/blob/BlobStore", {
|
|
80
|
+
/**
|
|
81
|
+
* Store a blob at `pathname`. The store refuses an existing pathname unless `allowOverwrite`
|
|
82
|
+
* or `ifMatch` is set; `ifMatch` fails with `BlobPreconditionFailed` when the blob has a
|
|
83
|
+
* different ETag or does not exist. `access` must be the store's.
|
|
84
|
+
*/
|
|
85
|
+
readonly put: <E = never, R = never>(pathname: BlobPathname, body: BlobBody<E, R>, options: PutOptions) => Effect.Effect<PutBlobResult, BlobWriteError | E, R>;
|
|
86
|
+
/**
|
|
87
|
+
* Optimize an image with Vercel Image Optimization and store only the result. The source is
|
|
88
|
+
* the image content, or a `URL` the store fetches itself. Requires OIDC credentials. A source
|
|
89
|
+
* whose known media type is not an image fails with `BlobUploadRejected` before any request.
|
|
90
|
+
*/
|
|
91
|
+
readonly putImage: <E = never, R = never>(pathname: BlobPathname, source: BlobBody<E, R> | URL, options: PutImageOptions) => Effect.Effect<PutBlobResult, BlobWriteError | E, R>;
|
|
92
|
+
/** Read a blob's metadata without its content. */
|
|
93
|
+
readonly head: (blob: BlobLocator) => Effect.Effect<BlobMetadata, BlobRequestError | BlobNotFound>;
|
|
94
|
+
/**
|
|
95
|
+
* Read a blob's content from its store's host. A pathname is resolved against the configured
|
|
96
|
+
* store; a URL must point at a Blob store (or the configured API origin, for emulators).
|
|
97
|
+
*/
|
|
98
|
+
readonly get: (blob: BlobLocator, options: GetOptions) => Effect.Effect<GetBlobResult, BlobRequestError | BlobNotFound>;
|
|
99
|
+
/** Read one page of blobs. */
|
|
100
|
+
readonly list: (options?: ListOptions & {
|
|
101
|
+
readonly cursor?: string | undefined;
|
|
102
|
+
}) => Effect.Effect<ListPage, BlobRequestError>;
|
|
103
|
+
/** Every blob matching `options`, fetching pages as the stream is read. */
|
|
104
|
+
readonly listAll: (options?: ListOptions) => Stream.Stream<ListedBlob, BlobRequestError>;
|
|
105
|
+
/**
|
|
106
|
+
* Delete a blob. Deleting a missing blob succeeds; with `ifMatch`, a different ETag or a
|
|
107
|
+
* missing blob fails with `BlobPreconditionFailed`. CDN caches may serve the blob for up to a
|
|
108
|
+
* minute afterwards.
|
|
109
|
+
*/
|
|
110
|
+
readonly del: (blob: BlobLocator, options?: {
|
|
111
|
+
readonly ifMatch?: ETag | undefined;
|
|
112
|
+
}) => Effect.Effect<void, BlobRequestError | BlobPreconditionFailed>;
|
|
113
|
+
/** Delete several blobs in one request; each counts as one operation for rate limits. */
|
|
114
|
+
readonly delMany: (blobs: Array.NonEmptyReadonlyArray<BlobLocator>) => Effect.Effect<void, BlobRequestError>;
|
|
115
|
+
/**
|
|
116
|
+
* Copy a blob to `to`. The copy does not inherit the source's media type or cache lifetime;
|
|
117
|
+
* pass them again. `ifMatch` is checked against the source. The store replaces a blob at `to`
|
|
118
|
+
* even when `allowOverwrite` is false. A missing source fails with `BlobNotFound`.
|
|
119
|
+
*/
|
|
120
|
+
readonly copy: (from: BlobLocator, to: BlobPathname, options: CreateBlobOptions) => Effect.Effect<PutBlobResult, BlobWriteError | BlobNotFound>;
|
|
121
|
+
/**
|
|
122
|
+
* Move a blob to `to`: copied, then the source deleted. Unlike `copy`, an existing `to` is
|
|
123
|
+
* refused unless `allowOverwrite` is set, so if the delete fails the blob exists at both
|
|
124
|
+
* pathnames; retry with `allowOverwrite: true`. A missing source fails with `BlobNotFound`.
|
|
125
|
+
*/
|
|
126
|
+
readonly rename: (from: BlobLocator, to: BlobPathname, options: CreateBlobOptions) => Effect.Effect<PutBlobResult, BlobWriteError | BlobNotFound>;
|
|
127
|
+
/**
|
|
128
|
+
* Create an empty folder marker; a trailing `/` is added when missing. An existing folder is
|
|
129
|
+
* refused. `access` defaults to `public`, which a private store refuses.
|
|
130
|
+
*/
|
|
131
|
+
readonly createFolder: (pathname: BlobPathname, options?: {
|
|
132
|
+
readonly access?: BlobAccess | undefined;
|
|
133
|
+
}) => Effect.Effect<CreateFolderResult, BlobWriteError>;
|
|
134
|
+
/**
|
|
135
|
+
* Start a multipart upload to control part sizes and concurrency yourself. Parts must be at
|
|
136
|
+
* least 5 MB except the last, and should all have the same size. `addRandomSuffix` defaults
|
|
137
|
+
* to true here.
|
|
138
|
+
*/
|
|
139
|
+
readonly createMultipartUpload: (pathname: BlobPathname, options: CreateMultipartUploadOptions) => Effect.Effect<MultipartUpload, BlobWriteError>;
|
|
140
|
+
/** Upload one part of a multipart upload. */
|
|
141
|
+
readonly uploadPart: <E = never, R = never>(upload: MultipartUpload, partNumber: PartNumber, body: BlobBody<E, R>) => Effect.Effect<UploadedPart, BlobWriteError | E, R>;
|
|
142
|
+
/** Assemble the uploaded parts into the blob. */
|
|
143
|
+
readonly completeMultipartUpload: (upload: MultipartUpload, parts: Array.NonEmptyReadonlyArray<UploadedPart>) => Effect.Effect<PutBlobResult, BlobWriteError>;
|
|
144
|
+
}>;
|
|
145
|
+
/**
|
|
146
|
+
* The Vercel Blob server API: upload, read, list, copy, rename and delete blobs in one store.
|
|
147
|
+
*
|
|
148
|
+
* Credentials and endpoints come from `BlobConfig`.
|
|
149
|
+
*/
|
|
150
|
+
export declare class BlobStore extends BlobStore_base {
|
|
151
|
+
}
|
|
152
|
+
export {};
|
|
153
|
+
//# sourceMappingURL=blob-store.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"blob-store.d.ts","sourceRoot":"","sources":["../../src/contracts/blob-store.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,cAAc,EAAE,MAAM,yCAAyC,CAAC;AACpG,OAAO,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAE9D,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAEzC,OAAO,KAAK,EACV,UAAU,EACV,QAAQ,EACR,WAAW,EACX,YAAY,EACZ,YAAY,EACZ,iBAAiB,EACjB,kBAAkB,EAClB,IAAI,EACJ,aAAa,EACb,UAAU,EACV,QAAQ,EACR,eAAe,EACf,gBAAgB,EAChB,gBAAgB,EAChB,UAAU,EACV,aAAa,EACb,YAAY,EACb,MAAM,kBAAkB,CAAC;AAC1B,OAAO,KAAK,EACV,YAAY,EACZ,6BAA6B,EAC7B,sBAAsB,EACtB,oBAAoB,EACpB,kBAAkB,EACnB,MAAM,kBAAkB,CAAC;AAE1B,+CAA+C;AAC/C,MAAM,MAAM,gBAAgB,GACxB,cAAc,GACd,oBAAoB,GACpB,6BAA6B,GAC7B,oBAAoB,CAAC;AAEzB,gDAAgD;AAChD,MAAM,MAAM,cAAc,GAAG,gBAAgB,GAAG,sBAAsB,GAAG,kBAAkB,CAAC;AAE5F,2CAA2C;AAC3C,MAAM,MAAM,UAAU,GAAG,iBAAiB,GAAG;IAC3C;;;OAGG;IACH,QAAQ,CAAC,SAAS,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IAEzC;;;OAGG;IACH,QAAQ,CAAC,kBAAkB,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAEjD,QAAQ,CAAC,gBAAgB,CAAC,EAAE,gBAAgB,GAAG,SAAS,CAAC;CAC1D,CAAC;AAEF,wEAAwE;AACxE,eAAO,MAAM,UAAU,wCAEtB,CAAC;AAEF,6CAA6C;AAC7C,MAAM,MAAM,UAAU,GAAG,OAAO,UAAU,CAAC,IAAI,CAAC;AAEhD,+DAA+D;AAC/D,eAAO,MAAM,YAAY,0CAExB,CAAC;AAEF,+DAA+D;AAC/D,MAAM,MAAM,YAAY,GAAG,OAAO,YAAY,CAAC,IAAI,CAAC;AAEpD,2CAA2C;AAC3C,eAAO,MAAM,WAAW,2DAAmD,CAAC;AAE5E,2CAA2C;AAC3C,MAAM,MAAM,WAAW,GAAG,OAAO,WAAW,CAAC,IAAI,CAAC;AAElD,6EAA6E;AAC7E,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,KAAK,EAAE,UAAU,CAAC;IAE3B,sBAAsB;IACtB,QAAQ,CAAC,OAAO,CAAC,EAAE,YAAY,GAAG,SAAS,CAAC;IAE5C,qCAAqC;IACrC,QAAQ,CAAC,MAAM,CAAC,EAAE,WAAW,GAAG,SAAS,CAAC;CAC3C;AAED,gGAAgG;AAChG,MAAM,MAAM,eAAe,GAAG,gBAAgB,GAAG;IAC/C,QAAQ,CAAC,MAAM,EAAE,UAAU,CAAC;IAC5B,QAAQ,CAAC,eAAe,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IAC/C,QAAQ,CAAC,kBAAkB,CAAC,EAAE,QAAQ,CAAC,KAAK,GAAG,SAAS,CAAC;IACzD,QAAQ,CAAC,aAAa,EAAE,iBAAiB,CAAC;IAC1C,QAAQ,CAAC,gBAAgB,CAAC,EAAE,gBAAgB,GAAG,SAAS,CAAC;CAC1D,CAAC;AAEF,2CAA2C;AAC3C,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,MAAM,EAAE,UAAU,CAAC;IAE5B;;;OAGG;IACH,QAAQ,CAAC,QAAQ,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IAExC,qFAAqF;IACrF,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAE1C,oFAAoF;IACpF,QAAQ,CAAC,OAAO,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,GAAG,SAAS,CAAC;CACjE;AAED,0DAA0D;AAC1D,MAAM,WAAW,WAAW;IAC1B,iEAAiE;IACjE,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAEpC,kDAAkD;IAClD,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAErC;;;OAGG;IACH,QAAQ,CAAC,IAAI,CAAC,EAAE,UAAU,GAAG,QAAQ,GAAG,SAAS,CAAC;CACnD;AAED,6DAA6D;AAC7D,MAAM,MAAM,4BAA4B,GAAG,iBAAiB,CAAC;;IAUzD;;;;OAIG;kBACW,CAAC,CAAC,GAAG,KAAK,EAAE,CAAC,GAAG,KAAK,EACjC,QAAQ,EAAE,YAAY,EACtB,IAAI,EAAE,QAAQ,CAAC,CAAC,EAAE,CAAC,CAAC,EACpB,OAAO,EAAE,UAAU,KAChB,MAAM,CAAC,MAAM,CAAC,aAAa,EAAE,cAAc,GAAG,CAAC,EAAE,CAAC,CAAC;IAExD;;;;OAIG;uBACgB,CAAC,CAAC,GAAG,KAAK,EAAE,CAAC,GAAG,KAAK,EACtC,QAAQ,EAAE,YAAY,EACtB,MAAM,EAAE,QAAQ,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,GAAG,EAC5B,OAAO,EAAE,eAAe,KACrB,MAAM,CAAC,MAAM,CAAC,aAAa,EAAE,cAAc,GAAG,CAAC,EAAE,CAAC,CAAC;IAExD,kDAAkD;mBACnC,CACb,IAAI,EAAE,WAAW,KACd,MAAM,CAAC,MAAM,CAAC,YAAY,EAAE,gBAAgB,GAAG,YAAY,CAAC;IAEjE;;;OAGG;kBACW,CACZ,IAAI,EAAE,WAAW,EACjB,OAAO,EAAE,UAAU,KAChB,MAAM,CAAC,MAAM,CAAC,aAAa,EAAE,gBAAgB,GAAG,YAAY,CAAC;IAElE,8BAA8B;mBACf,CACb,OAAO,CAAC,EAAE,WAAW,GAAG;QAAE,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;KAAE,KAC7D,MAAM,CAAC,MAAM,CAAC,QAAQ,EAAE,gBAAgB,CAAC;IAE9C,2EAA2E;sBACzD,CAAC,OAAO,CAAC,EAAE,WAAW,KAAK,MAAM,CAAC,MAAM,CAAC,UAAU,EAAE,gBAAgB,CAAC;IAExF;;;;OAIG;kBACW,CACZ,IAAI,EAAE,WAAW,EACjB,OAAO,CAAC,EAAE;QAAE,QAAQ,CAAC,OAAO,CAAC,EAAE,IAAI,GAAG,SAAS,CAAA;KAAE,KAC9C,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,gBAAgB,GAAG,sBAAsB,CAAC;IAEnE,yFAAyF;sBACvE,CAChB,KAAK,EAAE,KAAK,CAAC,qBAAqB,CAAC,WAAW,CAAC,KAC5C,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,gBAAgB,CAAC;IAE1C;;;;OAIG;mBACY,CACb,IAAI,EAAE,WAAW,EACjB,EAAE,EAAE,YAAY,EAChB,OAAO,EAAE,iBAAiB,KACvB,MAAM,CAAC,MAAM,CAAC,aAAa,EAAE,cAAc,GAAG,YAAY,CAAC;IAEhE;;;;OAIG;qBACc,CACf,IAAI,EAAE,WAAW,EACjB,EAAE,EAAE,YAAY,EAChB,OAAO,EAAE,iBAAiB,KACvB,MAAM,CAAC,MAAM,CAAC,aAAa,EAAE,cAAc,GAAG,YAAY,CAAC;IAEhE;;;OAGG;2BACoB,CACrB,QAAQ,EAAE,YAAY,EACtB,OAAO,CAAC,EAAE;QAAE,QAAQ,CAAC,MAAM,CAAC,EAAE,UAAU,GAAG,SAAS,CAAA;KAAE,KACnD,MAAM,CAAC,MAAM,CAAC,kBAAkB,EAAE,cAAc,CAAC;IAEtD;;;;OAIG;oCAC6B,CAC9B,QAAQ,EAAE,YAAY,EACtB,OAAO,EAAE,4BAA4B,KAClC,MAAM,CAAC,MAAM,CAAC,eAAe,EAAE,cAAc,CAAC;IAEnD,6CAA6C;yBACxB,CAAC,CAAC,GAAG,KAAK,EAAE,CAAC,GAAG,KAAK,EACxC,MAAM,EAAE,eAAe,EACvB,UAAU,EAAE,UAAU,EACtB,IAAI,EAAE,QAAQ,CAAC,CAAC,EAAE,CAAC,CAAC,KACjB,MAAM,CAAC,MAAM,CAAC,YAAY,EAAE,cAAc,GAAG,CAAC,EAAE,CAAC,CAAC;IAEvD,iDAAiD;sCACf,CAChC,MAAM,EAAE,eAAe,EACvB,KAAK,EAAE,KAAK,CAAC,qBAAqB,CAAC,YAAY,CAAC,KAC7C,MAAM,CAAC,MAAM,CAAC,aAAa,EAAE,cAAc,CAAC;;AAvHrD;;;;GAIG;AACH,qBAAa,SAAU,SAAQ,cAoHK;CAAG"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { Context, Schema } from "effect";
|
|
2
|
+
/** Width of an optimized image in pixels: an integer from 1 to 8192. */
|
|
3
|
+
export const ImageWidth = Schema.Int.check(Schema.isBetween({ minimum: 1, maximum: 8192 })).pipe(Schema.brand("ImageWidth"));
|
|
4
|
+
/** Quality of an optimized image: an integer from 1 to 100. */
|
|
5
|
+
export const ImageQuality = Schema.Int.check(Schema.isBetween({ minimum: 1, maximum: 100 })).pipe(Schema.brand("ImageQuality"));
|
|
6
|
+
/** Output format of an optimized image. */
|
|
7
|
+
export const ImageFormat = Schema.Literals(["jpeg", "png", "webp", "avif"]);
|
|
8
|
+
/**
|
|
9
|
+
* The Vercel Blob server API: upload, read, list, copy, rename and delete blobs in one store.
|
|
10
|
+
*
|
|
11
|
+
* Credentials and endpoints come from `BlobConfig`.
|
|
12
|
+
*/
|
|
13
|
+
export class BlobStore extends Context.Service()("@effect-vercel/blob/BlobStore") {
|
|
14
|
+
}
|
|
15
|
+
//# sourceMappingURL=blob-store.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"blob-store.js","sourceRoot":"","sources":["../../src/contracts/blob-store.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAwDzC,wEAAwE;AACxE,MAAM,CAAC,MAAM,UAAU,GAAG,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,SAAS,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI,CAC9F,MAAM,CAAC,KAAK,CAAC,YAAY,CAAC,CAC3B,CAAC;AAKF,+DAA+D;AAC/D,MAAM,CAAC,MAAM,YAAY,GAAG,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,SAAS,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,OAAO,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC,IAAI,CAC/F,MAAM,CAAC,KAAK,CAAC,cAAc,CAAC,CAC7B,CAAC;AAKF,2CAA2C;AAC3C,MAAM,CAAC,MAAM,WAAW,GAAG,MAAM,CAAC,QAAQ,CAAC,CAAC,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;AA4D5E;;;;GAIG;AACH,MAAM,OAAO,SAAU,SAAQ,OAAO,CAAC,OAAO,EAoH3C,CAAC,+BAA+B,CAAC;CAAG"}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import type { Effect } from "effect";
|
|
2
|
+
import type { HttpServerRequest, HttpServerResponse } from "effect/http";
|
|
3
|
+
import { Context } from "effect";
|
|
4
|
+
import type { ClientToken, ClientTokenConstraints, UploadCompleted, UploadRequest } from "./blob-domain.ts";
|
|
5
|
+
import type { BlobPresignFailed, BlobReadWriteTokenRequired, BlobUploadEventRejected } from "./blob-errors.ts";
|
|
6
|
+
import type { PresignOptions, SigningToken } from "./blob-signed-urls.ts";
|
|
7
|
+
/** Callback the store calls after a browser upload completes. */
|
|
8
|
+
export interface UploadCompletedCallback {
|
|
9
|
+
/** Absolute URL of the route that handles `blob.upload-completed`. */
|
|
10
|
+
readonly callbackUrl: string;
|
|
11
|
+
/** Data passed back to the callback, such as the uploading user's id. */
|
|
12
|
+
readonly tokenPayload?: string | undefined;
|
|
13
|
+
}
|
|
14
|
+
/** Everything a client token encodes. */
|
|
15
|
+
export type ClientTokenOptions = ClientTokenConstraints & {
|
|
16
|
+
/** The only pathname the token may upload to. */
|
|
17
|
+
readonly pathname: string;
|
|
18
|
+
readonly onUploadCompleted?: UploadCompletedCallback | undefined;
|
|
19
|
+
};
|
|
20
|
+
/** What an upload route allows for one browser upload; returned by `onBeforeGenerateToken`. */
|
|
21
|
+
export type UploadAuthorization = ClientTokenConstraints & {
|
|
22
|
+
/** Passed to `onUploadCompleted`; defaults to the browser's `clientPayload`. */
|
|
23
|
+
readonly tokenPayload?: string | undefined;
|
|
24
|
+
/**
|
|
25
|
+
* Where the upload-completed callback goes. Derived from the environment when omitted:
|
|
26
|
+
* `VERCEL_BLOB_CALLBACK_URL`, else the preview or production URL on Vercel, plus this route's
|
|
27
|
+
* path. Never taken from the browser.
|
|
28
|
+
*/
|
|
29
|
+
readonly callbackUrl?: string | undefined;
|
|
30
|
+
};
|
|
31
|
+
/** Hooks of a client-token upload route. */
|
|
32
|
+
export interface UploadHandlerOptions<E, R, E2, R2> {
|
|
33
|
+
/**
|
|
34
|
+
* Authenticate and authorize the user, then constrain the upload. Fail to refuse it; the error
|
|
35
|
+
* leaves the handler so the route can answer 401 or 403.
|
|
36
|
+
*/
|
|
37
|
+
readonly onBeforeGenerateToken: (request: UploadRequest) => Effect.Effect<UploadAuthorization, E, R>;
|
|
38
|
+
/**
|
|
39
|
+
* Runs when the store reports the upload finished, after the callback's signature is verified.
|
|
40
|
+
* Without it no callback is requested. Fail to make the store retry the callback.
|
|
41
|
+
*/
|
|
42
|
+
readonly onUploadCompleted?: ((event: UploadCompleted) => Effect.Effect<void, E2, R2>) | undefined;
|
|
43
|
+
}
|
|
44
|
+
/** What a presigned upload route allows for one browser upload; returned by `getSignedToken`. */
|
|
45
|
+
export interface PresignedUploadAuthorization {
|
|
46
|
+
/** Token to sign the upload URL with, usually cached by the route. */
|
|
47
|
+
readonly token: SigningToken;
|
|
48
|
+
/** Constraints signed into the URL; they may only narrow the token's. */
|
|
49
|
+
readonly urlOptions?: (Omit<Extract<PresignOptions, {
|
|
50
|
+
readonly operation: "put";
|
|
51
|
+
}>, "operation" | "pathname" | "onUploadCompleted"> & {
|
|
52
|
+
/** As {@link UploadAuthorization.callbackUrl}. */
|
|
53
|
+
readonly callbackUrl?: string | undefined;
|
|
54
|
+
/** Passed to `onUploadCompleted`; defaults to the browser's `clientPayload`. */
|
|
55
|
+
readonly tokenPayload?: string | undefined;
|
|
56
|
+
}) | undefined;
|
|
57
|
+
}
|
|
58
|
+
/** Hooks of a presigned upload route. */
|
|
59
|
+
export interface PresignedUploadHandlerOptions<E, R, E2, R2> {
|
|
60
|
+
/** Authenticate and authorize the user, then choose the token and constraints. */
|
|
61
|
+
readonly getSignedToken: (request: UploadRequest) => Effect.Effect<PresignedUploadAuthorization, E, R>;
|
|
62
|
+
/** As {@link UploadHandlerOptions.onUploadCompleted}; callbacks are verified with Ed25519. */
|
|
63
|
+
readonly onUploadCompleted?: ((event: UploadCompleted) => Effect.Effect<void, E2, R2>) | undefined;
|
|
64
|
+
}
|
|
65
|
+
declare const BlobUploads_base: Context.ServiceClass<BlobUploads, "@effect-vercel/blob/BlobUploads", {
|
|
66
|
+
/**
|
|
67
|
+
* Sign a client token with the store's read-write token. Defaults `validUntil` to 30 seconds
|
|
68
|
+
* from now; an `ifMatch` without `allowOverwrite` allows overwriting.
|
|
69
|
+
*/
|
|
70
|
+
readonly generateClientToken: (options: ClientTokenOptions) => Effect.Effect<ClientToken, BlobReadWriteTokenRequired>;
|
|
71
|
+
/**
|
|
72
|
+
* Handle one request to a client-token upload route (`handleUpload`): answer
|
|
73
|
+
* `blob.generate-client-token` with `{ type, clientToken }` (valid for one hour unless
|
|
74
|
+
* `validUntil` says otherwise) and acknowledge a verified `blob.upload-completed` with
|
|
75
|
+
* `{ type, response: "ok" }`. Requires a read-write token.
|
|
76
|
+
*/
|
|
77
|
+
readonly handler: <E, R, E2 = never, R2 = never>(options: UploadHandlerOptions<E, R, E2, R2>) => Effect.Effect<HttpServerResponse.HttpServerResponse, E | E2 | BlobUploadEventRejected | BlobReadWriteTokenRequired, HttpServerRequest.HttpServerRequest | R | R2>;
|
|
78
|
+
/**
|
|
79
|
+
* Handle one request to a presigned upload route (`handleUploadPresigned`): answer
|
|
80
|
+
* `blob.generate-presigned-url` with `{ type, presignedUrlPayload }` and acknowledge a
|
|
81
|
+
* `blob.upload-completed` verified against `BLOB_WEBHOOK_PUBLIC_KEY`. Works with OIDC.
|
|
82
|
+
*/
|
|
83
|
+
readonly presignedHandler: <E, R, E2 = never, R2 = never>(options: PresignedUploadHandlerOptions<E, R, E2, R2>) => Effect.Effect<HttpServerResponse.HttpServerResponse, E | E2 | BlobUploadEventRejected | BlobPresignFailed, HttpServerRequest.HttpServerRequest | R | R2>;
|
|
84
|
+
}>;
|
|
85
|
+
/**
|
|
86
|
+
* The server side of browser uploads: a route that authorizes uploads and receives the store's
|
|
87
|
+
* upload-completed callbacks.
|
|
88
|
+
*
|
|
89
|
+
* ```ts
|
|
90
|
+
* export const POST = HttpEffect.toWebHandlerLayer(
|
|
91
|
+
* BlobUploads.use((uploads) =>
|
|
92
|
+
* uploads.handler({ onBeforeGenerateToken: authorize, onUploadCompleted: saveAvatar }),
|
|
93
|
+
* ).pipe(Effect.catchTag("Unauthorized", () => HttpServerResponse.empty({ status: 401 }))),
|
|
94
|
+
* AppLayer,
|
|
95
|
+
* ).handler;
|
|
96
|
+
* ```
|
|
97
|
+
*/
|
|
98
|
+
export declare class BlobUploads extends BlobUploads_base {
|
|
99
|
+
}
|
|
100
|
+
export {};
|
|
101
|
+
//# sourceMappingURL=blob-uploads.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"blob-uploads.d.ts","sourceRoot":"","sources":["../../src/contracts/blob-uploads.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { Context } from "effect";
|
|
2
|
+
/**
|
|
3
|
+
* The server side of browser uploads: a route that authorizes uploads and receives the store's
|
|
4
|
+
* upload-completed callbacks.
|
|
5
|
+
*
|
|
6
|
+
* ```ts
|
|
7
|
+
* export const POST = HttpEffect.toWebHandlerLayer(
|
|
8
|
+
* BlobUploads.use((uploads) =>
|
|
9
|
+
* uploads.handler({ onBeforeGenerateToken: authorize, onUploadCompleted: saveAvatar }),
|
|
10
|
+
* ).pipe(Effect.catchTag("Unauthorized", () => HttpServerResponse.empty({ status: 401 }))),
|
|
11
|
+
* AppLayer,
|
|
12
|
+
* ).handler;
|
|
13
|
+
* ```
|
|
14
|
+
*/
|
|
15
|
+
export class BlobUploads extends Context.Service()("@effect-vercel/blob/BlobUploads") {
|
|
16
|
+
}
|
|
17
|
+
//# sourceMappingURL=blob-uploads.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"blob-uploads.js","sourceRoot":"","sources":["../../src/contracts/blob-uploads.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAC;AAgGjC;;;;;;;;;;;;GAYG;AACH,MAAM,OAAO,WAAY,SAAQ,OAAO,CAAC,OAAO,EAsC7C,CAAC,iCAAiC,CAAC;CAAG"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { Config, Layer } from "effect";
|
|
2
|
+
import { HttpClient } from "effect/http";
|
|
3
|
+
import { BlobClient } from "../contracts/blob-client.ts";
|
|
4
|
+
/** Values that replace what {@link BlobClientLive} reads from the environment. */
|
|
5
|
+
export interface BlobClientOptions {
|
|
6
|
+
/**
|
|
7
|
+
* Blob API base URL; replaces `VERCEL_BLOB_API_URL` and `NEXT_PUBLIC_VERCEL_BLOB_API_URL`, for an
|
|
8
|
+
* emulator or a test server.
|
|
9
|
+
*/
|
|
10
|
+
readonly apiUrl?: URL | string | undefined;
|
|
11
|
+
/**
|
|
12
|
+
* Extra headers for every Blob API request, merged over the environment's. Headers for the
|
|
13
|
+
* upload route are given per upload instead.
|
|
14
|
+
*/
|
|
15
|
+
readonly headers?: Readonly<Record<string, string>> | undefined;
|
|
16
|
+
/** Retries after the first attempt; replaces `VERCEL_BLOB_RETRIES` (default 10). */
|
|
17
|
+
readonly retries?: number | undefined;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Builds {@link BlobClient} over the given `HttpClient`, with any given values taking precedence
|
|
21
|
+
* over the environment.
|
|
22
|
+
*
|
|
23
|
+
* Reads, through `Config` (trimmed, blank means absent): `VERCEL_BLOB_API_URL` or
|
|
24
|
+
* `NEXT_PUBLIC_VERCEL_BLOB_API_URL`, `VERCEL_BLOB_API_VERSION_OVERRIDE` or its `NEXT_PUBLIC_` twin
|
|
25
|
+
* (default `13`), `VERCEL_BLOB_RETRIES` (default 10), `VERCEL_BLOB_USE_X_CONTENT_LENGTH`, and
|
|
26
|
+
* `VERCEL_BLOB_PROXY_THROUGH_ALTERNATIVE_API` or its `NEXT_PUBLIC_` twin. In browsers these are
|
|
27
|
+
* usually absent or inlined `NEXT_PUBLIC_*` values, so the defaults apply.
|
|
28
|
+
*
|
|
29
|
+
* Uploads through an upload route with a relative `handleUploadUrl` need `globalThis.location`
|
|
30
|
+
* (pages and web workers); elsewhere that is a defect, so pass an absolute URL.
|
|
31
|
+
*
|
|
32
|
+
* Fails with a `ConfigError` when the API URL or `VERCEL_BLOB_RETRIES` is invalid.
|
|
33
|
+
*/
|
|
34
|
+
export declare const blobClientLayer: (options?: BlobClientOptions) => Layer.Layer<BlobClient, Config.ConfigError, HttpClient.HttpClient>;
|
|
35
|
+
/** {@link BlobClient} configured from the environment; needs an `HttpClient`. */
|
|
36
|
+
export declare const BlobClientLive: Layer.Layer<BlobClient, Config.ConfigError, HttpClient.HttpClient>;
|
|
37
|
+
//# sourceMappingURL=blob-client-live.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"blob-client-live.d.ts","sourceRoot":"","sources":["../../src/implementation/blob-client-live.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,MAAM,EAAU,KAAK,EAAuC,MAAM,QAAQ,CAAC;AACpF,OAAO,EAAE,UAAU,EAAqB,MAAM,aAAa,CAAC;AAmB5D,OAAO,EAAE,UAAU,EAAE,MAAM,6BAA6B,CAAC;AAczD,kFAAkF;AAClF,MAAM,WAAW,iBAAiB;IAChC;;;OAGG;IACH,QAAQ,CAAC,MAAM,CAAC,EAAE,GAAG,GAAG,MAAM,GAAG,SAAS,CAAC;IAE3C;;;OAGG;IACH,QAAQ,CAAC,OAAO,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,GAAG,SAAS,CAAC;IAEhE,oFAAoF;IACpF,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CACvC;AAwTD;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,eAAe,aACjB,iBAAiB,KACzB,KAAK,CAAC,KAAK,CAAC,UAAU,EAAE,MAAM,CAAC,WAAW,EAAE,UAAU,CAAC,UAAU,CACjB,CAAC;AAEpD,iFAAiF;AACjF,eAAO,MAAM,cAAc,EAAE,KAAK,CAAC,KAAK,CAAC,UAAU,EAAE,MAAM,CAAC,WAAW,EAAE,UAAU,CAAC,UAAU,CAC3E,CAAC"}
|
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
import { Config, Effect, Layer, Option, Predicate, Redacted, Schema } from "effect";
|
|
2
|
+
import { HttpClient, HttpClientRequest } from "effect/http";
|
|
3
|
+
import { BlobClient } from "../contracts/blob-client.js";
|
|
4
|
+
import { ClientToken as ClientTokenSchema, MultipartUpload, PresignedUrlPayload, } from "../contracts/blob-domain.js";
|
|
5
|
+
import { BlobUploadAuthorizationFailed } from "../contracts/blob-errors.js";
|
|
6
|
+
import { BlobRequestAuth, blobRequester } from "../internal/blob-request.js";
|
|
7
|
+
import { requestEnv } from "../internal/env.js";
|
|
8
|
+
import * as Multipart from "../internal/multipart.js";
|
|
9
|
+
import { storeIdFromClientToken, storeIdFromDelegationToken } from "../internal/store-id.js";
|
|
10
|
+
import { PutBlobResponse } from "../internal/wire.js";
|
|
11
|
+
import { allowedWriteOptions, writeHeaders } from "../internal/write-headers.js";
|
|
12
|
+
/** The SDK wraps a single upload's `onUploadProgress` in `throttle(…, 100)`. */
|
|
13
|
+
const singleUploadProgressInterval = "100 millis";
|
|
14
|
+
/** The domain errors {@link BlobClientError} declares; other error codes become `VercelApiError`. */
|
|
15
|
+
const clientDomainErrors = [
|
|
16
|
+
"BlobStoreUnavailable",
|
|
17
|
+
"BlobUploadRejected",
|
|
18
|
+
"BlobPreconditionFailed",
|
|
19
|
+
"BlobClientTokenNotAllowed",
|
|
20
|
+
];
|
|
21
|
+
/**
|
|
22
|
+
* The request settings of the browser client, read like the SDK's `requestApi` reads them. There
|
|
23
|
+
* is no server `BlobConfig` here: credentials come with each upload.
|
|
24
|
+
*/
|
|
25
|
+
const resolveClientSettings = Effect.fnUntraced(function* (options, httpClient) {
|
|
26
|
+
const { apiUrl, apiVersion, retries, sendContentLength, headers } = yield* requestEnv(options);
|
|
27
|
+
return { httpClient, apiUrl, apiVersion, retries, sendContentLength, headers };
|
|
28
|
+
});
|
|
29
|
+
/** The SDK's messages for a route that cannot be reached or answers with a non-2xx status. */
|
|
30
|
+
const routeFailedMessages = {
|
|
31
|
+
"blob.generate-client-token": "Failed to retrieve the client token",
|
|
32
|
+
"blob.generate-presigned-url": "Failed to retrieve the presigned URL",
|
|
33
|
+
};
|
|
34
|
+
/** The SDK's messages for a 2xx route response whose body cannot be read. */
|
|
35
|
+
const routeBodyMessages = {
|
|
36
|
+
"blob.generate-client-token": "Failed to retrieve the client token",
|
|
37
|
+
"blob.generate-presigned-url": "Failed to retrieve the presigned URL",
|
|
38
|
+
};
|
|
39
|
+
const ClientTokenResponse = Schema.Struct({ clientToken: ClientTokenSchema });
|
|
40
|
+
const PresignedUrlResponse = Schema.Struct({
|
|
41
|
+
presignedUrlPayload: Schema.optionalKey(Schema.NullOr(PresignedUrlPayload)),
|
|
42
|
+
});
|
|
43
|
+
const decodeAbsoluteUrl = Schema.decodeUnknownOption(Schema.URLFromString);
|
|
44
|
+
/**
|
|
45
|
+
* The upload route's absolute URL, as the SDK's `isAbsoluteUrl`/`toAbsoluteUrl`: an absolute URL
|
|
46
|
+
* is used as given, a relative one resolves against `globalThis.location.href` (pages and web
|
|
47
|
+
* workers). A relative URL where there is no `location`, such as on a server, is a defect.
|
|
48
|
+
*/
|
|
49
|
+
const resolveUploadRouteUrl = (handleUploadUrl) => Effect.suspend(() => {
|
|
50
|
+
if (Option.isSome(decodeAbsoluteUrl(handleUploadUrl))) {
|
|
51
|
+
return Effect.succeed(handleUploadUrl);
|
|
52
|
+
}
|
|
53
|
+
const location = Reflect.get(globalThis, "location");
|
|
54
|
+
if (!Predicate.hasProperty(location, "href") || !Predicate.isString(location.href)) {
|
|
55
|
+
return Effect.die(new Error(`Cannot resolve the relative handleUploadUrl "${handleUploadUrl}": there is no ` +
|
|
56
|
+
"globalThis.location. Pass an absolute URL outside of browsers."));
|
|
57
|
+
}
|
|
58
|
+
const base = location.href;
|
|
59
|
+
return Effect.try({
|
|
60
|
+
try: () => new URL(handleUploadUrl, base).href,
|
|
61
|
+
catch: (cause) => cause,
|
|
62
|
+
}).pipe(Effect.orDie);
|
|
63
|
+
});
|
|
64
|
+
const withoutTracePropagation = Effect.provideService(HttpClient.TracerPropagationEnabled, false);
|
|
65
|
+
const clientTokenAuth = (token) => BlobRequestAuth.Bearer({
|
|
66
|
+
token: Redacted.make(token),
|
|
67
|
+
// The SDK sends an empty store id when the token has none.
|
|
68
|
+
storeId: Option.getOrElse(storeIdFromClientToken(token), () => ""),
|
|
69
|
+
});
|
|
70
|
+
const clientWriteHeaders = (options) => writeHeaders(allowedWriteOptions.client, {
|
|
71
|
+
access: options.access,
|
|
72
|
+
contentType: options.contentType,
|
|
73
|
+
});
|
|
74
|
+
const makeBlobClient = Effect.fnUntraced(function* (options) {
|
|
75
|
+
const httpClient = yield* HttpClient.HttpClient;
|
|
76
|
+
const requester = blobRequester(yield* resolveClientSettings(options, httpClient));
|
|
77
|
+
/** The multipart engine with the client's write headers and domain errors, for one upload's auth. */
|
|
78
|
+
const multipartTarget = (auth) => ({
|
|
79
|
+
requester,
|
|
80
|
+
auth: Effect.succeed(auth),
|
|
81
|
+
service: "BlobClient",
|
|
82
|
+
domainErrors: clientDomainErrors,
|
|
83
|
+
writeOptions: Multipart.clientMultipartWriteOptions,
|
|
84
|
+
});
|
|
85
|
+
/** POST the event to the upload route, as the SDK's `retrieveClientToken` does. */
|
|
86
|
+
const postUploadEvent = Effect.fnUntraced(function* (type, pathname, options) {
|
|
87
|
+
const url = yield* resolveUploadRouteUrl(options.handleUploadUrl);
|
|
88
|
+
const event = {
|
|
89
|
+
type,
|
|
90
|
+
payload: {
|
|
91
|
+
pathname,
|
|
92
|
+
clientPayload: options.clientPayload ?? null,
|
|
93
|
+
multipart: options.multipart ?? false,
|
|
94
|
+
},
|
|
95
|
+
};
|
|
96
|
+
const request = HttpClientRequest.post(url).pipe(HttpClientRequest.bodyText(JSON.stringify(event), "application/json"), HttpClientRequest.setHeaders({ "content-type": "application/json", ...options.headers }));
|
|
97
|
+
const response = yield* httpClient.execute(request).pipe(Effect.mapError((cause) => new BlobUploadAuthorizationFailed({
|
|
98
|
+
status: Option.none(),
|
|
99
|
+
message: routeFailedMessages[type],
|
|
100
|
+
cause,
|
|
101
|
+
})), withoutTracePropagation);
|
|
102
|
+
if (response.status < 200 || response.status >= 300) {
|
|
103
|
+
yield* Effect.ignore(response.arrayBuffer);
|
|
104
|
+
return yield* new BlobUploadAuthorizationFailed({
|
|
105
|
+
status: Option.some(response.status),
|
|
106
|
+
message: routeFailedMessages[type],
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
const body = yield* response.json.pipe(Effect.mapError((cause) => new BlobUploadAuthorizationFailed({
|
|
110
|
+
status: Option.some(response.status),
|
|
111
|
+
message: routeBodyMessages[type],
|
|
112
|
+
cause,
|
|
113
|
+
})));
|
|
114
|
+
return { status: response.status, body };
|
|
115
|
+
});
|
|
116
|
+
const retrieveClientToken = Effect.fnUntraced(function* (pathname, options) {
|
|
117
|
+
const type = "blob.generate-client-token";
|
|
118
|
+
const { status, body } = yield* postUploadEvent(type, pathname, options);
|
|
119
|
+
const decoded = yield* Schema.decodeUnknownEffect(ClientTokenResponse)(body).pipe(Effect.mapError((cause) => new BlobUploadAuthorizationFailed({
|
|
120
|
+
status: Option.some(status),
|
|
121
|
+
message: routeBodyMessages[type],
|
|
122
|
+
cause,
|
|
123
|
+
})));
|
|
124
|
+
return decoded.clientToken;
|
|
125
|
+
});
|
|
126
|
+
const retrievePresignedAuth = Effect.fnUntraced(function* (pathname, options) {
|
|
127
|
+
const type = "blob.generate-presigned-url";
|
|
128
|
+
const { status, body } = yield* postUploadEvent(type, pathname, options);
|
|
129
|
+
const fail = (message, cause) => new BlobUploadAuthorizationFailed({ status: Option.some(status), message, cause });
|
|
130
|
+
const decoded = yield* Schema.decodeUnknownEffect(PresignedUrlResponse)(body).pipe(Effect.mapError((cause) => fail(routeBodyMessages[type], cause)));
|
|
131
|
+
const payload = decoded.presignedUrlPayload;
|
|
132
|
+
if (payload === undefined || payload === null) {
|
|
133
|
+
return yield* fail("Missing presignedUrlPayload");
|
|
134
|
+
}
|
|
135
|
+
const storeId = storeIdFromDelegationToken(payload.delegationToken);
|
|
136
|
+
if (Option.isNone(storeId)) {
|
|
137
|
+
return yield* fail(payload.delegationToken.includes(".")
|
|
138
|
+
? "Invalid delegation token payload."
|
|
139
|
+
: "Invalid delegation token format.");
|
|
140
|
+
}
|
|
141
|
+
return BlobRequestAuth.Presigned({ payload, storeId: storeId.value });
|
|
142
|
+
});
|
|
143
|
+
/** `PUT /?pathname=…` with the client write headers, or automatic multipart. */
|
|
144
|
+
const send = (operation, auth, pathname, body, options) => {
|
|
145
|
+
if (options.multipart === true) {
|
|
146
|
+
return Multipart.multipartPut(multipartTarget(auth), pathname, body, {
|
|
147
|
+
access: options.access,
|
|
148
|
+
contentType: options.contentType,
|
|
149
|
+
onUploadProgress: options.onUploadProgress,
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
const headers = clientWriteHeaders(options);
|
|
153
|
+
return requester.call({
|
|
154
|
+
operation,
|
|
155
|
+
method: "PUT",
|
|
156
|
+
path: `/?${new URLSearchParams({ pathname }).toString()}`,
|
|
157
|
+
auth: Effect.succeed(auth),
|
|
158
|
+
headers,
|
|
159
|
+
body,
|
|
160
|
+
response: PutBlobResponse,
|
|
161
|
+
domainErrors: clientDomainErrors,
|
|
162
|
+
onUploadProgress: options.onUploadProgress,
|
|
163
|
+
progressInterval: singleUploadProgressInterval,
|
|
164
|
+
});
|
|
165
|
+
};
|
|
166
|
+
const upload = Effect.fn("BlobClient.upload")(function* (pathname, body, options) {
|
|
167
|
+
const token = yield* retrieveClientToken(pathname, options);
|
|
168
|
+
return yield* send("BlobClient.upload", clientTokenAuth(token), pathname, body, options);
|
|
169
|
+
});
|
|
170
|
+
const uploadPresigned = Effect.fn("BlobClient.uploadPresigned")(function* (pathname, body, options) {
|
|
171
|
+
const auth = yield* retrievePresignedAuth(pathname, options);
|
|
172
|
+
return yield* send("BlobClient.uploadPresigned", auth, pathname, body, options);
|
|
173
|
+
});
|
|
174
|
+
const put = Effect.fn("BlobClient.put")(function* (pathname, body, options) {
|
|
175
|
+
return yield* send("BlobClient.put", clientTokenAuth(options.token), pathname, body, options);
|
|
176
|
+
});
|
|
177
|
+
const createMultipartUpload = Effect.fn("BlobClient.createMultipartUpload")(function* (pathname, options) {
|
|
178
|
+
return yield* Multipart.createMultipartUpload(multipartTarget(clientTokenAuth(options.token)), pathname, { access: options.access, contentType: options.contentType });
|
|
179
|
+
});
|
|
180
|
+
const uploadPart = Effect.fn("BlobClient.uploadPart")(function* (upload, partNumber, body, options) {
|
|
181
|
+
return yield* Multipart.uploadPart(multipartTarget(clientTokenAuth(options.token)), upload, partNumber, body);
|
|
182
|
+
});
|
|
183
|
+
const completeMultipartUpload = Effect.fn("BlobClient.completeMultipartUpload")(function* (upload, parts, options) {
|
|
184
|
+
return yield* Multipart.completeMultipartUpload(multipartTarget(clientTokenAuth(options.token)), upload, parts);
|
|
185
|
+
});
|
|
186
|
+
return BlobClient.of({
|
|
187
|
+
upload,
|
|
188
|
+
uploadPresigned,
|
|
189
|
+
put,
|
|
190
|
+
createMultipartUpload,
|
|
191
|
+
uploadPart,
|
|
192
|
+
completeMultipartUpload,
|
|
193
|
+
});
|
|
194
|
+
});
|
|
195
|
+
/**
|
|
196
|
+
* Builds {@link BlobClient} over the given `HttpClient`, with any given values taking precedence
|
|
197
|
+
* over the environment.
|
|
198
|
+
*
|
|
199
|
+
* Reads, through `Config` (trimmed, blank means absent): `VERCEL_BLOB_API_URL` or
|
|
200
|
+
* `NEXT_PUBLIC_VERCEL_BLOB_API_URL`, `VERCEL_BLOB_API_VERSION_OVERRIDE` or its `NEXT_PUBLIC_` twin
|
|
201
|
+
* (default `13`), `VERCEL_BLOB_RETRIES` (default 10), `VERCEL_BLOB_USE_X_CONTENT_LENGTH`, and
|
|
202
|
+
* `VERCEL_BLOB_PROXY_THROUGH_ALTERNATIVE_API` or its `NEXT_PUBLIC_` twin. In browsers these are
|
|
203
|
+
* usually absent or inlined `NEXT_PUBLIC_*` values, so the defaults apply.
|
|
204
|
+
*
|
|
205
|
+
* Uploads through an upload route with a relative `handleUploadUrl` need `globalThis.location`
|
|
206
|
+
* (pages and web workers); elsewhere that is a defect, so pass an absolute URL.
|
|
207
|
+
*
|
|
208
|
+
* Fails with a `ConfigError` when the API URL or `VERCEL_BLOB_RETRIES` is invalid.
|
|
209
|
+
*/
|
|
210
|
+
export const blobClientLayer = (options = {}) => Layer.effect(BlobClient, makeBlobClient(options));
|
|
211
|
+
/** {@link BlobClient} configured from the environment; needs an `HttpClient`. */
|
|
212
|
+
export const BlobClientLive = blobClientLayer();
|
|
213
|
+
//# sourceMappingURL=blob-client-live.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"blob-client-live.js","sourceRoot":"","sources":["../../src/implementation/blob-client-live.ts"],"names":[],"mappings":"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"}
|