// src/helpers.ts
import { isNodeProcess } from "is-node-process";

// src/multipart/helpers.ts
import isBuffer from "is-buffer";
import { Readable } from "stream";
var supportsNewBlobFromArrayBuffer = new Promise((resolve) => {
  try {
    const helloAsArrayBuffer = new Uint8Array([104, 101, 108, 108, 111]);
    const blob = new Blob([helloAsArrayBuffer]);
    blob.text().then((text) => {
      resolve(text === "hello");
    }).catch(() => {
      resolve(false);
    });
  } catch {
    resolve(false);
  }
});
async function toReadableStream(value) {
  if (value instanceof ReadableStream) {
    return value;
  }
  if (value instanceof Blob) {
    return value.stream();
  }
  if (isNodeJsReadableStream(value)) {
    return Readable.toWeb(value);
  }
  let streamValue;
  if (value instanceof ArrayBuffer) {
    streamValue = new Uint8Array(value);
  } else if (isNodeJsBuffer(value)) {
    streamValue = value;
  } else {
    streamValue = stringToUint8Array(value);
  }
  if (await supportsNewBlobFromArrayBuffer) {
    return new Blob([streamValue]).stream();
  }
  return new ReadableStream({
    start(controller) {
      controller.enqueue(streamValue);
      controller.close();
    }
  });
}
function isNodeJsReadableStream(value) {
  return typeof value === "object" && typeof value.pipe === "function" && value.readable && typeof value._read === "function" && // @ts-expect-error _readableState does exists on Readable
  typeof value._readableState === "object";
}
function stringToUint8Array(s) {
  const enc = new TextEncoder();
  return enc.encode(s);
}
function isNodeJsBuffer(value) {
  return isBuffer(value);
}

// src/vercel-oidc-token.ts
import { getVercelOidcToken as getVercelOidcTokenWithRefresh } from "@vercel/oidc";
async function getVercelOidcToken() {
  try {
    const token = (await getVercelOidcTokenWithRefresh()).trim();
    return token === "" ? void 0 : token;
  } catch {
    return void 0;
  }
}

// src/bytes.ts
var parseRegExp = /^((-|\+)?(\d+(?:\.\d+)?)) *(kb|mb|gb|tb|pb)$/i;
var map = {
  b: 1,
  kb: 1 << 10,
  mb: 1 << 20,
  gb: 1 << 30,
  tb: 1024 ** 4,
  pb: 1024 ** 5
};
function bytes(val) {
  if (typeof val === "number" && !Number.isNaN(val)) {
    return val;
  }
  if (typeof val !== "string") {
    return null;
  }
  const results = parseRegExp.exec(val);
  let floatValue;
  let unit = "b";
  if (!results) {
    floatValue = parseInt(val, 10);
  } else {
    const [, res, , , unitMatch] = results;
    if (!res) {
      return null;
    }
    floatValue = parseFloat(res);
    if (unitMatch) {
      unit = unitMatch.toLowerCase();
    }
  }
  if (Number.isNaN(floatValue)) {
    return null;
  }
  return Math.floor(map[unit] * floatValue);
}

// src/helpers.ts
var defaultVercelBlobApiUrl = "https://vercel.com/api/blob";
function readEnv(name) {
  try {
    const value = process.env[name];
    return typeof value === "string" && value.trim() !== "" ? value.trim() : void 0;
  } catch {
    return void 0;
  }
}
function parseStoreIdFromReadWriteToken(token) {
  const [, , , storeId = ""] = token.split("_");
  return storeId;
}
function base64UrlDecodeDelegationSegment(segment) {
  let base64 = segment.replace(/-/g, "+").replace(/_/g, "/");
  const padding = 4 - base64.length % 4;
  if (padding !== 4) {
    base64 += "=".repeat(padding);
  }
  if (typeof atob === "function") {
    return atob(base64);
  }
  if (typeof Buffer !== "undefined") {
    return Buffer.from(base64, "base64").toString("utf8");
  }
  throw new BlobError("Cannot decode base64: no atob or Buffer available.");
}
function parseStoreIdFromDelegationToken(delegationToken) {
  const dot = delegationToken.indexOf(".");
  if (dot < 0) {
    throw new BlobError("Invalid delegation token format.");
  }
  const payloadSeg = delegationToken.slice(0, dot);
  let parsed;
  try {
    parsed = JSON.parse(base64UrlDecodeDelegationSegment(payloadSeg));
  } catch {
    throw new BlobError("Invalid delegation token payload.");
  }
  if (!parsed.storeId || typeof parsed.storeId !== "string") {
    throw new BlobError("Delegation token payload is missing `storeId`.");
  }
  return normalizeStoreId(parsed.storeId);
}
function parseStoreIdFromPresignedUrl(presignedUrlPayload) {
  const delegation = presignedUrlPayload.delegationToken;
  return parseStoreIdFromDelegationToken(delegation);
}
function normalizeStoreId(storeId) {
  return storeId.startsWith("store_") ? storeId.slice("store_".length) : storeId;
}
async function resolveBlobAuth(options) {
  var _a3, _b2;
  if (options == null ? void 0 : options.presignedUrlPayload) {
    const storeId = parseStoreIdFromDelegationToken(
      options.presignedUrlPayload.delegationToken
    );
    return { kind: "presigned", storeId };
  }
  if (options == null ? void 0 : options.token) {
    const storeId = parseStoreIdFromReadWriteToken(options.token);
    return { kind: "readWrite", token: options.token, storeId };
  }
  const manualOidcToken = (_a3 = options == null ? void 0 : options.oidcToken) == null ? void 0 : _a3.trim();
  const oidcToken = manualOidcToken || await getVercelOidcToken();
  if (oidcToken) {
    const manualStoreId = (_b2 = options == null ? void 0 : options.storeId) == null ? void 0 : _b2.trim();
    if (manualStoreId) {
      return {
        kind: "oidc",
        token: oidcToken,
        storeId: normalizeStoreId(manualStoreId)
      };
    }
    const blobStoreId = readEnv("BLOB_STORE_ID");
    if (blobStoreId) {
      return {
        kind: "oidc",
        token: oidcToken,
        storeId: normalizeStoreId(blobStoreId)
      };
    }
    if (manualOidcToken) {
      throw new BlobError(
        "oidcToken was passed, but no storeId was found. Pass a `storeId` option or set `BLOB_STORE_ID` to use OIDC auth"
      );
    }
  }
  const readWrite = readEnv("BLOB_READ_WRITE_TOKEN");
  if (readWrite) {
    const storeId = parseStoreIdFromReadWriteToken(readWrite);
    return { kind: "readWrite", token: readWrite, storeId };
  }
  throw new BlobError(
    "No blob credentials found. Pass a `token` option, set `BLOB_READ_WRITE_TOKEN`, or use `oidcToken` (or `VERCEL_OIDC_TOKEN`) with `storeId` or `BLOB_STORE_ID`."
  );
}
function getReadWriteBlobTokenFromOptionsOrEnv(options) {
  if (options == null ? void 0 : options.token) {
    return options.token;
  }
  const readWrite = readEnv("BLOB_READ_WRITE_TOKEN");
  if (readWrite) {
    return readWrite;
  }
  throw new BlobError(
    "No read-write token found. Either configure the `BLOB_READ_WRITE_TOKEN` environment variable, or pass a `token` option to your calls."
  );
}
var BlobError = class extends Error {
  constructor(message) {
    super(`Vercel Blob: ${message}`);
  }
};
function getDownloadUrl(blobUrl) {
  const url = new URL(blobUrl);
  url.searchParams.set("download", "1");
  return url.toString();
}
function isPlainObject(value) {
  if (typeof value !== "object" || value === null) {
    return false;
  }
  const prototype = Object.getPrototypeOf(value);
  return (prototype === null || prototype === Object.prototype || Object.getPrototypeOf(prototype) === null) && !(Symbol.toStringTag in value) && !(Symbol.iterator in value);
}
var disallowedPathnameCharacters = ["//"];
var supportsRequestStreams = (() => {
  if (isNodeProcess()) {
    return true;
  }
  const apiUrl = getApiUrl();
  if (apiUrl.startsWith("http://localhost")) {
    return false;
  }
  let duplexAccessed = false;
  const hasContentType = new Request(getApiUrl(), {
    body: new ReadableStream(),
    method: "POST",
    // @ts-expect-error -- TypeScript doesn't yet have duplex but it's in the spec: https://github.com/microsoft/TypeScript-DOM-lib-generator/pull/1729
    get duplex() {
      duplexAccessed = true;
      return "half";
    }
  }).headers.has("Content-Type");
  return duplexAccessed && !hasContentType;
})();
function getApiUrl(pathname = "") {
  let baseUrl = null;
  try {
    baseUrl = process.env.VERCEL_BLOB_API_URL || process.env.NEXT_PUBLIC_VERCEL_BLOB_API_URL;
  } catch {
  }
  return `${baseUrl || defaultVercelBlobApiUrl}${pathname}`;
}
var TEXT_ENCODER = typeof TextEncoder === "function" ? new TextEncoder() : null;
function computeBodyLength(body) {
  if (!body) {
    return 0;
  }
  if (typeof body === "string") {
    if (TEXT_ENCODER) {
      return TEXT_ENCODER.encode(body).byteLength;
    }
    return new Blob([body]).size;
  }
  if ("byteLength" in body && typeof body.byteLength === "number") {
    return body.byteLength;
  }
  if ("size" in body && typeof body.size === "number") {
    return body.size;
  }
  return 0;
}
var createChunkTransformStream = (chunkSize, onProgress) => {
  let buffer = new Uint8Array(0);
  return new TransformStream({
    transform(chunk, controller) {
      const newBuffer = new Uint8Array(buffer.length + chunk.byteLength);
      newBuffer.set(buffer);
      newBuffer.set(new Uint8Array(chunk), buffer.length);
      buffer = newBuffer;
      while (buffer.length >= chunkSize) {
        const newChunk = buffer.slice(0, chunkSize);
        controller.enqueue(newChunk);
        onProgress == null ? void 0 : onProgress(newChunk.byteLength);
        buffer = buffer.slice(chunkSize);
      }
    },
    flush(controller) {
      if (buffer.length > 0) {
        controller.enqueue(buffer);
        onProgress == null ? void 0 : onProgress(buffer.byteLength);
      }
    }
  });
};
function isReadableStream(value) {
  return globalThis.ReadableStream && // TODO: Can be removed once Node.js 16 is no more required internally
  value instanceof ReadableStream;
}
function isStream(value) {
  if (isReadableStream(value)) {
    return true;
  }
  if (isNodeJsReadableStream(value)) {
    return true;
  }
  return false;
}
var addPresignedParams = (url, presignedUrlPayload) => {
  const urlObj = new URL(url);
  for (const [key, value] of Object.entries(presignedUrlPayload.params)) {
    urlObj.searchParams.set(key, value);
  }
  urlObj.searchParams.set(
    "vercel-blob-delegation",
    presignedUrlPayload.delegationToken
  );
  urlObj.searchParams.set(
    "vercel-blob-signature",
    presignedUrlPayload.signature
  );
  return urlObj.toString();
};
function isUrl(urlOrPathname) {
  return urlOrPathname.startsWith("http://") || urlOrPathname.startsWith("https://");
}
function constructBlobUrl(storeId, pathname, access) {
  return `https://${storeId}.${access}.blob.vercel-storage.com/${pathname}`;
}

