class m extends Error {
  response;
  request;
  options;
  constructor(e, r, s) {
    const n = e.status || e.status === 0 ? e.status : "", i = e.statusText ?? "", o = `${n} ${i}`.trim(), u = o ? `status code ${o}` : "an unknown error";
    super(`Request failed with ${u}: ${r.method} ${r.url}`), this.name = "HTTPError", this.response = e, this.request = r, this.options = s;
  }
}
class x extends Error {
  name = "NonError";
  value;
  constructor(e) {
    let r = "Non-error value was thrown";
    try {
      typeof e == "string" ? r = e : e && typeof e == "object" && "message" in e && typeof e.message == "string" && (r = e.message);
    } catch {
    }
    super(r), this.value = e;
  }
}
class y extends Error {
  name = "ForceRetryError";
  customDelay;
  code;
  customRequest;
  constructor(e) {
    const r = e?.cause ? e.cause instanceof Error ? e.cause : new x(e.cause) : void 0;
    super(e?.code ? `Forced retry: ${e.code}` : "Forced retry", r ? { cause: r } : void 0), this.customDelay = e?.delay, this.code = e?.code, this.customRequest = e?.request;
  }
}
const R = (() => {
  let t = !1, e = !1;
  const r = typeof globalThis.ReadableStream == "function", s = typeof globalThis.Request == "function";
  if (r && s)
    try {
      e = new globalThis.Request("https://empty.invalid", {
        body: new globalThis.ReadableStream(),
        method: "POST",
        // @ts-expect-error - Types are outdated.
        get duplex() {
          return t = !0, "half";
        }
      }).headers.has("Content-Type");
    } catch (n) {
      if (n instanceof Error && n.message === "unsupported BodyInit type")
        return !1;
      throw n;
    }
  return t && !e;
})(), j = typeof globalThis.AbortController == "function", q = typeof globalThis.AbortSignal == "function" && typeof globalThis.AbortSignal.any == "function", U = typeof globalThis.ReadableStream == "function", C = typeof globalThis.FormData == "function", S = ["get", "post", "put", "patch", "head", "delete"], L = {
  json: "application/json",
  text: "text/*",
  formData: "multipart/form-data",
  arrayBuffer: "*/*",
  blob: "*/*",
  // Supported in modern Fetch implementations (for example, browsers and recent Node.js/undici).
  // We still feature-check at runtime before exposing the shortcut.
  bytes: "*/*"
}, p = 2147483647, N = new TextEncoder().encode("------WebKitFormBoundaryaxpyiPgbbPti10Rw").length, E = Symbol("stop");
class P {
  options;
  constructor(e) {
    this.options = e;
  }
}
const D = (t) => new P(t), H = {
  json: !0,
  parseJson: !0,
  stringifyJson: !0,
  searchParams: !0,
  prefixUrl: !0,
  retry: !0,
  timeout: !0,
  hooks: !0,
  throwHttpErrors: !0,
  onDownloadProgress: !0,
  onUploadProgress: !0,
  fetch: !0,
  context: !0
}, v = {
  next: !0
  // Next.js cache revalidation (revalidate, tags)
}, I = {
  method: !0,
  headers: !0,
  body: !0,
  mode: !0,
  credentials: !0,
  cache: !0,
  redirect: !0,
  referrer: !0,
  referrerPolicy: !0,
  integrity: !0,
  keepalive: !0,
  signal: !0,
  window: !0,
  duplex: !0
}, z = (t) => {
  if (!t)
    return 0;
  if (t instanceof FormData) {
    let e = 0;
    for (const [r, s] of t)
      e += N, e += new TextEncoder().encode(`Content-Disposition: form-data; name="${r}"`).length, e += typeof s == "string" ? new TextEncoder().encode(s).length : s.size;
    return e;
  }
  if (t instanceof Blob)
    return t.size;
  if (t instanceof ArrayBuffer)
    return t.byteLength;
  if (typeof t == "string")
    return new TextEncoder().encode(t).length;
  if (t instanceof URLSearchParams)
    return new TextEncoder().encode(t.toString()).length;
  if ("byteLength" in t)
    return t.byteLength;
  if (typeof t == "object" && t !== null)
    try {
      const e = JSON.stringify(t);
      return new TextEncoder().encode(e).length;
    } catch {
      return 0;
    }
  return 0;
}, A = (t, e, r) => {
  let s, n = 0;
  return t.pipeThrough(new TransformStream({
    transform(i, o) {
      if (o.enqueue(i), s) {
        n += s.byteLength;
        let u = e === 0 ? 0 : n / e;
        u >= 1 && (u = 1 - Number.EPSILON), r?.({ percent: u, totalBytes: Math.max(e, n), transferredBytes: n }, s);
      }
      s = i;
    },
    flush() {
      s && (n += s.byteLength, r?.({ percent: 1, totalBytes: Math.max(e, n), transferredBytes: n }, s));
    }
  }));
}, F = (t, e) => {
  if (!t.body)
    return t;
  if (t.status === 204)
    return new Response(null, {
      status: t.status,
      statusText: t.statusText,
      headers: t.headers
    });
  const r = Math.max(0, Number(t.headers.get("content-length")) || 0);
  return new Response(A(t.body, r, e), {
    status: t.status,
    statusText: t.statusText,
    headers: t.headers
  });
}, M = (t, e, r) => {
  if (!t.body)
    return t;
  const s = z(r ?? t.body);
  return new Request(t, {
    // @ts-expect-error - Types are outdated.
    duplex: "half",
    body: A(t.body, s, e)
  });
}, c = (t) => t !== null && typeof t == "object", l = (...t) => {
  for (const e of t)
    if ((!c(e) || Array.isArray(e)) && e !== void 0)
      throw new TypeError("The `options` argument must be an object");
  return w({}, ...t);
}, k = (t = {}, e = {}) => {
  const r = new globalThis.Headers(t), s = e instanceof globalThis.Headers, n = new globalThis.Headers(e);
  for (const [i, o] of n.entries())
    s && o === "undefined" || o === void 0 ? r.delete(i) : r.set(i, o);
  return r;
};
function d(t, e, r) {
  return Object.hasOwn(e, r) && e[r] === void 0 ? [] : w(t[r] ?? [], e[r] ?? []);
}
const O = (t = {}, e = {}) => ({
  beforeRequest: d(t, e, "beforeRequest"),
  beforeRetry: d(t, e, "beforeRetry"),
  afterResponse: d(t, e, "afterResponse"),
  beforeError: d(t, e, "beforeError")
}), $ = (t, e) => {
  const r = new URLSearchParams();
  for (const s of [t, e])
    if (s !== void 0)
      if (s instanceof URLSearchParams)
        for (const [n, i] of s.entries())
          r.append(n, i);
      else if (Array.isArray(s))
        for (const n of s) {
          if (!Array.isArray(n) || n.length !== 2)
            throw new TypeError("Array search parameters must be provided in [[key, value], ...] format");
          r.append(String(n[0]), String(n[1]));
        }
      else if (c(s))
        for (const [n, i] of Object.entries(s))
          i !== void 0 && r.append(n, String(i));
      else {
        const n = new URLSearchParams(s);
        for (const [i, o] of n.entries())
          r.append(i, o);
      }
  return r;
}, w = (...t) => {
  let e = {}, r = {}, s = {}, n;
  const i = [];
  for (const o of t)
    if (Array.isArray(o))
      Array.isArray(e) || (e = []), e = [...e, ...o];
    else if (c(o)) {
      for (let [u, a] of Object.entries(o)) {
        if (u === "signal" && a instanceof globalThis.AbortSignal) {
          i.push(a);
          continue;
        }
        if (u === "context") {
          if (a != null && (!c(a) || Array.isArray(a)))
            throw new TypeError("The `context` option must be an object");
          e = {
            ...e,
            context: a == null ? {} : { ...e.context, ...a }
          };
          continue;
        }
        if (u === "searchParams") {
          a == null ? n = void 0 : n = n === void 0 ? a : $(n, a);
          continue;
        }
        c(a) && u in e && (a = w(e[u], a)), e = { ...e, [u]: a };
      }
      c(o.hooks) && (s = O(s, o.hooks), e.hooks = s), c(o.headers) && (r = k(r, o.headers), e.headers = r);
    }
  return n !== void 0 && (e.searchParams = n), i.length > 0 && (i.length === 1 ? e.signal = i[0] : q ? e.signal = AbortSignal.any(i) : e.signal = i.at(-1)), e.context === void 0 && (e.context = {}), e;
}, B = (t) => S.includes(t) ? t.toUpperCase() : t, J = ["get", "put", "head", "delete", "options", "trace"], V = [408, 413, 429, 500, 502, 503, 504], W = [413, 429, 503], T = {
  limit: 2,
  methods: J,
  statusCodes: V,
  afterStatusCodes: W,
  maxRetryAfter: Number.POSITIVE_INFINITY,
  backoffLimit: Number.POSITIVE_INFINITY,
  delay: (t) => 0.3 * 2 ** (t - 1) * 1e3,
  jitter: void 0,
  retryOnTimeout: !1
}, _ = (t = {}) => {
  if (typeof t == "number")
    return {
      ...T,
      limit: t
    };
  if (t.methods && !Array.isArray(t.methods))
    throw new Error("retry.methods must be an array");
  if (t.statusCodes && !Array.isArray(t.statusCodes))
    throw new Error("retry.statusCodes must be an array");
  return {
    ...T,
    ...t
  };
};
class g extends Error {
  request;
  constructor(e) {
    super(`Request timed out: ${e.method} ${e.url}`), this.name = "TimeoutError", this.request = e;
  }
}
async function X(t, e, r, s) {
  return new Promise((n, i) => {
    const o = setTimeout(() => {
      r && r.abort(), i(new g(t));
    }, s.timeout);
    s.fetch(t, e).then(n).catch(i).then(() => {
      clearTimeout(o);
    });
  });
}
async function Y(t, { signal: e }) {
  return new Promise((r, s) => {
    e && (e.throwIfAborted(), e.addEventListener("abort", n, { once: !0 }));
    function n() {
      clearTimeout(i), s(e.reason);
    }
    const i = setTimeout(() => {
      e?.removeEventListener("abort", n), r();
    }, t);
  });
}
const G = (t, e) => {
  const r = {};
  for (const s in e)
    Object.hasOwn(e, s) && !(s in I) && !(s in H) && (!(s in t) || s in v) && (r[s] = e[s]);
  return r;
}, K = (t) => t === void 0 ? !1 : Array.isArray(t) ? t.length > 0 : t instanceof URLSearchParams ? t.size > 0 : typeof t == "object" ? Object.keys(t).length > 0 : typeof t == "string" ? t.trim().length > 0 : !!t;
function Q(t) {
  return t instanceof m || t?.name === m.name;
}
function Z(t) {
  return t instanceof g || t?.name === g.name;
}
class f {
  static create(e, r) {
    const s = new f(e, r), n = async () => {
      if (typeof s.#e.timeout == "number" && s.#e.timeout > p)
        throw new RangeError(`The \`timeout\` option cannot be greater than ${p}`);
      await Promise.resolve();
      let o = await s.#p();
      for (const u of s.#e.hooks.afterResponse) {
        const a = s.#c(o.clone()), h = await u(s.request, s.#a(), a, { retryCount: s.#r });
        if (h instanceof globalThis.Response && (o = h), h instanceof P)
          throw await Promise.all([
            a.body?.cancel(),
            o.body?.cancel()
          ]), new y(h.options);
      }
      if (s.#c(o), !o.ok && (typeof s.#e.throwHttpErrors == "function" ? s.#e.throwHttpErrors(o.status) : s.#e.throwHttpErrors)) {
        let u = new m(o, s.request, s.#a());
        for (const a of s.#e.hooks.beforeError)
          u = await a(u, { retryCount: s.#r });
        throw u;
      }
      if (s.#e.onDownloadProgress) {
        if (typeof s.#e.onDownloadProgress != "function")
          throw new TypeError("The `onDownloadProgress` option must be a function");
        if (!U)
          throw new Error("Streams are not supported in your environment. `ReadableStream` is missing.");
        return F(o.clone(), s.#e.onDownloadProgress);
      }
      return o;
    }, i = s.#f(n).finally(async () => {
      const o = s.#o, u = [];
      o && !o.bodyUsed && u.push(o.body?.cancel()), s.request.bodyUsed || u.push(s.request.body?.cancel()), await Promise.all(u);
    });
    for (const [o, u] of Object.entries(L))
      o === "bytes" && typeof globalThis.Response?.prototype?.bytes != "function" || (i[o] = async () => {
        s.request.headers.set("accept", s.request.headers.get("accept") || u);
        const a = await i;
        if (o === "json") {
          if (a.status === 204)
            return "";
          const h = await a.text();
          return h === "" ? "" : r.parseJson ? r.parseJson(h) : JSON.parse(h);
        }
        return a[o]();
      });
    return i;
  }
  // eslint-disable-next-line unicorn/prevent-abbreviations
  static #d(e) {
    return e && typeof e == "object" && !Array.isArray(e) && !(e instanceof URLSearchParams) ? Object.fromEntries(Object.entries(e).filter(([, r]) => r !== void 0)) : e;
  }
  request;
  #s;
  #r = 0;
  // eslint-disable-next-line @typescript-eslint/prefer-readonly -- False positive: #input is reassigned on line 202
  #t;
  #e;
  #o;
  #n;
  #i;
  // eslint-disable-next-line complexity
  constructor(e, r = {}) {
    if (this.#t = e, this.#e = {
      ...r,
      headers: k(this.#t.headers, r.headers),
      hooks: O({
        beforeRequest: [],
        beforeRetry: [],
        beforeError: [],
        afterResponse: []
      }, r.hooks),
      method: B(r.method ?? this.#t.method ?? "GET"),
      // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
      prefixUrl: String(r.prefixUrl || ""),
      retry: _(r.retry),
      throwHttpErrors: r.throwHttpErrors ?? !0,
      timeout: r.timeout ?? 1e4,
      fetch: r.fetch ?? globalThis.fetch.bind(globalThis),
      context: r.context ?? {}
    }, typeof this.#t != "string" && !(this.#t instanceof URL || this.#t instanceof globalThis.Request))
      throw new TypeError("`input` must be a string, URL, or Request");
    if (this.#e.prefixUrl && typeof this.#t == "string") {
      if (this.#t.startsWith("/"))
        throw new Error("`input` must not begin with a slash when using `prefixUrl`");
      this.#e.prefixUrl.endsWith("/") || (this.#e.prefixUrl += "/"), this.#t = this.#e.prefixUrl + this.#t;
    }
    j && q && (this.#n = this.#e.signal ?? this.#t.signal, this.#s = new globalThis.AbortController(), this.#e.signal = this.#n ? AbortSignal.any([this.#n, this.#s.signal]) : this.#s.signal), R && (this.#e.duplex = "half"), this.#e.json !== void 0 && (this.#e.body = this.#e.stringifyJson?.(this.#e.json) ?? JSON.stringify(this.#e.json), this.#e.headers.set("content-type", this.#e.headers.get("content-type") ?? "application/json"));
    const s = r.headers && new globalThis.Headers(r.headers).has("content-type");
    if (this.#t instanceof globalThis.Request && (C && this.#e.body instanceof globalThis.FormData || this.#e.body instanceof URLSearchParams) && !s && this.#e.headers.delete("content-type"), this.request = new globalThis.Request(this.#t, this.#e), K(this.#e.searchParams)) {
      const i = "?" + (typeof this.#e.searchParams == "string" ? this.#e.searchParams.replace(/^\?/, "") : new URLSearchParams(f.#d(this.#e.searchParams)).toString()), o = this.request.url.replace(/(?:\?.*?)?(?=#|$)/, i);
      this.request = new globalThis.Request(o, this.#e);
    }
    if (this.#e.onUploadProgress) {
      if (typeof this.#e.onUploadProgress != "function")
        throw new TypeError("The `onUploadProgress` option must be a function");
      if (!R)
        throw new Error("Request streams are not supported in your environment. The `duplex` option for `Request` is not available.");
      this.request = this.#l(this.request, this.#e.body ?? void 0);
    }
  }
  #u() {
    const e = this.#e.retry.delay(this.#r);
    let r = e;
    return this.#e.retry.jitter === !0 ? r = Math.random() * e : typeof this.#e.retry.jitter == "function" && (r = this.#e.retry.jitter(e), (!Number.isFinite(r) || r < 0) && (r = e)), Math.min(this.#e.retry.backoffLimit, r);
  }
  async #y(e) {
    if (this.#r++, this.#r > this.#e.retry.limit)
      throw e;
    const r = e instanceof Error ? e : new x(e);
    if (r instanceof y)
      return r.customDelay ?? this.#u();
    if (!this.#e.retry.methods.includes(this.request.method.toLowerCase()))
      throw e;
    if (this.#e.retry.shouldRetry !== void 0) {
      const s = await this.#e.retry.shouldRetry({ error: r, retryCount: this.#r });
      if (s === !1)
        throw e;
      if (s === !0)
        return this.#u();
    }
    if (Z(e) && !this.#e.retry.retryOnTimeout)
      throw e;
    if (Q(e)) {
      if (!this.#e.retry.statusCodes.includes(e.response.status))
        throw e;
      const s = e.response.headers.get("Retry-After") ?? e.response.headers.get("RateLimit-Reset") ?? e.response.headers.get("X-RateLimit-Retry-After") ?? e.response.headers.get("X-RateLimit-Reset") ?? e.response.headers.get("X-Rate-Limit-Reset");
      if (s && this.#e.retry.afterStatusCodes.includes(e.response.status)) {
        let n = Number(s) * 1e3;
        Number.isNaN(n) ? n = Date.parse(s) - Date.now() : n >= Date.parse("2024-01-01") && (n -= Date.now());
        const i = this.#e.retry.maxRetryAfter ?? n;
        return n < i ? n : i;
      }
      if (e.response.status === 413)
        throw e;
    }
    return this.#u();
  }
  #c(e) {
    return this.#e.parseJson && (e.json = async () => this.#e.parseJson(await e.text())), e;
  }
  async #f(e) {
    try {
      return await e();
    } catch (r) {
      const s = Math.min(await this.#y(r), p);
      if (this.#r < 1)
        throw r;
      if (await Y(s, this.#n ? { signal: this.#n } : {}), r instanceof y && r.customRequest) {
        const n = this.#e.signal ? new globalThis.Request(r.customRequest, { signal: this.#e.signal }) : new globalThis.Request(r.customRequest);
        this.#h(n);
      }
      for (const n of this.#e.hooks.beforeRetry) {
        const i = await n({
          request: this.request,
          options: this.#a(),
          error: r,
          retryCount: this.#r
        });
        if (i instanceof globalThis.Request) {
          this.#h(i);
          break;
        }
        if (i instanceof globalThis.Response)
          return i;
        if (i === E)
          return;
      }
      return this.#f(e);
    }
  }
  async #p() {
    this.#s?.signal.aborted && (this.#s = new globalThis.AbortController(), this.#e.signal = this.#n ? AbortSignal.any([this.#n, this.#s.signal]) : this.#s.signal, this.request = new globalThis.Request(this.request, { signal: this.#e.signal }));
    for (const r of this.#e.hooks.beforeRequest) {
      const s = await r(this.request, this.#a(), { retryCount: this.#r });
      if (s instanceof Response)
        return s;
      if (s instanceof globalThis.Request) {
        this.#h(s);
        break;
      }
    }
    const e = G(this.request, this.#e);
    return this.#o = this.request, this.request = this.#o.clone(), this.#e.timeout === !1 ? this.#e.fetch(this.#o, e) : X(this.#o, e, this.#s, this.#e);
  }
  #a() {
    if (!this.#i) {
      const { hooks: e, ...r } = this.#e;
      this.#i = Object.freeze(r);
    }
    return this.#i;
  }
  #h(e) {
    this.#i = void 0, this.request = this.#l(e);
  }
  #l(e, r) {
    return !this.#e.onUploadProgress || !e.body ? e : M(e, this.#e.onUploadProgress, r ?? this.#e.body ?? void 0);
  }
}
const b = (t) => {
  const e = (r, s) => f.create(r, l(t, s));
  for (const r of S)
    e[r] = (s, n) => f.create(s, l(t, n, { method: r }));
  return e.create = (r) => b(l(r)), e.extend = (r) => (typeof r == "function" && (r = r(t ?? {})), b(l(t, r))), e.stop = E, e.retry = D, e;
}, ee = b();
function te(t = {}) {
  return ee.create(t);
}
export {
  te as createHttpClient
};
//# sourceMappingURL=http.mjs.map
