{"version":3,"file":"index.mjs","sources":[""],"sourcesContent":["\r\nimport { getDocument, getWindow } from \"ssr-window\";\nimport { bubble } from \"../../evt/bubble/index.ts\";\nimport { getObjFromFormData } from \"../../obj/getObjFromFormData/index.ts\";\nimport { getFormDataFromObj } from \"../getFormDataFromObj/index.ts\";\nimport { getUrlWithQueryParams } from \"../getUrlWithQueryParams/index.ts\";\n\nexport type TGetFromServerArgs<TResp = unknown, TSuccess = TResp> = {\n  contentType?: \"auto\" | \"application/json\" | \"application/x-www-form-urlencoded\" | \"multipart/form-data\";\n  isBubble?: boolean;\n  timeout?: number;\n  method?: \"GET\" | \"PUT\" | \"POST\" | \"DELETE\" | \"HEAD\" | \"CONNECT\" | \"OPTIONS\" | \"TRACE\" | \"PATCH\";\n  mode?: RequestMode;\n  signal?: AbortSignal | null;\n  data?: Record<string, unknown> | FormData | null;\n  getSuccessResp?: (data: TResp) => TSuccess;\n  getResp?: (resp: Response) => Promise<TResp>;\n  type?: \"text\" | \"json\" | \"blob\" | \"arrayBuffer\";\n  url?: string;\n  headers?: Record<string, string>;\n  allowedCodes?: number[];\n  credentials?: RequestCredentials;\n  redirect?: RequestRedirect;\r\n  cache?: RequestCache;\r\n  referrerPolicy?: ReferrerPolicy;\r\n  fetchProps?: Omit<RequestInit, \"method\" | \"headers\" | \"body\" | \"signal\" | \"mode\" | \"credentials\" | \"redirect\" | \"cache\" | \"referrerPolicy\">;\r\n};\r\n\r\nexport type TGetFromServerReturn = ReturnType<typeof getFromServer>;\r\n\r\n/**\r\n * Performs an HTTP request (`fetch`) with handy defaults, content-type handling,\r\n * query param building, and optional bubbling of a \"getFromServer\" event.\r\n *\r\n * @template T The expected response data type.\r\n * @param {Object} [props] Request parameters (all optional).\r\n * @param {string} [props.url] The URL to request. Defaults to current window location or './'.\r\n * @param {(\"auto\"|\"application/json\"|\"application/x-www-form-urlencoded\"|\"multipart/form-data\")} [props.contentType=\"auto\"] Content type header. If \"auto\", sets based on data/method.\r\n * @param {boolean} [props.isBubble=true] Whether to bubble a \"getFromServer\" event after success.\r\n * @param {number} [props.timeout=15000] Timeout in milliseconds (use Infinity to disable).\r\n * @param {(\"GET\"|\"PUT\"|\"POST\"|\"DELETE\"|\"HEAD\"|\"CONNECT\"|\"OPTIONS\"|\"TRACE\")} [props.method=\"GET\"] HTTP method.\r\n * @param {RequestMode} [props.mode=\"cors\"] Fetch mode.\r\n * @param {AbortSignal|null} [props.signal=null] AbortSignal for cancellation.\r\n * @param {Record<string,unknown>|FormData|null} [props.data=null] Request data. For GET-like methods, appended as query params.\r\n * @param {function(T): T} [props.getSuccessResp] Transform function for successful response. Defaults to identity function.\r\n * @param {function(Response): Promise<T>} [props.getResp] Custom response parser. If provided, overrides `type`.\r\n * @param {(\"text\"|\"json\"|\"blob\"|\"arrayBuffer\")} [props.type=\"json\"] Response body parsing type (used when `getResp` not provided).\r\n * @param {Record<string,string>} [props.headers={}] Additional headers.\r\n * @param {number[]} [props.allowedCodes=[]] Array of HTTP status codes to treat as success even if not 2xx.\r\n * @param {RequestCredentials} [props.credentials=\"same-origin\"] Credentials mode.\r\n * @param {RequestRedirect} [props.redirect=\"follow\"] Redirect mode.\r\n * @param {RequestCache} [props.cache=\"default\"] Cache mode.\r\n * @param {ReferrerPolicy} [props.referrerPolicy=\"no-referrer-when-downgrade\"] Referrer policy.\r\n * @param {Omit<RequestInit, \"method\"|\"headers\"|\"body\"|\"signal\"|\"mode\"|\"credentials\"|\"redirect\"|\"cache\"|\"referrerPolicy\">} [props.fetchProps={}] Additional fetch options.\r\n * @returns {Promise<T>} Promise with parsed response (type depends on `type` option).\r\n * @throws {TypeError} getFromServer: url must be a string\n * @throws {TypeError} getFromServer: allowedCodes must be an array of integers\n * @throws {TypeError} getFromServer: data must be a plain object, FormData, or null\n * @throws {TypeError} getFromServer: timeout must be a non-negative number or Infinity\n * @see https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API\n * @example\n * const user = await getFromServer<{ userId: number }>({ url: \"/api/user?id=1\", method: \"GET\" });\n */\nexport const getFromServer = async <TResp = unknown, TSuccess = TResp>(\n  props: TGetFromServerArgs<TResp, TSuccess> = {}\n): Promise<TSuccess> => {\n  const {\n    contentType = \"auto\",\n    isBubble = true,\n    timeout = 15000,\n    method = \"GET\",\n    mode = \"cors\",\n    signal = null,\n    data = null,\n    getResp,\n    type = \"json\",\n    url = getWindow().location.href || \"./\",\n    headers = {},\n    allowedCodes = [],\n    credentials = \"same-origin\",\r\n    redirect = \"follow\",\r\n    referrerPolicy = \"no-referrer-when-downgrade\",\r\n    cache = \"default\",\n    fetchProps = {},\n  } = props;\n\n  const getSuccessResp = props.getSuccessResp ?? ((resp: TResp) => resp as unknown as TSuccess);\n  const methodNormalized = String(method).toUpperCase() as Uppercase<typeof method>;\n  const methodsWithBody = new Set([\n    \"POST\",\n    \"PUT\",\n    \"DELETE\",\n    \"PATCH\",\n  ]);\n  const methodsNoBody = new Set([\n    \"GET\",\n    \"HEAD\",\n    \"CONNECT\",\n    \"OPTIONS\",\n    \"TRACE\",\n  ]);\n  const isFormData = (v: unknown): v is FormData => typeof FormData !== \"undefined\" && v instanceof FormData;\n  const isPlainObject = (v: unknown): v is Record<string, unknown> => {\n    return Object.prototype.toString.call(v) === \"[object Object]\";\n  };\n\n  if (typeof url !== \"string\") {\n    throw new TypeError(\"getFromServer: url must be a string\");\n  }\n\n  if (!Array.isArray(allowedCodes) || !allowedCodes.every((c) => Number.isInteger(c))) {\n    throw new TypeError(\"getFromServer: allowedCodes must be an array of integers\");\n  }\n\n  if (typeof timeout !== \"number\" || (Number.isFinite(timeout) && timeout < 0) || Number.isNaN(timeout)) {\n    throw new TypeError(\"getFromServer: timeout must be a non-negative number or Infinity\");\n  }\n\n  if (data !== null && !isFormData(data) && !isPlainObject(data)) {\n    throw new TypeError(\"getFromServer: data must be a plain object, FormData, or null\");\n  }\n\n  let timer: ReturnType<typeof setTimeout> | null = null;\n  let isTimedOut = false;\n  const requestController = new AbortController();\n  const externalAbortListener = (): void => {\n    requestController.abort();\n  };\n  if (signal) {\n    if (signal.aborted) {\n      externalAbortListener();\n    } else {\n      signal.addEventListener(\"abort\", externalAbortListener, { once: true });\n    }\n  }\n\n  const getDataAsObject = (): Record<string, unknown> => {\n    return isFormData(data) ? getObjFromFormData(data) : (data ?? {});\n  };\n\n  /**\n   * Produces request body based on contentType and data\n   * @private\n   * @returns {BodyInit | null}\n   */\n  const getBody = (): BodyInit | null => {\n    if (!methodsWithBody.has(methodNormalized)) {\n      return null;\n    }\n\n    switch (true) {\n      case contentType === \"application/json\":\n        return JSON.stringify(getDataAsObject());\n      case contentType === \"application/x-www-form-urlencoded\": {\n        const params = new URLSearchParams();\n        Object.entries(getDataAsObject())\n          .forEach(([ key, value ]) => {\n            params.set(key, String(value ?? \"\"));\n          });\n        return params.toString();\n      }\n      case contentType === \"multipart/form-data\":\n        return isFormData(data)\n          ? data\n          : getFormDataFromObj(getDataAsObject());\n      case contentType === \"auto\":\n        return isFormData(data)\n          ? data\n          : getFormDataFromObj(getDataAsObject());\n      default:\n        return null;\n    }\n  };\n\n  /**\r\n   * URL builder (adds query params for GET-like methods)\n   * @private\n   */\n  const getUrl = (): string => {\n    return (methodsNoBody.has(methodNormalized) && data !== null)\n      ? getUrlWithQueryParams(\n        url, isFormData(data)\n          ? data\n          : (data as Record<string, string | number | boolean | null>)\n      )\n      : url;\r\n  };\r\n\r\n  /**\r\n   * Response parser\n   * @private\n   */\n  const getResponse = async (resp: Response): Promise<TResp> => {\n    if (typeof getResp === \"function\") {\n      return await getResp(resp);\n    }\n    const { ok, status } = resp;\n    if (ok || (allowedCodes.length > 0 && allowedCodes.includes(status))) {\n      switch (type) {\n        case \"arrayBuffer\": return await resp.arrayBuffer() as unknown as TResp;\n        case \"json\": return await resp.json() as TResp;\n        case \"blob\": return await resp.blob() as unknown as TResp;\n        default: return await resp.text() as unknown as TResp;\n      }\n    }\n    throw resp;\n  };\n\n  /**\n   * Headers builder\n   * @private\n   */\r\n  const getHeaders = (): Record<string, string> => {\n    const result: Record<string, string> = { ...(headers || {}) };\n    if (contentType === \"multipart/form-data\") {\n      Object.keys(result).forEach((key) => {\n        if (key.toLowerCase() === \"content-type\") {\n          delete result[key];\n        }\n      });\n      return result;\n    }\n    if ([ \"application/json\", \"application/x-www-form-urlencoded\" ].includes(contentType)) {\n      result[\"Content-Type\"] = contentType;\n    }\n    return result;\n  };\n\n  if (timeout && timeout !== Infinity) {\n    timer = setTimeout(() => {\n      isTimedOut = true;\n      requestController.abort();\n    }, timeout);\n  }\n\n  const fetchParams: RequestInit = {\n    ...fetchProps,\n    method: methodNormalized,\n    body: getBody(),\n    mode,\n    signal: requestController.signal,\n    credentials,\n    redirect,\n    cache,\n    referrerPolicy,\n    headers: getHeaders(),\n  };\n\n  try {\n    const resp = await fetch(getUrl(), fetchParams);\n    const parsed = await getResponse(resp);\n\n    if (isBubble && typeof window !== \"undefined\") {\n      bubble(getDocument(), getFromServer.name, parsed);\n    }\n\n    return getSuccessResp(parsed);\n  } catch (error) {\n    if (isTimedOut) {\n      throw 408;\n    }\n    throw error;\n  } finally {\n    if (timer) {\n      clearTimeout(timer);\n    }\n    if (signal) {\n      signal.removeEventListener(\"abort\", externalAbortListener);\n    }\n  }\n};\n"],"names":["getFromServer","async","props","contentType","isBubble","timeout","method","mode","signal","data","getResp","type","url","getWindow","location","href","headers","allowedCodes","credentials","redirect","referrerPolicy","cache","fetchProps","getSuccessResp","resp","methodNormalized","String","toUpperCase","methodsWithBody","Set","methodsNoBody","isFormData","v","FormData","isPlainObject","Object","prototype","toString","call","TypeError","Array","isArray","every","c","Number","isInteger","isFinite","isNaN","timer","isTimedOut","requestController","AbortController","externalAbortListener","abort","aborted","addEventListener","once","getDataAsObject","getObjFromFormData","getBody","has","JSON","stringify","params","URLSearchParams","entries","forEach","key","value","set","getFormDataFromObj","getUrl","getUrlWithQueryParams","getResponse","ok","status","length","includes","arrayBuffer","json","blob","text","getHeaders","result","keys","toLowerCase","Infinity","setTimeout","fetchParams","body","fetch","parsed","window","bubble","getDocument","name","error","clearTimeout","removeEventListener"],"mappings":"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"}