// src/api.ts
import retry from "async-retry";

// src/debug.ts
var debugIsActive = false;
var _a, _b;
try {
  if (((_a = process.env.DEBUG) == null ? void 0 : _a.includes("blob")) || ((_b = process.env.NEXT_PUBLIC_DEBUG) == null ? void 0 : _b.includes("blob"))) {
    debugIsActive = true;
  }
} catch {
}
function debug(message, ...args) {
  if (debugIsActive) {
    console.debug(`vercel-blob: ${message}`, ...args);
  }
}

// src/dom-exception.ts
var _a2;
var DOMException2 = (_a2 = globalThis.DOMException) != null ? _a2 : (() => {
  try {
    atob("~");
  } catch (err) {
    return Object.getPrototypeOf(err).constructor;
  }
})();

// src/is-network-error.ts
var objectToString = Object.prototype.toString;
var isError = (value) => objectToString.call(value) === "[object Error]";
var errorMessages = /* @__PURE__ */ new Set([
  "network error",
  // Chrome
  "Failed to fetch",
  // Chrome
  "NetworkError when attempting to fetch resource.",
  // Firefox
  "The Internet connection appears to be offline.",
  // Safari 16
  "Load failed",
  // Safari 17+
  "Network request failed",
  // `cross-fetch`
  "fetch failed",
  // Undici (Node.js)
  "terminated"
  // Undici (Node.js)
]);
function isNetworkError(error) {
  const isValid = error && isError(error) && error.name === "TypeError" && typeof error.message === "string";
  if (!isValid) {
    return false;
  }
  if (error.message === "Load failed") {
    return error.stack === void 0;
  }
  return errorMessages.has(error.message);
}

// src/fetch.ts
import { fetch } from "undici";
var hasFetch = typeof fetch === "function";
var hasFetchWithUploadProgress = hasFetch && supportsRequestStreams;
var CHUNK_SIZE = 64 * 1024;
var blobFetch = async ({
  input,
  init,
  onUploadProgress
}) => {
  debug("using fetch");
  let body;
  if (init.body) {
    if (onUploadProgress) {
      const stream = await toReadableStream(init.body);
      let loaded = 0;
      const chunkTransformStream = createChunkTransformStream(
        CHUNK_SIZE,
        (newLoaded) => {
          loaded += newLoaded;
          onUploadProgress(loaded);
        }
      );
      body = stream.pipeThrough(chunkTransformStream);
    } else {
      body = init.body;
    }
  }
  const duplex = supportsRequestStreams && body && isStream(body) ? "half" : void 0;
  return fetch(
    input,
    // @ts-expect-error -- Blob and Nodejs Blob are triggering type errors, fine with it
    {
      ...init,
      ...init.body ? { body } : {},
      duplex
    }
  );
};

// src/xhr.ts
var hasXhr = typeof XMLHttpRequest !== "undefined";
var blobXhr = async ({
  input,
  init,
  onUploadProgress
}) => {
  debug("using xhr");
  let body = null;
  if (init.body) {
    if (isReadableStream(init.body)) {
      body = await new Response(init.body).blob();
    } else {
      body = init.body;
    }
  }
  return new Promise((resolve, reject) => {
    const xhr = new XMLHttpRequest();
    xhr.open(init.method || "GET", input.toString(), true);
    if (onUploadProgress) {
      xhr.upload.addEventListener("progress", (event) => {
        if (event.lengthComputable) {
          onUploadProgress(event.loaded);
        }
      });
    }
    xhr.onload = () => {
      var _a3;
      if ((_a3 = init.signal) == null ? void 0 : _a3.aborted) {
        reject(new DOMException("The user aborted the request.", "AbortError"));
        return;
      }
      const headers = new Headers();
      const rawHeaders = xhr.getAllResponseHeaders().trim().split(/[\r\n]+/);
      rawHeaders.forEach((line) => {
        const parts = line.split(": ");
        const key = parts.shift();
        const value = parts.join(": ");
        if (key) headers.set(key.toLowerCase(), value);
      });
      const response = new Response(xhr.response, {
        status: xhr.status,
        statusText: xhr.statusText,
        headers
      });
      resolve(response);
    };
    xhr.onerror = () => {
      reject(new TypeError("Network request failed"));
    };
    xhr.ontimeout = () => {
      reject(new TypeError("Network request timed out"));
    };
    xhr.onabort = () => {
      reject(new DOMException("The user aborted a request.", "AbortError"));
    };
    if (init.headers) {
      const headers = new Headers(init.headers);
      headers.forEach((value, key) => {
        xhr.setRequestHeader(key, value);
      });
    }
    if (init.signal) {
      init.signal.addEventListener("abort", () => {
        xhr.abort();
      });
      if (init.signal.aborted) {
        xhr.abort();
        return;
      }
    }
    xhr.send(body);
  });
};

// src/request.ts
var blobRequest = async ({
  input,
  init,
  onUploadProgress
}) => {
  if (onUploadProgress) {
    if (hasFetchWithUploadProgress) {
      return blobFetch({ input, init, onUploadProgress });
    }
    if (hasXhr) {
      return blobXhr({ input, init, onUploadProgress });
    }
  }
  if (hasFetch) {
    return blobFetch({ input, init });
  }
  if (hasXhr) {
    return blobXhr({ input, init });
  }
  throw new Error("No request implementation available");
};

