@panorama-industries/effect-vercel-blob 0.0.0 → 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 +12 -1
- 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 +58 -4
- 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,291 @@
|
|
|
1
|
+
import { ApiUnexpectedResponse, VercelApiError, vercelApiErrorFromHttpClientError, vercelApiTransientRetry, } from "@panorama-industries/effect-vercel-core";
|
|
2
|
+
import { Clock, Data, Duration, Effect, Fiber, Option, Queue, Random, Redacted, Ref, Schema, Stream, } from "effect";
|
|
3
|
+
import { HttpBody, HttpClient, HttpClientRequest } from "effect/http";
|
|
4
|
+
import { BlobAuth } from "../contracts/blob-config.js";
|
|
5
|
+
import { blobErrorFromHttpResponse, isRetryableBlobError } from "./blob-errors.js";
|
|
6
|
+
import { storeIdFromReadWriteToken } from "./store-id.js";
|
|
7
|
+
/** Settings for server-side services, read from `BlobConfig`. */
|
|
8
|
+
export const blobRequestSettings = (config, httpClient) => ({
|
|
9
|
+
httpClient,
|
|
10
|
+
apiUrl: config.apiUrl,
|
|
11
|
+
apiVersion: config.apiVersion,
|
|
12
|
+
retries: config.retries,
|
|
13
|
+
sendContentLength: config.sendContentLength,
|
|
14
|
+
headers: config.headers,
|
|
15
|
+
});
|
|
16
|
+
/** Constructors and matchers for {@link BlobRequestAuth}. */
|
|
17
|
+
export const BlobRequestAuth = Data.taggedEnum();
|
|
18
|
+
/**
|
|
19
|
+
* The per-call auth of server-side services. `ReadWrite` uses its token. `Oidc` evaluates
|
|
20
|
+
* `VercelOidc.token` on every call; when it is unavailable and `BlobConfig.readWriteToken` is set,
|
|
21
|
+
* the call uses that token and its store id instead, as the SDK falls through to
|
|
22
|
+
* `BLOB_READ_WRITE_TOKEN`. Otherwise it fails with the `OidcTokenUnavailable`.
|
|
23
|
+
*/
|
|
24
|
+
export const serverBlobAuth = (config, oidc) => {
|
|
25
|
+
const fallback = Option.flatMap(config.readWriteToken, (token) => Option.map(storeIdFromReadWriteToken(Redacted.value(token)), (storeId) => BlobRequestAuth.Bearer({ token, storeId })));
|
|
26
|
+
return BlobAuth.$match(config.auth, {
|
|
27
|
+
ReadWrite: ({ token, storeId }) => Effect.succeed(BlobRequestAuth.Bearer({ token, storeId })),
|
|
28
|
+
Oidc: ({ storeId }) => oidc.token.pipe(Effect.map((token) => BlobRequestAuth.Bearer({ token, storeId })), Effect.catchTag("OidcTokenUnavailable", (error) => Option.match(fallback, {
|
|
29
|
+
onNone: () => Effect.fail(error),
|
|
30
|
+
onSome: Effect.succeed,
|
|
31
|
+
}))),
|
|
32
|
+
});
|
|
33
|
+
};
|
|
34
|
+
/** Size of the chunks a progress-tracked body is sent in, as the SDK's `CHUNK_SIZE`. */
|
|
35
|
+
export const progressChunkSize = 64 * 1024;
|
|
36
|
+
const concatBytes = (a, b) => {
|
|
37
|
+
const result = new Uint8Array(a.length + b.length);
|
|
38
|
+
result.set(a);
|
|
39
|
+
result.set(b, a.length);
|
|
40
|
+
return result;
|
|
41
|
+
};
|
|
42
|
+
/**
|
|
43
|
+
* Regroup a byte stream into chunks of exactly `size` bytes, the last one possibly smaller, like
|
|
44
|
+
* the SDK's `createChunkTransformStream`. Empty input chunks produce nothing.
|
|
45
|
+
*/
|
|
46
|
+
export const chunkBytes = (size) => (stream) => Stream.mapAccum(stream, () => new Uint8Array(0), (pending, chunk) => {
|
|
47
|
+
let buffer = pending.length === 0 ? chunk : concatBytes(pending, chunk);
|
|
48
|
+
const out = [];
|
|
49
|
+
while (buffer.length >= size) {
|
|
50
|
+
out.push(buffer.slice(0, size));
|
|
51
|
+
buffer = buffer.subarray(size);
|
|
52
|
+
}
|
|
53
|
+
return [buffer, out];
|
|
54
|
+
}, { onHalt: (buffer) => (buffer.length > 0 ? [buffer.slice()] : []) });
|
|
55
|
+
const textEncoder = new TextEncoder();
|
|
56
|
+
const isBlob = (body) => typeof globalThis.Blob !== "undefined" && body instanceof globalThis.Blob;
|
|
57
|
+
const isStreamBody = (body) => Stream.isStream(body);
|
|
58
|
+
/**
|
|
59
|
+
* Bytes a body will send when known up front, as the SDK's `computeBodyLength`: UTF-8 length of a
|
|
60
|
+
* string, byte length, `Blob` size; 0 for a stream.
|
|
61
|
+
*/
|
|
62
|
+
export const bodyLength = (body) => {
|
|
63
|
+
if (typeof body === "string")
|
|
64
|
+
return textEncoder.encode(body).byteLength;
|
|
65
|
+
if (body instanceof Uint8Array)
|
|
66
|
+
return body.byteLength;
|
|
67
|
+
if (isBlob(body))
|
|
68
|
+
return body.size;
|
|
69
|
+
return 0;
|
|
70
|
+
};
|
|
71
|
+
/** A body as a stream of bytes. A `Blob` that cannot be read is a defect. */
|
|
72
|
+
export const bodyStream = (body) => {
|
|
73
|
+
if (typeof body === "string")
|
|
74
|
+
return Stream.succeed(textEncoder.encode(body));
|
|
75
|
+
if (body instanceof Uint8Array)
|
|
76
|
+
return Stream.succeed(body);
|
|
77
|
+
if (isBlob(body)) {
|
|
78
|
+
return Stream.fromReadableStream({
|
|
79
|
+
evaluate: () => body.stream(),
|
|
80
|
+
onError: (cause) => cause,
|
|
81
|
+
}).pipe(Stream.orDie);
|
|
82
|
+
}
|
|
83
|
+
return body;
|
|
84
|
+
};
|
|
85
|
+
const isNodeProcess = () => {
|
|
86
|
+
if (typeof navigator !== "undefined" && navigator.product === "ReactNative")
|
|
87
|
+
return true;
|
|
88
|
+
const process = globalThis.process;
|
|
89
|
+
if (process === undefined)
|
|
90
|
+
return false;
|
|
91
|
+
if (process.type === "renderer" || process.type === "worker")
|
|
92
|
+
return false;
|
|
93
|
+
return process.versions?.node !== undefined;
|
|
94
|
+
};
|
|
95
|
+
/**
|
|
96
|
+
* Whether `fetch` can stream a request body here, detected like the SDK's
|
|
97
|
+
* `supportsRequestStreams`: always on Node; never against `http://localhost` (no HTTP/2); otherwise
|
|
98
|
+
* when `Request` reads the `duplex` option and does not type a stream body (Chromium, Edge
|
|
99
|
+
* runtimes, not Safari or Firefox).
|
|
100
|
+
*/
|
|
101
|
+
export const supportsRequestStreams = (apiUrl) => {
|
|
102
|
+
if (isNodeProcess())
|
|
103
|
+
return true;
|
|
104
|
+
if (apiUrl.startsWith("http://localhost"))
|
|
105
|
+
return false;
|
|
106
|
+
try {
|
|
107
|
+
let duplexAccessed = false;
|
|
108
|
+
const init = {
|
|
109
|
+
body: new ReadableStream(),
|
|
110
|
+
method: "POST",
|
|
111
|
+
get duplex() {
|
|
112
|
+
duplexAccessed = true;
|
|
113
|
+
return "half";
|
|
114
|
+
},
|
|
115
|
+
};
|
|
116
|
+
const hasContentType = new Request(apiUrl, init).headers.has("Content-Type");
|
|
117
|
+
return duplexAccessed && !hasContentType;
|
|
118
|
+
}
|
|
119
|
+
catch {
|
|
120
|
+
return false;
|
|
121
|
+
}
|
|
122
|
+
};
|
|
123
|
+
/**
|
|
124
|
+
* Throttle progress events like `throttleit`, which the SDK wraps `onUploadProgress` in: the first
|
|
125
|
+
* event after a quiet interval is reported at once, later ones at most once per `interval`, and the
|
|
126
|
+
* latest event of an interval is reported when it ends (earlier ones are dropped).
|
|
127
|
+
*
|
|
128
|
+
* The interval starts now, as if an event had just been reported (callers report 0 % first). Call
|
|
129
|
+
* `stop` before the final 100 % event, which callers report directly so it is never delayed.
|
|
130
|
+
* Without an interval (or a zero one), events are reported immediately.
|
|
131
|
+
*/
|
|
132
|
+
export const uploadProgressThrottle = Effect.fnUntraced(function* (onUploadProgress, interval) {
|
|
133
|
+
if (interval === undefined || Duration.isZero(Duration.fromInputUnsafe(interval))) {
|
|
134
|
+
return { report: onUploadProgress, stop: Effect.void };
|
|
135
|
+
}
|
|
136
|
+
const latest = yield* Queue.sliding(1);
|
|
137
|
+
const fiber = yield* Effect.forkChild(Effect.sleep(interval).pipe(Effect.andThen(Effect.forever(Queue.take(latest).pipe(Effect.flatMap(onUploadProgress), Effect.andThen(Effect.sleep(interval)))))));
|
|
138
|
+
return {
|
|
139
|
+
report: (progress) => Effect.asVoid(Queue.offer(latest, progress)),
|
|
140
|
+
stop: Fiber.interrupt(fiber),
|
|
141
|
+
};
|
|
142
|
+
});
|
|
143
|
+
const unexpectedResponse = (operation, status, message) => new VercelApiError({
|
|
144
|
+
operation,
|
|
145
|
+
errorCode: Option.none(),
|
|
146
|
+
reason: new ApiUnexpectedResponse({ message, status }),
|
|
147
|
+
});
|
|
148
|
+
const withoutTracePropagation = Effect.provideService(HttpClient.TracerPropagationEnabled, false);
|
|
149
|
+
/**
|
|
150
|
+
* Build the {@link BlobRequester} that every service uses for Blob API calls.
|
|
151
|
+
*
|
|
152
|
+
* Requests carry no `traceparent`/`b3` headers (the SDK sends none, and browsers would need CORS
|
|
153
|
+
* approval for them); the HTTP client still records a span per attempt.
|
|
154
|
+
*/
|
|
155
|
+
export const blobRequester = (settings) => {
|
|
156
|
+
const baseUrl = settings.apiUrl.href.replace(/\/+$/, "");
|
|
157
|
+
const streamsSupported = settings.streamRequestBodies ?? supportsRequestStreams(settings.apiUrl.href);
|
|
158
|
+
const client = settings.httpClient;
|
|
159
|
+
const requestUrl = (path, auth) => {
|
|
160
|
+
const url = `${baseUrl}${path}`;
|
|
161
|
+
return BlobRequestAuth.$match(auth, {
|
|
162
|
+
Bearer: () => url,
|
|
163
|
+
Presigned: ({ payload }) => {
|
|
164
|
+
const presigned = new URL(url);
|
|
165
|
+
for (const [key, value] of Object.entries(payload.params)) {
|
|
166
|
+
presigned.searchParams.set(key, value);
|
|
167
|
+
}
|
|
168
|
+
presigned.searchParams.set("vercel-blob-delegation", payload.delegationToken);
|
|
169
|
+
presigned.searchParams.set("vercel-blob-signature", payload.signature);
|
|
170
|
+
return presigned.toString();
|
|
171
|
+
},
|
|
172
|
+
});
|
|
173
|
+
};
|
|
174
|
+
const call = Effect.fnUntraced(function* (call) {
|
|
175
|
+
const { operation } = call;
|
|
176
|
+
const auth = yield* call.auth;
|
|
177
|
+
const url = requestUrl(call.path, auth);
|
|
178
|
+
const now = yield* Clock.currentTimeMillis;
|
|
179
|
+
const random = yield* Random.next;
|
|
180
|
+
const requestId = `${auth.storeId}:${now}:${random.toString(16).slice(2)}`;
|
|
181
|
+
const body = call.json === undefined ? call.body : JSON.stringify(call.json);
|
|
182
|
+
const onUploadProgress = call.onUploadProgress;
|
|
183
|
+
const sendBodyLength = onUploadProgress !== undefined || settings.sendContentLength;
|
|
184
|
+
const totalLength = body !== undefined && sendBodyLength ? bodyLength(body) : 0;
|
|
185
|
+
const streamBody = body !== undefined && isStreamBody(body);
|
|
186
|
+
const context = yield* Effect.context();
|
|
187
|
+
const bodyFailure = yield* Ref.make(Option.none());
|
|
188
|
+
const totalLoaded = yield* Ref.make(0);
|
|
189
|
+
const userStream = (stream) => stream.pipe(Stream.tapError((error) => Ref.set(bodyFailure, Option.some(error))), Stream.provideContext(context));
|
|
190
|
+
const headersFor = (attempt) => ({
|
|
191
|
+
"x-api-blob-request-id": requestId,
|
|
192
|
+
"x-vercel-blob-store-id": auth.storeId,
|
|
193
|
+
"x-api-blob-request-attempt": String(attempt),
|
|
194
|
+
"x-api-version": settings.apiVersion,
|
|
195
|
+
...(sendBodyLength ? { "x-content-length": String(totalLength) } : {}),
|
|
196
|
+
...BlobRequestAuth.$match(auth, {
|
|
197
|
+
Bearer: ({ token }) => ({ authorization: `Bearer ${Redacted.value(token)}` }),
|
|
198
|
+
Presigned: () => ({}),
|
|
199
|
+
}),
|
|
200
|
+
...settings.headers,
|
|
201
|
+
...(call.json === undefined ? {} : { "content-type": "application/json" }),
|
|
202
|
+
...call.headers,
|
|
203
|
+
});
|
|
204
|
+
// A streamed body is sent untyped, like the SDK's `ReadableStream` bodies.
|
|
205
|
+
const streamedBody = (stream) => (request) => request.pipe(HttpClientRequest.setBody(HttpBody.stream(stream)), HttpClientRequest.removeHeader("content-type"));
|
|
206
|
+
const withBody = (reporter) => Effect.gen(function* () {
|
|
207
|
+
if (body === undefined) {
|
|
208
|
+
return (request) => request;
|
|
209
|
+
}
|
|
210
|
+
if (!streamsSupported) {
|
|
211
|
+
const bytes = streamBody
|
|
212
|
+
? (yield* Stream.runCollect(Stream.provideContext(body, context))).reduce(concatBytes, new Uint8Array(0))
|
|
213
|
+
: undefined;
|
|
214
|
+
yield* Ref.set(totalLoaded, bytes === undefined ? totalLength : bytes.length);
|
|
215
|
+
return HttpClientRequest.setBody(HttpBody.raw(bytes ?? body));
|
|
216
|
+
}
|
|
217
|
+
if (reporter !== undefined) {
|
|
218
|
+
const loaded = yield* Ref.make(0);
|
|
219
|
+
const source = streamBody
|
|
220
|
+
? userStream(body)
|
|
221
|
+
: bodyStream(body);
|
|
222
|
+
const tracked = source.pipe(chunkBytes(progressChunkSize), Stream.tap((chunk) => Effect.gen(function* () {
|
|
223
|
+
const sent = yield* Ref.updateAndGet(loaded, (n) => n + chunk.length);
|
|
224
|
+
yield* Ref.set(totalLoaded, sent);
|
|
225
|
+
const total = totalLength !== 0 ? totalLength : sent;
|
|
226
|
+
const percentage = totalLength > 0 ? Number(((sent / total) * 100).toFixed(2)) : 0;
|
|
227
|
+
if (percentage === 100 && totalLength > 0)
|
|
228
|
+
return;
|
|
229
|
+
yield* reporter.report({ loaded: sent, total, percentage });
|
|
230
|
+
})));
|
|
231
|
+
return streamedBody(tracked);
|
|
232
|
+
}
|
|
233
|
+
if (streamBody) {
|
|
234
|
+
return streamedBody(userStream(body));
|
|
235
|
+
}
|
|
236
|
+
return HttpClientRequest.setBody(HttpBody.raw(body));
|
|
237
|
+
});
|
|
238
|
+
const failTransport = (error) => Effect.flatMap(Ref.get(bodyFailure), Option.match({
|
|
239
|
+
onNone: () => vercelApiErrorFromHttpClientError(error, { operation }),
|
|
240
|
+
onSome: (failure) => Effect.fail(failure),
|
|
241
|
+
}));
|
|
242
|
+
const attempts = yield* Ref.make(0);
|
|
243
|
+
const attempt = (reporter) => Effect.gen(function* () {
|
|
244
|
+
const index = yield* Ref.getAndUpdate(attempts, (n) => n + 1);
|
|
245
|
+
const setBody = yield* withBody(reporter);
|
|
246
|
+
const request = HttpClientRequest.make(call.method)(url).pipe(setBody, HttpClientRequest.setHeaders(headersFor(index)));
|
|
247
|
+
const response = yield* client
|
|
248
|
+
.execute(request)
|
|
249
|
+
.pipe(Effect.catchTag("HttpClientError", failTransport));
|
|
250
|
+
if (response.status >= 200 && response.status < 300) {
|
|
251
|
+
return response;
|
|
252
|
+
}
|
|
253
|
+
return yield* blobErrorFromHttpResponse(response, {
|
|
254
|
+
operation,
|
|
255
|
+
locator: call.locator ?? call.path,
|
|
256
|
+
domainErrors: call.domainErrors,
|
|
257
|
+
});
|
|
258
|
+
}).pipe(Effect.retry(vercelApiTransientRetry({
|
|
259
|
+
maxAttempts: streamBody ? 1 : settings.retries + 1,
|
|
260
|
+
baseDelay: "1 second",
|
|
261
|
+
isRetryable: isRetryableBlobError,
|
|
262
|
+
})));
|
|
263
|
+
const response = onUploadProgress === undefined
|
|
264
|
+
? yield* attempt(undefined)
|
|
265
|
+
: yield* Effect.gen(function* () {
|
|
266
|
+
yield* onUploadProgress({ loaded: 0, total: totalLength, percentage: 0 });
|
|
267
|
+
const reporter = yield* uploadProgressThrottle(onUploadProgress, call.progressInterval);
|
|
268
|
+
const response = yield* attempt(reporter).pipe(Effect.ensuring(reporter.stop));
|
|
269
|
+
const loaded = yield* Ref.get(totalLoaded);
|
|
270
|
+
yield* onUploadProgress({ loaded, total: loaded, percentage: 100 });
|
|
271
|
+
return response;
|
|
272
|
+
});
|
|
273
|
+
if (call.response === undefined) {
|
|
274
|
+
yield* Effect.ignore(response.arrayBuffer);
|
|
275
|
+
return undefined;
|
|
276
|
+
}
|
|
277
|
+
const json = yield* response.json.pipe(Effect.mapError((error) => unexpectedResponse(operation, response.status, error.message)));
|
|
278
|
+
return yield* Schema.decodeUnknownEffect(call.response)(json).pipe(Effect.mapError((error) => unexpectedResponse(operation, response.status, `Unexpected response body: ${error.message}`)));
|
|
279
|
+
});
|
|
280
|
+
const fetch = (request) => client
|
|
281
|
+
.execute(HttpClientRequest.get(request.url).pipe(HttpClientRequest.setHeaders({
|
|
282
|
+
authorization: `Bearer ${Redacted.value(request.token)}`,
|
|
283
|
+
...request.headers,
|
|
284
|
+
})))
|
|
285
|
+
.pipe(Effect.catchTag("HttpClientError", (error) => vercelApiErrorFromHttpClientError(error, { operation: request.operation })), withoutTracePropagation);
|
|
286
|
+
return {
|
|
287
|
+
call: (request) => withoutTracePropagation(call(request)),
|
|
288
|
+
fetch,
|
|
289
|
+
};
|
|
290
|
+
};
|
|
291
|
+
//# sourceMappingURL=blob-request.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"blob-request.js","sourceRoot":"","sources":["../../src/internal/blob-request.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import type { VercelSystemEnv } from "@panorama-industries/effect-vercel-core";
|
|
2
|
+
import { Effect, Option } from "effect";
|
|
3
|
+
/** Header that carries the signature of an upload-completed callback. */
|
|
4
|
+
export declare const callbackSignatureHeader = "x-vercel-signature";
|
|
5
|
+
/** The SDK's warning when an upload route has `onUploadCompleted` but no callback URL. */
|
|
6
|
+
export declare const callbackUrlUndeterminedWarning = "onUploadCompleted provided but no callbackUrl could be determined. Please provide a callbackUrl in onBeforeGenerateToken or set the VERCEL_BLOB_CALLBACK_URL environment variable.";
|
|
7
|
+
/** The SDK's warning when an upload route returns a callback URL but has no `onUploadCompleted`. */
|
|
8
|
+
export declare const callbackUrlUnhandledWarning = "callbackUrl was provided but onUploadCompleted is not defined. The callback will not be handled.";
|
|
9
|
+
/**
|
|
10
|
+
* Path and query of a request URL, absolute or relative, as the SDK's `getPathFromRequestUrl`.
|
|
11
|
+
*
|
|
12
|
+
* @returns None when the URL cannot be parsed.
|
|
13
|
+
*/
|
|
14
|
+
export declare const requestPath: (url: string) => Option.Option<string>;
|
|
15
|
+
/**
|
|
16
|
+
* Where the store should send the upload-completed callback of this route when the route gave no
|
|
17
|
+
* URL, as the SDK's `getCallbackUrl`, in order: `callbackBaseUrl` (`VERCEL_BLOB_CALLBACK_URL`) plus
|
|
18
|
+
* the request's path and query; on Vercel, the branch URL, else the deployment URL, of a preview, or
|
|
19
|
+
* the production URL of production. Logs the SDK's warning when the request URL cannot be parsed or
|
|
20
|
+
* the code runs neither with a callback base URL nor on Vercel.
|
|
21
|
+
*
|
|
22
|
+
* @param requestUrl - The request's original URL, absolute or a path.
|
|
23
|
+
*/
|
|
24
|
+
export declare const deriveCallbackUrl: (args: {
|
|
25
|
+
readonly requestUrl: string;
|
|
26
|
+
readonly callbackBaseUrl: Option.Option<string>;
|
|
27
|
+
readonly env: VercelSystemEnv["Service"];
|
|
28
|
+
}) => Effect.Effect<Option.Option<string>, never, never>;
|
|
29
|
+
/**
|
|
30
|
+
* The callback URL to sign into an upload, as `handleUpload` and `handleUploadPresigned` choose it:
|
|
31
|
+
* the route's URL, else (with `onUploadCompleted`) the derived one. Without `onUploadCompleted`, a
|
|
32
|
+
* route URL is kept and the SDK's warning logged, since nothing will handle the callback.
|
|
33
|
+
*
|
|
34
|
+
* @param derive - {@link deriveCallbackUrl} for this request; run only when needed.
|
|
35
|
+
*/
|
|
36
|
+
export declare const resolveCallbackUrl: <E, R>(args: {
|
|
37
|
+
readonly provided: string | undefined;
|
|
38
|
+
readonly handlesCallback: boolean;
|
|
39
|
+
readonly derive: Effect.Effect<Option.Option<string>, E, R>;
|
|
40
|
+
}) => Effect.Effect<Option.Option<string>, E, R>;
|
|
41
|
+
/**
|
|
42
|
+
* The text a callback signature covers: the body re-serialized as `JSON.stringify(JSON.parse(body))`,
|
|
43
|
+
* as the SDK signs the parsed body.
|
|
44
|
+
*
|
|
45
|
+
* @returns None when the body is not JSON.
|
|
46
|
+
*/
|
|
47
|
+
export declare const parseCallbackBody: (body: string) => Option.Option<{
|
|
48
|
+
readonly json: unknown;
|
|
49
|
+
readonly normalized: string;
|
|
50
|
+
}>;
|
|
51
|
+
/**
|
|
52
|
+
* Whether `signatureHex` is the HMAC-SHA256 (hex) of `body` keyed by the store's read-write token,
|
|
53
|
+
* as `handleUpload` verifies `x-vercel-signature`. Compared in constant time by Web Crypto `verify`;
|
|
54
|
+
* a signature that is not hex never verifies.
|
|
55
|
+
*/
|
|
56
|
+
export declare const verifyHmacCallbackSignature: (readWriteToken: string, signatureHex: string, body: string) => Effect.Effect<boolean, never, never>;
|
|
57
|
+
/**
|
|
58
|
+
* DER bytes of a PEM `-----BEGIN PUBLIC KEY-----` (SPKI) block, as the SDK's
|
|
59
|
+
* `publicKeyDerFromPem`.
|
|
60
|
+
*
|
|
61
|
+
* @returns None when there is no such block or its content is not base64.
|
|
62
|
+
*/
|
|
63
|
+
export declare const publicKeyDerFromPem: (pem: string) => Option.Option<Uint8Array>;
|
|
64
|
+
/**
|
|
65
|
+
* Whether `signatureHex` is an Ed25519 signature of `body` by the key in `publicKeyPem` (SPKI PEM,
|
|
66
|
+
* `BLOB_WEBHOOK_PUBLIC_KEY`), as `handleUploadPresigned` verifies `x-vercel-signature`. The
|
|
67
|
+
* signature must be 128 hex characters; a key that cannot be imported never verifies.
|
|
68
|
+
*/
|
|
69
|
+
export declare const verifyEd25519CallbackSignature: (publicKeyPem: string, signatureHex: string, body: string) => Effect.Effect<boolean, never, never>;
|
|
70
|
+
//# sourceMappingURL=callback.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"callback.d.ts","sourceRoot":"","sources":["../../src/internal/callback.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,yCAAyC,CAAC;AAE/E,OAAO,EAAE,MAAM,EAAE,MAAM,EAAU,MAAM,QAAQ,CAAC;AAQhD,yEAAyE;AACzE,eAAO,MAAM,uBAAuB,uBAAuB,CAAC;AAE5D,0FAA0F;AAC1F,eAAO,MAAM,8BAA8B,uLAC2I,CAAC;AAEvL,oGAAoG;AACpG,eAAO,MAAM,2BAA2B,qGAC4D,CAAC;AAErG;;;;GAIG;AACH,eAAO,MAAM,WAAW,QAAS,MAAM,KAAG,MAAM,CAAC,MAAM,CAAC,MAAM,CAO7D,CAAC;AAEF;;;;;;;;GAQG;AACH,eAAO,MAAM,iBAAiB;yBACP,MAAM;8BACD,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC;kBACjC,eAAe,CAAC,SAAS,CAAC;wDA0BxC,CAAC;AAEH;;;;;;GAMG;AACH,eAAO,MAAM,kBAAkB,GAAgC,CAAC,EAAE,CAAC;uBAC9C,MAAM,GAAG,SAAS;8BACX,OAAO;qBAChB,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;gDAU3D,CAAC;AAEH;;;;;GAKG;AACH,eAAO,MAAM,iBAAiB,SACtB,MAAM,KACX,MAAM,CAAC,MAAM,CAAC;IAAE,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAA;CAAE,CAOvE,CAAC;AAIF;;;;GAIG;AACH,eAAO,MAAM,2BAA2B,sGA0BtC,CAAC;AAEH;;;;;GAKG;AACH,eAAO,MAAM,mBAAmB,QAAS,MAAM,KAAG,MAAM,CAAC,MAAM,CAAC,UAAU,CAOzE,CAAC;AAIF;;;;GAIG;AACH,eAAO,MAAM,8BAA8B,oGA4BzC,CAAC"}
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
import { Effect, Option, Result } from "effect";
|
|
2
|
+
import { Base64, Hex } from "effect/encoding";
|
|
3
|
+
/*
|
|
4
|
+
* Upload-completed callbacks, as the SDK's `client.ts` handles them: where the store sends them
|
|
5
|
+
* (`getCallbackUrl`) and how their `x-vercel-signature` is verified.
|
|
6
|
+
*/
|
|
7
|
+
/** Header that carries the signature of an upload-completed callback. */
|
|
8
|
+
export const callbackSignatureHeader = "x-vercel-signature";
|
|
9
|
+
/** The SDK's warning when an upload route has `onUploadCompleted` but no callback URL. */
|
|
10
|
+
export const callbackUrlUndeterminedWarning = "onUploadCompleted provided but no callbackUrl could be determined. Please provide a callbackUrl in onBeforeGenerateToken or set the VERCEL_BLOB_CALLBACK_URL environment variable.";
|
|
11
|
+
/** The SDK's warning when an upload route returns a callback URL but has no `onUploadCompleted`. */
|
|
12
|
+
export const callbackUrlUnhandledWarning = "callbackUrl was provided but onUploadCompleted is not defined. The callback will not be handled.";
|
|
13
|
+
/**
|
|
14
|
+
* Path and query of a request URL, absolute or relative, as the SDK's `getPathFromRequestUrl`.
|
|
15
|
+
*
|
|
16
|
+
* @returns None when the URL cannot be parsed.
|
|
17
|
+
*/
|
|
18
|
+
export const requestPath = (url) => {
|
|
19
|
+
const base = "https://dummy.com";
|
|
20
|
+
if (!URL.canParse(url, base)) {
|
|
21
|
+
return Option.none();
|
|
22
|
+
}
|
|
23
|
+
const parsed = new URL(url, base);
|
|
24
|
+
return Option.some(parsed.pathname + parsed.search);
|
|
25
|
+
};
|
|
26
|
+
/**
|
|
27
|
+
* Where the store should send the upload-completed callback of this route when the route gave no
|
|
28
|
+
* URL, as the SDK's `getCallbackUrl`, in order: `callbackBaseUrl` (`VERCEL_BLOB_CALLBACK_URL`) plus
|
|
29
|
+
* the request's path and query; on Vercel, the branch URL, else the deployment URL, of a preview, or
|
|
30
|
+
* the production URL of production. Logs the SDK's warning when the request URL cannot be parsed or
|
|
31
|
+
* the code runs neither with a callback base URL nor on Vercel.
|
|
32
|
+
*
|
|
33
|
+
* @param requestUrl - The request's original URL, absolute or a path.
|
|
34
|
+
*/
|
|
35
|
+
export const deriveCallbackUrl = Effect.fnUntraced(function* (args) {
|
|
36
|
+
const path = requestPath(args.requestUrl);
|
|
37
|
+
if (Option.isNone(path)) {
|
|
38
|
+
yield* Effect.logWarning(callbackUrlUndeterminedWarning);
|
|
39
|
+
return Option.none();
|
|
40
|
+
}
|
|
41
|
+
if (Option.isSome(args.callbackBaseUrl)) {
|
|
42
|
+
return Option.some(`${args.callbackBaseUrl.value}${path.value}`);
|
|
43
|
+
}
|
|
44
|
+
const { env } = args;
|
|
45
|
+
if (!env.isVercel) {
|
|
46
|
+
yield* Effect.logWarning(callbackUrlUndeterminedWarning);
|
|
47
|
+
return Option.none();
|
|
48
|
+
}
|
|
49
|
+
const onHost = (host) => `https://${host}${path.value}`;
|
|
50
|
+
if (Option.contains(env.target, "preview")) {
|
|
51
|
+
const previewHost = Option.orElse(env.branchUrl, () => env.url);
|
|
52
|
+
if (Option.isSome(previewHost)) {
|
|
53
|
+
return Option.some(onHost(previewHost.value));
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
if (Option.contains(env.target, "production")) {
|
|
57
|
+
return Option.map(env.projectProductionUrl, onHost);
|
|
58
|
+
}
|
|
59
|
+
return Option.none();
|
|
60
|
+
});
|
|
61
|
+
/**
|
|
62
|
+
* The callback URL to sign into an upload, as `handleUpload` and `handleUploadPresigned` choose it:
|
|
63
|
+
* the route's URL, else (with `onUploadCompleted`) the derived one. Without `onUploadCompleted`, a
|
|
64
|
+
* route URL is kept and the SDK's warning logged, since nothing will handle the callback.
|
|
65
|
+
*
|
|
66
|
+
* @param derive - {@link deriveCallbackUrl} for this request; run only when needed.
|
|
67
|
+
*/
|
|
68
|
+
export const resolveCallbackUrl = Effect.fnUntraced(function* (args) {
|
|
69
|
+
let callbackUrl = Option.filter(Option.fromUndefinedOr(args.provided), (url) => url !== "");
|
|
70
|
+
if (args.handlesCallback && Option.isNone(callbackUrl)) {
|
|
71
|
+
callbackUrl = yield* args.derive;
|
|
72
|
+
}
|
|
73
|
+
if (!args.handlesCallback && Option.isSome(callbackUrl)) {
|
|
74
|
+
yield* Effect.logWarning(callbackUrlUnhandledWarning);
|
|
75
|
+
}
|
|
76
|
+
return callbackUrl;
|
|
77
|
+
});
|
|
78
|
+
/**
|
|
79
|
+
* The text a callback signature covers: the body re-serialized as `JSON.stringify(JSON.parse(body))`,
|
|
80
|
+
* as the SDK signs the parsed body.
|
|
81
|
+
*
|
|
82
|
+
* @returns None when the body is not JSON.
|
|
83
|
+
*/
|
|
84
|
+
export const parseCallbackBody = (body) => {
|
|
85
|
+
try {
|
|
86
|
+
const json = JSON.parse(body);
|
|
87
|
+
return Option.some({ json, normalized: JSON.stringify(json) });
|
|
88
|
+
}
|
|
89
|
+
catch {
|
|
90
|
+
return Option.none();
|
|
91
|
+
}
|
|
92
|
+
};
|
|
93
|
+
const utf8 = new TextEncoder();
|
|
94
|
+
/**
|
|
95
|
+
* Whether `signatureHex` is the HMAC-SHA256 (hex) of `body` keyed by the store's read-write token,
|
|
96
|
+
* as `handleUpload` verifies `x-vercel-signature`. Compared in constant time by Web Crypto `verify`;
|
|
97
|
+
* a signature that is not hex never verifies.
|
|
98
|
+
*/
|
|
99
|
+
export const verifyHmacCallbackSignature = Effect.fnUntraced(function* (readWriteToken, signatureHex, body) {
|
|
100
|
+
const signature = Result.getSuccess(Hex.decode(signatureHex));
|
|
101
|
+
if (Option.isNone(signature)) {
|
|
102
|
+
return false;
|
|
103
|
+
}
|
|
104
|
+
const key = yield* Effect.promise(() => globalThis.crypto.subtle.importKey("raw", utf8.encode(readWriteToken), { name: "HMAC", hash: "SHA-256" }, false, ["verify"]));
|
|
105
|
+
return yield* Effect.promise(() => globalThis.crypto.subtle.verify("HMAC", key, Uint8Array.from(signature.value), utf8.encode(body)));
|
|
106
|
+
});
|
|
107
|
+
/**
|
|
108
|
+
* DER bytes of a PEM `-----BEGIN PUBLIC KEY-----` (SPKI) block, as the SDK's
|
|
109
|
+
* `publicKeyDerFromPem`.
|
|
110
|
+
*
|
|
111
|
+
* @returns None when there is no such block or its content is not base64.
|
|
112
|
+
*/
|
|
113
|
+
export const publicKeyDerFromPem = (pem) => {
|
|
114
|
+
const match = /-----BEGIN PUBLIC KEY-----([^-]*)-----END PUBLIC KEY-----/s.exec(pem.trim());
|
|
115
|
+
const base64 = match?.[1]?.replace(/\s+/g, "");
|
|
116
|
+
if (!base64) {
|
|
117
|
+
return Option.none();
|
|
118
|
+
}
|
|
119
|
+
return Result.getSuccess(Base64.decode(base64));
|
|
120
|
+
};
|
|
121
|
+
const ed25519SignatureHex = /^[0-9a-fA-F]{128}$/;
|
|
122
|
+
/**
|
|
123
|
+
* Whether `signatureHex` is an Ed25519 signature of `body` by the key in `publicKeyPem` (SPKI PEM,
|
|
124
|
+
* `BLOB_WEBHOOK_PUBLIC_KEY`), as `handleUploadPresigned` verifies `x-vercel-signature`. The
|
|
125
|
+
* signature must be 128 hex characters; a key that cannot be imported never verifies.
|
|
126
|
+
*/
|
|
127
|
+
export const verifyEd25519CallbackSignature = Effect.fnUntraced(function* (publicKeyPem, signatureHex, body) {
|
|
128
|
+
if (!ed25519SignatureHex.test(signatureHex)) {
|
|
129
|
+
return false;
|
|
130
|
+
}
|
|
131
|
+
const der = publicKeyDerFromPem(publicKeyPem);
|
|
132
|
+
const signature = Result.getSuccess(Hex.decode(signatureHex));
|
|
133
|
+
if (Option.isNone(der) || Option.isNone(signature)) {
|
|
134
|
+
return false;
|
|
135
|
+
}
|
|
136
|
+
return yield* Effect.tryPromise(async () => {
|
|
137
|
+
const key = await globalThis.crypto.subtle.importKey("spki", Uint8Array.from(der.value), { name: "Ed25519" }, false, ["verify"]);
|
|
138
|
+
return globalThis.crypto.subtle.verify("Ed25519", key, Uint8Array.from(signature.value), utf8.encode(body));
|
|
139
|
+
}).pipe(Effect.orElseSucceed(() => false));
|
|
140
|
+
});
|
|
141
|
+
//# sourceMappingURL=callback.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"callback.js","sourceRoot":"","sources":["../../src/internal/callback.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { Effect, Option, Schema } from "effect";
|
|
2
|
+
/** Prefix of every client token. */
|
|
3
|
+
export declare const clientTokenPrefix = "vercel_blob_client_";
|
|
4
|
+
/** How long a client token generated without `validUntil` stays valid, as the SDK: 30 seconds. */
|
|
5
|
+
export declare const defaultClientTokenLifetimeMillis = 30000;
|
|
6
|
+
/**
|
|
7
|
+
* Fields of a client token's JSON, already in wire form (`validUntil` in epoch milliseconds), in
|
|
8
|
+
* the order they are serialized. `undefined` values are omitted, as `JSON.stringify` omits them.
|
|
9
|
+
*/
|
|
10
|
+
export type ClientTokenFields = Readonly<Record<string, unknown>>;
|
|
11
|
+
/**
|
|
12
|
+
* The JSON a client token encodes, as the SDK serializes it: the fields in their order, with
|
|
13
|
+
* `allowOverwrite: true` appended when `ifMatch` is set and `allowOverwrite` is not, and
|
|
14
|
+
* `validUntil` defaulted to `defaultValidUntil` (kept in place when the fields have it).
|
|
15
|
+
*
|
|
16
|
+
* Callers reject `ifMatch` with `allowOverwrite: false` first; see {@link contradictsIfMatch}.
|
|
17
|
+
*/
|
|
18
|
+
export declare const clientTokenPayloadJson: (fields: ClientTokenFields, defaultValidUntil: number) => string;
|
|
19
|
+
/** The SDK's message for an `ifMatch` with `allowOverwrite: false`, which it refuses to sign. */
|
|
20
|
+
export declare const ifMatchContradictionMessage = "ifMatch and allowOverwrite: false are contradictory. ifMatch is used for conditional overwrites, which requires allowOverwrite to be true.";
|
|
21
|
+
/** Whether the fields set `ifMatch` together with `allowOverwrite: false`, which the SDK rejects. */
|
|
22
|
+
export declare const contradictsIfMatch: (fields: ClientTokenFields) => boolean;
|
|
23
|
+
/** HMAC-SHA256 of `data` keyed by `secret` (both UTF-8), as lowercase hex. */
|
|
24
|
+
export declare const hmacSha256Hex: (secret: string, data: string) => Effect.Effect<string, never, never>;
|
|
25
|
+
/**
|
|
26
|
+
* Sign a client token's JSON with the store's read-write token.
|
|
27
|
+
*
|
|
28
|
+
* @param payloadJson - The token's JSON, from {@link clientTokenPayloadJson}.
|
|
29
|
+
* @returns `vercel_blob_client_<storeId>_<base64("<hex HMAC>.<base64 payloadJson>")>`.
|
|
30
|
+
*/
|
|
31
|
+
export declare const signClientToken: (readWriteToken: string, storeId: string & import("effect/Brand").Brand<"StoreId">, payloadJson: string) => Effect.Effect<string & import("effect/Brand").Brand<"ClientToken">, never, never>;
|
|
32
|
+
/** `onUploadCompleted` as a client token carries it. */
|
|
33
|
+
export declare const ClientTokenCallback: Schema.Struct<{
|
|
34
|
+
readonly callbackUrl: Schema.String;
|
|
35
|
+
readonly tokenPayload: Schema.optionalKey<Schema.NullOr<Schema.String>>;
|
|
36
|
+
}>;
|
|
37
|
+
/** The JSON a client token encodes, as the SDK's `DecodedClientTokenPayload`. */
|
|
38
|
+
export declare const ClientTokenPayload: Schema.Struct<{
|
|
39
|
+
readonly pathname: Schema.String;
|
|
40
|
+
/** Expiry in epoch milliseconds. */
|
|
41
|
+
readonly validUntil: Schema.Number;
|
|
42
|
+
readonly onUploadCompleted: Schema.optionalKey<Schema.Struct<{
|
|
43
|
+
readonly callbackUrl: Schema.String;
|
|
44
|
+
readonly tokenPayload: Schema.optionalKey<Schema.NullOr<Schema.String>>;
|
|
45
|
+
}>>;
|
|
46
|
+
readonly maximumSizeInBytes: Schema.optionalKey<Schema.Number>;
|
|
47
|
+
readonly allowedContentTypes: Schema.optionalKey<Schema.$Array<Schema.String>>;
|
|
48
|
+
readonly addRandomSuffix: Schema.optionalKey<Schema.Boolean>;
|
|
49
|
+
readonly allowOverwrite: Schema.optionalKey<Schema.Boolean>;
|
|
50
|
+
readonly cacheControlMaxAge: Schema.optionalKey<Schema.Number>;
|
|
51
|
+
readonly ifMatch: Schema.optionalKey<Schema.String>;
|
|
52
|
+
/** Set by upload routes, which copy the route's `tokenPayload` into the token as the SDK does. */
|
|
53
|
+
readonly tokenPayload: Schema.optionalKey<Schema.NullOr<Schema.String>>;
|
|
54
|
+
}>;
|
|
55
|
+
/** The JSON a client token encodes. */
|
|
56
|
+
export type ClientTokenPayload = typeof ClientTokenPayload.Type;
|
|
57
|
+
/**
|
|
58
|
+
* Read the JSON a client token encodes without verifying its signature, as the SDK's
|
|
59
|
+
* `getPayloadFromClientToken`: the fifth `_`-separated segment is base64 of `<hmac>.<base64 JSON>`.
|
|
60
|
+
* Works in browsers.
|
|
61
|
+
*
|
|
62
|
+
* @returns None when the token does not have that shape or its JSON is not a client token payload.
|
|
63
|
+
*/
|
|
64
|
+
export declare const getPayloadFromClientToken: (clientToken: string) => Option.Option<ClientTokenPayload>;
|
|
65
|
+
//# sourceMappingURL=client-token.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client-token.d.ts","sourceRoot":"","sources":["../../src/internal/client-token.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,EAAU,MAAM,EAAE,MAAM,QAAQ,CAAC;AAcxD,oCAAoC;AACpC,eAAO,MAAM,iBAAiB,wBAAwB,CAAC;AAEvD,kGAAkG;AAClG,eAAO,MAAM,gCAAgC,QAAS,CAAC;AAEvD;;;GAGG;AACH,MAAM,MAAM,iBAAiB,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;AAElE;;;;;;GAMG;AACH,eAAO,MAAM,sBAAsB,WACzB,iBAAiB,qBACN,MAAM,KACxB,MAMF,CAAC;AAEF,iGAAiG;AACjG,eAAO,MAAM,2BAA2B,+IACsG,CAAC;AAE/I,qGAAqG;AACrG,eAAO,MAAM,kBAAkB,WAAY,iBAAiB,KAAG,OACG,CAAC;AAInE,8EAA8E;AAC9E,eAAO,MAAM,aAAa,uEAcxB,CAAC;AAEH;;;;;GAKG;AACH,eAAO,MAAM,eAAe,+LAU1B,CAAC;AAEH,wDAAwD;AACxD,eAAO,MAAM,mBAAmB;;;EAG9B,CAAC;AAEH,iFAAiF;AACjF,eAAO,MAAM,kBAAkB;;IAE7B,oCAAoC;;;;;;;;;;;;IASpC,kGAAkG;;EAElG,CAAC;AAEH,uCAAuC;AACvC,MAAM,MAAM,kBAAkB,GAAG,OAAO,kBAAkB,CAAC,IAAI,CAAC;AAOhE;;;;;;GAMG;AACH,eAAO,MAAM,yBAAyB,gBAAiB,MAAM,KAAG,MAAM,CAAC,MAAM,CAAC,kBAAkB,CAK7F,CAAC"}
|