{"version":3,"file":"fetchAllPaginated-CodywQBm.mjs","names":[],"sources":["../src/api/ApiError.ts","../src/api/fetchJson.ts","../src/api/fetchAllPaginated.ts"],"sourcesContent":["/**\n * Error thrown by the API layer when a request resolves with a non-2xx status.\n * Carries the HTTP status so callers can branch (e.g. distinguish 401/403 from\n * 5xx) instead of collapsing every failure into one generic message.\n */\nexport class ApiError extends Error {\n  public readonly status: number\n\n  /**\n   * Creates an ApiError carrying the failed response status.\n   * @param {number} status - The HTTP status code of the failed response.\n   * @param {string} message - A human-readable error message.\n   */\n  public constructor(status: number, message: string) {\n    super(message)\n    this.name = 'ApiError'\n    this.status = status\n  }\n}\n","import { ApiError } from './ApiError'\n\n/**\n * Fetches JSON from a URL using Staffbase session credentials.\n *\n * Throws {@link ApiError} (carrying the HTTP status) on a non-2xx response so\n * callers can branch on the status. Network/parse errors propagate as-is. This\n * helper does not log; the calling service layer owns error logging.\n * @template T The expected shape of the parsed JSON body.\n * @param {string} url - The API URL to fetch.\n * @param {RequestInit} [init] - Optional fetch overrides (merged after credentials).\n * @returns {Promise<T>} The parsed JSON body.\n * @throws {ApiError} When the response status is not ok.\n */\nexport const fetchJson = async <T>(\n  url: string,\n  init?: RequestInit,\n): Promise<T> => {\n  const response = await fetch(url, { credentials: 'include', ...init })\n\n  if (!response.ok) {\n    throw new ApiError(\n      response.status,\n      `API request failed with status: ${response.status}`,\n    )\n  }\n\n  return (await response.json()) as T\n}\n","import type { FetchAllPaginatedOptions } from '../types/api/FetchAllPaginatedOptions'\nimport { fetchJson } from './fetchJson'\n\nconst DEFAULT_LIMIT = 50\nconst DEFAULT_MAX_PAGES = 1000\n\n/**\n * Fetches every page of a Staffbase `{ data, total }` collection endpoint.\n *\n * Termination is driven by page contents (a short page ends the loop) rather\n * than the API's reported `total`, which avoids under-fetching when `total` is\n * under-reported. A `maxPages` cap bounds worst-case latency/memory; reaching it\n * invokes `onError` so the truncation is never silent.\n * @template TItem The mapped item type returned to the caller.\n * @template TSource The raw item type returned by the API before mapping.\n * @param {string} baseUrl - The base API URL (without limit/offset parameters).\n * @param {FetchAllPaginatedOptions<TItem, TSource>} [options] - Mapping and pagination options.\n * @returns {Promise<TItem[]>} All fetched (and optionally mapped) items.\n */\nexport const fetchAllPaginated = async <TItem, TSource = TItem>(\n  baseUrl: string,\n  options: FetchAllPaginatedOptions<TItem, TSource> = {},\n): Promise<TItem[]> => {\n  const {\n    mapItem,\n    limit = DEFAULT_LIMIT,\n    includeDrafts = false,\n    maxPages = DEFAULT_MAX_PAGES,\n    onError,\n  } = options\n\n  const results: TItem[] = []\n  let offset = 0\n  let page = 0\n\n  while (page < maxPages) {\n    const separator = baseUrl.includes('?') ? '&' : '?'\n    const draftsParam = includeDrafts ? '&includeDrafts=true' : ''\n    const url = `${baseUrl}${separator}limit=${limit}&offset=${offset}${draftsParam}`\n\n    const data = await fetchJson<{ data: TSource[]; total?: number }>(url)\n    const rawItems = data.data ?? []\n\n    if (rawItems.length === 0) break\n\n    const mapped = mapItem\n      ? rawItems.map(mapItem).filter((item): item is TItem => item !== null)\n      : (rawItems as unknown as TItem[])\n\n    results.push(...mapped)\n\n    // A short page means we reached the end of the collection.\n    if (rawItems.length < limit) break\n\n    offset += limit\n    page += 1\n  }\n\n  if (page >= maxPages) {\n    onError?.(\n      `Pagination cap (${maxPages} pages) reached for ${baseUrl}; results may be truncated.`,\n    )\n  }\n\n  return results\n}\n"],"mappings":";AAKA,IAAa,IAAb,cAA8B,MAAM;CAClC;CAOA,YAAmB,GAAgB,GAAiB;EAGlD,AAFA,MAAM,CAAO,GACb,KAAK,OAAO,YACZ,KAAK,SAAS;CAChB;AACF,GCJa,IAAY,OACvB,GACA,MACe;CACf,IAAM,IAAW,MAAM,MAAM,GAAK;EAAE,aAAa;EAAW,GAAG;CAAK,CAAC;CAErE,IAAI,CAAC,EAAS,IACZ,MAAM,IAAI,EACR,EAAS,QACT,mCAAmC,EAAS,QAC9C;CAGF,OAAQ,MAAM,EAAS,KAAK;AAC9B,GCzBM,IAAgB,IAChB,IAAoB,KAeb,IAAoB,OAC/B,GACA,IAAoD,CAAC,MAChC;CACrB,IAAM,EACJ,YACA,WAAQ,GACR,mBAAgB,IAChB,cAAW,GACX,eACE,GAEE,IAAmB,CAAC,GACtB,IAAS,GACT,IAAO;CAEX,OAAO,IAAO,IAAU;EAMtB,IAAM,KAAW,MADE,EAA+C,GAFnD,IAFG,EAAQ,SAAS,GAAG,IAAI,MAAM,IAEb,QAAQ,EAAM,UAAU,IADvC,IAAgB,wBAAwB,IAGS,GAC/C,QAAQ,CAAC;EAE/B,IAAI,EAAS,WAAW,GAAG;EAE3B,IAAM,IAAS,IACX,EAAS,IAAI,CAAO,EAAE,QAAQ,MAAwB,MAAS,IAAI,IAClE;EAKL,IAHA,EAAQ,KAAK,GAAG,CAAM,GAGlB,EAAS,SAAS,GAAO;EAG7B,AADA,KAAU,GACV,KAAQ;CACV;CAQA,OANI,KAAQ,KACV,IACE,mBAAmB,EAAS,sBAAsB,EAAQ,4BAC5D,GAGK;AACT"}