// src/api.ts
var MAXIMUM_PATHNAME_LENGTH = 950;
var BlobAccessError = class extends BlobError {
  constructor() {
    super("Access denied, please provide a valid token for this resource.");
  }
};
var BlobOidcEnvironmentNotAllowedError = class extends BlobError {
  constructor(message) {
    super(
      message != null ? message : "OIDC is enabled for this project, but not for this token's environment."
    );
  }
};
var BlobContentTypeNotAllowedError = class extends BlobError {
  constructor(message) {
    super(`Content type mismatch, ${message}.`);
  }
};
var BlobPathnameMismatchError = class extends BlobError {
  constructor(message) {
    super(
      `Pathname mismatch, ${message}. Check the pathname used in upload() or put() matches the one from the client token.`
    );
  }
};
var BlobClientTokenExpiredError = class extends BlobError {
  constructor() {
    super("Client token has expired.");
  }
};
var BlobFileTooLargeError = class extends BlobError {
  constructor(message) {
    super(`File is too large, ${message}.`);
  }
};
var BlobStoreNotFoundError = class extends BlobError {
  constructor() {
    super("This store does not exist.");
  }
};
var BlobStoreSuspendedError = class extends BlobError {
  constructor() {
    super("This store has been suspended.");
  }
};
var BlobUnknownError = class extends BlobError {
  constructor() {
    super("Unknown error, please visit https://vercel.com/help.");
  }
};
var BlobNotFoundError = class extends BlobError {
  constructor() {
    super("The requested blob does not exist");
  }
};
var BlobServiceNotAvailable = class extends BlobError {
  constructor() {
    super("The blob service is currently not available. Please try again.");
  }
};
var BlobServiceRateLimited = class extends BlobError {
  constructor(seconds) {
    super(
      `Too many requests please lower the number of concurrent requests ${seconds ? ` - try again in ${seconds} seconds` : ""}.`
    );
    this.retryAfter = seconds != null ? seconds : 0;
  }
};
var BlobRequestAbortedError = class extends BlobError {
  constructor() {
    super("The request was aborted.");
  }
};
var BlobPreconditionFailedError = class extends BlobError {
  constructor() {
    super("Precondition failed: ETag mismatch.");
  }
};
var BLOB_API_VERSION = 12;
function getApiVersion() {
  let versionOverride = null;
  try {
    versionOverride = process.env.VERCEL_BLOB_API_VERSION_OVERRIDE || process.env.NEXT_PUBLIC_VERCEL_BLOB_API_VERSION_OVERRIDE;
  } catch {
  }
  return `${versionOverride != null ? versionOverride : BLOB_API_VERSION}`;
}
function getRetries() {
  try {
    const retries = process.env.VERCEL_BLOB_RETRIES || "10";
    return parseInt(retries, 10);
  } catch {
    return 10;
  }
}
function createBlobServiceRateLimited(response) {
  const retryAfter = response.headers.get("retry-after");
  return new BlobServiceRateLimited(
    retryAfter ? parseInt(retryAfter, 10) : void 0
  );
}
async function getBlobError(response) {
  var _a3, _b2, _c;
  let code;
  let message;
  try {
    const data = await response.json();
    code = (_b2 = (_a3 = data.error) == null ? void 0 : _a3.code) != null ? _b2 : "unknown_error";
    message = (_c = data.error) == null ? void 0 : _c.message;
  } catch {
    code = "unknown_error";
  }
  if ((message == null ? void 0 : message.includes("contentType")) && message.includes("is not allowed")) {
    code = "content_type_not_allowed";
  }
  if ((message == null ? void 0 : message.includes('"pathname"')) && message.includes("does not match the token payload")) {
    code = "client_token_pathname_mismatch";
  }
  if (message === "Token expired") {
    code = "client_token_expired";
  }
  if (message == null ? void 0 : message.includes("the file length cannot be greater than")) {
    code = "file_too_large";
  }
  if ((message == null ? void 0 : message.startsWith("OIDC is enabled for this project, but not for the")) && message.includes("environment.")) {
    code = "oidc_environment_not_allowed";
  }
  let error;
  switch (code) {
    case "store_suspended":
      error = new BlobStoreSuspendedError();
      break;
    case "forbidden":
      error = new BlobAccessError();
      break;
    case "oidc_environment_not_allowed":
      error = new BlobOidcEnvironmentNotAllowedError(message);
      break;
    case "content_type_not_allowed":
      error = new BlobContentTypeNotAllowedError(message);
      break;
    case "client_token_pathname_mismatch":
      error = new BlobPathnameMismatchError(message);
      break;
    case "client_token_expired":
      error = new BlobClientTokenExpiredError();
      break;
    case "file_too_large":
      error = new BlobFileTooLargeError(message);
      break;
    case "not_found":
      error = new BlobNotFoundError();
      break;
    case "client_token_not_allowed":
      error = new BlobError(
        message != null ? message : "This operation is not available when using a client token. Use a read\u2013write or OIDC token on the server."
      );
      break;
    case "store_not_found":
      error = new BlobStoreNotFoundError();
      break;
    case "bad_request":
      error = new BlobError(message != null ? message : "Bad request");
      break;
    case "service_unavailable":
      error = new BlobServiceNotAvailable();
      break;
    case "rate_limited":
      error = createBlobServiceRateLimited(response);
      break;
    case "precondition_failed":
      error = new BlobPreconditionFailedError();
      break;
    case "unknown_error":
    case "not_allowed":
    default:
      error = new BlobUnknownError();
      break;
  }
  return { code, error };
}
async function requestApi(pathname, init, commandOptions) {
  const apiVersion = getApiVersion();
  const auth = await resolveBlobAuth(commandOptions);
  const bearerToken = auth.kind === "presigned" ? void 0 : auth.token;
  const extraHeaders = getProxyThroughAlternativeApiHeaderFromEnv();
  let requestInput = getApiUrl(pathname);
  if (commandOptions == null ? void 0 : commandOptions.presignedUrlPayload) {
    requestInput = addPresignedParams(
      requestInput,
      commandOptions.presignedUrlPayload
    );
  }
  const requestId = `${auth.storeId}:${Date.now()}:${Math.random().toString(16).slice(2)}`;
  let retryCount = 0;
  let bodyLength = 0;
  let totalLoaded = 0;
  const sendBodyLength = (commandOptions == null ? void 0 : commandOptions.onUploadProgress) || shouldUseXContentLength();
  if (init.body && // 1. For upload progress we always need to know the total size of the body
  // 2. In development we need the header for put() to work correctly when passing a stream
  sendBodyLength) {
    bodyLength = computeBodyLength(init.body);
  }
  if (commandOptions == null ? void 0 : commandOptions.onUploadProgress) {
    commandOptions.onUploadProgress({
      loaded: 0,
      total: bodyLength,
      percentage: 0
    });
  }
  const apiResponse = await retry(
    async (bail) => {
      let res;
      try {
        res = await blobRequest({
          input: requestInput,
          init: {
            ...init,
            headers: {
              "x-api-blob-request-id": requestId,
              // Store ID is not encoded in OIDC token, so pass it separately as a header
              "x-vercel-blob-store-id": auth.storeId,
              "x-api-blob-request-attempt": String(retryCount),
              "x-api-version": apiVersion,
              ...sendBodyLength ? { "x-content-length": String(bodyLength) } : {},
              ...bearerToken !== void 0 ? { authorization: `Bearer ${bearerToken}` } : {},
              ...extraHeaders,
              ...init.headers
            }
          },
          onUploadProgress: (commandOptions == null ? void 0 : commandOptions.onUploadProgress) ? (loaded) => {
            var _a3;
            const total = bodyLength !== 0 ? bodyLength : loaded;
            totalLoaded = loaded;
            const percentage = bodyLength > 0 ? Number((loaded / total * 100).toFixed(2)) : 0;
            if (percentage === 100 && bodyLength > 0) {
              return;
            }
            (_a3 = commandOptions.onUploadProgress) == null ? void 0 : _a3.call(commandOptions, {
              loaded,
              // When passing a stream to put(), we have no way to know the total size of the body.
              // Instead of defining total as total?: number we decided to set the total to the currently
              // loaded number. This is not inaccurate and way more practical for DX.
              // Passing down a stream to put() is very rare
              total,
              percentage
            });
          } : void 0
        });
      } catch (error2) {
        if (error2 instanceof DOMException2 && error2.name === "AbortError") {
          bail(new BlobRequestAbortedError());
          return;
        }
        if (isNetworkError(error2)) {
          throw error2;
        }
        if (error2 instanceof TypeError) {
          bail(error2);
          return;
        }
        throw error2;
      }
      if (res.ok) {
        return res;
      }
      const { code, error } = await getBlobError(res);
      if (code === "unknown_error" || code === "service_unavailable" || code === "internal_server_error") {
        throw error;
      }
      bail(error);
    },
    {
      retries: getRetries(),
      onRetry: (error) => {
        if (error instanceof Error) {
          debug(`retrying API request to ${pathname}`, error.message);
        }
        retryCount = retryCount + 1;
      }
    }
  );
  if (!apiResponse) {
    throw new BlobUnknownError();
  }
  if (commandOptions == null ? void 0 : commandOptions.onUploadProgress) {
    commandOptions.onUploadProgress({
      loaded: totalLoaded,
      total: totalLoaded,
      percentage: 100
    });
  }
  return await apiResponse.json();
}
function getProxyThroughAlternativeApiHeaderFromEnv() {
  const extraHeaders = {};
  try {
    if ("VERCEL_BLOB_PROXY_THROUGH_ALTERNATIVE_API" in process.env && process.env.VERCEL_BLOB_PROXY_THROUGH_ALTERNATIVE_API !== void 0) {
      extraHeaders["x-proxy-through-alternative-api"] = process.env.VERCEL_BLOB_PROXY_THROUGH_ALTERNATIVE_API;
    } else if ("NEXT_PUBLIC_VERCEL_BLOB_PROXY_THROUGH_ALTERNATIVE_API" in process.env && process.env.NEXT_PUBLIC_VERCEL_BLOB_PROXY_THROUGH_ALTERNATIVE_API !== void 0) {
      extraHeaders["x-proxy-through-alternative-api"] = process.env.NEXT_PUBLIC_VERCEL_BLOB_PROXY_THROUGH_ALTERNATIVE_API;
    }
  } catch {
  }
  return extraHeaders;
}
function shouldUseXContentLength() {
  try {
    return process.env.VERCEL_BLOB_USE_X_CONTENT_LENGTH === "1";
  } catch {
    return false;
  }
}

