@vercel/blob 0.27.0 → 0.27.1

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/dist/client.cjs CHANGED
@@ -7,66 +7,56 @@
7
7
 
8
8
 
9
9
 
10
- var _chunkXTBGGUVNcjs = require('./chunk-XTBGGUVN.cjs');
10
+ var _chunkA3XDFQYYcjs = require('./chunk-A3XDFQYY.cjs');
11
11
 
12
12
  // src/client.ts
13
13
  var _crypto = require('crypto'); var crypto = _interopRequireWildcard(_crypto);
14
14
  var _undici = require('undici');
15
15
  function createPutExtraChecks(methodName) {
16
16
  return function extraChecks(options) {
17
- if (typeof window === "undefined") {
18
- throw new (0, _chunkXTBGGUVNcjs.BlobError)(
19
- `${methodName} must be called from a client environment`
20
- );
21
- }
22
17
  if (!options.token.startsWith("vercel_blob_client_")) {
23
- throw new (0, _chunkXTBGGUVNcjs.BlobError)(`${methodName} must be called with a client token`);
18
+ throw new (0, _chunkA3XDFQYYcjs.BlobError)(`${methodName} must be called with a client token`);
24
19
  }
25
20
  if (
26
21
  // @ts-expect-error -- Runtime check for DX.
27
22
  options.addRandomSuffix !== void 0 || // @ts-expect-error -- Runtime check for DX.
28
23
  options.cacheControlMaxAge !== void 0
29
24
  ) {
30
- throw new (0, _chunkXTBGGUVNcjs.BlobError)(
25
+ throw new (0, _chunkA3XDFQYYcjs.BlobError)(
31
26
  `${methodName} doesn't allow addRandomSuffix and cacheControlMaxAge. Configure these options at the server side when generating client tokens.`
32
27
  );
33
28
  }
34
29
  };
35
30
  }
36
- var put = _chunkXTBGGUVNcjs.createPutMethod.call(void 0, {
31
+ var put = _chunkA3XDFQYYcjs.createPutMethod.call(void 0, {
37
32
  allowedOptions: ["contentType"],
38
33
  extraChecks: createPutExtraChecks("client/`put`")
39
34
  });
40
- var createMultipartUpload = _chunkXTBGGUVNcjs.createCreateMultipartUploadMethod.call(void 0, {
35
+ var createMultipartUpload = _chunkA3XDFQYYcjs.createCreateMultipartUploadMethod.call(void 0, {
41
36
  allowedOptions: ["contentType"],
42
37
  extraChecks: createPutExtraChecks("client/`createMultipartUpload`")
43
38
  });
44
- var createMultipartUploader = _chunkXTBGGUVNcjs.createCreateMultipartUploaderMethod.call(void 0,
39
+ var createMultipartUploader = _chunkA3XDFQYYcjs.createCreateMultipartUploaderMethod.call(void 0,
45
40
  {
46
41
  allowedOptions: ["contentType"],
47
42
  extraChecks: createPutExtraChecks("client/`createMultipartUpload`")
48
43
  }
49
44
  );
50
- var uploadPart = _chunkXTBGGUVNcjs.createUploadPartMethod.call(void 0, {
45
+ var uploadPart = _chunkA3XDFQYYcjs.createUploadPartMethod.call(void 0, {
51
46
  allowedOptions: ["contentType"],
52
47
  extraChecks: createPutExtraChecks("client/`multipartUpload`")
53
48
  });
54
- var completeMultipartUpload = _chunkXTBGGUVNcjs.createCompleteMultipartUploadMethod.call(void 0,
49
+ var completeMultipartUpload = _chunkA3XDFQYYcjs.createCompleteMultipartUploadMethod.call(void 0,
55
50
  {
56
51
  allowedOptions: ["contentType"],
57
52
  extraChecks: createPutExtraChecks("client/`completeMultipartUpload`")
58
53
  }
59
54
  );
60
- var upload = _chunkXTBGGUVNcjs.createPutMethod.call(void 0, {
55
+ var upload = _chunkA3XDFQYYcjs.createPutMethod.call(void 0, {
61
56
  allowedOptions: ["contentType"],
62
57
  extraChecks(options) {
63
- if (typeof window === "undefined") {
64
- throw new (0, _chunkXTBGGUVNcjs.BlobError)(
65
- "client/`upload` must be called from a client environment"
66
- );
67
- }
68
58
  if (options.handleUploadUrl === void 0) {
69
- throw new (0, _chunkXTBGGUVNcjs.BlobError)(
59
+ throw new (0, _chunkA3XDFQYYcjs.BlobError)(
70
60
  "client/`upload` requires the 'handleUploadUrl' parameter"
71
61
  );
72
62
  }
@@ -75,7 +65,7 @@ var upload = _chunkXTBGGUVNcjs.createPutMethod.call(void 0, {
75
65
  options.addRandomSuffix !== void 0 || // @ts-expect-error -- Runtime check for DX.
76
66
  options.cacheControlMaxAge !== void 0
77
67
  ) {
78
- throw new (0, _chunkXTBGGUVNcjs.BlobError)(
68
+ throw new (0, _chunkA3XDFQYYcjs.BlobError)(
79
69
  "client/`upload` doesn't allow addRandomSuffix and cacheControlMaxAge. Configure these options at the server side when generating client tokens."
80
70
  );
81
71
  }
@@ -158,7 +148,7 @@ async function handleUpload({
158
148
  onUploadCompleted
159
149
  }) {
160
150
  var _a, _b, _c, _d;
161
- const resolvedToken = _chunkXTBGGUVNcjs.getTokenFromOptionsOrEnv.call(void 0, { token });
151
+ const resolvedToken = _chunkA3XDFQYYcjs.getTokenFromOptionsOrEnv.call(void 0, { token });
162
152
  const type = body.type;
163
153
  switch (type) {
164
154
  case "blob.generate-client-token": {
@@ -190,7 +180,7 @@ async function handleUpload({
190
180
  const signatureHeader = "x-vercel-signature";
191
181
  const signature = "credentials" in request ? (_c = request.headers.get(signatureHeader)) != null ? _c : "" : (_d = request.headers[signatureHeader]) != null ? _d : "";
192
182
  if (!signature) {
193
- throw new (0, _chunkXTBGGUVNcjs.BlobError)("Missing callback signature");
183
+ throw new (0, _chunkA3XDFQYYcjs.BlobError)("Missing callback signature");
194
184
  }
195
185
  const isVerified = await verifyCallbackSignature({
196
186
  token: resolvedToken,
@@ -198,13 +188,13 @@ async function handleUpload({
198
188
  body: JSON.stringify(body)
199
189
  });
200
190
  if (!isVerified) {
201
- throw new (0, _chunkXTBGGUVNcjs.BlobError)("Invalid callback signature");
191
+ throw new (0, _chunkA3XDFQYYcjs.BlobError)("Invalid callback signature");
202
192
  }
203
193
  await onUploadCompleted(body.payload);
204
194
  return { type, response: "ok" };
205
195
  }
206
196
  default:
207
- throw new (0, _chunkXTBGGUVNcjs.BlobError)("Invalid event type");
197
+ throw new (0, _chunkA3XDFQYYcjs.BlobError)("Invalid event type");
208
198
  }
209
199
  }
210
200
  async function retrieveClientToken(options) {
@@ -228,17 +218,17 @@ async function retrieveClientToken(options) {
228
218
  signal: options.abortSignal
229
219
  });
230
220
  if (!res.ok) {
231
- throw new (0, _chunkXTBGGUVNcjs.BlobError)("Failed to retrieve the client token");
221
+ throw new (0, _chunkA3XDFQYYcjs.BlobError)("Failed to retrieve the client token");
232
222
  }
233
223
  try {
234
224
  const { clientToken } = await res.json();
235
225
  return clientToken;
236
226
  } catch (e) {
237
- throw new (0, _chunkXTBGGUVNcjs.BlobError)("Failed to retrieve the client token");
227
+ throw new (0, _chunkA3XDFQYYcjs.BlobError)("Failed to retrieve the client token");
238
228
  }
239
229
  }
240
230
  function toAbsoluteUrl(url) {
241
- return new URL(url, window.location.href).href;
231
+ return new URL(url, location.href).href;
242
232
  }
243
233
  function isAbsoluteUrl(url) {
244
234
  try {
@@ -253,16 +243,16 @@ async function generateClientTokenFromReadWriteToken({
253
243
  }) {
254
244
  var _a;
255
245
  if (typeof window !== "undefined") {
256
- throw new (0, _chunkXTBGGUVNcjs.BlobError)(
246
+ throw new (0, _chunkA3XDFQYYcjs.BlobError)(
257
247
  '"generateClientTokenFromReadWriteToken" must be called from a server environment'
258
248
  );
259
249
  }
260
250
  const timestamp = /* @__PURE__ */ new Date();
261
251
  timestamp.setSeconds(timestamp.getSeconds() + 30);
262
- const readWriteToken = _chunkXTBGGUVNcjs.getTokenFromOptionsOrEnv.call(void 0, { token });
252
+ const readWriteToken = _chunkA3XDFQYYcjs.getTokenFromOptionsOrEnv.call(void 0, { token });
263
253
  const [, , , storeId = null] = readWriteToken.split("_");
264
254
  if (!storeId) {
265
- throw new (0, _chunkXTBGGUVNcjs.BlobError)(
255
+ throw new (0, _chunkA3XDFQYYcjs.BlobError)(
266
256
  token ? "Invalid `token` parameter" : "Invalid `BLOB_READ_WRITE_TOKEN`"
267
257
  );
268
258
  }
@@ -274,7 +264,7 @@ async function generateClientTokenFromReadWriteToken({
274
264
  ).toString("base64");
275
265
  const securedKey = await signPayload(payload, readWriteToken);
276
266
  if (!securedKey) {
277
- throw new (0, _chunkXTBGGUVNcjs.BlobError)("Unable to sign client token");
267
+ throw new (0, _chunkA3XDFQYYcjs.BlobError)("Unable to sign client token");
278
268
  }
279
269
  return `vercel_blob_client_${storeId}_${Buffer.from(
280
270
  `${securedKey}.${payload}`
@@ -291,5 +281,5 @@ async function generateClientTokenFromReadWriteToken({
291
281
 
292
282
 
293
283
 
294
- exports.completeMultipartUpload = completeMultipartUpload; exports.createFolder = _chunkXTBGGUVNcjs.createFolder; exports.createMultipartUpload = createMultipartUpload; exports.createMultipartUploader = createMultipartUploader; exports.generateClientTokenFromReadWriteToken = generateClientTokenFromReadWriteToken; exports.getPayloadFromClientToken = getPayloadFromClientToken; exports.handleUpload = handleUpload; exports.put = put; exports.upload = upload; exports.uploadPart = uploadPart;
284
+ exports.completeMultipartUpload = completeMultipartUpload; exports.createFolder = _chunkA3XDFQYYcjs.createFolder; exports.createMultipartUpload = createMultipartUpload; exports.createMultipartUploader = createMultipartUploader; exports.generateClientTokenFromReadWriteToken = generateClientTokenFromReadWriteToken; exports.getPayloadFromClientToken = getPayloadFromClientToken; exports.handleUpload = handleUpload; exports.put = put; exports.upload = upload; exports.uploadPart = uploadPart;
295
285
  //# sourceMappingURL=client.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["/home/runner/work/storage/storage/packages/blob/dist/client.cjs","../src/client.ts"],"names":[],"mappings":"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","file":"/home/runner/work/storage/storage/packages/blob/dist/client.cjs","sourcesContent":[null,"// eslint-disable-next-line unicorn/prefer-node-protocol -- node:crypto does not resolve correctly in browser and edge runtime\nimport * as crypto from 'crypto';\nimport type { IncomingMessage } from 'node:http';\n// When bundled via a bundler supporting the `browser` field, then\n// the `undici` module will be replaced with https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API\n// for browser contexts. See ./undici-browser.js and ./package.json\nimport { fetch } from 'undici';\nimport type { BlobCommandOptions, WithUploadProgress } from './helpers';\nimport { BlobError, getTokenFromOptionsOrEnv } from './helpers';\nimport { createPutMethod } from './put';\nimport type { PutBlobResult } from './put-helpers';\nimport type { CommonCompleteMultipartUploadOptions } from './multipart/complete';\nimport { createCompleteMultipartUploadMethod } from './multipart/complete';\nimport { createCreateMultipartUploadMethod } from './multipart/create';\nimport { createUploadPartMethod } from './multipart/upload';\nimport type { CommonMultipartUploadOptions } from './multipart/upload';\nimport { createCreateMultipartUploaderMethod } from './multipart/create-uploader';\n\n// interface for put, upload and multipartUpload.\n// This types omits all options that are encoded in the client token.\nexport interface ClientCommonCreateBlobOptions {\n /**\n * Whether the blob should be publicly accessible.\n */\n access: 'public';\n /**\n * Defines the content type of the blob. By default, this value is inferred from the pathname. Sent as the 'content-type' header when downloading a blob.\n */\n contentType?: string;\n /**\n * `AbortSignal` to cancel the running request. See https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal\n */\n abortSignal?: AbortSignal;\n}\n\n// shared interface for put and multipartUpload\nexport interface ClientTokenOptions {\n /**\n * A client token that was generated by your server using the `generateClientToken` method.\n */\n token: string;\n}\n\n// shared interface for put and upload\ninterface ClientCommonPutOptions\n extends ClientCommonCreateBlobOptions,\n WithUploadProgress {\n /**\n * Whether to use multipart upload. Use this when uploading large files. It will split the file into multiple parts, upload them in parallel and retry failed parts.\n */\n multipart?: boolean;\n}\n\nfunction createPutExtraChecks<\n TOptions extends ClientTokenOptions & ClientCommonCreateBlobOptions,\n>(methodName: string) {\n return function extraChecks(options: TOptions) {\n if (typeof window === 'undefined') {\n throw new BlobError(\n `${methodName} must be called from a client environment`,\n );\n }\n\n if (!options.token.startsWith('vercel_blob_client_')) {\n throw new BlobError(`${methodName} must be called with a client token`);\n }\n\n if (\n // @ts-expect-error -- Runtime check for DX.\n options.addRandomSuffix !== undefined ||\n // @ts-expect-error -- Runtime check for DX.\n options.cacheControlMaxAge !== undefined\n ) {\n throw new BlobError(\n `${methodName} doesn't allow addRandomSuffix and cacheControlMaxAge. Configure these options at the server side when generating client tokens.`,\n );\n }\n };\n}\n\n// client.put()\n\nexport type ClientPutCommandOptions = ClientCommonPutOptions &\n ClientTokenOptions;\n\nexport const put = createPutMethod<ClientPutCommandOptions>({\n allowedOptions: ['contentType'],\n extraChecks: createPutExtraChecks('client/`put`'),\n});\n\n// vercelBlob. createMultipartUpload()\n// vercelBlob. uploadPart()\n// vercelBlob. completeMultipartUpload()\n// vercelBlob. createMultipartUploader()\n\nexport type ClientCreateMultipartUploadCommandOptions =\n ClientCommonCreateBlobOptions & ClientTokenOptions;\n\nexport const createMultipartUpload =\n createCreateMultipartUploadMethod<ClientCreateMultipartUploadCommandOptions>({\n allowedOptions: ['contentType'],\n extraChecks: createPutExtraChecks('client/`createMultipartUpload`'),\n });\n\nexport const createMultipartUploader =\n createCreateMultipartUploaderMethod<ClientCreateMultipartUploadCommandOptions>(\n {\n allowedOptions: ['contentType'],\n extraChecks: createPutExtraChecks('client/`createMultipartUpload`'),\n },\n );\n\ntype ClientMultipartUploadCommandOptions = ClientCommonCreateBlobOptions &\n ClientTokenOptions &\n CommonMultipartUploadOptions &\n WithUploadProgress;\n\nexport const uploadPart =\n createUploadPartMethod<ClientMultipartUploadCommandOptions>({\n allowedOptions: ['contentType'],\n extraChecks: createPutExtraChecks('client/`multipartUpload`'),\n });\n\ntype ClientCompleteMultipartUploadCommandOptions =\n ClientCommonCreateBlobOptions &\n ClientTokenOptions &\n CommonCompleteMultipartUploadOptions;\n\nexport const completeMultipartUpload =\n createCompleteMultipartUploadMethod<ClientCompleteMultipartUploadCommandOptions>(\n {\n allowedOptions: ['contentType'],\n extraChecks: createPutExtraChecks('client/`completeMultipartUpload`'),\n },\n );\n\n// upload methods\n\nexport interface CommonUploadOptions {\n /**\n * A route that implements the `handleUpload` function for generating a client token.\n */\n handleUploadUrl: string;\n /**\n * Additional data which will be sent to your `handleUpload` route.\n */\n clientPayload?: string;\n}\n\n// client.upload()\n// This is a client-side wrapper that will fetch the client token for you and then upload the file\nexport type UploadOptions = ClientCommonPutOptions & CommonUploadOptions;\n/**\n * Uploads a blob into your store from the client.\n * Detailed documentation can be found here: https://vercel.com/docs/storage/vercel-blob/using-blob-sdk#client-uploads\n *\n * If you want to upload from your server instead, check out the documentation for the put operation: https://vercel.com/docs/storage/vercel-blob/using-blob-sdk#upload-a-blob\n *\n * @param pathname - The pathname to upload the blob to. This includes the filename.\n * @param body - The contents of your blob. This has to be a supported fetch body type https://developer.mozilla.org/en-US/docs/Web/API/fetch#body.\n * @param options - Additional options.\n */\nexport const upload = createPutMethod<UploadOptions>({\n allowedOptions: ['contentType'],\n extraChecks(options) {\n if (typeof window === 'undefined') {\n throw new BlobError(\n 'client/`upload` must be called from a client environment',\n );\n }\n\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- Runtime check for DX.\n if (options.handleUploadUrl === undefined) {\n throw new BlobError(\n \"client/`upload` requires the 'handleUploadUrl' parameter\",\n );\n }\n\n if (\n // @ts-expect-error -- Runtime check for DX.\n options.addRandomSuffix !== undefined ||\n // @ts-expect-error -- Runtime check for DX.\n options.cacheControlMaxAge !== undefined\n ) {\n throw new BlobError(\n \"client/`upload` doesn't allow addRandomSuffix and cacheControlMaxAge. Configure these options at the server side when generating client tokens.\",\n );\n }\n },\n async getToken(pathname, options) {\n return retrieveClientToken({\n handleUploadUrl: options.handleUploadUrl,\n pathname,\n clientPayload: options.clientPayload ?? null,\n multipart: options.multipart ?? false,\n });\n },\n});\n\nasync function importKey(token: string): Promise<CryptoKey> {\n return globalThis.crypto.subtle.importKey(\n 'raw',\n new TextEncoder().encode(token),\n { name: 'HMAC', hash: 'SHA-256' },\n false,\n ['sign', 'verify'],\n );\n}\n\nasync function signPayload(\n payload: string,\n token: string,\n): Promise<string | undefined> {\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- Node.js < 20: globalThis.crypto is undefined (in a real script.js, because the REPL has it linked to the crypto module). Node.js >= 20, Browsers and Cloudflare workers: globalThis.crypto is defined and is the Web Crypto API.\n if (!globalThis.crypto) {\n return crypto.createHmac('sha256', token).update(payload).digest('hex');\n }\n\n const signature = await globalThis.crypto.subtle.sign(\n 'HMAC',\n await importKey(token),\n new TextEncoder().encode(payload),\n );\n return Buffer.from(new Uint8Array(signature)).toString('hex');\n}\n\nasync function verifyCallbackSignature({\n token,\n signature,\n body,\n}: {\n token: string;\n signature: string;\n body: string;\n}): Promise<boolean> {\n // callback signature is signed using the server token\n const secret = token;\n // Browsers, Edge runtime and Node >=20 implement the Web Crypto API\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- Node.js < 20: globalThis.crypto is undefined (in a real script.js, because the REPL has it linked to the crypto module). Node.js >= 20, Browsers and Cloudflare workers: globalThis.crypto is defined and is the Web Crypto API.\n if (!globalThis.crypto) {\n // Node <20 falls back to the Node.js crypto module\n const digest = crypto\n .createHmac('sha256', secret)\n .update(body)\n .digest('hex');\n const digestBuffer = Buffer.from(digest);\n const signatureBuffer = Buffer.from(signature);\n\n return (\n digestBuffer.length === signatureBuffer.length &&\n crypto.timingSafeEqual(digestBuffer, signatureBuffer)\n );\n }\n\n const verified = await globalThis.crypto.subtle.verify(\n 'HMAC',\n await importKey(token),\n hexToArrayByte(signature),\n new TextEncoder().encode(body),\n );\n return verified;\n}\n\nfunction hexToArrayByte(input: string): ArrayBuffer {\n if (input.length % 2 !== 0) {\n throw new RangeError('Expected string to be an even number of characters');\n }\n const view = new Uint8Array(input.length / 2);\n\n for (let i = 0; i < input.length; i += 2) {\n view[i / 2] = parseInt(input.substring(i, i + 2), 16);\n }\n\n return Buffer.from(view);\n}\n\nexport type DecodedClientTokenPayload = Omit<\n GenerateClientTokenOptions,\n 'token'\n> & {\n validUntil: number;\n};\n\nexport function getPayloadFromClientToken(\n clientToken: string,\n): DecodedClientTokenPayload {\n const [, , , , encodedToken] = clientToken.split('_');\n const encodedPayload = Buffer.from(encodedToken ?? '', 'base64')\n .toString()\n .split('.')[1];\n const decodedPayload = Buffer.from(encodedPayload ?? '', 'base64').toString();\n return JSON.parse(decodedPayload) as DecodedClientTokenPayload;\n}\n\nconst EventTypes = {\n generateClientToken: 'blob.generate-client-token',\n uploadCompleted: 'blob.upload-completed',\n} as const;\n\ninterface GenerateClientTokenEvent {\n type: (typeof EventTypes)['generateClientToken'];\n payload: {\n pathname: string;\n callbackUrl: string;\n multipart: boolean;\n clientPayload: string | null;\n };\n}\ninterface UploadCompletedEvent {\n type: (typeof EventTypes)['uploadCompleted'];\n payload: {\n blob: PutBlobResult;\n tokenPayload?: string | null;\n };\n}\n\nexport type HandleUploadBody = GenerateClientTokenEvent | UploadCompletedEvent;\n\ntype RequestType = IncomingMessage | Request;\n\nexport interface HandleUploadOptions {\n body: HandleUploadBody;\n onBeforeGenerateToken: (\n pathname: string,\n clientPayload: string | null,\n multipart: boolean,\n ) => Promise<\n Pick<\n GenerateClientTokenOptions,\n | 'allowedContentTypes'\n | 'maximumSizeInBytes'\n | 'validUntil'\n | 'addRandomSuffix'\n | 'cacheControlMaxAge'\n > & { tokenPayload?: string | null }\n >;\n onUploadCompleted: (body: UploadCompletedEvent['payload']) => Promise<void>;\n token?: string;\n request: RequestType;\n}\n\nexport async function handleUpload({\n token,\n request,\n body,\n onBeforeGenerateToken,\n onUploadCompleted,\n}: HandleUploadOptions): Promise<\n | { type: GenerateClientTokenEvent['type']; clientToken: string }\n | { type: UploadCompletedEvent['type']; response: 'ok' }\n> {\n const resolvedToken = getTokenFromOptionsOrEnv({ token });\n\n const type = body.type;\n switch (type) {\n case 'blob.generate-client-token': {\n const { pathname, callbackUrl, clientPayload, multipart } = body.payload;\n const payload = await onBeforeGenerateToken(\n pathname,\n clientPayload,\n multipart,\n );\n const tokenPayload = payload.tokenPayload ?? clientPayload;\n\n // one hour\n const oneHourInSeconds = 60 * 60;\n const now = new Date();\n const validUntil =\n payload.validUntil ??\n now.setSeconds(now.getSeconds() + oneHourInSeconds);\n\n return {\n type,\n clientToken: await generateClientTokenFromReadWriteToken({\n ...payload,\n token: resolvedToken,\n pathname,\n onUploadCompleted: {\n callbackUrl,\n tokenPayload,\n },\n validUntil,\n }),\n };\n }\n case 'blob.upload-completed': {\n const signatureHeader = 'x-vercel-signature';\n const signature = (\n 'credentials' in request\n ? (request.headers.get(signatureHeader) ?? '')\n : (request.headers[signatureHeader] ?? '')\n ) as string;\n\n if (!signature) {\n throw new BlobError('Missing callback signature');\n }\n\n const isVerified = await verifyCallbackSignature({\n token: resolvedToken,\n signature,\n body: JSON.stringify(body),\n });\n\n if (!isVerified) {\n throw new BlobError('Invalid callback signature');\n }\n await onUploadCompleted(body.payload);\n return { type, response: 'ok' };\n }\n default:\n throw new BlobError('Invalid event type');\n }\n}\n\nasync function retrieveClientToken(options: {\n pathname: string;\n handleUploadUrl: string;\n clientPayload: string | null;\n multipart: boolean;\n abortSignal?: AbortSignal;\n}): Promise<string> {\n const { handleUploadUrl, pathname } = options;\n const url = isAbsoluteUrl(handleUploadUrl)\n ? handleUploadUrl\n : toAbsoluteUrl(handleUploadUrl);\n\n const event: GenerateClientTokenEvent = {\n type: EventTypes.generateClientToken,\n payload: {\n pathname,\n callbackUrl: url,\n clientPayload: options.clientPayload,\n multipart: options.multipart,\n },\n };\n\n const res = await fetch(url, {\n method: 'POST',\n body: JSON.stringify(event),\n headers: {\n 'content-type': 'application/json',\n },\n signal: options.abortSignal,\n });\n\n if (!res.ok) {\n throw new BlobError('Failed to retrieve the client token');\n }\n\n try {\n const { clientToken } = (await res.json()) as { clientToken: string };\n return clientToken;\n } catch (e) {\n throw new BlobError('Failed to retrieve the client token');\n }\n}\n\nfunction toAbsoluteUrl(url: string): string {\n return new URL(url, window.location.href).href;\n}\n\nfunction isAbsoluteUrl(url: string): boolean {\n try {\n return Boolean(new URL(url));\n } catch (e) {\n return false;\n }\n}\n\nexport async function generateClientTokenFromReadWriteToken({\n token,\n ...argsWithoutToken\n}: GenerateClientTokenOptions): Promise<string> {\n if (typeof window !== 'undefined') {\n throw new BlobError(\n '\"generateClientTokenFromReadWriteToken\" must be called from a server environment',\n );\n }\n\n const timestamp = new Date();\n timestamp.setSeconds(timestamp.getSeconds() + 30);\n const readWriteToken = getTokenFromOptionsOrEnv({ token });\n\n const [, , , storeId = null] = readWriteToken.split('_');\n\n if (!storeId) {\n throw new BlobError(\n token ? 'Invalid `token` parameter' : 'Invalid `BLOB_READ_WRITE_TOKEN`',\n );\n }\n\n const payload = Buffer.from(\n JSON.stringify({\n ...argsWithoutToken,\n validUntil: argsWithoutToken.validUntil ?? timestamp.getTime(),\n }),\n ).toString('base64');\n\n const securedKey = await signPayload(payload, readWriteToken);\n\n if (!securedKey) {\n throw new BlobError('Unable to sign client token');\n }\n return `vercel_blob_client_${storeId}_${Buffer.from(\n `${securedKey}.${payload}`,\n ).toString('base64')}`;\n}\n\nexport interface GenerateClientTokenOptions extends BlobCommandOptions {\n pathname: string;\n onUploadCompleted?: {\n callbackUrl: string;\n tokenPayload?: string | null;\n };\n maximumSizeInBytes?: number;\n allowedContentTypes?: string[];\n validUntil?: number;\n addRandomSuffix?: boolean;\n cacheControlMaxAge?: number;\n}\n\nexport { createFolder } from './create-folder';\n"]}
1
+ {"version":3,"sources":["/home/runner/work/storage/storage/packages/blob/dist/client.cjs","../src/client.ts"],"names":[],"mappings":"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","file":"/home/runner/work/storage/storage/packages/blob/dist/client.cjs","sourcesContent":[null,"// eslint-disable-next-line unicorn/prefer-node-protocol -- node:crypto does not resolve correctly in browser and edge runtime\nimport * as crypto from 'crypto';\nimport type { IncomingMessage } from 'node:http';\n// When bundled via a bundler supporting the `browser` field, then\n// the `undici` module will be replaced with https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API\n// for browser contexts. See ./undici-browser.js and ./package.json\nimport { fetch } from 'undici';\nimport type { BlobCommandOptions, WithUploadProgress } from './helpers';\nimport { BlobError, getTokenFromOptionsOrEnv } from './helpers';\nimport { createPutMethod } from './put';\nimport type { PutBlobResult } from './put-helpers';\nimport type { CommonCompleteMultipartUploadOptions } from './multipart/complete';\nimport { createCompleteMultipartUploadMethod } from './multipart/complete';\nimport { createCreateMultipartUploadMethod } from './multipart/create';\nimport { createUploadPartMethod } from './multipart/upload';\nimport type { CommonMultipartUploadOptions } from './multipart/upload';\nimport { createCreateMultipartUploaderMethod } from './multipart/create-uploader';\n\n// interface for put, upload and multipartUpload.\n// This types omits all options that are encoded in the client token.\nexport interface ClientCommonCreateBlobOptions {\n /**\n * Whether the blob should be publicly accessible.\n */\n access: 'public';\n /**\n * Defines the content type of the blob. By default, this value is inferred from the pathname. Sent as the 'content-type' header when downloading a blob.\n */\n contentType?: string;\n /**\n * `AbortSignal` to cancel the running request. See https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal\n */\n abortSignal?: AbortSignal;\n}\n\n// shared interface for put and multipartUpload\nexport interface ClientTokenOptions {\n /**\n * A client token that was generated by your server using the `generateClientToken` method.\n */\n token: string;\n}\n\n// shared interface for put and upload\ninterface ClientCommonPutOptions\n extends ClientCommonCreateBlobOptions,\n WithUploadProgress {\n /**\n * Whether to use multipart upload. Use this when uploading large files. It will split the file into multiple parts, upload them in parallel and retry failed parts.\n */\n multipart?: boolean;\n}\n\nfunction createPutExtraChecks<\n TOptions extends ClientTokenOptions & ClientCommonCreateBlobOptions,\n>(methodName: string) {\n return function extraChecks(options: TOptions) {\n if (!options.token.startsWith('vercel_blob_client_')) {\n throw new BlobError(`${methodName} must be called with a client token`);\n }\n\n if (\n // @ts-expect-error -- Runtime check for DX.\n options.addRandomSuffix !== undefined ||\n // @ts-expect-error -- Runtime check for DX.\n options.cacheControlMaxAge !== undefined\n ) {\n throw new BlobError(\n `${methodName} doesn't allow addRandomSuffix and cacheControlMaxAge. Configure these options at the server side when generating client tokens.`,\n );\n }\n };\n}\n\n// client.put()\n\nexport type ClientPutCommandOptions = ClientCommonPutOptions &\n ClientTokenOptions;\n\nexport const put = createPutMethod<ClientPutCommandOptions>({\n allowedOptions: ['contentType'],\n extraChecks: createPutExtraChecks('client/`put`'),\n});\n\n// vercelBlob. createMultipartUpload()\n// vercelBlob. uploadPart()\n// vercelBlob. completeMultipartUpload()\n// vercelBlob. createMultipartUploader()\n\nexport type ClientCreateMultipartUploadCommandOptions =\n ClientCommonCreateBlobOptions & ClientTokenOptions;\n\nexport const createMultipartUpload =\n createCreateMultipartUploadMethod<ClientCreateMultipartUploadCommandOptions>({\n allowedOptions: ['contentType'],\n extraChecks: createPutExtraChecks('client/`createMultipartUpload`'),\n });\n\nexport const createMultipartUploader =\n createCreateMultipartUploaderMethod<ClientCreateMultipartUploadCommandOptions>(\n {\n allowedOptions: ['contentType'],\n extraChecks: createPutExtraChecks('client/`createMultipartUpload`'),\n },\n );\n\ntype ClientMultipartUploadCommandOptions = ClientCommonCreateBlobOptions &\n ClientTokenOptions &\n CommonMultipartUploadOptions &\n WithUploadProgress;\n\nexport const uploadPart =\n createUploadPartMethod<ClientMultipartUploadCommandOptions>({\n allowedOptions: ['contentType'],\n extraChecks: createPutExtraChecks('client/`multipartUpload`'),\n });\n\ntype ClientCompleteMultipartUploadCommandOptions =\n ClientCommonCreateBlobOptions &\n ClientTokenOptions &\n CommonCompleteMultipartUploadOptions;\n\nexport const completeMultipartUpload =\n createCompleteMultipartUploadMethod<ClientCompleteMultipartUploadCommandOptions>(\n {\n allowedOptions: ['contentType'],\n extraChecks: createPutExtraChecks('client/`completeMultipartUpload`'),\n },\n );\n\n// upload methods\n\nexport interface CommonUploadOptions {\n /**\n * A route that implements the `handleUpload` function for generating a client token.\n */\n handleUploadUrl: string;\n /**\n * Additional data which will be sent to your `handleUpload` route.\n */\n clientPayload?: string;\n}\n\n// client.upload()\n// This is a client-side wrapper that will fetch the client token for you and then upload the file\nexport type UploadOptions = ClientCommonPutOptions & CommonUploadOptions;\n/**\n * Uploads a blob into your store from the client.\n * Detailed documentation can be found here: https://vercel.com/docs/storage/vercel-blob/using-blob-sdk#client-uploads\n *\n * If you want to upload from your server instead, check out the documentation for the put operation: https://vercel.com/docs/storage/vercel-blob/using-blob-sdk#upload-a-blob\n *\n * @param pathname - The pathname to upload the blob to. This includes the filename.\n * @param body - The contents of your blob. This has to be a supported fetch body type https://developer.mozilla.org/en-US/docs/Web/API/fetch#body.\n * @param options - Additional options.\n */\nexport const upload = createPutMethod<UploadOptions>({\n allowedOptions: ['contentType'],\n extraChecks(options) {\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- Runtime check for DX.\n if (options.handleUploadUrl === undefined) {\n throw new BlobError(\n \"client/`upload` requires the 'handleUploadUrl' parameter\",\n );\n }\n\n if (\n // @ts-expect-error -- Runtime check for DX.\n options.addRandomSuffix !== undefined ||\n // @ts-expect-error -- Runtime check for DX.\n options.cacheControlMaxAge !== undefined\n ) {\n throw new BlobError(\n \"client/`upload` doesn't allow addRandomSuffix and cacheControlMaxAge. Configure these options at the server side when generating client tokens.\",\n );\n }\n },\n async getToken(pathname, options) {\n return retrieveClientToken({\n handleUploadUrl: options.handleUploadUrl,\n pathname,\n clientPayload: options.clientPayload ?? null,\n multipart: options.multipart ?? false,\n });\n },\n});\n\nasync function importKey(token: string): Promise<CryptoKey> {\n return globalThis.crypto.subtle.importKey(\n 'raw',\n new TextEncoder().encode(token),\n { name: 'HMAC', hash: 'SHA-256' },\n false,\n ['sign', 'verify'],\n );\n}\n\nasync function signPayload(\n payload: string,\n token: string,\n): Promise<string | undefined> {\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- Node.js < 20: globalThis.crypto is undefined (in a real script.js, because the REPL has it linked to the crypto module). Node.js >= 20, Browsers and Cloudflare workers: globalThis.crypto is defined and is the Web Crypto API.\n if (!globalThis.crypto) {\n return crypto.createHmac('sha256', token).update(payload).digest('hex');\n }\n\n const signature = await globalThis.crypto.subtle.sign(\n 'HMAC',\n await importKey(token),\n new TextEncoder().encode(payload),\n );\n return Buffer.from(new Uint8Array(signature)).toString('hex');\n}\n\nasync function verifyCallbackSignature({\n token,\n signature,\n body,\n}: {\n token: string;\n signature: string;\n body: string;\n}): Promise<boolean> {\n // callback signature is signed using the server token\n const secret = token;\n // Browsers, Edge runtime and Node >=20 implement the Web Crypto API\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- Node.js < 20: globalThis.crypto is undefined (in a real script.js, because the REPL has it linked to the crypto module). Node.js >= 20, Browsers and Cloudflare workers: globalThis.crypto is defined and is the Web Crypto API.\n if (!globalThis.crypto) {\n // Node <20 falls back to the Node.js crypto module\n const digest = crypto\n .createHmac('sha256', secret)\n .update(body)\n .digest('hex');\n const digestBuffer = Buffer.from(digest);\n const signatureBuffer = Buffer.from(signature);\n\n return (\n digestBuffer.length === signatureBuffer.length &&\n crypto.timingSafeEqual(digestBuffer, signatureBuffer)\n );\n }\n\n const verified = await globalThis.crypto.subtle.verify(\n 'HMAC',\n await importKey(token),\n hexToArrayByte(signature),\n new TextEncoder().encode(body),\n );\n return verified;\n}\n\nfunction hexToArrayByte(input: string): Buffer {\n if (input.length % 2 !== 0) {\n throw new RangeError('Expected string to be an even number of characters');\n }\n const view = new Uint8Array(input.length / 2);\n\n for (let i = 0; i < input.length; i += 2) {\n view[i / 2] = parseInt(input.substring(i, i + 2), 16);\n }\n\n return Buffer.from(view);\n}\n\nexport type DecodedClientTokenPayload = Omit<\n GenerateClientTokenOptions,\n 'token'\n> & {\n validUntil: number;\n};\n\nexport function getPayloadFromClientToken(\n clientToken: string,\n): DecodedClientTokenPayload {\n const [, , , , encodedToken] = clientToken.split('_');\n const encodedPayload = Buffer.from(encodedToken ?? '', 'base64')\n .toString()\n .split('.')[1];\n const decodedPayload = Buffer.from(encodedPayload ?? '', 'base64').toString();\n return JSON.parse(decodedPayload) as DecodedClientTokenPayload;\n}\n\nconst EventTypes = {\n generateClientToken: 'blob.generate-client-token',\n uploadCompleted: 'blob.upload-completed',\n} as const;\n\ninterface GenerateClientTokenEvent {\n type: (typeof EventTypes)['generateClientToken'];\n payload: {\n pathname: string;\n callbackUrl: string;\n multipart: boolean;\n clientPayload: string | null;\n };\n}\ninterface UploadCompletedEvent {\n type: (typeof EventTypes)['uploadCompleted'];\n payload: {\n blob: PutBlobResult;\n tokenPayload?: string | null;\n };\n}\n\nexport type HandleUploadBody = GenerateClientTokenEvent | UploadCompletedEvent;\n\ntype RequestType = IncomingMessage | Request;\n\nexport interface HandleUploadOptions {\n body: HandleUploadBody;\n onBeforeGenerateToken: (\n pathname: string,\n clientPayload: string | null,\n multipart: boolean,\n ) => Promise<\n Pick<\n GenerateClientTokenOptions,\n | 'allowedContentTypes'\n | 'maximumSizeInBytes'\n | 'validUntil'\n | 'addRandomSuffix'\n | 'cacheControlMaxAge'\n > & { tokenPayload?: string | null }\n >;\n onUploadCompleted: (body: UploadCompletedEvent['payload']) => Promise<void>;\n token?: string;\n request: RequestType;\n}\n\nexport async function handleUpload({\n token,\n request,\n body,\n onBeforeGenerateToken,\n onUploadCompleted,\n}: HandleUploadOptions): Promise<\n | { type: GenerateClientTokenEvent['type']; clientToken: string }\n | { type: UploadCompletedEvent['type']; response: 'ok' }\n> {\n const resolvedToken = getTokenFromOptionsOrEnv({ token });\n\n const type = body.type;\n switch (type) {\n case 'blob.generate-client-token': {\n const { pathname, callbackUrl, clientPayload, multipart } = body.payload;\n const payload = await onBeforeGenerateToken(\n pathname,\n clientPayload,\n multipart,\n );\n const tokenPayload = payload.tokenPayload ?? clientPayload;\n\n // one hour\n const oneHourInSeconds = 60 * 60;\n const now = new Date();\n const validUntil =\n payload.validUntil ??\n now.setSeconds(now.getSeconds() + oneHourInSeconds);\n\n return {\n type,\n clientToken: await generateClientTokenFromReadWriteToken({\n ...payload,\n token: resolvedToken,\n pathname,\n onUploadCompleted: {\n callbackUrl,\n tokenPayload,\n },\n validUntil,\n }),\n };\n }\n case 'blob.upload-completed': {\n const signatureHeader = 'x-vercel-signature';\n const signature = (\n 'credentials' in request\n ? (request.headers.get(signatureHeader) ?? '')\n : (request.headers[signatureHeader] ?? '')\n ) as string;\n\n if (!signature) {\n throw new BlobError('Missing callback signature');\n }\n\n const isVerified = await verifyCallbackSignature({\n token: resolvedToken,\n signature,\n body: JSON.stringify(body),\n });\n\n if (!isVerified) {\n throw new BlobError('Invalid callback signature');\n }\n await onUploadCompleted(body.payload);\n return { type, response: 'ok' };\n }\n default:\n throw new BlobError('Invalid event type');\n }\n}\n\nasync function retrieveClientToken(options: {\n pathname: string;\n handleUploadUrl: string;\n clientPayload: string | null;\n multipart: boolean;\n abortSignal?: AbortSignal;\n}): Promise<string> {\n const { handleUploadUrl, pathname } = options;\n const url = isAbsoluteUrl(handleUploadUrl)\n ? handleUploadUrl\n : toAbsoluteUrl(handleUploadUrl);\n\n const event: GenerateClientTokenEvent = {\n type: EventTypes.generateClientToken,\n payload: {\n pathname,\n callbackUrl: url,\n clientPayload: options.clientPayload,\n multipart: options.multipart,\n },\n };\n\n const res = await fetch(url, {\n method: 'POST',\n body: JSON.stringify(event),\n headers: {\n 'content-type': 'application/json',\n },\n signal: options.abortSignal,\n });\n\n if (!res.ok) {\n throw new BlobError('Failed to retrieve the client token');\n }\n\n try {\n const { clientToken } = (await res.json()) as { clientToken: string };\n return clientToken;\n } catch (e) {\n throw new BlobError('Failed to retrieve the client token');\n }\n}\n\nfunction toAbsoluteUrl(url: string): string {\n // location is available in web workers too: https://developer.mozilla.org/en-US/docs/Web/API/Window/location\n return new URL(url, location.href).href;\n}\n\nfunction isAbsoluteUrl(url: string): boolean {\n try {\n return Boolean(new URL(url));\n } catch (e) {\n return false;\n }\n}\n\nexport async function generateClientTokenFromReadWriteToken({\n token,\n ...argsWithoutToken\n}: GenerateClientTokenOptions): Promise<string> {\n if (typeof window !== 'undefined') {\n throw new BlobError(\n '\"generateClientTokenFromReadWriteToken\" must be called from a server environment',\n );\n }\n\n const timestamp = new Date();\n timestamp.setSeconds(timestamp.getSeconds() + 30);\n const readWriteToken = getTokenFromOptionsOrEnv({ token });\n\n const [, , , storeId = null] = readWriteToken.split('_');\n\n if (!storeId) {\n throw new BlobError(\n token ? 'Invalid `token` parameter' : 'Invalid `BLOB_READ_WRITE_TOKEN`',\n );\n }\n\n const payload = Buffer.from(\n JSON.stringify({\n ...argsWithoutToken,\n validUntil: argsWithoutToken.validUntil ?? timestamp.getTime(),\n }),\n ).toString('base64');\n\n const securedKey = await signPayload(payload, readWriteToken);\n\n if (!securedKey) {\n throw new BlobError('Unable to sign client token');\n }\n return `vercel_blob_client_${storeId}_${Buffer.from(\n `${securedKey}.${payload}`,\n ).toString('base64')}`;\n}\n\nexport interface GenerateClientTokenOptions extends BlobCommandOptions {\n pathname: string;\n onUploadCompleted?: {\n callbackUrl: string;\n tokenPayload?: string | null;\n };\n maximumSizeInBytes?: number;\n allowedContentTypes?: string[];\n validUntil?: number;\n addRandomSuffix?: boolean;\n cacheControlMaxAge?: number;\n}\n\nexport { createFolder } from './create-folder';\n"]}
package/dist/client.js CHANGED
@@ -7,18 +7,13 @@ import {
7
7
  createPutMethod,
8
8
  createUploadPartMethod,
9
9
  getTokenFromOptionsOrEnv
10
- } from "./chunk-KN6WT5GP.js";
10
+ } from "./chunk-JGHUXF3X.js";
11
11
 
12
12
  // src/client.ts
13
13
  import * as crypto from "crypto";
14
14
  import { fetch } from "undici";
15
15
  function createPutExtraChecks(methodName) {
16
16
  return function extraChecks(options) {
17
- if (typeof window === "undefined") {
18
- throw new BlobError(
19
- `${methodName} must be called from a client environment`
20
- );
21
- }
22
17
  if (!options.token.startsWith("vercel_blob_client_")) {
23
18
  throw new BlobError(`${methodName} must be called with a client token`);
24
19
  }
@@ -60,11 +55,6 @@ var completeMultipartUpload = createCompleteMultipartUploadMethod(
60
55
  var upload = createPutMethod({
61
56
  allowedOptions: ["contentType"],
62
57
  extraChecks(options) {
63
- if (typeof window === "undefined") {
64
- throw new BlobError(
65
- "client/`upload` must be called from a client environment"
66
- );
67
- }
68
58
  if (options.handleUploadUrl === void 0) {
69
59
  throw new BlobError(
70
60
  "client/`upload` requires the 'handleUploadUrl' parameter"
@@ -238,7 +228,7 @@ async function retrieveClientToken(options) {
238
228
  }
239
229
  }
240
230
  function toAbsoluteUrl(url) {
241
- return new URL(url, window.location.href).href;
231
+ return new URL(url, location.href).href;
242
232
  }
243
233
  function isAbsoluteUrl(url) {
244
234
  try {
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/client.ts"],"sourcesContent":["// eslint-disable-next-line unicorn/prefer-node-protocol -- node:crypto does not resolve correctly in browser and edge runtime\nimport * as crypto from 'crypto';\nimport type { IncomingMessage } from 'node:http';\n// When bundled via a bundler supporting the `browser` field, then\n// the `undici` module will be replaced with https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API\n// for browser contexts. See ./undici-browser.js and ./package.json\nimport { fetch } from 'undici';\nimport type { BlobCommandOptions, WithUploadProgress } from './helpers';\nimport { BlobError, getTokenFromOptionsOrEnv } from './helpers';\nimport { createPutMethod } from './put';\nimport type { PutBlobResult } from './put-helpers';\nimport type { CommonCompleteMultipartUploadOptions } from './multipart/complete';\nimport { createCompleteMultipartUploadMethod } from './multipart/complete';\nimport { createCreateMultipartUploadMethod } from './multipart/create';\nimport { createUploadPartMethod } from './multipart/upload';\nimport type { CommonMultipartUploadOptions } from './multipart/upload';\nimport { createCreateMultipartUploaderMethod } from './multipart/create-uploader';\n\n// interface for put, upload and multipartUpload.\n// This types omits all options that are encoded in the client token.\nexport interface ClientCommonCreateBlobOptions {\n /**\n * Whether the blob should be publicly accessible.\n */\n access: 'public';\n /**\n * Defines the content type of the blob. By default, this value is inferred from the pathname. Sent as the 'content-type' header when downloading a blob.\n */\n contentType?: string;\n /**\n * `AbortSignal` to cancel the running request. See https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal\n */\n abortSignal?: AbortSignal;\n}\n\n// shared interface for put and multipartUpload\nexport interface ClientTokenOptions {\n /**\n * A client token that was generated by your server using the `generateClientToken` method.\n */\n token: string;\n}\n\n// shared interface for put and upload\ninterface ClientCommonPutOptions\n extends ClientCommonCreateBlobOptions,\n WithUploadProgress {\n /**\n * Whether to use multipart upload. Use this when uploading large files. It will split the file into multiple parts, upload them in parallel and retry failed parts.\n */\n multipart?: boolean;\n}\n\nfunction createPutExtraChecks<\n TOptions extends ClientTokenOptions & ClientCommonCreateBlobOptions,\n>(methodName: string) {\n return function extraChecks(options: TOptions) {\n if (typeof window === 'undefined') {\n throw new BlobError(\n `${methodName} must be called from a client environment`,\n );\n }\n\n if (!options.token.startsWith('vercel_blob_client_')) {\n throw new BlobError(`${methodName} must be called with a client token`);\n }\n\n if (\n // @ts-expect-error -- Runtime check for DX.\n options.addRandomSuffix !== undefined ||\n // @ts-expect-error -- Runtime check for DX.\n options.cacheControlMaxAge !== undefined\n ) {\n throw new BlobError(\n `${methodName} doesn't allow addRandomSuffix and cacheControlMaxAge. Configure these options at the server side when generating client tokens.`,\n );\n }\n };\n}\n\n// client.put()\n\nexport type ClientPutCommandOptions = ClientCommonPutOptions &\n ClientTokenOptions;\n\nexport const put = createPutMethod<ClientPutCommandOptions>({\n allowedOptions: ['contentType'],\n extraChecks: createPutExtraChecks('client/`put`'),\n});\n\n// vercelBlob. createMultipartUpload()\n// vercelBlob. uploadPart()\n// vercelBlob. completeMultipartUpload()\n// vercelBlob. createMultipartUploader()\n\nexport type ClientCreateMultipartUploadCommandOptions =\n ClientCommonCreateBlobOptions & ClientTokenOptions;\n\nexport const createMultipartUpload =\n createCreateMultipartUploadMethod<ClientCreateMultipartUploadCommandOptions>({\n allowedOptions: ['contentType'],\n extraChecks: createPutExtraChecks('client/`createMultipartUpload`'),\n });\n\nexport const createMultipartUploader =\n createCreateMultipartUploaderMethod<ClientCreateMultipartUploadCommandOptions>(\n {\n allowedOptions: ['contentType'],\n extraChecks: createPutExtraChecks('client/`createMultipartUpload`'),\n },\n );\n\ntype ClientMultipartUploadCommandOptions = ClientCommonCreateBlobOptions &\n ClientTokenOptions &\n CommonMultipartUploadOptions &\n WithUploadProgress;\n\nexport const uploadPart =\n createUploadPartMethod<ClientMultipartUploadCommandOptions>({\n allowedOptions: ['contentType'],\n extraChecks: createPutExtraChecks('client/`multipartUpload`'),\n });\n\ntype ClientCompleteMultipartUploadCommandOptions =\n ClientCommonCreateBlobOptions &\n ClientTokenOptions &\n CommonCompleteMultipartUploadOptions;\n\nexport const completeMultipartUpload =\n createCompleteMultipartUploadMethod<ClientCompleteMultipartUploadCommandOptions>(\n {\n allowedOptions: ['contentType'],\n extraChecks: createPutExtraChecks('client/`completeMultipartUpload`'),\n },\n );\n\n// upload methods\n\nexport interface CommonUploadOptions {\n /**\n * A route that implements the `handleUpload` function for generating a client token.\n */\n handleUploadUrl: string;\n /**\n * Additional data which will be sent to your `handleUpload` route.\n */\n clientPayload?: string;\n}\n\n// client.upload()\n// This is a client-side wrapper that will fetch the client token for you and then upload the file\nexport type UploadOptions = ClientCommonPutOptions & CommonUploadOptions;\n/**\n * Uploads a blob into your store from the client.\n * Detailed documentation can be found here: https://vercel.com/docs/storage/vercel-blob/using-blob-sdk#client-uploads\n *\n * If you want to upload from your server instead, check out the documentation for the put operation: https://vercel.com/docs/storage/vercel-blob/using-blob-sdk#upload-a-blob\n *\n * @param pathname - The pathname to upload the blob to. This includes the filename.\n * @param body - The contents of your blob. This has to be a supported fetch body type https://developer.mozilla.org/en-US/docs/Web/API/fetch#body.\n * @param options - Additional options.\n */\nexport const upload = createPutMethod<UploadOptions>({\n allowedOptions: ['contentType'],\n extraChecks(options) {\n if (typeof window === 'undefined') {\n throw new BlobError(\n 'client/`upload` must be called from a client environment',\n );\n }\n\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- Runtime check for DX.\n if (options.handleUploadUrl === undefined) {\n throw new BlobError(\n \"client/`upload` requires the 'handleUploadUrl' parameter\",\n );\n }\n\n if (\n // @ts-expect-error -- Runtime check for DX.\n options.addRandomSuffix !== undefined ||\n // @ts-expect-error -- Runtime check for DX.\n options.cacheControlMaxAge !== undefined\n ) {\n throw new BlobError(\n \"client/`upload` doesn't allow addRandomSuffix and cacheControlMaxAge. Configure these options at the server side when generating client tokens.\",\n );\n }\n },\n async getToken(pathname, options) {\n return retrieveClientToken({\n handleUploadUrl: options.handleUploadUrl,\n pathname,\n clientPayload: options.clientPayload ?? null,\n multipart: options.multipart ?? false,\n });\n },\n});\n\nasync function importKey(token: string): Promise<CryptoKey> {\n return globalThis.crypto.subtle.importKey(\n 'raw',\n new TextEncoder().encode(token),\n { name: 'HMAC', hash: 'SHA-256' },\n false,\n ['sign', 'verify'],\n );\n}\n\nasync function signPayload(\n payload: string,\n token: string,\n): Promise<string | undefined> {\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- Node.js < 20: globalThis.crypto is undefined (in a real script.js, because the REPL has it linked to the crypto module). Node.js >= 20, Browsers and Cloudflare workers: globalThis.crypto is defined and is the Web Crypto API.\n if (!globalThis.crypto) {\n return crypto.createHmac('sha256', token).update(payload).digest('hex');\n }\n\n const signature = await globalThis.crypto.subtle.sign(\n 'HMAC',\n await importKey(token),\n new TextEncoder().encode(payload),\n );\n return Buffer.from(new Uint8Array(signature)).toString('hex');\n}\n\nasync function verifyCallbackSignature({\n token,\n signature,\n body,\n}: {\n token: string;\n signature: string;\n body: string;\n}): Promise<boolean> {\n // callback signature is signed using the server token\n const secret = token;\n // Browsers, Edge runtime and Node >=20 implement the Web Crypto API\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- Node.js < 20: globalThis.crypto is undefined (in a real script.js, because the REPL has it linked to the crypto module). Node.js >= 20, Browsers and Cloudflare workers: globalThis.crypto is defined and is the Web Crypto API.\n if (!globalThis.crypto) {\n // Node <20 falls back to the Node.js crypto module\n const digest = crypto\n .createHmac('sha256', secret)\n .update(body)\n .digest('hex');\n const digestBuffer = Buffer.from(digest);\n const signatureBuffer = Buffer.from(signature);\n\n return (\n digestBuffer.length === signatureBuffer.length &&\n crypto.timingSafeEqual(digestBuffer, signatureBuffer)\n );\n }\n\n const verified = await globalThis.crypto.subtle.verify(\n 'HMAC',\n await importKey(token),\n hexToArrayByte(signature),\n new TextEncoder().encode(body),\n );\n return verified;\n}\n\nfunction hexToArrayByte(input: string): ArrayBuffer {\n if (input.length % 2 !== 0) {\n throw new RangeError('Expected string to be an even number of characters');\n }\n const view = new Uint8Array(input.length / 2);\n\n for (let i = 0; i < input.length; i += 2) {\n view[i / 2] = parseInt(input.substring(i, i + 2), 16);\n }\n\n return Buffer.from(view);\n}\n\nexport type DecodedClientTokenPayload = Omit<\n GenerateClientTokenOptions,\n 'token'\n> & {\n validUntil: number;\n};\n\nexport function getPayloadFromClientToken(\n clientToken: string,\n): DecodedClientTokenPayload {\n const [, , , , encodedToken] = clientToken.split('_');\n const encodedPayload = Buffer.from(encodedToken ?? '', 'base64')\n .toString()\n .split('.')[1];\n const decodedPayload = Buffer.from(encodedPayload ?? '', 'base64').toString();\n return JSON.parse(decodedPayload) as DecodedClientTokenPayload;\n}\n\nconst EventTypes = {\n generateClientToken: 'blob.generate-client-token',\n uploadCompleted: 'blob.upload-completed',\n} as const;\n\ninterface GenerateClientTokenEvent {\n type: (typeof EventTypes)['generateClientToken'];\n payload: {\n pathname: string;\n callbackUrl: string;\n multipart: boolean;\n clientPayload: string | null;\n };\n}\ninterface UploadCompletedEvent {\n type: (typeof EventTypes)['uploadCompleted'];\n payload: {\n blob: PutBlobResult;\n tokenPayload?: string | null;\n };\n}\n\nexport type HandleUploadBody = GenerateClientTokenEvent | UploadCompletedEvent;\n\ntype RequestType = IncomingMessage | Request;\n\nexport interface HandleUploadOptions {\n body: HandleUploadBody;\n onBeforeGenerateToken: (\n pathname: string,\n clientPayload: string | null,\n multipart: boolean,\n ) => Promise<\n Pick<\n GenerateClientTokenOptions,\n | 'allowedContentTypes'\n | 'maximumSizeInBytes'\n | 'validUntil'\n | 'addRandomSuffix'\n | 'cacheControlMaxAge'\n > & { tokenPayload?: string | null }\n >;\n onUploadCompleted: (body: UploadCompletedEvent['payload']) => Promise<void>;\n token?: string;\n request: RequestType;\n}\n\nexport async function handleUpload({\n token,\n request,\n body,\n onBeforeGenerateToken,\n onUploadCompleted,\n}: HandleUploadOptions): Promise<\n | { type: GenerateClientTokenEvent['type']; clientToken: string }\n | { type: UploadCompletedEvent['type']; response: 'ok' }\n> {\n const resolvedToken = getTokenFromOptionsOrEnv({ token });\n\n const type = body.type;\n switch (type) {\n case 'blob.generate-client-token': {\n const { pathname, callbackUrl, clientPayload, multipart } = body.payload;\n const payload = await onBeforeGenerateToken(\n pathname,\n clientPayload,\n multipart,\n );\n const tokenPayload = payload.tokenPayload ?? clientPayload;\n\n // one hour\n const oneHourInSeconds = 60 * 60;\n const now = new Date();\n const validUntil =\n payload.validUntil ??\n now.setSeconds(now.getSeconds() + oneHourInSeconds);\n\n return {\n type,\n clientToken: await generateClientTokenFromReadWriteToken({\n ...payload,\n token: resolvedToken,\n pathname,\n onUploadCompleted: {\n callbackUrl,\n tokenPayload,\n },\n validUntil,\n }),\n };\n }\n case 'blob.upload-completed': {\n const signatureHeader = 'x-vercel-signature';\n const signature = (\n 'credentials' in request\n ? (request.headers.get(signatureHeader) ?? '')\n : (request.headers[signatureHeader] ?? '')\n ) as string;\n\n if (!signature) {\n throw new BlobError('Missing callback signature');\n }\n\n const isVerified = await verifyCallbackSignature({\n token: resolvedToken,\n signature,\n body: JSON.stringify(body),\n });\n\n if (!isVerified) {\n throw new BlobError('Invalid callback signature');\n }\n await onUploadCompleted(body.payload);\n return { type, response: 'ok' };\n }\n default:\n throw new BlobError('Invalid event type');\n }\n}\n\nasync function retrieveClientToken(options: {\n pathname: string;\n handleUploadUrl: string;\n clientPayload: string | null;\n multipart: boolean;\n abortSignal?: AbortSignal;\n}): Promise<string> {\n const { handleUploadUrl, pathname } = options;\n const url = isAbsoluteUrl(handleUploadUrl)\n ? handleUploadUrl\n : toAbsoluteUrl(handleUploadUrl);\n\n const event: GenerateClientTokenEvent = {\n type: EventTypes.generateClientToken,\n payload: {\n pathname,\n callbackUrl: url,\n clientPayload: options.clientPayload,\n multipart: options.multipart,\n },\n };\n\n const res = await fetch(url, {\n method: 'POST',\n body: JSON.stringify(event),\n headers: {\n 'content-type': 'application/json',\n },\n signal: options.abortSignal,\n });\n\n if (!res.ok) {\n throw new BlobError('Failed to retrieve the client token');\n }\n\n try {\n const { clientToken } = (await res.json()) as { clientToken: string };\n return clientToken;\n } catch (e) {\n throw new BlobError('Failed to retrieve the client token');\n }\n}\n\nfunction toAbsoluteUrl(url: string): string {\n return new URL(url, window.location.href).href;\n}\n\nfunction isAbsoluteUrl(url: string): boolean {\n try {\n return Boolean(new URL(url));\n } catch (e) {\n return false;\n }\n}\n\nexport async function generateClientTokenFromReadWriteToken({\n token,\n ...argsWithoutToken\n}: GenerateClientTokenOptions): Promise<string> {\n if (typeof window !== 'undefined') {\n throw new BlobError(\n '\"generateClientTokenFromReadWriteToken\" must be called from a server environment',\n );\n }\n\n const timestamp = new Date();\n timestamp.setSeconds(timestamp.getSeconds() + 30);\n const readWriteToken = getTokenFromOptionsOrEnv({ token });\n\n const [, , , storeId = null] = readWriteToken.split('_');\n\n if (!storeId) {\n throw new BlobError(\n token ? 'Invalid `token` parameter' : 'Invalid `BLOB_READ_WRITE_TOKEN`',\n );\n }\n\n const payload = Buffer.from(\n JSON.stringify({\n ...argsWithoutToken,\n validUntil: argsWithoutToken.validUntil ?? timestamp.getTime(),\n }),\n ).toString('base64');\n\n const securedKey = await signPayload(payload, readWriteToken);\n\n if (!securedKey) {\n throw new BlobError('Unable to sign client token');\n }\n return `vercel_blob_client_${storeId}_${Buffer.from(\n `${securedKey}.${payload}`,\n ).toString('base64')}`;\n}\n\nexport interface GenerateClientTokenOptions extends BlobCommandOptions {\n pathname: string;\n onUploadCompleted?: {\n callbackUrl: string;\n tokenPayload?: string | null;\n };\n maximumSizeInBytes?: number;\n allowedContentTypes?: string[];\n validUntil?: number;\n addRandomSuffix?: boolean;\n cacheControlMaxAge?: number;\n}\n\nexport { createFolder } from './create-folder';\n"],"mappings":";;;;;;;;;;;;AACA,YAAY,YAAY;AAKxB,SAAS,aAAa;AA+CtB,SAAS,qBAEP,YAAoB;AACpB,SAAO,SAAS,YAAY,SAAmB;AAC7C,QAAI,OAAO,WAAW,aAAa;AACjC,YAAM,IAAI;AAAA,QACR,GAAG,UAAU;AAAA,MACf;AAAA,IACF;AAEA,QAAI,CAAC,QAAQ,MAAM,WAAW,qBAAqB,GAAG;AACpD,YAAM,IAAI,UAAU,GAAG,UAAU,qCAAqC;AAAA,IACxE;AAEA;AAAA;AAAA,MAEE,QAAQ,oBAAoB;AAAA,MAE5B,QAAQ,uBAAuB;AAAA,MAC/B;AACA,YAAM,IAAI;AAAA,QACR,GAAG,UAAU;AAAA,MACf;AAAA,IACF;AAAA,EACF;AACF;AAOO,IAAM,MAAM,gBAAyC;AAAA,EAC1D,gBAAgB,CAAC,aAAa;AAAA,EAC9B,aAAa,qBAAqB,cAAc;AAClD,CAAC;AAUM,IAAM,wBACX,kCAA6E;AAAA,EAC3E,gBAAgB,CAAC,aAAa;AAAA,EAC9B,aAAa,qBAAqB,gCAAgC;AACpE,CAAC;AAEI,IAAM,0BACX;AAAA,EACE;AAAA,IACE,gBAAgB,CAAC,aAAa;AAAA,IAC9B,aAAa,qBAAqB,gCAAgC;AAAA,EACpE;AACF;AAOK,IAAM,aACX,uBAA4D;AAAA,EAC1D,gBAAgB,CAAC,aAAa;AAAA,EAC9B,aAAa,qBAAqB,0BAA0B;AAC9D,CAAC;AAOI,IAAM,0BACX;AAAA,EACE;AAAA,IACE,gBAAgB,CAAC,aAAa;AAAA,IAC9B,aAAa,qBAAqB,kCAAkC;AAAA,EACtE;AACF;AA4BK,IAAM,SAAS,gBAA+B;AAAA,EACnD,gBAAgB,CAAC,aAAa;AAAA,EAC9B,YAAY,SAAS;AACnB,QAAI,OAAO,WAAW,aAAa;AACjC,YAAM,IAAI;AAAA,QACR;AAAA,MACF;AAAA,IACF;AAGA,QAAI,QAAQ,oBAAoB,QAAW;AACzC,YAAM,IAAI;AAAA,QACR;AAAA,MACF;AAAA,IACF;AAEA;AAAA;AAAA,MAEE,QAAQ,oBAAoB;AAAA,MAE5B,QAAQ,uBAAuB;AAAA,MAC/B;AACA,YAAM,IAAI;AAAA,QACR;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAAA,EACA,MAAM,SAAS,UAAU,SAAS;AA7LpC;AA8LI,WAAO,oBAAoB;AAAA,MACzB,iBAAiB,QAAQ;AAAA,MACzB;AAAA,MACA,gBAAe,aAAQ,kBAAR,YAAyB;AAAA,MACxC,YAAW,aAAQ,cAAR,YAAqB;AAAA,IAClC,CAAC;AAAA,EACH;AACF,CAAC;AAED,eAAe,UAAU,OAAmC;AAC1D,SAAO,WAAW,OAAO,OAAO;AAAA,IAC9B;AAAA,IACA,IAAI,YAAY,EAAE,OAAO,KAAK;AAAA,IAC9B,EAAE,MAAM,QAAQ,MAAM,UAAU;AAAA,IAChC;AAAA,IACA,CAAC,QAAQ,QAAQ;AAAA,EACnB;AACF;AAEA,eAAe,YACb,SACA,OAC6B;AAE7B,MAAI,CAAC,WAAW,QAAQ;AACtB,WAAc,kBAAW,UAAU,KAAK,EAAE,OAAO,OAAO,EAAE,OAAO,KAAK;AAAA,EACxE;AAEA,QAAM,YAAY,MAAM,WAAW,OAAO,OAAO;AAAA,IAC/C;AAAA,IACA,MAAM,UAAU,KAAK;AAAA,IACrB,IAAI,YAAY,EAAE,OAAO,OAAO;AAAA,EAClC;AACA,SAAO,OAAO,KAAK,IAAI,WAAW,SAAS,CAAC,EAAE,SAAS,KAAK;AAC9D;AAEA,eAAe,wBAAwB;AAAA,EACrC;AAAA,EACA;AAAA,EACA;AACF,GAIqB;AAEnB,QAAM,SAAS;AAGf,MAAI,CAAC,WAAW,QAAQ;AAEtB,UAAM,SACH,kBAAW,UAAU,MAAM,EAC3B,OAAO,IAAI,EACX,OAAO,KAAK;AACf,UAAM,eAAe,OAAO,KAAK,MAAM;AACvC,UAAM,kBAAkB,OAAO,KAAK,SAAS;AAE7C,WACE,aAAa,WAAW,gBAAgB,UACjC,uBAAgB,cAAc,eAAe;AAAA,EAExD;AAEA,QAAM,WAAW,MAAM,WAAW,OAAO,OAAO;AAAA,IAC9C;AAAA,IACA,MAAM,UAAU,KAAK;AAAA,IACrB,eAAe,SAAS;AAAA,IACxB,IAAI,YAAY,EAAE,OAAO,IAAI;AAAA,EAC/B;AACA,SAAO;AACT;AAEA,SAAS,eAAe,OAA4B;AAClD,MAAI,MAAM,SAAS,MAAM,GAAG;AAC1B,UAAM,IAAI,WAAW,oDAAoD;AAAA,EAC3E;AACA,QAAM,OAAO,IAAI,WAAW,MAAM,SAAS,CAAC;AAE5C,WAAS,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK,GAAG;AACxC,SAAK,IAAI,CAAC,IAAI,SAAS,MAAM,UAAU,GAAG,IAAI,CAAC,GAAG,EAAE;AAAA,EACtD;AAEA,SAAO,OAAO,KAAK,IAAI;AACzB;AASO,SAAS,0BACd,aAC2B;AAC3B,QAAM,CAAC,EAAE,EAAE,EAAE,EAAE,YAAY,IAAI,YAAY,MAAM,GAAG;AACpD,QAAM,iBAAiB,OAAO,KAAK,sCAAgB,IAAI,QAAQ,EAC5D,SAAS,EACT,MAAM,GAAG,EAAE,CAAC;AACf,QAAM,iBAAiB,OAAO,KAAK,0CAAkB,IAAI,QAAQ,EAAE,SAAS;AAC5E,SAAO,KAAK,MAAM,cAAc;AAClC;AAEA,IAAM,aAAa;AAAA,EACjB,qBAAqB;AAAA,EACrB,iBAAiB;AACnB;AA4CA,eAAsB,aAAa;AAAA,EACjC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAGE;AA9VF;AA+VE,QAAM,gBAAgB,yBAAyB,EAAE,MAAM,CAAC;AAExD,QAAM,OAAO,KAAK;AAClB,UAAQ,MAAM;AAAA,IACZ,KAAK,8BAA8B;AACjC,YAAM,EAAE,UAAU,aAAa,eAAe,UAAU,IAAI,KAAK;AACjE,YAAM,UAAU,MAAM;AAAA,QACpB;AAAA,QACA;AAAA,QACA;AAAA,MACF;AACA,YAAM,gBAAe,aAAQ,iBAAR,YAAwB;AAG7C,YAAM,mBAAmB,KAAK;AAC9B,YAAM,MAAM,oBAAI,KAAK;AACrB,YAAM,cACJ,aAAQ,eAAR,YACA,IAAI,WAAW,IAAI,WAAW,IAAI,gBAAgB;AAEpD,aAAO;AAAA,QACL;AAAA,QACA,aAAa,MAAM,sCAAsC;AAAA,UACvD,GAAG;AAAA,UACH,OAAO;AAAA,UACP;AAAA,UACA,mBAAmB;AAAA,YACjB;AAAA,YACA;AAAA,UACF;AAAA,UACA;AAAA,QACF,CAAC;AAAA,MACH;AAAA,IACF;AAAA,IACA,KAAK,yBAAyB;AAC5B,YAAM,kBAAkB;AACxB,YAAM,YACJ,iBAAiB,WACZ,aAAQ,QAAQ,IAAI,eAAe,MAAnC,YAAwC,MACxC,aAAQ,QAAQ,eAAe,MAA/B,YAAoC;AAG3C,UAAI,CAAC,WAAW;AACd,cAAM,IAAI,UAAU,4BAA4B;AAAA,MAClD;AAEA,YAAM,aAAa,MAAM,wBAAwB;AAAA,QAC/C,OAAO;AAAA,QACP;AAAA,QACA,MAAM,KAAK,UAAU,IAAI;AAAA,MAC3B,CAAC;AAED,UAAI,CAAC,YAAY;AACf,cAAM,IAAI,UAAU,4BAA4B;AAAA,MAClD;AACA,YAAM,kBAAkB,KAAK,OAAO;AACpC,aAAO,EAAE,MAAM,UAAU,KAAK;AAAA,IAChC;AAAA,IACA;AACE,YAAM,IAAI,UAAU,oBAAoB;AAAA,EAC5C;AACF;AAEA,eAAe,oBAAoB,SAMf;AAClB,QAAM,EAAE,iBAAiB,SAAS,IAAI;AACtC,QAAM,MAAM,cAAc,eAAe,IACrC,kBACA,cAAc,eAAe;AAEjC,QAAM,QAAkC;AAAA,IACtC,MAAM,WAAW;AAAA,IACjB,SAAS;AAAA,MACP;AAAA,MACA,aAAa;AAAA,MACb,eAAe,QAAQ;AAAA,MACvB,WAAW,QAAQ;AAAA,IACrB;AAAA,EACF;AAEA,QAAM,MAAM,MAAM,MAAM,KAAK;AAAA,IAC3B,QAAQ;AAAA,IACR,MAAM,KAAK,UAAU,KAAK;AAAA,IAC1B,SAAS;AAAA,MACP,gBAAgB;AAAA,IAClB;AAAA,IACA,QAAQ,QAAQ;AAAA,EAClB,CAAC;AAED,MAAI,CAAC,IAAI,IAAI;AACX,UAAM,IAAI,UAAU,sCAAsC;AAAA,EAC5D;AAEA,MAAI;AACF,UAAM,EAAE,YAAY,IAAK,MAAM,IAAI,KAAK;AACxC,WAAO;AAAA,EACT,SAAS,GAAG;AACV,UAAM,IAAI,UAAU,qCAAqC;AAAA,EAC3D;AACF;AAEA,SAAS,cAAc,KAAqB;AAC1C,SAAO,IAAI,IAAI,KAAK,OAAO,SAAS,IAAI,EAAE;AAC5C;AAEA,SAAS,cAAc,KAAsB;AAC3C,MAAI;AACF,WAAO,QAAQ,IAAI,IAAI,GAAG,CAAC;AAAA,EAC7B,SAAS,GAAG;AACV,WAAO;AAAA,EACT;AACF;AAEA,eAAsB,sCAAsC;AAAA,EAC1D;AAAA,EACA,GAAG;AACL,GAAgD;AAxdhD;AAydE,MAAI,OAAO,WAAW,aAAa;AACjC,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AAAA,EACF;AAEA,QAAM,YAAY,oBAAI,KAAK;AAC3B,YAAU,WAAW,UAAU,WAAW,IAAI,EAAE;AAChD,QAAM,iBAAiB,yBAAyB,EAAE,MAAM,CAAC;AAEzD,QAAM,CAAC,EAAE,EAAE,EAAE,UAAU,IAAI,IAAI,eAAe,MAAM,GAAG;AAEvD,MAAI,CAAC,SAAS;AACZ,UAAM,IAAI;AAAA,MACR,QAAQ,8BAA8B;AAAA,IACxC;AAAA,EACF;AAEA,QAAM,UAAU,OAAO;AAAA,IACrB,KAAK,UAAU;AAAA,MACb,GAAG;AAAA,MACH,aAAY,sBAAiB,eAAjB,YAA+B,UAAU,QAAQ;AAAA,IAC/D,CAAC;AAAA,EACH,EAAE,SAAS,QAAQ;AAEnB,QAAM,aAAa,MAAM,YAAY,SAAS,cAAc;AAE5D,MAAI,CAAC,YAAY;AACf,UAAM,IAAI,UAAU,6BAA6B;AAAA,EACnD;AACA,SAAO,sBAAsB,OAAO,IAAI,OAAO;AAAA,IAC7C,GAAG,UAAU,IAAI,OAAO;AAAA,EAC1B,EAAE,SAAS,QAAQ,CAAC;AACtB;","names":[]}
1
+ {"version":3,"sources":["../src/client.ts"],"sourcesContent":["// eslint-disable-next-line unicorn/prefer-node-protocol -- node:crypto does not resolve correctly in browser and edge runtime\nimport * as crypto from 'crypto';\nimport type { IncomingMessage } from 'node:http';\n// When bundled via a bundler supporting the `browser` field, then\n// the `undici` module will be replaced with https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API\n// for browser contexts. See ./undici-browser.js and ./package.json\nimport { fetch } from 'undici';\nimport type { BlobCommandOptions, WithUploadProgress } from './helpers';\nimport { BlobError, getTokenFromOptionsOrEnv } from './helpers';\nimport { createPutMethod } from './put';\nimport type { PutBlobResult } from './put-helpers';\nimport type { CommonCompleteMultipartUploadOptions } from './multipart/complete';\nimport { createCompleteMultipartUploadMethod } from './multipart/complete';\nimport { createCreateMultipartUploadMethod } from './multipart/create';\nimport { createUploadPartMethod } from './multipart/upload';\nimport type { CommonMultipartUploadOptions } from './multipart/upload';\nimport { createCreateMultipartUploaderMethod } from './multipart/create-uploader';\n\n// interface for put, upload and multipartUpload.\n// This types omits all options that are encoded in the client token.\nexport interface ClientCommonCreateBlobOptions {\n /**\n * Whether the blob should be publicly accessible.\n */\n access: 'public';\n /**\n * Defines the content type of the blob. By default, this value is inferred from the pathname. Sent as the 'content-type' header when downloading a blob.\n */\n contentType?: string;\n /**\n * `AbortSignal` to cancel the running request. See https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal\n */\n abortSignal?: AbortSignal;\n}\n\n// shared interface for put and multipartUpload\nexport interface ClientTokenOptions {\n /**\n * A client token that was generated by your server using the `generateClientToken` method.\n */\n token: string;\n}\n\n// shared interface for put and upload\ninterface ClientCommonPutOptions\n extends ClientCommonCreateBlobOptions,\n WithUploadProgress {\n /**\n * Whether to use multipart upload. Use this when uploading large files. It will split the file into multiple parts, upload them in parallel and retry failed parts.\n */\n multipart?: boolean;\n}\n\nfunction createPutExtraChecks<\n TOptions extends ClientTokenOptions & ClientCommonCreateBlobOptions,\n>(methodName: string) {\n return function extraChecks(options: TOptions) {\n if (!options.token.startsWith('vercel_blob_client_')) {\n throw new BlobError(`${methodName} must be called with a client token`);\n }\n\n if (\n // @ts-expect-error -- Runtime check for DX.\n options.addRandomSuffix !== undefined ||\n // @ts-expect-error -- Runtime check for DX.\n options.cacheControlMaxAge !== undefined\n ) {\n throw new BlobError(\n `${methodName} doesn't allow addRandomSuffix and cacheControlMaxAge. Configure these options at the server side when generating client tokens.`,\n );\n }\n };\n}\n\n// client.put()\n\nexport type ClientPutCommandOptions = ClientCommonPutOptions &\n ClientTokenOptions;\n\nexport const put = createPutMethod<ClientPutCommandOptions>({\n allowedOptions: ['contentType'],\n extraChecks: createPutExtraChecks('client/`put`'),\n});\n\n// vercelBlob. createMultipartUpload()\n// vercelBlob. uploadPart()\n// vercelBlob. completeMultipartUpload()\n// vercelBlob. createMultipartUploader()\n\nexport type ClientCreateMultipartUploadCommandOptions =\n ClientCommonCreateBlobOptions & ClientTokenOptions;\n\nexport const createMultipartUpload =\n createCreateMultipartUploadMethod<ClientCreateMultipartUploadCommandOptions>({\n allowedOptions: ['contentType'],\n extraChecks: createPutExtraChecks('client/`createMultipartUpload`'),\n });\n\nexport const createMultipartUploader =\n createCreateMultipartUploaderMethod<ClientCreateMultipartUploadCommandOptions>(\n {\n allowedOptions: ['contentType'],\n extraChecks: createPutExtraChecks('client/`createMultipartUpload`'),\n },\n );\n\ntype ClientMultipartUploadCommandOptions = ClientCommonCreateBlobOptions &\n ClientTokenOptions &\n CommonMultipartUploadOptions &\n WithUploadProgress;\n\nexport const uploadPart =\n createUploadPartMethod<ClientMultipartUploadCommandOptions>({\n allowedOptions: ['contentType'],\n extraChecks: createPutExtraChecks('client/`multipartUpload`'),\n });\n\ntype ClientCompleteMultipartUploadCommandOptions =\n ClientCommonCreateBlobOptions &\n ClientTokenOptions &\n CommonCompleteMultipartUploadOptions;\n\nexport const completeMultipartUpload =\n createCompleteMultipartUploadMethod<ClientCompleteMultipartUploadCommandOptions>(\n {\n allowedOptions: ['contentType'],\n extraChecks: createPutExtraChecks('client/`completeMultipartUpload`'),\n },\n );\n\n// upload methods\n\nexport interface CommonUploadOptions {\n /**\n * A route that implements the `handleUpload` function for generating a client token.\n */\n handleUploadUrl: string;\n /**\n * Additional data which will be sent to your `handleUpload` route.\n */\n clientPayload?: string;\n}\n\n// client.upload()\n// This is a client-side wrapper that will fetch the client token for you and then upload the file\nexport type UploadOptions = ClientCommonPutOptions & CommonUploadOptions;\n/**\n * Uploads a blob into your store from the client.\n * Detailed documentation can be found here: https://vercel.com/docs/storage/vercel-blob/using-blob-sdk#client-uploads\n *\n * If you want to upload from your server instead, check out the documentation for the put operation: https://vercel.com/docs/storage/vercel-blob/using-blob-sdk#upload-a-blob\n *\n * @param pathname - The pathname to upload the blob to. This includes the filename.\n * @param body - The contents of your blob. This has to be a supported fetch body type https://developer.mozilla.org/en-US/docs/Web/API/fetch#body.\n * @param options - Additional options.\n */\nexport const upload = createPutMethod<UploadOptions>({\n allowedOptions: ['contentType'],\n extraChecks(options) {\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- Runtime check for DX.\n if (options.handleUploadUrl === undefined) {\n throw new BlobError(\n \"client/`upload` requires the 'handleUploadUrl' parameter\",\n );\n }\n\n if (\n // @ts-expect-error -- Runtime check for DX.\n options.addRandomSuffix !== undefined ||\n // @ts-expect-error -- Runtime check for DX.\n options.cacheControlMaxAge !== undefined\n ) {\n throw new BlobError(\n \"client/`upload` doesn't allow addRandomSuffix and cacheControlMaxAge. Configure these options at the server side when generating client tokens.\",\n );\n }\n },\n async getToken(pathname, options) {\n return retrieveClientToken({\n handleUploadUrl: options.handleUploadUrl,\n pathname,\n clientPayload: options.clientPayload ?? null,\n multipart: options.multipart ?? false,\n });\n },\n});\n\nasync function importKey(token: string): Promise<CryptoKey> {\n return globalThis.crypto.subtle.importKey(\n 'raw',\n new TextEncoder().encode(token),\n { name: 'HMAC', hash: 'SHA-256' },\n false,\n ['sign', 'verify'],\n );\n}\n\nasync function signPayload(\n payload: string,\n token: string,\n): Promise<string | undefined> {\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- Node.js < 20: globalThis.crypto is undefined (in a real script.js, because the REPL has it linked to the crypto module). Node.js >= 20, Browsers and Cloudflare workers: globalThis.crypto is defined and is the Web Crypto API.\n if (!globalThis.crypto) {\n return crypto.createHmac('sha256', token).update(payload).digest('hex');\n }\n\n const signature = await globalThis.crypto.subtle.sign(\n 'HMAC',\n await importKey(token),\n new TextEncoder().encode(payload),\n );\n return Buffer.from(new Uint8Array(signature)).toString('hex');\n}\n\nasync function verifyCallbackSignature({\n token,\n signature,\n body,\n}: {\n token: string;\n signature: string;\n body: string;\n}): Promise<boolean> {\n // callback signature is signed using the server token\n const secret = token;\n // Browsers, Edge runtime and Node >=20 implement the Web Crypto API\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- Node.js < 20: globalThis.crypto is undefined (in a real script.js, because the REPL has it linked to the crypto module). Node.js >= 20, Browsers and Cloudflare workers: globalThis.crypto is defined and is the Web Crypto API.\n if (!globalThis.crypto) {\n // Node <20 falls back to the Node.js crypto module\n const digest = crypto\n .createHmac('sha256', secret)\n .update(body)\n .digest('hex');\n const digestBuffer = Buffer.from(digest);\n const signatureBuffer = Buffer.from(signature);\n\n return (\n digestBuffer.length === signatureBuffer.length &&\n crypto.timingSafeEqual(digestBuffer, signatureBuffer)\n );\n }\n\n const verified = await globalThis.crypto.subtle.verify(\n 'HMAC',\n await importKey(token),\n hexToArrayByte(signature),\n new TextEncoder().encode(body),\n );\n return verified;\n}\n\nfunction hexToArrayByte(input: string): Buffer {\n if (input.length % 2 !== 0) {\n throw new RangeError('Expected string to be an even number of characters');\n }\n const view = new Uint8Array(input.length / 2);\n\n for (let i = 0; i < input.length; i += 2) {\n view[i / 2] = parseInt(input.substring(i, i + 2), 16);\n }\n\n return Buffer.from(view);\n}\n\nexport type DecodedClientTokenPayload = Omit<\n GenerateClientTokenOptions,\n 'token'\n> & {\n validUntil: number;\n};\n\nexport function getPayloadFromClientToken(\n clientToken: string,\n): DecodedClientTokenPayload {\n const [, , , , encodedToken] = clientToken.split('_');\n const encodedPayload = Buffer.from(encodedToken ?? '', 'base64')\n .toString()\n .split('.')[1];\n const decodedPayload = Buffer.from(encodedPayload ?? '', 'base64').toString();\n return JSON.parse(decodedPayload) as DecodedClientTokenPayload;\n}\n\nconst EventTypes = {\n generateClientToken: 'blob.generate-client-token',\n uploadCompleted: 'blob.upload-completed',\n} as const;\n\ninterface GenerateClientTokenEvent {\n type: (typeof EventTypes)['generateClientToken'];\n payload: {\n pathname: string;\n callbackUrl: string;\n multipart: boolean;\n clientPayload: string | null;\n };\n}\ninterface UploadCompletedEvent {\n type: (typeof EventTypes)['uploadCompleted'];\n payload: {\n blob: PutBlobResult;\n tokenPayload?: string | null;\n };\n}\n\nexport type HandleUploadBody = GenerateClientTokenEvent | UploadCompletedEvent;\n\ntype RequestType = IncomingMessage | Request;\n\nexport interface HandleUploadOptions {\n body: HandleUploadBody;\n onBeforeGenerateToken: (\n pathname: string,\n clientPayload: string | null,\n multipart: boolean,\n ) => Promise<\n Pick<\n GenerateClientTokenOptions,\n | 'allowedContentTypes'\n | 'maximumSizeInBytes'\n | 'validUntil'\n | 'addRandomSuffix'\n | 'cacheControlMaxAge'\n > & { tokenPayload?: string | null }\n >;\n onUploadCompleted: (body: UploadCompletedEvent['payload']) => Promise<void>;\n token?: string;\n request: RequestType;\n}\n\nexport async function handleUpload({\n token,\n request,\n body,\n onBeforeGenerateToken,\n onUploadCompleted,\n}: HandleUploadOptions): Promise<\n | { type: GenerateClientTokenEvent['type']; clientToken: string }\n | { type: UploadCompletedEvent['type']; response: 'ok' }\n> {\n const resolvedToken = getTokenFromOptionsOrEnv({ token });\n\n const type = body.type;\n switch (type) {\n case 'blob.generate-client-token': {\n const { pathname, callbackUrl, clientPayload, multipart } = body.payload;\n const payload = await onBeforeGenerateToken(\n pathname,\n clientPayload,\n multipart,\n );\n const tokenPayload = payload.tokenPayload ?? clientPayload;\n\n // one hour\n const oneHourInSeconds = 60 * 60;\n const now = new Date();\n const validUntil =\n payload.validUntil ??\n now.setSeconds(now.getSeconds() + oneHourInSeconds);\n\n return {\n type,\n clientToken: await generateClientTokenFromReadWriteToken({\n ...payload,\n token: resolvedToken,\n pathname,\n onUploadCompleted: {\n callbackUrl,\n tokenPayload,\n },\n validUntil,\n }),\n };\n }\n case 'blob.upload-completed': {\n const signatureHeader = 'x-vercel-signature';\n const signature = (\n 'credentials' in request\n ? (request.headers.get(signatureHeader) ?? '')\n : (request.headers[signatureHeader] ?? '')\n ) as string;\n\n if (!signature) {\n throw new BlobError('Missing callback signature');\n }\n\n const isVerified = await verifyCallbackSignature({\n token: resolvedToken,\n signature,\n body: JSON.stringify(body),\n });\n\n if (!isVerified) {\n throw new BlobError('Invalid callback signature');\n }\n await onUploadCompleted(body.payload);\n return { type, response: 'ok' };\n }\n default:\n throw new BlobError('Invalid event type');\n }\n}\n\nasync function retrieveClientToken(options: {\n pathname: string;\n handleUploadUrl: string;\n clientPayload: string | null;\n multipart: boolean;\n abortSignal?: AbortSignal;\n}): Promise<string> {\n const { handleUploadUrl, pathname } = options;\n const url = isAbsoluteUrl(handleUploadUrl)\n ? handleUploadUrl\n : toAbsoluteUrl(handleUploadUrl);\n\n const event: GenerateClientTokenEvent = {\n type: EventTypes.generateClientToken,\n payload: {\n pathname,\n callbackUrl: url,\n clientPayload: options.clientPayload,\n multipart: options.multipart,\n },\n };\n\n const res = await fetch(url, {\n method: 'POST',\n body: JSON.stringify(event),\n headers: {\n 'content-type': 'application/json',\n },\n signal: options.abortSignal,\n });\n\n if (!res.ok) {\n throw new BlobError('Failed to retrieve the client token');\n }\n\n try {\n const { clientToken } = (await res.json()) as { clientToken: string };\n return clientToken;\n } catch (e) {\n throw new BlobError('Failed to retrieve the client token');\n }\n}\n\nfunction toAbsoluteUrl(url: string): string {\n // location is available in web workers too: https://developer.mozilla.org/en-US/docs/Web/API/Window/location\n return new URL(url, location.href).href;\n}\n\nfunction isAbsoluteUrl(url: string): boolean {\n try {\n return Boolean(new URL(url));\n } catch (e) {\n return false;\n }\n}\n\nexport async function generateClientTokenFromReadWriteToken({\n token,\n ...argsWithoutToken\n}: GenerateClientTokenOptions): Promise<string> {\n if (typeof window !== 'undefined') {\n throw new BlobError(\n '\"generateClientTokenFromReadWriteToken\" must be called from a server environment',\n );\n }\n\n const timestamp = new Date();\n timestamp.setSeconds(timestamp.getSeconds() + 30);\n const readWriteToken = getTokenFromOptionsOrEnv({ token });\n\n const [, , , storeId = null] = readWriteToken.split('_');\n\n if (!storeId) {\n throw new BlobError(\n token ? 'Invalid `token` parameter' : 'Invalid `BLOB_READ_WRITE_TOKEN`',\n );\n }\n\n const payload = Buffer.from(\n JSON.stringify({\n ...argsWithoutToken,\n validUntil: argsWithoutToken.validUntil ?? timestamp.getTime(),\n }),\n ).toString('base64');\n\n const securedKey = await signPayload(payload, readWriteToken);\n\n if (!securedKey) {\n throw new BlobError('Unable to sign client token');\n }\n return `vercel_blob_client_${storeId}_${Buffer.from(\n `${securedKey}.${payload}`,\n ).toString('base64')}`;\n}\n\nexport interface GenerateClientTokenOptions extends BlobCommandOptions {\n pathname: string;\n onUploadCompleted?: {\n callbackUrl: string;\n tokenPayload?: string | null;\n };\n maximumSizeInBytes?: number;\n allowedContentTypes?: string[];\n validUntil?: number;\n addRandomSuffix?: boolean;\n cacheControlMaxAge?: number;\n}\n\nexport { createFolder } from './create-folder';\n"],"mappings":"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","names":[]}
package/dist/index.cjs CHANGED
@@ -22,11 +22,11 @@
22
22
 
23
23
 
24
24
 
25
- var _chunkXTBGGUVNcjs = require('./chunk-XTBGGUVN.cjs');
25
+ var _chunkA3XDFQYYcjs = require('./chunk-A3XDFQYY.cjs');
26
26
 
27
27
  // src/del.ts
28
28
  async function del(url, options) {
29
- await _chunkXTBGGUVNcjs.requestApi.call(void 0,
29
+ await _chunkA3XDFQYYcjs.requestApi.call(void 0,
30
30
  "/delete",
31
31
  {
32
32
  method: "POST",
@@ -41,7 +41,7 @@ async function del(url, options) {
41
41
  // src/head.ts
42
42
  async function head(url, options) {
43
43
  const searchParams = new URLSearchParams({ url });
44
- const response = await _chunkXTBGGUVNcjs.requestApi.call(void 0,
44
+ const response = await _chunkA3XDFQYYcjs.requestApi.call(void 0,
45
45
  `?${searchParams.toString()}`,
46
46
  // HEAD can't have body as a response, so we use GET
47
47
  {
@@ -78,7 +78,7 @@ async function list(options) {
78
78
  if (options == null ? void 0 : options.mode) {
79
79
  searchParams.set("mode", options.mode);
80
80
  }
81
- const response = await _chunkXTBGGUVNcjs.requestApi.call(void 0,
81
+ const response = await _chunkA3XDFQYYcjs.requestApi.call(void 0,
82
82
  `?${searchParams.toString()}`,
83
83
  {
84
84
  method: "GET",
@@ -113,19 +113,19 @@ function mapBlobResult(blobResult) {
113
113
  // src/copy.ts
114
114
  async function copy(fromUrl, toPathname, options) {
115
115
  if (!options) {
116
- throw new (0, _chunkXTBGGUVNcjs.BlobError)("missing options, see usage");
116
+ throw new (0, _chunkA3XDFQYYcjs.BlobError)("missing options, see usage");
117
117
  }
118
118
  if (options.access !== "public") {
119
- throw new (0, _chunkXTBGGUVNcjs.BlobError)('access must be "public"');
119
+ throw new (0, _chunkA3XDFQYYcjs.BlobError)('access must be "public"');
120
120
  }
121
- if (toPathname.length > _chunkXTBGGUVNcjs.MAXIMUM_PATHNAME_LENGTH) {
122
- throw new (0, _chunkXTBGGUVNcjs.BlobError)(
123
- `pathname is too long, maximum length is ${_chunkXTBGGUVNcjs.MAXIMUM_PATHNAME_LENGTH}`
121
+ if (toPathname.length > _chunkA3XDFQYYcjs.MAXIMUM_PATHNAME_LENGTH) {
122
+ throw new (0, _chunkA3XDFQYYcjs.BlobError)(
123
+ `pathname is too long, maximum length is ${_chunkA3XDFQYYcjs.MAXIMUM_PATHNAME_LENGTH}`
124
124
  );
125
125
  }
126
- for (const invalidCharacter of _chunkXTBGGUVNcjs.disallowedPathnameCharacters) {
126
+ for (const invalidCharacter of _chunkA3XDFQYYcjs.disallowedPathnameCharacters) {
127
127
  if (toPathname.includes(invalidCharacter)) {
128
- throw new (0, _chunkXTBGGUVNcjs.BlobError)(
128
+ throw new (0, _chunkA3XDFQYYcjs.BlobError)(
129
129
  `pathname cannot contain "${invalidCharacter}", please encode it if needed`
130
130
  );
131
131
  }
@@ -140,7 +140,7 @@ async function copy(fromUrl, toPathname, options) {
140
140
  if (options.cacheControlMaxAge !== void 0) {
141
141
  headers["x-cache-control-max-age"] = options.cacheControlMaxAge.toString();
142
142
  }
143
- const response = await _chunkXTBGGUVNcjs.requestApi.call(void 0,
143
+ const response = await _chunkA3XDFQYYcjs.requestApi.call(void 0,
144
144
  `/${toPathname}?fromUrl=${fromUrl}`,
145
145
  {
146
146
  method: "PUT",
@@ -159,19 +159,19 @@ async function copy(fromUrl, toPathname, options) {
159
159
  }
160
160
 
161
161
  // src/index.ts
162
- var put = _chunkXTBGGUVNcjs.createPutMethod.call(void 0, {
162
+ var put = _chunkA3XDFQYYcjs.createPutMethod.call(void 0, {
163
163
  allowedOptions: ["cacheControlMaxAge", "addRandomSuffix", "contentType"]
164
164
  });
165
- var createMultipartUpload = _chunkXTBGGUVNcjs.createCreateMultipartUploadMethod.call(void 0, {
165
+ var createMultipartUpload = _chunkA3XDFQYYcjs.createCreateMultipartUploadMethod.call(void 0, {
166
166
  allowedOptions: ["cacheControlMaxAge", "addRandomSuffix", "contentType"]
167
167
  });
168
- var createMultipartUploader = _chunkXTBGGUVNcjs.createCreateMultipartUploaderMethod.call(void 0, {
168
+ var createMultipartUploader = _chunkA3XDFQYYcjs.createCreateMultipartUploaderMethod.call(void 0, {
169
169
  allowedOptions: ["cacheControlMaxAge", "addRandomSuffix", "contentType"]
170
170
  });
171
- var uploadPart = _chunkXTBGGUVNcjs.createUploadPartMethod.call(void 0, {
171
+ var uploadPart = _chunkA3XDFQYYcjs.createUploadPartMethod.call(void 0, {
172
172
  allowedOptions: ["cacheControlMaxAge", "addRandomSuffix", "contentType"]
173
173
  });
174
- var completeMultipartUpload = _chunkXTBGGUVNcjs.createCompleteMultipartUploadMethod.call(void 0, {
174
+ var completeMultipartUpload = _chunkA3XDFQYYcjs.createCompleteMultipartUploadMethod.call(void 0, {
175
175
  allowedOptions: ["cacheControlMaxAge", "addRandomSuffix", "contentType"]
176
176
  });
177
177
 
@@ -199,5 +199,5 @@ var completeMultipartUpload = _chunkXTBGGUVNcjs.createCompleteMultipartUploadMet
199
199
 
200
200
 
201
201
 
202
- exports.BlobAccessError = _chunkXTBGGUVNcjs.BlobAccessError; exports.BlobClientTokenExpiredError = _chunkXTBGGUVNcjs.BlobClientTokenExpiredError; exports.BlobContentTypeNotAllowedError = _chunkXTBGGUVNcjs.BlobContentTypeNotAllowedError; exports.BlobError = _chunkXTBGGUVNcjs.BlobError; exports.BlobFileTooLargeError = _chunkXTBGGUVNcjs.BlobFileTooLargeError; exports.BlobNotFoundError = _chunkXTBGGUVNcjs.BlobNotFoundError; exports.BlobPathnameMismatchError = _chunkXTBGGUVNcjs.BlobPathnameMismatchError; exports.BlobRequestAbortedError = _chunkXTBGGUVNcjs.BlobRequestAbortedError; exports.BlobServiceNotAvailable = _chunkXTBGGUVNcjs.BlobServiceNotAvailable; exports.BlobServiceRateLimited = _chunkXTBGGUVNcjs.BlobServiceRateLimited; exports.BlobStoreNotFoundError = _chunkXTBGGUVNcjs.BlobStoreNotFoundError; exports.BlobStoreSuspendedError = _chunkXTBGGUVNcjs.BlobStoreSuspendedError; exports.BlobUnknownError = _chunkXTBGGUVNcjs.BlobUnknownError; exports.completeMultipartUpload = completeMultipartUpload; exports.copy = copy; exports.createFolder = _chunkXTBGGUVNcjs.createFolder; exports.createMultipartUpload = createMultipartUpload; exports.createMultipartUploader = createMultipartUploader; exports.del = del; exports.getDownloadUrl = _chunkXTBGGUVNcjs.getDownloadUrl; exports.head = head; exports.list = list; exports.put = put; exports.uploadPart = uploadPart;
202
+ exports.BlobAccessError = _chunkA3XDFQYYcjs.BlobAccessError; exports.BlobClientTokenExpiredError = _chunkA3XDFQYYcjs.BlobClientTokenExpiredError; exports.BlobContentTypeNotAllowedError = _chunkA3XDFQYYcjs.BlobContentTypeNotAllowedError; exports.BlobError = _chunkA3XDFQYYcjs.BlobError; exports.BlobFileTooLargeError = _chunkA3XDFQYYcjs.BlobFileTooLargeError; exports.BlobNotFoundError = _chunkA3XDFQYYcjs.BlobNotFoundError; exports.BlobPathnameMismatchError = _chunkA3XDFQYYcjs.BlobPathnameMismatchError; exports.BlobRequestAbortedError = _chunkA3XDFQYYcjs.BlobRequestAbortedError; exports.BlobServiceNotAvailable = _chunkA3XDFQYYcjs.BlobServiceNotAvailable; exports.BlobServiceRateLimited = _chunkA3XDFQYYcjs.BlobServiceRateLimited; exports.BlobStoreNotFoundError = _chunkA3XDFQYYcjs.BlobStoreNotFoundError; exports.BlobStoreSuspendedError = _chunkA3XDFQYYcjs.BlobStoreSuspendedError; exports.BlobUnknownError = _chunkA3XDFQYYcjs.BlobUnknownError; exports.completeMultipartUpload = completeMultipartUpload; exports.copy = copy; exports.createFolder = _chunkA3XDFQYYcjs.createFolder; exports.createMultipartUpload = createMultipartUpload; exports.createMultipartUploader = createMultipartUploader; exports.del = del; exports.getDownloadUrl = _chunkA3XDFQYYcjs.getDownloadUrl; exports.head = head; exports.list = list; exports.put = put; exports.uploadPart = uploadPart;
203
203
  //# sourceMappingURL=index.cjs.map
package/dist/index.js CHANGED
@@ -22,7 +22,7 @@ import {
22
22
  disallowedPathnameCharacters,
23
23
  getDownloadUrl,
24
24
  requestApi
25
- } from "./chunk-KN6WT5GP.js";
25
+ } from "./chunk-JGHUXF3X.js";
26
26
 
27
27
  // src/del.ts
28
28
  async function del(url, options) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vercel/blob",
3
- "version": "0.27.0",
3
+ "version": "0.27.1",
4
4
  "description": "The Vercel Blob JavaScript API client",
5
5
  "homepage": "https://vercel.com/storage/blob",
6
6
  "repository": {
@@ -47,7 +47,6 @@
47
47
  },
48
48
  "dependencies": {
49
49
  "async-retry": "^1.3.3",
50
- "bytes": "^3.1.2",
51
50
  "is-buffer": "^2.0.5",
52
51
  "is-node-process": "^1.2.0",
53
52
  "throttleit": "^2.1.0",
@@ -57,9 +56,8 @@
57
56
  "@edge-runtime/jest-environment": "2.3.10",
58
57
  "@edge-runtime/types": "2.2.9",
59
58
  "@types/async-retry": "1.4.9",
60
- "@types/bytes": "3.1.4",
61
59
  "@types/jest": "29.5.14",
62
- "@types/node": "22.9.4",
60
+ "@types/node": "22.10.7",
63
61
  "eslint": "8.56.0",
64
62
  "jest": "29.7.0",
65
63
  "jest-environment-jsdom": "29.7.0",