{"version":3,"sources":["/home/runner/work/storage/storage/packages/blob/dist/index.cjs","../src/del.ts","../src/head.ts","../src/get.ts","../src/list.ts","../src/copy.ts","../src/index.ts"],"names":["lastModified"],"mappings":"AAAA;AACE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACF,wDAA6B;AAC7B;AACA;ACPA,MAAA,SAAsB,GAAA,CACpB,aAAA,EACA,OAAA,EACe;AACf,EAAA,MAAM,KAAA,EAAO,KAAA,CAAM,OAAA,CAAQ,aAAa,EAAA,EAAI,cAAA,EAAgB,CAAC,aAAa,CAAA;AAE1E,EAAA,GAAA,CAAA,CAAI,QAAA,GAAA,KAAA,EAAA,KAAA,EAAA,EAAA,OAAA,CAAS,OAAA,EAAA,GAAW,IAAA,CAAK,OAAA,EAAS,CAAA,EAAG;AACvC,IAAA,MAAM,IAAI,gCAAA,CAAU,sDAAsD,CAAA;AAAA,EAC5E;AAEA,EAAA,MAAM,QAAA,EAAkC;AAAA,IACtC,cAAA,EAAgB;AAAA,EAClB,CAAA;AAEA,EAAA,GAAA,CAAI,QAAA,GAAA,KAAA,EAAA,KAAA,EAAA,EAAA,OAAA,CAAS,OAAA,EAAS;AACpB,IAAA,OAAA,CAAQ,YAAY,EAAA,EAAI,OAAA,CAAQ,OAAA;AAAA,EAClC;AAEA,EAAA,MAAM,0CAAA;AAAA,IACJ,SAAA;AAAA,IACA;AAAA,MACE,MAAA,EAAQ,MAAA;AAAA,MACR,OAAA;AAAA,MACA,IAAA,EAAM,IAAA,CAAK,SAAA,CAAU,EAAE,KAAK,CAAC,CAAA;AAAA,MAC7B,MAAA,EAAQ,QAAA,GAAA,KAAA,EAAA,KAAA,EAAA,EAAA,OAAA,CAAS;AAAA,IACnB,CAAA;AAAA,IACA;AAAA,EACF,CAAA;AACF;ADEA;AACA;AEYA,MAAA,SAAsB,IAAA,CACpB,aAAA,EACA,OAAA,EACyB;AACzB,EAAA,MAAM,aAAA,EAAe,IAAI,eAAA,CAAgB,EAAE,GAAA,EAAK,cAAc,CAAC,CAAA;AAE/D,EAAA,MAAM,SAAA,EAAW,MAAM,0CAAA;AAAA,IACrB,CAAA,CAAA,EAAI,YAAA,CAAa,QAAA,CAAS,CAAC,CAAA,CAAA;AAAA;AAE3B,IAAA;AACU,MAAA;AACA,MAAA;AACV,IAAA;AACA,IAAA;AACF,EAAA;AAEO,EAAA;AACS,IAAA;AACQ,IAAA;AACH,IAAA;AACJ,IAAA;AACO,IAAA;AACF,IAAA;AACG,IAAA;AACF,IAAA;AACN,IAAA;AACjB,EAAA;AACF;AFfgC;AACA;AG7EI;AAiFW;AAE7B,EAAA;AAElB;AAKgC;AAC1B,EAAA;AACwB,IAAA;AAEA,IAAA;AACpB,EAAA;AACC,IAAA;AACT,EAAA;AACF;AAM6B;AACE,EAAA;AACtB,EAAA;AACT;AAME;AAI6B,EAAA;AAC/B;AA8BE;AAGoB,EAAA;AACE,IAAA;AACtB,EAAA;AAEc,EAAA;AACQ,IAAA;AACtB,EAAA;AAEuB,EAAA;AACX,IAAA;AACR,MAAA;AACF,IAAA;AACF,EAAA;AAEc,EAAA;AAEV,EAAA;AACA,EAAA;AACmB,EAAA;AAGG,EAAA;AACd,IAAA;AACC,IAAA;AAEP,IAAA;AACuB,MAAA;AACF,MAAA;AACX,QAAA;AACR,UAAA;AACF,QAAA;AACF,MAAA;AACc,IAAA;AACO,MAAA;AACD,MAAA;AACtB,IAAA;AACK,EAAA;AAEW,IAAA;AACF,IAAA;AACQ,MAAA;AACtB,IAAA;AACW,IAAA;AACgB,IAAA;AAC7B,EAAA;AAGoC,EAAA;AACN,IAAA;AACH,IAAA;AACd,IAAA;AAAA;AACb,EAAA;AAGe,EAAA;AACU,EAAA;AACI,IAAA;AACN,IAAA;AACG,IAAA;AAC1B,EAAA;AAE6B,EAAA;AACnB,IAAA;AACC,IAAA;AACO,IAAA;AACjB,EAAA;AAG4B,EAAA;AACA,IAAA;AACC,IAAA;AACP,IAAA;AACd,IAAA;AACO,MAAA;AACJ,MAAA;AACU,MAAA;AACZ,MAAA;AACC,QAAA;AACQ,QAAA;AACb,QAAA;AACa,QAAA;AACO,QAAA;AACG,QAAA;AACjB,QAAA;AACMA,QAAAA;AACW,QAAA;AACzB,MAAA;AACF,IAAA;AACF,EAAA;AAE6B,EAAA;AACpB,IAAA;AACT,EAAA;AAEkB,EAAA;AACN,IAAA;AACiB,MAAA;AAC3B,IAAA;AACF,EAAA;AAGwB,EAAA;AACX,EAAA;AACS,IAAA;AACtB,EAAA;AAGsB,EAAA;AACQ,EAAA;AAGF,EAAA;AACC,EAAA;AAEtB,EAAA;AACO,IAAA;AACZ,IAAA;AACkB,IAAA;AACZ,IAAA;AACC,MAAA;AACoB,MAAA;AACzB,MAAA;AAEW,MAAA;AACS,MAAA;AACG,MAAA;AACD,MAAA;AACV,MAAA;AACW,MAAA;AACzB,IAAA;AACF,EAAA;AACF;AH5EgC;AACA;AIjEkC;AA9IlE,EAAA;AA+I2B,EAAA;AAErB,EAAA;AACwB,IAAA;AAC5B,EAAA;AACI,EAAA;AACyB,IAAA;AAC7B,EAAA;AACI,EAAA;AACyB,IAAA;AAC7B,EAAA;AACI,EAAA;AACuB,IAAA;AAC3B,EAAA;AAEuB,EAAA;AACM,IAAA;AAC3B,IAAA;AACU,MAAA;AACA,MAAA;AACV,IAAA;AACA,IAAA;AACF,EAAA;AAEI,EAAA;AACK,IAAA;AACa,MAAA;AACD,MAAA;AACC,MAAA;AACQ,MAAA;AAC5B,IAAA;AACF,EAAA;AAEO,EAAA;AACY,IAAA;AACC,IAAA;AACQ,IAAA;AAC5B,EAAA;AACF;AAOE;AAEO,EAAA;AACW,IAAA;AACQ,IAAA;AACH,IAAA;AACJ,IAAA;AACI,IAAA;AACJ,IAAA;AACnB,EAAA;AACF;AJyDgC;AACA;AKrO9B;AAIc,EAAA;AACQ,IAAA;AACtB,EAAA;AAEuB,EAAA;AACX,IAAA;AACR,MAAA;AACF,IAAA;AACF,EAAA;AAEwB,EAAA;AACZ,IAAA;AACR,MAAA;AACF,IAAA;AACF,EAAA;AAEW,EAAA;AACe,IAAA;AACZ,MAAA;AACR,QAAA;AACF,MAAA;AACF,IAAA;AACF,EAAA;AAEyC,EAAA;AAGX,EAAA;AAElB,EAAA;AACF,IAAA;AACV,EAAA;AAEY,EAAA;AACiB,IAAA;AAC7B,EAAA;AAEyB,EAAA;AACK,IAAA;AAC9B,EAAA;AAEY,EAAA;AACF,IAAA;AACV,EAAA;AAEqB,EAAA;AACK,IAAA;AAC1B,EAAA;AAEmB,EAAA;AACP,IAAA;AACD,IAAA;AACV,EAAA;AAEsB,EAAA;AACA,IAAA;AACrB,IAAA;AACU,MAAA;AACR,MAAA;AACgB,MAAA;AAClB,IAAA;AACA,IAAA;AACF,EAAA;AAEO,EAAA;AACS,IAAA;AACQ,IAAA;AACH,IAAA;AACG,IAAA;AACF,IAAA;AACL,IAAA;AACjB,EAAA;AACF;ALsNgC;AACA;AMlQsB;AACpC,EAAA;AACd,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACF,EAAA;AACD;AAsDC;AACkB,EAAA;AACd,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACF,EAAA;AACD;AAsBD;AACkB,EAAA;AACd,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACF,EAAA;AACD;AAwBuB;AACR,EAAA;AACd,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACF,EAAA;AACD;AAuBC;AACkB,EAAA;AACd,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACF,EAAA;AACD;AN6I6B;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA","file":"/home/runner/work/storage/storage/packages/blob/dist/index.cjs","sourcesContent":[null,"import { requestApi } from './api';\nimport type { BlobCommandOptions } from './helpers';\nimport { BlobError } from './helpers';\n\nexport interface DeleteCommandOptions extends BlobCommandOptions {\n  /**\n   * Only delete the blob if its current ETag matches this value.\n   * Use this for optimistic concurrency control to prevent deleting a blob that has been modified since it was last read.\n   * If the ETag doesn't match, a `BlobPreconditionFailedError` will be thrown.\n   * Can only be used when deleting a single URL.\n   */\n  ifMatch?: string;\n}\n\n/**\n * Deletes one or multiple blobs from your store.\n * Detailed documentation can be found here: https://vercel.com/docs/vercel-blob/using-blob-sdk#delete-a-blob\n *\n * @param urlOrPathname - Blob url (or pathname) to delete. You can pass either a single value or an array of values. You can only delete blobs that are located in a store, that your 'BLOB_READ_WRITE_TOKEN' has access to.\n * @param options - Additional options for the request.\n */\nexport async function del(\n  urlOrPathname: string[] | string,\n  options?: DeleteCommandOptions,\n): Promise<void> {\n  const urls = Array.isArray(urlOrPathname) ? urlOrPathname : [urlOrPathname];\n\n  if (options?.ifMatch && urls.length > 1) {\n    throw new BlobError('ifMatch can only be used when deleting a single URL.');\n  }\n\n  const headers: Record<string, string> = {\n    'content-type': 'application/json',\n  };\n\n  if (options?.ifMatch) {\n    headers['x-if-match'] = options.ifMatch;\n  }\n\n  await requestApi(\n    '/delete',\n    {\n      method: 'POST',\n      headers,\n      body: JSON.stringify({ urls }),\n      signal: options?.abortSignal,\n    },\n    options,\n  );\n}\n","import { requestApi } from './api';\nimport type { BlobCommandOptions } from './helpers';\n\n/**\n * Result of the head method containing metadata about a blob.\n */\nexport interface HeadBlobResult {\n  /**\n   * The size of the blob in bytes.\n   */\n  size: number;\n\n  /**\n   * The date when the blob was uploaded.\n   */\n  uploadedAt: Date;\n\n  /**\n   * The pathname of the blob within the store.\n   */\n  pathname: string;\n\n  /**\n   * The content type of the blob.\n   */\n  contentType: string;\n\n  /**\n   * The content disposition header value.\n   */\n  contentDisposition: string;\n\n  /**\n   * The URL of the blob.\n   */\n  url: string;\n\n  /**\n   * A URL that will cause browsers to download the file instead of displaying it inline.\n   */\n  downloadUrl: string;\n\n  /**\n   * The cache control header value.\n   */\n  cacheControl: string;\n\n  /**\n   * The ETag of the blob. Can be used with `ifMatch` for conditional writes.\n   */\n  etag: string;\n}\n\ninterface HeadBlobApiResponse extends Omit<HeadBlobResult, 'uploadedAt'> {\n  uploadedAt: string; // when receiving data from our API, uploadedAt is a string\n}\n\n/**\n * Fetches metadata of a blob object.\n * Detailed documentation can be found here: https://vercel.com/docs/vercel-blob/using-blob-sdk#get-blob-metadata\n *\n * @param urlOrPathname - Blob url or pathname to lookup.\n * @param options - Additional options for the request.\n */\nexport async function head(\n  urlOrPathname: string,\n  options?: BlobCommandOptions,\n): Promise<HeadBlobResult> {\n  const searchParams = new URLSearchParams({ url: urlOrPathname });\n\n  const response = await requestApi<HeadBlobApiResponse>(\n    `?${searchParams.toString()}`,\n    // HEAD can't have body as a response, so we use GET\n    {\n      method: 'GET',\n      signal: options?.abortSignal,\n    },\n    options,\n  );\n\n  return {\n    url: response.url,\n    downloadUrl: response.downloadUrl,\n    pathname: response.pathname,\n    size: response.size,\n    contentType: response.contentType,\n    contentDisposition: response.contentDisposition,\n    cacheControl: response.cacheControl,\n    uploadedAt: new Date(response.uploadedAt),\n    etag: response.etag,\n  };\n}\n","import { fetch, type Headers } from 'undici';\nimport type { BlobAccessType, BlobCommandOptions } from './helpers';\nimport { BlobError, getTokenFromOptionsOrEnv } from './helpers';\n\n/**\n * Options for the get method.\n */\nexport interface GetCommandOptions extends BlobCommandOptions {\n  /**\n   * Whether the blob is publicly accessible or private.\n   * - 'public': The blob is publicly accessible via its URL.\n   * - 'private': The blob requires authentication to access.\n   */\n  access: BlobAccessType;\n  /**\n   * Whether to allow the blob to be served from CDN cache.\n   * When false, fetches directly from origin storage.\n   * Only effective for private blobs (ignored for public blobs).\n   * @defaultValue true\n   */\n  useCache?: boolean;\n  /**\n   * Only return the full response if the blob's ETag does not match this value.\n   * When the ETag matches (blob unchanged), returns statusCode 304 with stream: null.\n   * Use this to avoid re-downloading blobs the client already has cached.\n   */\n  ifNoneMatch?: string;\n  /**\n   * Advanced: Additional headers to include in the fetch request.\n   * You probably don't need this. The authorization header is automatically set.\n   */\n  headers?: HeadersInit;\n}\n\ninterface GetBlobResultBlobBase {\n  url: string;\n  downloadUrl: string;\n  pathname: string;\n  contentDisposition: string;\n  cacheControl: string;\n  uploadedAt: Date;\n  etag: string;\n}\n\n/**\n * Result of the get method containing the stream and blob metadata.\n * Discriminated union on `statusCode`:\n * - `200`: Full response with stream and complete metadata.\n * - `304`: Not Modified. Stream is null, contentType and size are null.\n */\nexport type GetBlobResult =\n  | {\n      /** HTTP 200: Full response with stream and complete metadata. */\n      statusCode: 200;\n      /** The readable stream from the fetch response. */\n      stream: ReadableStream<Uint8Array>;\n      /** The raw headers from the fetch response. */\n      headers: Headers;\n      /** The blob metadata. */\n      blob: GetBlobResultBlobBase & {\n        contentType: string;\n        size: number;\n      };\n    }\n  | {\n      /** HTTP 304: Not Modified. The blob hasn't changed since the conditional request. */\n      statusCode: 304;\n      /** Null for 304 responses — no body is returned. */\n      stream: null;\n      /** The raw headers from the fetch response. */\n      headers: Headers;\n      /** The blob metadata (contentType and size are null on 304 responses). */\n      blob: GetBlobResultBlobBase & {\n        contentType: null;\n        size: null;\n      };\n    };\n\n/**\n * Checks if the input is a URL (starts with http:// or https://).\n */\nfunction isUrl(urlOrPathname: string): boolean {\n  return (\n    urlOrPathname.startsWith('http://') || urlOrPathname.startsWith('https://')\n  );\n}\n\n/**\n * Extracts the pathname from a blob URL.\n */\nfunction extractPathnameFromUrl(url: string): string {\n  try {\n    const parsedUrl = new URL(url);\n    // Remove leading slash from pathname\n    return parsedUrl.pathname.slice(1);\n  } catch {\n    return url;\n  }\n}\n\n/**\n * Extracts the store ID from a blob token.\n * Token format: vercel_blob_rw_<storeId>_<rest>\n */\nfunction getStoreIdFromToken(token: string): string {\n  const [, , , storeId = ''] = token.split('_');\n  return storeId;\n}\n\n/**\n * Constructs the blob URL from storeId and pathname.\n */\nfunction constructBlobUrl(\n  storeId: string,\n  pathname: string,\n  access: BlobAccessType,\n): string {\n  return `https://${storeId}.${access}.blob.vercel-storage.com/${pathname}`;\n}\n\n/**\n * Fetches blob content by URL or pathname.\n * - If a URL is provided, fetches the blob directly.\n * - If a pathname is provided, constructs the URL from the token's store ID.\n *\n * Returns a stream (no automatic buffering) and blob metadata.\n *\n * @example\n * ```ts\n * // Basic usage\n * const { stream, headers, blob } = await get('user123/avatar.png', { access: 'private' });\n *\n * // Bypass cache for private blobs (always fetch fresh from storage)\n * const { stream, headers, blob } = await get('user123/data.json', { access: 'private', useCache: false });\n * ```\n *\n * Detailed documentation can be found here: https://vercel.com/docs/vercel-blob/using-blob-sdk\n *\n * @param urlOrPathname - The URL or pathname of the blob to fetch.\n * @param options - Configuration options including:\n *   - access - (Required) Must be 'public' or 'private'. Determines the access level of the blob.\n *   - useCache - (Optional) When false, fetches directly from origin storage instead of CDN cache. Only effective for private blobs. Defaults to true.\n *   - token - (Optional) A string specifying the token to use when making requests. It defaults to process.env.BLOB_READ_WRITE_TOKEN when deployed on Vercel.\n *   - abortSignal - (Optional) AbortSignal to cancel the operation.\n *   - headers - (Optional, advanced) Additional headers to include in the fetch request. You probably don't need this.\n * @returns A promise that resolves to { stream, blob } or null if not found.\n */\nexport async function get(\n  urlOrPathname: string,\n  options: GetCommandOptions,\n): Promise<GetBlobResult | null> {\n  if (!urlOrPathname) {\n    throw new BlobError('url or pathname is required');\n  }\n\n  if (!options) {\n    throw new BlobError('missing options, see usage');\n  }\n\n  if (options.access !== 'public' && options.access !== 'private') {\n    throw new BlobError(\n      'access must be \"private\" or \"public\", see https://vercel.com/docs/vercel-blob',\n    );\n  }\n\n  const token = getTokenFromOptionsOrEnv(options);\n\n  let blobUrl: string;\n  let pathname: string;\n  const access = options.access;\n\n  // Check if input is a URL or a pathname\n  if (isUrl(urlOrPathname)) {\n    blobUrl = urlOrPathname;\n    pathname = extractPathnameFromUrl(urlOrPathname);\n\n    try {\n      const { hostname } = new URL(blobUrl);\n      if (!hostname.endsWith('.blob.vercel-storage.com')) {\n        throw new BlobError(\n          'Invalid URL: the URL does not point to a Vercel Blob store. Use a pathname instead, see https://vercel.com/docs/vercel-blob',\n        );\n      }\n    } catch (error) {\n      if (error instanceof BlobError) throw error;\n      throw new BlobError('Invalid URL: unable to parse the provided URL');\n    }\n  } else {\n    // Construct the URL from the token's storeId and the pathname\n    const storeId = getStoreIdFromToken(token);\n    if (!storeId) {\n      throw new BlobError('Invalid token: unable to extract store ID');\n    }\n    pathname = urlOrPathname;\n    blobUrl = constructBlobUrl(storeId, pathname, access);\n  }\n\n  // Fetch the blob content with authentication headers\n  const requestHeaders: HeadersInit = {\n    ...(options.ifNoneMatch ? { 'If-None-Match': options.ifNoneMatch } : {}),\n    authorization: `Bearer ${token}`,\n    ...options.headers, // low-level escape hatch, applied last to override anything\n  };\n\n  // Construct fetch URL with optional cache bypass\n  let fetchUrl = blobUrl;\n  if (options.useCache === false) {\n    const url = new URL(blobUrl);\n    url.searchParams.set('cache', '0');\n    fetchUrl = url.toString();\n  }\n\n  const response = await fetch(fetchUrl, {\n    method: 'GET',\n    headers: requestHeaders,\n    signal: options.abortSignal,\n  });\n\n  // Handle 304 Not Modified (fetch considers this !ok, but it's a valid conditional response)\n  if (response.status === 304) {\n    const downloadUrlObj = new URL(blobUrl);\n    downloadUrlObj.searchParams.set('download', '1');\n    const lastModified = response.headers.get('last-modified');\n    return {\n      statusCode: 304,\n      stream: null,\n      headers: response.headers,\n      blob: {\n        url: blobUrl,\n        downloadUrl: downloadUrlObj.toString(),\n        pathname,\n        contentType: null,\n        contentDisposition: response.headers.get('content-disposition') || '',\n        cacheControl: response.headers.get('cache-control') || '',\n        size: null,\n        uploadedAt: lastModified ? new Date(lastModified) : new Date(),\n        etag: response.headers.get('etag') || '',\n      },\n    };\n  }\n\n  if (response.status === 404) {\n    return null;\n  }\n\n  if (!response.ok) {\n    throw new BlobError(\n      `Failed to fetch blob: ${response.status} ${response.statusText}`,\n    );\n  }\n\n  // Return the stream directly without buffering\n  const stream = response.body as ReadableStream;\n  if (!stream) {\n    throw new BlobError('Response body is null');\n  }\n\n  // Extract metadata from response headers\n  const contentLength = response.headers.get('content-length');\n  const lastModified = response.headers.get('last-modified');\n\n  // Build download URL by adding download=1 query param\n  const downloadUrl = new URL(blobUrl);\n  downloadUrl.searchParams.set('download', '1');\n\n  return {\n    statusCode: 200,\n    stream,\n    headers: response.headers,\n    blob: {\n      url: blobUrl,\n      downloadUrl: downloadUrl.toString(),\n      pathname,\n      contentType:\n        response.headers.get('content-type') || 'application/octet-stream',\n      contentDisposition: response.headers.get('content-disposition') || '',\n      cacheControl: response.headers.get('cache-control') || '',\n      size: contentLength ? parseInt(contentLength, 10) : 0,\n      uploadedAt: lastModified ? new Date(lastModified) : new Date(),\n      etag: response.headers.get('etag') || '',\n    },\n  };\n}\n","import { requestApi } from './api';\nimport type { BlobCommandOptions } from './helpers';\n\n/**\n * Basic blob object information returned by the list method.\n */\nexport interface ListBlobResultBlob {\n  /**\n   * The URL of the blob.\n   */\n  url: string;\n\n  /**\n   * A URL that will cause browsers to download the file instead of displaying it inline.\n   */\n  downloadUrl: string;\n\n  /**\n   * The pathname of the blob within the store.\n   */\n  pathname: string;\n\n  /**\n   * The size of the blob in bytes.\n   */\n  size: number;\n\n  /**\n   * The date when the blob was uploaded.\n   */\n  uploadedAt: Date;\n\n  /**\n   * The ETag of the blob. Can be used with `ifMatch` for conditional writes.\n   */\n  etag: string;\n}\n\n/**\n * Result of the list method in expanded mode (default).\n */\nexport interface ListBlobResult {\n  /**\n   * Array of blob objects in the store.\n   */\n  blobs: ListBlobResultBlob[];\n\n  /**\n   * Pagination cursor for the next set of results, if hasMore is true.\n   */\n  cursor?: string;\n\n  /**\n   * Indicates if there are more results available.\n   */\n  hasMore: boolean;\n}\n\n/**\n * Result of the list method in folded mode.\n */\nexport interface ListFoldedBlobResult extends ListBlobResult {\n  /**\n   * Array of folder paths in the store.\n   */\n  folders: string[];\n}\n\n/**\n * @internal Internal interface for the API response blob structure.\n * Maps the API response format where uploadedAt is a string, not a Date.\n */\ninterface ListBlobApiResponseBlob\n  extends Omit<ListBlobResultBlob, 'uploadedAt'> {\n  uploadedAt: string;\n}\n\n/**\n * @internal Internal interface for the API response structure.\n */\ninterface ListBlobApiResponse extends Omit<ListBlobResult, 'blobs'> {\n  blobs: ListBlobApiResponseBlob[];\n  folders?: string[];\n}\n\n/**\n * Options for the list method.\n */\nexport interface ListCommandOptions<\n  M extends 'expanded' | 'folded' | undefined = undefined,\n> extends BlobCommandOptions {\n  /**\n   * The maximum number of blobs to return.\n   * @defaultvalue 1000\n   */\n  limit?: number;\n\n  /**\n   * Filters the result to only include blobs that start with this prefix.\n   * If used together with `mode: 'folded'`, make sure to include a trailing slash after the foldername.\n   */\n  prefix?: string;\n\n  /**\n   * The cursor to use for pagination. Can be obtained from the response of a previous `list` request.\n   */\n  cursor?: string;\n\n  /**\n   * Defines how the blobs are listed\n   * - `expanded` the blobs property contains all blobs.\n   * - `folded` the blobs property contains only the blobs at the root level of your store. Blobs that are located inside a folder get merged into a single entry in the folder response property.\n   * @defaultvalue 'expanded'\n   */\n  mode?: M;\n}\n\n/**\n * @internal Type helper to determine the return type based on the mode parameter.\n */\ntype ListCommandResult<\n  M extends 'expanded' | 'folded' | undefined = undefined,\n> = M extends 'folded' ? ListFoldedBlobResult : ListBlobResult;\n\n/**\n * Fetches a paginated list of blob objects from your store.\n *\n * @param options - Configuration options including:\n *   - token - (Optional) A string specifying the read-write token to use when making requests. It defaults to process.env.BLOB_READ_WRITE_TOKEN when deployed on Vercel.\n *   - limit - (Optional) The maximum number of blobs to return. Defaults to 1000.\n *   - prefix - (Optional) Filters the result to only include blobs that start with this prefix. If used with mode: 'folded', include a trailing slash after the folder name.\n *   - cursor - (Optional) The cursor to use for pagination. Can be obtained from the response of a previous list request.\n *   - mode - (Optional) Defines how the blobs are listed. Can be 'expanded' (default) or 'folded'. In folded mode, blobs located inside a folder are merged into a single entry in the folders response property.\n *   - abortSignal - (Optional) AbortSignal to cancel the operation.\n * @returns A promise that resolves to an object containing:\n *   - blobs: An array of blob objects with size, uploadedAt, pathname, url, and downloadUrl properties\n *   - cursor: A string for pagination (if hasMore is true)\n *   - hasMore: A boolean indicating if there are more results available\n *   - folders: (Only in 'folded' mode) An array of folder paths\n */\nexport async function list<\n  M extends 'expanded' | 'folded' | undefined = undefined,\n>(options?: ListCommandOptions<M>): Promise<ListCommandResult<M>> {\n  const searchParams = new URLSearchParams();\n\n  if (options?.limit) {\n    searchParams.set('limit', options.limit.toString());\n  }\n  if (options?.prefix) {\n    searchParams.set('prefix', options.prefix);\n  }\n  if (options?.cursor) {\n    searchParams.set('cursor', options.cursor);\n  }\n  if (options?.mode) {\n    searchParams.set('mode', options.mode);\n  }\n\n  const response = await requestApi<ListBlobApiResponse>(\n    `?${searchParams.toString()}`,\n    {\n      method: 'GET',\n      signal: options?.abortSignal,\n    },\n    options,\n  );\n\n  if (options?.mode === 'folded') {\n    return {\n      folders: response.folders ?? [],\n      cursor: response.cursor,\n      hasMore: response.hasMore,\n      blobs: response.blobs.map(mapBlobResult),\n    } as ListCommandResult<M>;\n  }\n\n  return {\n    cursor: response.cursor,\n    hasMore: response.hasMore,\n    blobs: response.blobs.map(mapBlobResult),\n  } as ListCommandResult<M>;\n}\n\n/**\n * @internal Helper function to map API response blob format to the expected return type.\n * Converts the uploadedAt string into a Date object.\n */\nfunction mapBlobResult(\n  blobResult: ListBlobApiResponseBlob,\n): ListBlobResultBlob {\n  return {\n    url: blobResult.url,\n    downloadUrl: blobResult.downloadUrl,\n    pathname: blobResult.pathname,\n    size: blobResult.size,\n    uploadedAt: new Date(blobResult.uploadedAt),\n    etag: blobResult.etag,\n  };\n}\n","import { MAXIMUM_PATHNAME_LENGTH, requestApi } from './api';\nimport type { CommonCreateBlobOptions } from './helpers';\nimport { BlobError, disallowedPathnameCharacters } from './helpers';\n\nexport type CopyCommandOptions = CommonCreateBlobOptions;\n\nexport interface CopyBlobResult {\n  url: string;\n  downloadUrl: string;\n  pathname: string;\n  contentType: string;\n  contentDisposition: string;\n  /**\n   * The ETag of the blob. Can be used with `ifMatch` for conditional writes.\n   */\n  etag: string;\n}\n\n/**\n * Copies a blob to another location in your store.\n * Detailed documentation can be found here: https://vercel.com/docs/vercel-blob/using-blob-sdk#copy-a-blob\n *\n * @param fromUrlOrPathname - The blob URL (or pathname) to copy. You can only copy blobs that are in the store, that your 'BLOB_READ_WRITE_TOKEN' has access to.\n * @param toPathname - The pathname to copy the blob to. This includes the filename.\n * @param options - Additional options. The copy method will not preserve any metadata configuration (e.g.: 'cacheControlMaxAge') of the source blob. If you want to copy the metadata, you need to define it here again.\n */\nexport async function copy(\n  fromUrlOrPathname: string,\n  toPathname: string,\n  options: CopyCommandOptions,\n): Promise<CopyBlobResult> {\n  if (!options) {\n    throw new BlobError('missing options, see usage');\n  }\n\n  if (options.access !== 'public' && options.access !== 'private') {\n    throw new BlobError(\n      'access must be \"private\" or \"public\", see https://vercel.com/docs/vercel-blob',\n    );\n  }\n\n  if (toPathname.length > MAXIMUM_PATHNAME_LENGTH) {\n    throw new BlobError(\n      `pathname is too long, maximum length is ${MAXIMUM_PATHNAME_LENGTH}`,\n    );\n  }\n\n  for (const invalidCharacter of disallowedPathnameCharacters) {\n    if (toPathname.includes(invalidCharacter)) {\n      throw new BlobError(\n        `pathname cannot contain \"${invalidCharacter}\", please encode it if needed`,\n      );\n    }\n  }\n\n  const headers: Record<string, string> = {};\n\n  // access is always required, so always add it to headers\n  headers['x-vercel-blob-access'] = options.access;\n\n  if (options.addRandomSuffix !== undefined) {\n    headers['x-add-random-suffix'] = options.addRandomSuffix ? '1' : '0';\n  }\n\n  if (options.allowOverwrite !== undefined) {\n    headers['x-allow-overwrite'] = options.allowOverwrite ? '1' : '0';\n  }\n\n  if (options.contentType) {\n    headers['x-content-type'] = options.contentType;\n  }\n\n  if (options.cacheControlMaxAge !== undefined) {\n    headers['x-cache-control-max-age'] = options.cacheControlMaxAge.toString();\n  }\n\n  if (options.ifMatch) {\n    headers['x-if-match'] = options.ifMatch;\n  }\n\n  const params = new URLSearchParams({\n    pathname: toPathname,\n    fromUrl: fromUrlOrPathname,\n  });\n\n  const response = await requestApi<CopyBlobResult>(\n    `?${params.toString()}`,\n    {\n      method: 'PUT',\n      headers,\n      signal: options.abortSignal,\n    },\n    options,\n  );\n\n  return {\n    url: response.url,\n    downloadUrl: response.downloadUrl,\n    pathname: response.pathname,\n    contentType: response.contentType,\n    contentDisposition: response.contentDisposition,\n    etag: response.etag,\n  };\n}\n","import type { CommonCreateBlobOptions } from './helpers';\nimport type { CompleteMultipartUploadCommandOptions } from './multipart/complete';\nimport { createCompleteMultipartUploadMethod } from './multipart/complete';\nimport { createCreateMultipartUploadMethod } from './multipart/create';\nimport { createCreateMultipartUploaderMethod } from './multipart/create-uploader';\nimport type { UploadPartCommandOptions } from './multipart/upload';\nimport { createUploadPartMethod } from './multipart/upload';\nimport type { PutCommandOptions } from './put';\nimport { createPutMethod } from './put';\n\n// expose api BlobErrors\nexport {\n  BlobAccessError,\n  BlobClientTokenExpiredError,\n  BlobContentTypeNotAllowedError,\n  BlobFileTooLargeError,\n  BlobNotFoundError,\n  BlobPathnameMismatchError,\n  BlobPreconditionFailedError,\n  BlobRequestAbortedError,\n  BlobServiceNotAvailable,\n  BlobServiceRateLimited,\n  BlobStoreNotFoundError,\n  BlobStoreSuspendedError,\n  BlobUnknownError,\n} from './api';\n// expose generic BlobError and download url util\nexport {\n  type BlobAccessType,\n  BlobError,\n  getDownloadUrl,\n  type OnUploadProgressCallback,\n  type UploadProgressEvent,\n} from './helpers';\n\n// vercelBlob.put()\n\nexport type { PutBlobResult } from './put-helpers';\nexport type { PutCommandOptions };\n\n/**\n * Uploads a blob into your store from your server.\n * Detailed documentation can be found here: https://vercel.com/docs/vercel-blob/using-blob-sdk#upload-a-blob\n *\n * If you want to upload from the browser directly, or if you're hitting Vercel upload limits, check out the documentation for client uploads: https://vercel.com/docs/vercel-blob/using-blob-sdk#client-uploads\n *\n * @param pathname - The pathname to upload the blob to, including the extension. This will influence the URL of your blob like https://$storeId.public.blob.vercel-storage.com/$pathname.\n * @param body - The content of your blob, can be a: string, File, Blob, Buffer or Stream. We support almost everything fetch supports: https://developer.mozilla.org/en-US/docs/Web/API/RequestInit#body.\n * @param options - Configuration options including:\n *   - access - (Required) Must be 'public' or 'private'. Public blobs are accessible via URL, private blobs require authentication.\n *   - addRandomSuffix - (Optional) A boolean specifying whether to add a random suffix to the pathname. It defaults to false. We recommend using this option to ensure there are no conflicts in your blob filenames.\n *   - allowOverwrite - (Optional) A boolean to allow overwriting blobs. By default an error will be thrown if you try to overwrite a blob by using the same pathname for multiple blobs.\n *   - contentType - (Optional) A string indicating the media type. By default, it's extracted from the pathname's extension.\n *   - cacheControlMaxAge - (Optional) A number in seconds to configure how long Blobs are cached. Defaults to one month. Cannot be set to a value lower than 1 minute.\n *   - token - (Optional) A string specifying the token to use when making requests. It defaults to process.env.BLOB_READ_WRITE_TOKEN when deployed on Vercel.\n *   - multipart - (Optional) Whether to use multipart upload for large files. It will split the file into multiple parts, upload them in parallel and retry failed parts.\n *   - abortSignal - (Optional) AbortSignal to cancel the operation.\n *   - onUploadProgress - (Optional) Callback to track upload progress: onUploadProgress(\\{loaded: number, total: number, percentage: number\\})\n * @returns A promise that resolves to the blob information, including pathname, contentType, contentDisposition, url, and downloadUrl.\n */\nexport const put = createPutMethod<PutCommandOptions>({\n  allowedOptions: [\n    'cacheControlMaxAge',\n    'addRandomSuffix',\n    'allowOverwrite',\n    'contentType',\n    'ifMatch',\n  ],\n});\n\n//  vercelBlob.del()\n\nexport type { DeleteCommandOptions } from './del';\nexport { del } from './del';\n\n// vercelBlob.head()\n\nexport type { HeadBlobResult } from './head';\nexport { head } from './head';\n\n// vercelBlob.get()\n\nexport type { GetBlobResult, GetCommandOptions } from './get';\nexport { get } from './get';\n\n// vercelBlob.list()\n\nexport type {\n  ListBlobResult,\n  ListBlobResultBlob,\n  ListCommandOptions,\n  ListFoldedBlobResult,\n} from './list';\nexport { list } from './list';\n\n// vercelBlob.copy()\n\nexport type { CopyBlobResult, CopyCommandOptions } from './copy';\nexport { copy } from './copy';\n\n// vercelBlob. createMultipartUpload()\n// vercelBlob. uploadPart()\n// vercelBlob. completeMultipartUpload()\n// vercelBlob. createMultipartUploader()\n\n/**\n * Creates a multipart upload. This is the first step in the manual multipart upload process.\n *\n * @param pathname - A string specifying the path inside the blob store. This will be the base value of the return URL and includes the filename and extension.\n * @param options - Configuration options including:\n *   - access - (Required) Must be 'public' or 'private'. Public blobs are accessible via URL, private blobs require authentication.\n *   - addRandomSuffix - (Optional) A boolean specifying whether to add a random suffix to the pathname. It defaults to true.\n *   - allowOverwrite - (Optional) A boolean to allow overwriting blobs. By default an error will be thrown if you try to overwrite a blob by using the same pathname for multiple blobs.\n *   - contentType - (Optional) The media type for the file. If not specified, it's derived from the file extension. Falls back to application/octet-stream when no extension exists or can't be matched.\n *   - cacheControlMaxAge - (Optional) A number in seconds to configure the edge and browser cache. Defaults to one month.\n *   - token - (Optional) A string specifying the token to use when making requests. It defaults to process.env.BLOB_READ_WRITE_TOKEN when deployed on Vercel.\n *   - abortSignal - (Optional) AbortSignal to cancel the operation.\n * @returns A promise that resolves to an object containing:\n *   - key: A string that identifies the blob object.\n *   - uploadId: A string that identifies the multipart upload. Both are needed for subsequent uploadPart calls.\n */\nexport const createMultipartUpload =\n  createCreateMultipartUploadMethod<CommonCreateBlobOptions>({\n    allowedOptions: [\n      'cacheControlMaxAge',\n      'addRandomSuffix',\n      'allowOverwrite',\n      'contentType',\n      'ifMatch',\n    ],\n  });\n\n/**\n * Creates a multipart uploader that simplifies the multipart upload process.\n * This is a wrapper around the manual multipart upload process that provides a more convenient API.\n *\n * @param pathname - A string specifying the path inside the blob store. This will be the base value of the return URL and includes the filename and extension.\n * @param options - Configuration options including:\n *   - access - (Required) Must be 'public' or 'private'. Public blobs are accessible via URL, private blobs require authentication.\n *   - addRandomSuffix - (Optional) A boolean specifying whether to add a random suffix to the pathname. It defaults to true.\n *   - allowOverwrite - (Optional) A boolean to allow overwriting blobs. By default an error will be thrown if you try to overwrite a blob by using the same pathname for multiple blobs.\n *   - contentType - (Optional) The media type for the file. If not specified, it's derived from the file extension. Falls back to application/octet-stream when no extension exists or can't be matched.\n *   - cacheControlMaxAge - (Optional) A number in seconds to configure the edge and browser cache. Defaults to one month.\n *   - token - (Optional) A string specifying the token to use when making requests. It defaults to process.env.BLOB_READ_WRITE_TOKEN when deployed on Vercel.\n *   - abortSignal - (Optional) AbortSignal to cancel the operation.\n * @returns A promise that resolves to an uploader object with the following properties and methods:\n *   - key: A string that identifies the blob object.\n *   - uploadId: A string that identifies the multipart upload.\n *   - uploadPart: A method to upload a part of the file.\n *   - complete: A method to complete the multipart upload process.\n */\nexport const createMultipartUploader =\n  createCreateMultipartUploaderMethod<CommonCreateBlobOptions>({\n    allowedOptions: [\n      'cacheControlMaxAge',\n      'addRandomSuffix',\n      'allowOverwrite',\n      'contentType',\n      'ifMatch',\n    ],\n  });\n\nexport type { UploadPartCommandOptions };\n\n/**\n * Uploads a part of a multipart upload.\n * Used as part of the manual multipart upload process.\n *\n * @param pathname - Same value as the pathname parameter passed to createMultipartUpload. This will influence the final URL of your blob.\n * @param body - A blob object as ReadableStream, String, ArrayBuffer or Blob based on these supported body types. Each part must be a minimum of 5MB, except the last one which can be smaller.\n * @param options - Configuration options including:\n *   - access - (Required) Must be 'public' or 'private'. Public blobs are accessible via URL, private blobs require authentication.\n *   - uploadId - (Required) A string returned from createMultipartUpload which identifies the multipart upload.\n *   - key - (Required) A string returned from createMultipartUpload which identifies the blob object.\n *   - partNumber - (Required) A number identifying which part is uploaded (1-based index).\n *   - contentType - (Optional) The media type for the blob. By default, it's derived from the pathname.\n *   - token - (Optional) A string specifying the token to use when making requests. It defaults to process.env.BLOB_READ_WRITE_TOKEN when deployed on Vercel.\n *   - addRandomSuffix - (Optional) A boolean specifying whether to add a random suffix to the pathname.\n *   - allowOverwrite - (Optional) A boolean to allow overwriting blobs.\n *   - cacheControlMaxAge - (Optional) A number in seconds to configure how long Blobs are cached.\n *   - abortSignal - (Optional) AbortSignal to cancel the running request.\n *   - onUploadProgress - (Optional) Callback to track upload progress: onUploadProgress(\\{loaded: number, total: number, percentage: number\\})\n * @returns A promise that resolves to the uploaded part information containing etag and partNumber, which will be needed for the completeMultipartUpload call.\n */\nexport const uploadPart = createUploadPartMethod<UploadPartCommandOptions>({\n  allowedOptions: [\n    'cacheControlMaxAge',\n    'addRandomSuffix',\n    'allowOverwrite',\n    'contentType',\n  ],\n});\n\nexport type { CompleteMultipartUploadCommandOptions };\n\n/**\n * Completes a multipart upload by combining all uploaded parts.\n * This is the final step in the manual multipart upload process.\n *\n * @param pathname - Same value as the pathname parameter passed to createMultipartUpload.\n * @param parts - An array containing all the uploaded parts information from previous uploadPart calls. Each part must have properties etag and partNumber.\n * @param options - Configuration options including:\n *   - access - (Required) Must be 'public' or 'private'. Public blobs are accessible via URL, private blobs require authentication.\n *   - uploadId - (Required) A string returned from createMultipartUpload which identifies the multipart upload.\n *   - key - (Required) A string returned from createMultipartUpload which identifies the blob object.\n *   - contentType - (Optional) The media type for the file. If not specified, it's derived from the file extension.\n *   - token - (Optional) A string specifying the token to use when making requests. It defaults to process.env.BLOB_READ_WRITE_TOKEN when deployed on Vercel.\n *   - addRandomSuffix - (Optional) A boolean specifying whether to add a random suffix to the pathname. It defaults to true.\n *   - allowOverwrite - (Optional) A boolean to allow overwriting blobs.\n *   - cacheControlMaxAge - (Optional) A number in seconds to configure the edge and browser cache. Defaults to one month.\n *   - abortSignal - (Optional) AbortSignal to cancel the operation.\n * @returns A promise that resolves to the finalized blob information, including pathname, contentType, contentDisposition, url, and downloadUrl.\n */\nexport const completeMultipartUpload =\n  createCompleteMultipartUploadMethod<CompleteMultipartUploadCommandOptions>({\n    allowedOptions: [\n      'cacheControlMaxAge',\n      'addRandomSuffix',\n      'allowOverwrite',\n      'contentType',\n    ],\n  });\n\nexport type {\n  CreateFolderCommandOptions,\n  CreateFolderResult,\n} from './create-folder';\nexport { createFolder } from './create-folder';\nexport type { Part, PartInput } from './multipart/helpers';\n"]}