// src/put-helpers.ts
var optimizeImageFormatToMimeType = {
  jpeg: "image/jpeg",
  png: "image/png",
  webp: "image/webp",
  avif: "image/avif"
};
function validateOptimizeImageOptions(optimizeImage) {
  if (typeof optimizeImage !== "object" || optimizeImage === null) {
    throw new BlobError("optimizeImage must be an object, see usage");
  }
  const { width, quality, format } = optimizeImage;
  if (!Number.isInteger(width) || width < 1 || width > 8192) {
    throw new BlobError(
      "optimizeImage.width must be an integer between 1 and 8192"
    );
  }
  if (quality !== void 0 && (!Number.isInteger(quality) || quality < 1 || quality > 100)) {
    throw new BlobError(
      "optimizeImage.quality must be an integer between 1 and 100"
    );
  }
  if (format !== void 0 && !(format in optimizeImageFormatToMimeType)) {
    throw new BlobError(
      `optimizeImage.format must be one of: ${Object.keys(
        optimizeImageFormatToMimeType
      ).join(", ")}`
    );
  }
}
function validateOptimizeImageSourceContentType(contentType) {
  if (contentType && contentType !== "application/octet-stream" && !contentType.startsWith("image/")) {
    throw new BlobError(
      `optimizeImage requires an image body, but the content type is "${contentType}"`
    );
  }
}
function addOptimizeImageParams(params, optimizeImage) {
  var _a3;
  validateOptimizeImageOptions(optimizeImage);
  params.set("width", String(optimizeImage.width));
  params.set("quality", String((_a3 = optimizeImage.quality) != null ? _a3 : 75));
  if (optimizeImage.format) {
    params.set("format", optimizeImageFormatToMimeType[optimizeImage.format]);
  }
}
var putOptionHeaderMap = {
  cacheControlMaxAge: "x-cache-control-max-age",
  addRandomSuffix: "x-add-random-suffix",
  allowOverwrite: "x-allow-overwrite",
  contentType: "x-content-type",
  access: "x-vercel-blob-access",
  ifMatch: "x-if-match"
};
function createPutHeaders(allowedOptions, options) {
  const headers = {};
  headers[putOptionHeaderMap.access] = options.access;
  if (allowedOptions.includes("contentType") && options.contentType) {
    headers[putOptionHeaderMap.contentType] = options.contentType;
  }
  if (allowedOptions.includes("addRandomSuffix") && options.addRandomSuffix !== void 0) {
    headers[putOptionHeaderMap.addRandomSuffix] = options.addRandomSuffix ? "1" : "0";
  }
  if (allowedOptions.includes("ifMatch") && options.ifMatch) {
    if (options.allowOverwrite === false) {
      throw new BlobError(
        "ifMatch and allowOverwrite: false are contradictory. ifMatch is used for conditional overwrites, which requires allowOverwrite to be true."
      );
    }
    headers[putOptionHeaderMap.ifMatch] = options.ifMatch;
    if (allowedOptions.includes("allowOverwrite") && options.allowOverwrite === void 0) {
      headers[putOptionHeaderMap.allowOverwrite] = "1";
    }
  }
  if (allowedOptions.includes("allowOverwrite") && options.allowOverwrite !== void 0) {
    headers[putOptionHeaderMap.allowOverwrite] = options.allowOverwrite ? "1" : "0";
  }
  if (allowedOptions.includes("cacheControlMaxAge") && options.cacheControlMaxAge !== void 0) {
    headers[putOptionHeaderMap.cacheControlMaxAge] = options.cacheControlMaxAge.toString();
  }
  return headers;
}
async function createPutOptions({
  pathname,
  options,
  extraChecks,
  getToken
}) {
  if (!pathname) {
    throw new BlobError("pathname is required");
  }
  if (pathname.length > MAXIMUM_PATHNAME_LENGTH) {
    throw new BlobError(
      `pathname is too long, maximum length is ${MAXIMUM_PATHNAME_LENGTH}`
    );
  }
  for (const invalidCharacter of disallowedPathnameCharacters) {
    if (pathname.includes(invalidCharacter)) {
      throw new BlobError(
        `pathname cannot contain "${invalidCharacter}", please encode it if needed`
      );
    }
  }
  if (!options) {
    throw new BlobError("missing options, see usage");
  }
  if (options.access !== "public" && options.access !== "private") {
    throw new BlobError(
      'access must be "private" or "public", see https://vercel.com/docs/vercel-blob'
    );
  }
  if (extraChecks) {
    extraChecks(options);
  }
  if (getToken) {
    options.token = await getToken(pathname, options);
  }
  return options;
}

// src/multipart/complete.ts
function createCompleteMultipartUploadMethod({ allowedOptions, getToken, extraChecks }) {
  return async (pathname, parts, optionsInput) => {
    const options = await createPutOptions({
      pathname,
      options: optionsInput,
      extraChecks,
      getToken
    });
    const headers = createPutHeaders(allowedOptions, options);
    return completeMultipartUpload({
      uploadId: options.uploadId,
      key: options.key,
      pathname,
      headers,
      options,
      parts
    });
  };
}
async function completeMultipartUpload({
  uploadId,
  key,
  pathname,
  parts,
  headers,
  options
}) {
  const params = new URLSearchParams({ pathname });
  try {
    const response = await requestApi(
      `/mpu?${params.toString()}`,
      {
        method: "POST",
        headers: {
          ...headers,
          "content-type": "application/json",
          "x-mpu-action": "complete",
          "x-mpu-upload-id": uploadId,
          // key can be any utf8 character so we need to encode it as HTTP headers can only be us-ascii
          // https://www.rfc-editor.org/rfc/rfc7230#swection-3.2.4
          "x-mpu-key": encodeURIComponent(key)
        },
        body: JSON.stringify(parts),
        signal: options.abortSignal
      },
      options
    );
    debug("mpu: complete", response);
    return response;
  } catch (error) {
    if (error instanceof TypeError && (error.message === "Failed to fetch" || error.message === "fetch failed")) {
      throw new BlobServiceNotAvailable();
    } else {
      throw error;
    }
  }
}

// src/multipart/create.ts
function createCreateMultipartUploadMethod({ allowedOptions, getToken, extraChecks }) {
  return async (pathname, optionsInput) => {
    const options = await createPutOptions({
      pathname,
      options: optionsInput,
      extraChecks,
      getToken
    });
    const headers = createPutHeaders(allowedOptions, options);
    const createMultipartUploadResponse = await createMultipartUpload(
      pathname,
      headers,
      options
    );
    return {
      key: createMultipartUploadResponse.key,
      uploadId: createMultipartUploadResponse.uploadId
    };
  };
}
async function createMultipartUpload(pathname, headers, options) {
  debug("mpu: create", "pathname:", pathname);
  const params = new URLSearchParams({ pathname });
  try {
    const response = await requestApi(
      `/mpu?${params.toString()}`,
      {
        method: "POST",
        headers: {
          ...headers,
          "x-mpu-action": "create"
        },
        signal: options.abortSignal
      },
      options
    );
    debug("mpu: create", response);
    return response;
  } catch (error) {
    if (error instanceof TypeError && (error.message === "Failed to fetch" || error.message === "fetch failed")) {
      throw new BlobServiceNotAvailable();
    }
    throw error;
  }
}

// src/multipart/upload.ts
import throttle from "throttleit";
function createUploadPartMethod({ allowedOptions, getToken, extraChecks }) {
  return async (pathname, body, optionsInput) => {
    const options = await createPutOptions({
      pathname,
      options: optionsInput,
      extraChecks,
      getToken
    });
    const headers = createPutHeaders(allowedOptions, options);
    if (isPlainObject(body)) {
      throw new BlobError(
        "Body must be a string, buffer or stream. You sent a plain JavaScript object, double check what you're trying to upload."
      );
    }
    const result = await uploadPart({
      uploadId: options.uploadId,
      key: options.key,
      pathname,
      part: { blob: body, partNumber: options.partNumber },
      headers,
      options
    });
    return {
      etag: result.etag,
      partNumber: options.partNumber
    };
  };
}
async function uploadPart({
  uploadId,
  key,
  pathname,
  headers,
  options,
  internalAbortController = new AbortController(),
  part
}) {
  var _a3, _b2, _c;
  const params = new URLSearchParams({ pathname });
  const responsePromise = requestApi(
    `/mpu?${params.toString()}`,
    {
      signal: internalAbortController.signal,
      method: "POST",
      headers: {
        ...headers,
        "x-mpu-action": "upload",
        "x-mpu-key": encodeURIComponent(key),
        "x-mpu-upload-id": uploadId,
        "x-mpu-part-number": part.partNumber.toString()
      },
      // weird things between undici types and native fetch types
      body: part.blob
    },
    options
  );
  function handleAbort() {
    internalAbortController.abort();
  }
  if ((_a3 = options.abortSignal) == null ? void 0 : _a3.aborted) {
    handleAbort();
  } else {
    (_b2 = options.abortSignal) == null ? void 0 : _b2.addEventListener("abort", handleAbort);
  }
  const response = await responsePromise;
  (_c = options.abortSignal) == null ? void 0 : _c.removeEventListener("abort", handleAbort);
  return response;
}
var maxConcurrentUploads = typeof window !== "undefined" ? 6 : 8;
var partSizeInBytes = 8 * 1024 * 1024;
var maxBytesInMemory = maxConcurrentUploads * partSizeInBytes * 2;
function uploadAllParts({
  uploadId,
  key,
  pathname,
  stream,
  headers,
  options,
  totalToLoad
}) {
  debug("mpu: upload init", "key:", key);
  const internalAbortController = new AbortController();
  return new Promise((resolve, reject) => {
    const partsToUpload = [];
    const completedParts = [];
    const reader = stream.getReader();
    let activeUploads = 0;
    let reading = false;
    let currentPartNumber = 1;
    let rejected = false;
    let currentBytesInMemory = 0;
    let doneReading = false;
    let bytesSent = 0;
    let arrayBuffers = [];
    let currentPartBytesRead = 0;
    let onUploadProgress;
    const totalLoadedPerPartNumber = {};
    if (options.onUploadProgress) {
      onUploadProgress = throttle(() => {
        var _a3;
        const loaded = Object.values(totalLoadedPerPartNumber).reduce(
          (acc, cur) => {
            return acc + cur;
          },
          0
        );
        const total = totalToLoad || loaded;
        const percentage = totalToLoad > 0 ? Number(((loaded / totalToLoad || loaded) * 100).toFixed(2)) : 0;
        (_a3 = options.onUploadProgress) == null ? void 0 : _a3.call(options, { loaded, total, percentage });
      }, 150);
    }
    read().catch(cancel);
    async function read() {
      debug(
        "mpu: upload read start",
        "activeUploads:",
        activeUploads,
        "currentBytesInMemory:",
        `${bytes(currentBytesInMemory)}/${bytes(maxBytesInMemory)}`,
        "bytesSent:",
        bytes(bytesSent)
      );
      reading = true;
      while (currentBytesInMemory < maxBytesInMemory && !rejected) {
        try {
          const { value, done } = await reader.read();
          if (done) {
            doneReading = true;
            debug("mpu: upload read consumed the whole stream");
            if (arrayBuffers.length > 0) {
              partsToUpload.push({
                partNumber: currentPartNumber++,
                blob: new Blob(arrayBuffers, {
                  type: "application/octet-stream"
                })
              });
              sendParts();
            } else if (activeUploads === 0) {
              reader.releaseLock();
              resolve(completedParts);
            }
            reading = false;
            return;
          }
          currentBytesInMemory += value.byteLength;
          let valueOffset = 0;
          while (valueOffset < value.byteLength) {
            const remainingPartSize = partSizeInBytes - currentPartBytesRead;
            const endOffset = Math.min(
              valueOffset + remainingPartSize,
              value.byteLength
            );
            const chunk = value.slice(valueOffset, endOffset);
            arrayBuffers.push(chunk);
            currentPartBytesRead += chunk.byteLength;
            valueOffset = endOffset;
            if (currentPartBytesRead === partSizeInBytes) {
              partsToUpload.push({
                partNumber: currentPartNumber++,
                blob: new Blob(arrayBuffers, {
                  type: "application/octet-stream"
                })
              });
              arrayBuffers = [];
              currentPartBytesRead = 0;
              sendParts();
            }
          }
        } catch (error) {
          cancel(error);
        }
      }
      debug(
        "mpu: upload read end",
        "activeUploads:",
        activeUploads,
        "currentBytesInMemory:",
        `${bytes(currentBytesInMemory)}/${bytes(maxBytesInMemory)}`,
        "bytesSent:",
        bytes(bytesSent)
      );
      reading = false;
    }
    async function sendPart(part) {
      activeUploads++;
      debug(
        "mpu: upload send part start",
        "partNumber:",
        part.partNumber,
        "size:",
        part.blob.size,
        "activeUploads:",
        activeUploads,
        "currentBytesInMemory:",
        `${bytes(currentBytesInMemory)}/${bytes(maxBytesInMemory)}`,
        "bytesSent:",
        bytes(bytesSent)
      );
      try {
        const uploadProgressForPart = options.onUploadProgress ? (event) => {
          totalLoadedPerPartNumber[part.partNumber] = event.loaded;
          if (onUploadProgress) {
            onUploadProgress();
          }
        } : void 0;
        const completedPart = await uploadPart({
          uploadId,
          key,
          pathname,
          headers,
          options: {
            ...options,
            onUploadProgress: uploadProgressForPart
          },
          internalAbortController,
          part
        });
        debug(
          "mpu: upload send part end",
          "partNumber:",
          part.partNumber,
          "activeUploads",
          activeUploads,
          "currentBytesInMemory:",
          `${bytes(currentBytesInMemory)}/${bytes(maxBytesInMemory)}`,
          "bytesSent:",
          bytes(bytesSent)
        );
        if (rejected) {
          return;
        }
        completedParts.push({
          partNumber: part.partNumber,
          etag: completedPart.etag
        });
        currentBytesInMemory -= part.blob.size;
        activeUploads--;
        bytesSent += part.blob.size;
        if (partsToUpload.length > 0) {
          sendParts();
        }
        if (doneReading) {
          if (activeUploads === 0) {
            reader.releaseLock();
            resolve(completedParts);
          }
          return;
        }
        if (!reading) {
          read().catch(cancel);
        }
      } catch (error) {
        cancel(error);
      }
    }
    function sendParts() {
      if (rejected) {
        return;
      }
      debug(
        "send parts",
        "activeUploads",
        activeUploads,
        "partsToUpload",
        partsToUpload.length
      );
      while (activeUploads < maxConcurrentUploads && partsToUpload.length > 0) {
        const partToSend = partsToUpload.shift();
        if (partToSend) {
          void sendPart(partToSend);
        }
      }
    }
    function cancel(error) {
      if (rejected) {
        return;
      }
      rejected = true;
      internalAbortController.abort();
      reader.releaseLock();
      if (error instanceof TypeError && (error.message === "Failed to fetch" || error.message === "fetch failed")) {
        reject(new BlobServiceNotAvailable());
      } else {
        reject(error);
      }
    }
  });
}

// src/multipart/create-uploader.ts
function createCreateMultipartUploaderMethod({ allowedOptions, getToken, extraChecks }) {
  return async (pathname, optionsInput) => {
    const options = await createPutOptions({
      pathname,
      options: optionsInput,
      extraChecks,
      getToken
    });
    const headers = createPutHeaders(allowedOptions, options);
    const createMultipartUploadResponse = await createMultipartUpload(
      pathname,
      headers,
      options
    );
    return {
      key: createMultipartUploadResponse.key,
      uploadId: createMultipartUploadResponse.uploadId,
      async uploadPart(partNumber, body) {
        if (isPlainObject(body)) {
          throw new BlobError(
            "Body must be a string, buffer or stream. You sent a plain JavaScript object, double check what you're trying to upload."
          );
        }
        const result = await uploadPart({
          uploadId: createMultipartUploadResponse.uploadId,
          key: createMultipartUploadResponse.key,
          pathname,
          part: { partNumber, blob: body },
          headers,
          options
        });
        return {
          etag: result.etag,
          partNumber
        };
      },
      async complete(parts) {
        return completeMultipartUpload({
          uploadId: createMultipartUploadResponse.uploadId,
          key: createMultipartUploadResponse.key,
          pathname,
          parts,
          headers,
          options
        });
      }
    };
  };
}

// src/put.ts
import throttle2 from "throttleit";

// src/multipart/uncontrolled.ts
async function uncontrolledMultipartUpload(pathname, body, headers, options) {
  debug("mpu: init", "pathname:", pathname, "headers:", headers);
  const optionsWithoutOnUploadProgress = {
    ...options,
    onUploadProgress: void 0
  };
  if (options.maximumSizeInBytes !== void 0 && !isStream(body) && computeBodyLength(body) > options.maximumSizeInBytes) {
    throw new BlobError(
      `Body size of ${computeBodyLength(body)} bytes exceeds the maximum allowed size of ${options.maximumSizeInBytes} bytes`
    );
  }
  const createMultipartUploadResponse = await createMultipartUpload(
    pathname,
    headers,
    optionsWithoutOnUploadProgress
  );
  const totalToLoad = computeBodyLength(body);
  const stream = await toReadableStream(body);
  const parts = await uploadAllParts({
    uploadId: createMultipartUploadResponse.uploadId,
    key: createMultipartUploadResponse.key,
    pathname,
    // @ts-expect-error ReadableStream<ArrayBuffer | Uint8Array> is compatible at runtime
    stream,
    headers,
    options,
    totalToLoad
  });
  const blob = await completeMultipartUpload({
    uploadId: createMultipartUploadResponse.uploadId,
    key: createMultipartUploadResponse.key,
    pathname,
    parts,
    headers,
    options: optionsWithoutOnUploadProgress
  });
  return blob;
}

// src/put.ts
function createPutMethod({
  allowedOptions,
  getToken,
  getPresignedUrlPayload,
  extraChecks
}) {
  return async function put(pathname, body, optionsInput) {
    var _a3;
    if (!body) {
      throw new BlobError("body is required");
    }
    if (isPlainObject(body)) {
      throw new BlobError(
        "Body must be a string, buffer or stream. You sent a plain JavaScript object, double check what you're trying to upload."
      );
    }
    const options = await createPutOptions({
      pathname,
      options: optionsInput,
      extraChecks,
      getToken
    });
    const presignedUrlPayload = await (getPresignedUrlPayload == null ? void 0 : getPresignedUrlPayload(
      pathname,
      options
    ));
    const optionsWithPresignedUrlPayload = {
      ...options,
      presignedUrlPayload
    };
    const headers = createPutHeaders(allowedOptions, options);
    if (options.optimizeImage) {
      if (options.multipart === true) {
        throw new BlobError(
          "optimizeImage cannot be combined with multipart uploads"
        );
      }
      validateOptimizeImageSourceContentType(
        (_a3 = options.contentType) != null ? _a3 : typeof Blob !== "undefined" && body instanceof Blob ? body.type : void 0
      );
      const params2 = new URLSearchParams({ pathname });
      addOptimizeImageParams(params2, options.optimizeImage);
      const response2 = await requestApi(
        `/put-optimized?${params2.toString()}`,
        {
          method: "POST",
          body,
          headers,
          signal: options.abortSignal
        },
        optionsWithPresignedUrlPayload
      );
      return {
        url: response2.url,
        downloadUrl: response2.downloadUrl,
        pathname: response2.pathname,
        contentType: response2.contentType,
        contentDisposition: response2.contentDisposition,
        etag: response2.etag
      };
    }
    if (options.multipart === true) {
      return uncontrolledMultipartUpload(
        pathname,
        body,
        headers,
        optionsWithPresignedUrlPayload
      );
    }
    const onUploadProgress = options.onUploadProgress ? throttle2(options.onUploadProgress, 100) : void 0;
    const params = new URLSearchParams({ pathname });
    const response = await requestApi(
      `/?${params.toString()}`,
      {
        method: "PUT",
        body,
        headers,
        signal: options.abortSignal
      },
      {
        ...optionsWithPresignedUrlPayload,
        onUploadProgress
      }
    );
    return {
      url: response.url,
      downloadUrl: response.downloadUrl,
      pathname: response.pathname,
      contentType: response.contentType,
      contentDisposition: response.contentDisposition,
      etag: response.etag
    };
  };
}

// src/presign-query-params.ts
var BLOB_PRESIGN_QUERY_VALID_UNTIL = "vercel-blob-valid-until";
var BLOB_PRESIGN_QUERY_MAXIMUM_SIZE = "vercel-blob-maximum-size-in-bytes";
var BLOB_PRESIGN_QUERY_ALLOWED_CONTENT_TYPES = "vercel-blob-allowed-content-types";
var BLOB_PRESIGN_QUERY_ADD_RANDOM_SUFFIX = "vercel-blob-add-random-suffix";
var BLOB_PRESIGN_QUERY_ALLOW_OVERWRITE = "vercel-blob-allow-overwrite";
var BLOB_PRESIGN_QUERY_CACHE_CONTROL_MAX_AGE = "vercel-blob-cache-control-max-age";
var BLOB_PRESIGN_QUERY_IF_MATCH = "vercel-blob-if-match";
var BLOB_PRESIGN_QUERY_CALLBACK_URL = "vercel-blob-callback-url";
var BLOB_PRESIGN_QUERY_CALLBACK_TOKEN_PAYLOAD = "vercel-blob-callback-token-payload";
var PRESIGN_CANONICAL_QUERY_KEYS = [
  BLOB_PRESIGN_QUERY_ADD_RANDOM_SUFFIX,
  BLOB_PRESIGN_QUERY_ALLOW_OVERWRITE,
  BLOB_PRESIGN_QUERY_ALLOWED_CONTENT_TYPES,
  BLOB_PRESIGN_QUERY_CACHE_CONTROL_MAX_AGE,
  BLOB_PRESIGN_QUERY_CALLBACK_TOKEN_PAYLOAD,
  BLOB_PRESIGN_QUERY_CALLBACK_URL,
  BLOB_PRESIGN_QUERY_IF_MATCH,
  BLOB_PRESIGN_QUERY_MAXIMUM_SIZE,
  BLOB_PRESIGN_QUERY_VALID_UNTIL
];
var MAX_PRESIGN_CALLBACK_URL_CHARS = 4096;
var MAX_PRESIGN_CALLBACK_TOKEN_PAYLOAD_CHARS = 8192;
function contentTypeAllowedByList(contentType, allowed) {
  const [type] = contentType.split("/");
  const wildcard = `${type}/*`;
  return allowed.includes(contentType) || (type ? allowed.includes(wildcard) : false);
}
function assertAllowedContentTypesSubset(optionsTypes, delegationTypes, label) {
  if (!(optionsTypes == null ? void 0 : optionsTypes.length)) {
    return;
  }
  if (!(delegationTypes == null ? void 0 : delegationTypes.length)) {
    return;
  }
  for (const ct of optionsTypes) {
    if (!contentTypeAllowedByList(ct, delegationTypes)) {
      throw new Error(
        `${label}: allowedContentTypes entry "${ct}" is not permitted by the delegation token.`
      );
    }
  }
}
function assertNumberSubset(name, optionVal, delegationVal, label, mode) {
  if (optionVal === void 0) {
    return;
  }
  if (delegationVal === void 0) {
    return;
  }
  if (mode === "lte" && optionVal > delegationVal) {
    throw new Error(
      `${label}: ${name} must be \u2264 delegation (${String(delegationVal)}).`
    );
  }
}
function isPlausibleAbsoluteUrl(s) {
  if (typeof URL !== "undefined" && typeof URL.canParse === "function") {
    return URL.canParse(s);
  }
  try {
    new URL(s);
    return true;
  } catch {
    return false;
  }
}
function validatePresignUrlOnUploadCompletedWire(opt, label) {
  if (!opt) {
    return;
  }
  if (typeof opt.callbackUrl !== "string" || opt.callbackUrl.length === 0) {
    throw new Error(
      `${label}: onUploadCompleted.callbackUrl must be a non-empty string.`
    );
  }
  if (opt.callbackUrl.length > MAX_PRESIGN_CALLBACK_URL_CHARS) {
    throw new Error(`${label}: onUploadCompleted.callbackUrl is too long.`);
  }
  if (!isPlausibleAbsoluteUrl(opt.callbackUrl)) {
    throw new Error(
      `${label}: onUploadCompleted.callbackUrl must be a valid URL.`
    );
  }
  if (opt.tokenPayload !== void 0 && opt.tokenPayload !== null) {
    if (typeof opt.tokenPayload !== "string") {
      throw new Error(
        `${label}: onUploadCompleted.tokenPayload must be a string.`
      );
    }
    if (opt.tokenPayload.length > MAX_PRESIGN_CALLBACK_TOKEN_PAYLOAD_CHARS) {
      throw new Error(`${label}: onUploadCompleted.tokenPayload is too long.`);
    }
  }
}
var MAX_PRESIGN_CACHE_CONTROL_MAX_AGE_SECONDS = 365 * 24 * 60 * 60;
var MAX_PRESIGN_IF_MATCH_LENGTH = 256;
var IF_MATCH_CONTROL_CHARS_RE = /[\x00-\x1f\x7f]/;
function validateUrlOnlyPresignUploadOptions(urlOptions, label) {
  if (urlOptions.cacheControlMaxAge !== void 0) {
    const n = urlOptions.cacheControlMaxAge;
    if (!Number.isInteger(n) || n < 0 || n > MAX_PRESIGN_CACHE_CONTROL_MAX_AGE_SECONDS) {
      throw new Error(
        `${label}: cacheControlMaxAge must be an integer between 0 and ${MAX_PRESIGN_CACHE_CONTROL_MAX_AGE_SECONDS}.`
      );
    }
  }
  if (urlOptions.ifMatch !== void 0) {
    const im = urlOptions.ifMatch;
    if (typeof im !== "string" || im.length === 0) {
      throw new Error(`${label}: ifMatch must be a non-empty string.`);
    }
    if (im.length > MAX_PRESIGN_IF_MATCH_LENGTH) {
      throw new Error(`${label}: ifMatch is too long.`);
    }
    if (IF_MATCH_CONTROL_CHARS_RE.test(im)) {
      throw new Error(
        `${label}: ifMatch contains disallowed control characters.`
      );
    }
  }
}
function sortedContentTypesCsv(types) {
  return [...types].sort((a, b) => a < b ? -1 : a > b ? 1 : 0).join(",");
}
function resolvePresignUrlValidUntilMs(args) {
  const { delegationValidUntil, urlOptions, nowMs } = args;
  let t;
  if ((urlOptions == null ? void 0 : urlOptions.validUntil) !== void 0) {
    if (typeof urlOptions.validUntil !== "number" || !Number.isFinite(urlOptions.validUntil)) {
      throw new Error("presignUrl: validUntil must be a finite number (ms).");
    }
    t = Math.trunc(urlOptions.validUntil);
  } else {
    t = Math.trunc(delegationValidUntil);
  }
  if (Number.isFinite(delegationValidUntil)) {
    t = Math.min(t, Math.trunc(delegationValidUntil));
  }
  if (t <= nowMs) {
    throw new Error(
      "presignUrl: resolved URL expiry is not after the current time; issue a new delegation token or pass a later validUntil."
    );
  }
  return t;
}
function buildPresignCanonicalQueryEntries(args) {
  const { operation, delegation, urlOptions, nowMs } = args;
  const label = "presignUrl";
  const resolvedUntil = resolvePresignUrlValidUntilMs({
    delegationValidUntil: delegation.validUntil,
    urlOptions,
    nowMs
  });
  const delegUntil = Math.trunc(delegation.validUntil);
  const entries = [];
  if (resolvedUntil < delegUntil) {
    entries.push([BLOB_PRESIGN_QUERY_VALID_UNTIL, String(resolvedUntil)]);
  }
  if (operation === "delete") {
    if ((urlOptions == null ? void 0 : urlOptions.ifMatch) !== void 0) {
      entries.push([BLOB_PRESIGN_QUERY_IF_MATCH, urlOptions.ifMatch]);
    }
    return entries;
  }
  if (operation !== "put" || !urlOptions) {
    return entries;
  }
  assertAllowedContentTypesSubset(
    urlOptions.allowedContentTypes,
    delegation.allowedContentTypes,
    label
  );
  assertNumberSubset(
    "maximumSizeInBytes",
    urlOptions.maximumSizeInBytes,
    delegation.maximumSizeInBytes,
    label,
    "lte"
  );
  validateUrlOnlyPresignUploadOptions(urlOptions, label);
  validatePresignUrlOnUploadCompletedWire(urlOptions.onUploadCompleted, label);
  if (urlOptions.allowedContentTypes !== void 0) {
    const csv = sortedContentTypesCsv(urlOptions.allowedContentTypes);
    if (csv.length > 16384) {
      throw new Error(`${label}: allowedContentTypes query value is too long.`);
    }
    entries.push([BLOB_PRESIGN_QUERY_ALLOWED_CONTENT_TYPES, csv]);
  }
  if (urlOptions.maximumSizeInBytes !== void 0) {
    entries.push([
      BLOB_PRESIGN_QUERY_MAXIMUM_SIZE,
      String(Math.trunc(urlOptions.maximumSizeInBytes))
    ]);
  }
  if (urlOptions.addRandomSuffix !== void 0) {
    entries.push([
      BLOB_PRESIGN_QUERY_ADD_RANDOM_SUFFIX,
      urlOptions.addRandomSuffix ? "true" : "false"
    ]);
  }
  if (urlOptions.allowOverwrite !== void 0) {
    entries.push([
      BLOB_PRESIGN_QUERY_ALLOW_OVERWRITE,
      urlOptions.allowOverwrite ? "true" : "false"
    ]);
  }
  if (urlOptions.cacheControlMaxAge !== void 0) {
    entries.push([
      BLOB_PRESIGN_QUERY_CACHE_CONTROL_MAX_AGE,
      String(Math.trunc(urlOptions.cacheControlMaxAge))
    ]);
  }
  if (urlOptions.ifMatch !== void 0) {
    entries.push([BLOB_PRESIGN_QUERY_IF_MATCH, urlOptions.ifMatch]);
  }
  if (urlOptions.onUploadCompleted !== void 0) {
    const { callbackUrl, tokenPayload } = urlOptions.onUploadCompleted;
    if (callbackUrl.length > MAX_PRESIGN_CALLBACK_URL_CHARS) {
      throw new Error(`${label}: onUploadCompleted.callbackUrl is too long.`);
    }
    entries.push([BLOB_PRESIGN_QUERY_CALLBACK_URL, callbackUrl]);
    if (tokenPayload !== void 0 && tokenPayload !== null && tokenPayload !== "") {
      if (tokenPayload.length > MAX_PRESIGN_CALLBACK_TOKEN_PAYLOAD_CHARS) {
        throw new Error(
          `${label}: onUploadCompleted.tokenPayload is too long.`
        );
      }
      entries.push([BLOB_PRESIGN_QUERY_CALLBACK_TOKEN_PAYLOAD, tokenPayload]);
    }
  }
  return entries;
}

// src/signed-token.ts
function assertIssueSignedTokenValidUntilOption(validUntil) {
  const now = Date.now();
  if (typeof validUntil !== "number" || !Number.isInteger(validUntil) || !Number.isFinite(validUntil)) {
    throw new BlobError(
      "`issueSignedToken`: validUntil must be an integer milliseconds timestamp."
    );
  }
  if (validUntil <= now) {
    throw new BlobError(
      "`issueSignedToken`: validUntil must be in the future."
    );
  }
}
async function issueSignedToken(options) {
  if (!options) {
    throw new BlobError("`issueSignedToken` requires an options object");
  }
  const body = {};
  if (options.pathname !== void 0) {
    body.pathname = options.pathname;
  }
  if (options.operations !== void 0) {
    if (options.operations.length === 0) {
      throw new BlobError("`operations` must be a non-empty array if provided");
    }
    body.operations = dedupeOps(options.operations);
  }
  if (options.validUntil !== void 0) {
    assertIssueSignedTokenValidUntilOption(options.validUntil);
    body.validUntil = options.validUntil;
  }
  if (options.maximumSizeInBytes !== void 0) {
    body.maximumSizeInBytes = options.maximumSizeInBytes;
  }
  if (options.allowedContentTypes !== void 0) {
    body.allowedContentTypes = options.allowedContentTypes;
  }
  return requestApi(
    "/signed-token",
    {
      method: "POST",
      headers: { "content-type": "application/json" },
      body: JSON.stringify(body),
      signal: options.abortSignal
    },
    options
  );
}
function dedupeOps(operations) {
  return Array.from(new Set(operations));
}
function base64UrlDecodeToString(segment) {
  let base64 = segment.replace(/-/g, "+").replace(/_/g, "/");
  const padding = 4 - base64.length % 4;
  if (padding !== 4) {
    base64 += "=".repeat(padding);
  }
  if (typeof atob === "function") {
    return atob(base64);
  }
  if (typeof Buffer !== "undefined") {
    return Buffer.from(base64, "base64").toString("utf8");
  }
  throw new BlobError("Cannot decode base64: no atob or Buffer available.");
}
function tryDecodePayload(delegationToken) {
  const dot = delegationToken.indexOf(".");
  if (dot < 0) {
    return null;
  }
  const payloadSeg = delegationToken.slice(0, dot);
  try {
    return JSON.parse(
      base64UrlDecodeToString(payloadSeg)
    );
  } catch {
    return null;
  }
}
function uint8ToBase64(bytes2) {
  if (typeof Buffer !== "undefined") {
    return Buffer.from(
      bytes2.buffer,
      bytes2.byteOffset,
      bytes2.byteLength
    ).toString("base64");
  }
  let s = "";
  for (let i = 0; i < bytes2.length; i++) {
    s += String.fromCharCode(bytes2[i]);
  }
  return btoa(s);
}
async function hmacSha256Base64Url(key, data) {
  var _a3;
  if (!((_a3 = globalThis.crypto) == null ? void 0 : _a3.subtle)) {
    throw new BlobError(
      "HMAC is not available: expected globalThis.crypto.subtle (Node 20+ or a modern browser)."
    );
  }
  const enc = new TextEncoder();
  const cryptoKey = await globalThis.crypto.subtle.importKey(
    "raw",
    enc.encode(key),
    { name: "HMAC", hash: "SHA-256" },
    false,
    ["sign"]
  );
  const buf = await globalThis.crypto.subtle.sign(
    "HMAC",
    cryptoKey,
    enc.encode(data)
  );
  return toBase64Url(uint8ToBase64(new Uint8Array(buf)));
}
function toBase64Url(base64) {
  return base64.replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
}
async function presign(signedToken, options) {
  var _a3, _b2, _c, _d;
  if (!(signedToken == null ? void 0 : signedToken.clientSigningToken) || !(signedToken == null ? void 0 : signedToken.delegationToken)) {
    throw new BlobError(
      "`clientSigningToken` and `delegationToken` from `issueSignedToken` are required."
    );
  }
  const scope = tryDecodePayload(signedToken.delegationToken);
  if (!scope) {
    throw new BlobError("Invalid or unreadable `delegationToken` payload.");
  }
  const p = scope.pathname;
  if (p && p !== "*") {
    if (options.pathname !== p) {
      throw new BlobError(
        `Blob path does not match the signed token scope; expected \`${p}\`, got \`${options.pathname}\`.`
      );
    }
  }
  if (Number.isFinite(scope.validUntil) && Date.now() > scope.validUntil) {
    throw new BlobError(
      "The signed delegation has expired; issue a new token first."
    );
  }
  if (options.operation === "get" && !((_a3 = scope.operations) == null ? void 0 : _a3.includes("get"))) {
    throw new BlobError(
      'The delegation token is not valid for `GET` requests. Include `"get"` in `operations` when calling `issueSignedToken`.'
    );
  }
  if (options.operation === "head" && !((_b2 = scope.operations) == null ? void 0 : _b2.includes("head"))) {
    throw new BlobError(
      'The delegation token is not valid for `HEAD` requests. Include `"head"` in `operations` when calling `issueSignedToken`.'
    );
  }
  if (options.operation === "put" && !((_c = scope.operations) == null ? void 0 : _c.includes("put"))) {
    throw new BlobError(
      'The delegation token is not valid for presigned write requests. Include `"put"` in `operations` when calling `issueSignedToken`.'
    );
  }
  if (options.operation === "delete" && !((_d = scope.operations) == null ? void 0 : _d.includes("delete"))) {
    throw new BlobError(
      'The delegation token is not valid for presigned delete requests. Include `"delete"` in `operations` when calling `issueSignedToken`.'
    );
  }
  const delegationForOptions = {
    validUntil: scope.validUntil,
    maximumSizeInBytes: scope.maximumSizeInBytes,
    allowedContentTypes: scope.allowedContentTypes
  };
  let presignEntries;
  try {
    presignEntries = buildPresignCanonicalQueryEntries({
      operation: options.operation,
      delegation: delegationForOptions,
      urlOptions: options,
      nowMs: Date.now()
    });
  } catch (e) {
    const msg = e instanceof Error ? e.message : String(e);
    throw new BlobError(msg);
  }
  const canonical = canonicalString(
    options.pathname,
    presignEntries,
    options.operation
  );
  const signature = await hmacSha256Base64Url(
    signedToken.clientSigningToken,
    canonical
  );
  return {
    delegationToken: signedToken.delegationToken,
    signature,
    params: Object.fromEntries(presignEntries)
  };
}
function buildPresignedGetUrl(pathnameOrUrl, presignedUrlPayload, options) {
  const storeId = parseStoreIdFromDelegationToken(
    presignedUrlPayload.delegationToken
  );
  let blobUrl = isUrl(pathnameOrUrl) ? pathnameOrUrl : constructBlobUrl(storeId, pathnameOrUrl, options.access);
  if (options.useCache === false && options.access === "private") {
    const url = new URL(blobUrl);
    url.searchParams.set("cache", "0");
    blobUrl = url.toString();
  }
  return addPresignedParams(blobUrl, presignedUrlPayload);
}
function buildPresignedPutUrl(pathname, presignedUrlPayload) {
  const params = new URLSearchParams({ pathname });
  const apiUrl = getApiUrl(`/?${params.toString()}`);
  return addPresignedParams(apiUrl, presignedUrlPayload);
}
function buildPresignedDeleteUrl(pathname, presignedUrlPayload) {
  const params = new URLSearchParams({ pathname });
  const apiUrl = getApiUrl(`/?${params.toString()}`);
  return addPresignedParams(apiUrl, presignedUrlPayload);
}
async function presignUrl(signedToken, options) {
  const payload = await presign(signedToken, options);
  if (options.operation === "get" || options.operation === "head") {
    return {
      presignedUrl: buildPresignedGetUrl(options.pathname, payload, options)
    };
  }
  if (options.operation === "put") {
    return {
      presignedUrl: buildPresignedPutUrl(options.pathname, payload)
    };
  }
  if (options.operation === "delete") {
    return {
      presignedUrl: buildPresignedDeleteUrl(options.pathname, payload)
    };
  }
  throw new BlobError(`Unknown operation`);
}
function canonicalString(pathname, presignEntries, operation) {
  var _a3;
  const lines = [`operation=${operation}`, `pathname=${pathname}`];
  for (const k of PRESIGN_CANONICAL_QUERY_KEYS) {
    const v = (_a3 = presignEntries.find(([key]) => key === k)) == null ? void 0 : _a3[1];
    if (v) {
      lines.push(`${k}=${v}`);
    }
  }
  lines.sort((a, b) => compareUtf8(a, b));
  return lines.join("\n");
}
var utf8Encoder = new TextEncoder();
function compareUtf8(a, b) {
  const ab = utf8Encoder.encode(a);
  const bb = utf8Encoder.encode(b);
  const n = Math.min(ab.length, bb.length);
  for (let i = 0; i < n; i++) {
    const d = ab[i] - bb[i];
    if (d !== 0) {
      return d;
    }
  }
  return ab.length - bb.length;
}

// src/create-folder.ts
async function createFolder(pathname, options = { access: "public" }) {
  var _a3;
  const access = (_a3 = options.access) != null ? _a3 : "public";
  const folderPathname = pathname.endsWith("/") ? pathname : `${pathname}/`;
  const headers = {};
  headers[putOptionHeaderMap.access] = access;
  headers[putOptionHeaderMap.addRandomSuffix] = "0";
  const params = new URLSearchParams({ pathname: folderPathname });
  const response = await requestApi(
    `/?${params.toString()}`,
    {
      method: "PUT",
      headers,
      signal: options.abortSignal
    },
    options
  );
  return {
    url: response.url,
    pathname: response.pathname
  };
}

export {
  parseStoreIdFromReadWriteToken,
  parseStoreIdFromDelegationToken,
  parseStoreIdFromPresignedUrl,
  resolveBlobAuth,
  getReadWriteBlobTokenFromOptionsOrEnv,
  BlobError,
  getDownloadUrl,
  disallowedPathnameCharacters,
  isUrl,
  constructBlobUrl,
  MAXIMUM_PATHNAME_LENGTH,
  BlobAccessError,
  BlobContentTypeNotAllowedError,
  BlobPathnameMismatchError,
  BlobClientTokenExpiredError,
  BlobFileTooLargeError,
  BlobStoreNotFoundError,
  BlobStoreSuspendedError,
  BlobUnknownError,
  BlobNotFoundError,
  BlobServiceNotAvailable,
  BlobServiceRateLimited,
  BlobRequestAbortedError,
  BlobPreconditionFailedError,
  requestApi,
  addOptimizeImageParams,
  createPutHeaders,
  createPutOptions,
  createCompleteMultipartUploadMethod,
  createCreateMultipartUploadMethod,
  createUploadPartMethod,
  createCreateMultipartUploaderMethod,
  createPutMethod,
  issueSignedToken,
  presign,
  presignUrl,
  createFolder
};
/*!
 * bytes
 * Copyright(c) 2012-2014 TJ Holowaychuk
 * Copyright(c) 2015 Jed Watson
 * MIT Licensed
 */
//# sourceMappingURL=chunk-OYCIHDFF.js.map