{"version":3,"file":"index.mjs","names":[],"sources":["../src/utils.ts","../src/sbFetch.ts","../src/constants.ts","../src/rateLimit.ts","../src/throttlePromise.ts","../src/throttleQueueManager.ts","../src/index.ts"],"sourcesContent":["import type { AsyncFn, HtmlEscapes, ISbResult, ISbStoriesParams } from \"./interfaces\";\n\n// TODO: Revise this type, is it needed?\ninterface ISbParams extends ISbStoriesParams {\n  [key: string]: any;\n}\n\ntype ArrayFn = (...args: any) => void;\ntype FlatMapFn = (...args: any) => [] | any;\ntype RangeFn = (...args: any) => [];\n\n/**\n * Checks if a URL is a CDN URL\n * @param url - The URL to check\n * @returns boolean indicating if the URL is a CDN URL\n */\nexport const isCDNUrl = (url = \"\"): boolean => url.includes(\"/cdn/\");\n\n/**\n * Gets pagination options for the API request\n * @param options - The base options\n * @param perPage - Number of items per page\n * @param page - Current page number\n * @returns Object with pagination options\n */\nexport const getOptionsPage = (options: ISbStoriesParams, perPage = 25, page = 1) => ({\n  ...options,\n  per_page: perPage,\n  page,\n});\n\n/**\n * Creates a promise that resolves after the specified milliseconds\n * @param ms - Milliseconds to delay\n * @returns Promise that resolves after the delay\n */\nexport const delay = (ms: number): Promise<void> => new Promise((res) => setTimeout(res, ms));\n\n/**\n * Creates an array of specified length using a mapping function\n * @param length - Length of the array\n * @param func - Mapping function\n * @returns Array of specified length\n */\nexport const arrayFrom = (length = 0, func: ArrayFn) => Array.from({ length }, func);\n\n/**\n * Creates an array of numbers in the specified range\n * @param start - Start of the range\n * @param end - End of the range\n * @returns Array of numbers in the range\n */\nexport const range = (start = 0, end = start): Array<any> => {\n  const length = Math.abs(end - start) || 0;\n  const step = start < end ? 1 : -1;\n  return arrayFrom(length, (_, i: number) => i * step + start);\n};\n\n/**\n * Maps an array asynchronously\n * @param arr - Array to map\n * @param func - Async mapping function\n * @returns Promise resolving to mapped array\n */\nexport const asyncMap = async (arr: RangeFn[], func: AsyncFn) => Promise.all(arr.map(func));\n\n/**\n * Flattens an array using a mapping function\n * @param arr - Array to flatten\n * @param func - Mapping function\n * @returns Flattened array\n */\nexport const flatMap = (arr: ISbResult[] = [], func: FlatMapFn) =>\n  arr.map(func).reduce((xs, ys) => [...xs, ...ys], []);\n\n/**\n * Decodes a string if it appears to be URL-encoded.\n * Detects common encoded characters (%2C for comma, %20 for space, etc.)\n * @param value - The string to potentially decode\n * @returns The decoded string, or the original if not encoded\n */\nexport const decodeIfEncoded = (value: string): string => {\n  // Check if the string contains URL-encoded characters (% followed by hex digits)\n  if (/%[0-9A-F]{2}/i.test(value)) {\n    try {\n      return decodeURIComponent(value);\n    } catch {\n      // If decoding fails (malformed encoding), return original\n      return value;\n    }\n  }\n  return value;\n};\n\n/**\n * Stringifies an object into a URL query string\n * @param params - Parameters to stringify\n * @param prefix - Prefix for nested keys\n * @param isArray - Whether the current level is an array\n * @returns Stringified query parameters\n */\nexport const stringify = (params: ISbParams, prefix?: string, isArray?: boolean): string => {\n  const pairs: string[] = [];\n  for (const key in params) {\n    if (!Object.prototype.hasOwnProperty.call(params, key)) {\n      continue;\n    }\n    const value = params[key];\n    if (value === null || value === undefined) {\n      continue;\n    }\n    const enkey = isArray ? \"\" : encodeURIComponent(key);\n    let pair;\n    if (typeof value === \"object\") {\n      pair = stringify(value, prefix ? `${prefix}[${enkey}]` : enkey, Array.isArray(value));\n    } else {\n      pair = `${prefix ? `${prefix}[${enkey}]` : enkey}=${encodeURIComponent(value)}`;\n    }\n    pairs.push(pair);\n  }\n  return pairs.join(\"&\");\n};\n\n/**\n * Gets the base URL for a specific region\n * @param regionCode - Region code (eu, us, cn, ap, ca)\n * @returns Base URL for the region\n */\nexport const getRegionURL = (regionCode?: string): string => {\n  const REGION_URLS = {\n    eu: \"api.storyblok.com\",\n    us: \"api-us.storyblok.com\",\n    cn: \"app.storyblokchina.cn\",\n    ap: \"api-ap.storyblok.com\",\n    ca: \"api-ca.storyblok.com\",\n  } as const;\n\n  return REGION_URLS[regionCode as keyof typeof REGION_URLS] ?? REGION_URLS.eu;\n};\n\n/**\n * Escapes HTML special characters in a string\n * @param string - String to escape\n * @returns Escaped string\n */\nexport const escapeHTML = (string: string): string => {\n  const htmlEscapes = {\n    \"&\": \"&amp;\",\n    \"<\": \"&lt;\",\n    \">\": \"&gt;\",\n    '\"': \"&quot;\",\n    \"'\": \"&#39;\",\n  } as HtmlEscapes;\n\n  const reUnescapedHtml = /[&<>\"']/g;\n  const reHasUnescapedHtml = new RegExp(reUnescapedHtml.source);\n\n  return string && reHasUnescapedHtml.test(string)\n    ? string.replace(reUnescapedHtml, (chr) => htmlEscapes[chr])\n    : string;\n};\n","import { stringify } from \"./utils\";\n\nimport type { ISbCustomFetch, ISbError, ISbResponse, ISbStoriesParams } from \"./interfaces\";\nimport type Method from \"./constants\";\n\nexport interface ResponseFn {\n  (arg?: ISbResponse | any): any;\n}\n\nexport interface ISbFetch {\n  baseURL: string;\n  timeout?: number;\n  headers: Headers;\n  responseInterceptor?: ResponseFn;\n  fetch?: typeof fetch;\n}\n\nclass SbFetch {\n  private baseURL: string;\n  private timeout?: number;\n  private headers: Headers;\n  private responseInterceptor?: ResponseFn;\n  private fetch: typeof fetch;\n  private ejectInterceptor?: boolean;\n  private url: string;\n  private parameters: ISbStoriesParams;\n  private fetchOptions: ISbCustomFetch;\n\n  public constructor($c: ISbFetch) {\n    this.baseURL = $c.baseURL;\n    this.headers = $c.headers || new Headers();\n    this.timeout = $c?.timeout ? $c.timeout * 1000 : 0;\n    this.responseInterceptor = $c.responseInterceptor;\n    this.fetch = (...args: [any]) => ($c.fetch ? $c.fetch(...args) : fetch(...args));\n    this.ejectInterceptor = false;\n    this.url = \"\";\n    this.parameters = {} as ISbStoriesParams;\n    this.fetchOptions = {};\n  }\n\n  /**\n   *\n   * @param url string\n   * @param params ISbStoriesParams\n   * @returns Promise<ISbResponse | Error>\n   */\n  public get(url: string, params: ISbStoriesParams) {\n    this.url = url;\n    this.parameters = params;\n    return this._methodHandler(\"get\");\n  }\n\n  public post(url: string, params: ISbStoriesParams) {\n    this.url = url;\n    this.parameters = params;\n    return this._methodHandler(\"post\");\n  }\n\n  public put(url: string, params: ISbStoriesParams) {\n    this.url = url;\n    this.parameters = params;\n    return this._methodHandler(\"put\");\n  }\n\n  public patch(url: string, params: ISbStoriesParams) {\n    this.url = url;\n    this.parameters = params;\n    return this._methodHandler(\"patch\");\n  }\n\n  public delete(url: string, params?: ISbStoriesParams) {\n    this.url = url;\n    this.parameters = params ?? ({} as ISbStoriesParams);\n    return this._methodHandler(\"delete\");\n  }\n\n  private async _responseHandler(res: Response) {\n    const headers: string[] = [];\n    const response = {\n      data: {},\n      headers: {},\n      status: 0,\n      statusText: \"\",\n    };\n\n    if (res.status !== 204) {\n      await res.json().then(($r) => {\n        response.data = $r;\n      });\n    }\n\n    for (const pair of res.headers.entries()) {\n      headers[pair[0] as any] = pair[1];\n    }\n\n    response.headers = { ...headers };\n    response.status = res.status;\n    response.statusText = res.statusText;\n\n    return response;\n  }\n\n  private async _methodHandler(method: Method): Promise<ISbResponse | ISbError> {\n    let urlString = `${this.baseURL}${this.url}`;\n\n    let body: string | null = null;\n\n    if (method === \"get\") {\n      urlString = `${this.baseURL}${this.url}?${stringify(this.parameters)}`;\n    } else {\n      body = JSON.stringify(this.parameters);\n    }\n\n    const url = new URL(urlString);\n\n    const controller = new AbortController();\n    const { signal } = controller;\n\n    let timeout: ReturnType<typeof setTimeout> | null = null;\n\n    if (this.timeout) {\n      timeout = setTimeout(() => controller.abort(), this.timeout);\n    }\n\n    try {\n      const fetchResponse = await this.fetch(`${url}`, {\n        method,\n        headers: this.headers,\n        body,\n        signal,\n        ...this.fetchOptions,\n      });\n\n      if (this.timeout && timeout) {\n        clearTimeout(timeout);\n      }\n\n      const response = (await this._responseHandler(fetchResponse)) as ISbResponse;\n\n      if (this.responseInterceptor && !this.ejectInterceptor) {\n        return this._statusHandler(this.responseInterceptor(response));\n      } else {\n        return this._statusHandler(response);\n      }\n    } catch (err: any) {\n      // Check if it's a timeout/abort error\n      if (err.name === \"AbortError\") {\n        const error: ISbError = {\n          message: \"Request timeout: The request was aborted due to timeout\",\n        };\n        return error;\n      }\n\n      // For other errors, try to extract a meaningful message\n      const error: ISbError = {\n        message: err.message || err.toString() || \"An unknown error occurred\",\n      };\n      return error;\n    }\n  }\n\n  public setFetchOptions(fetchOptions: ISbCustomFetch = {}) {\n    if (Object.keys(fetchOptions).length > 0 && \"method\" in fetchOptions) {\n      delete fetchOptions.method;\n    }\n    this.fetchOptions = { ...fetchOptions };\n  }\n\n  public eject() {\n    this.ejectInterceptor = true;\n  }\n\n  /**\n   * Normalizes error messages from different response structures\n   * @param data The response data that might contain error information\n   * @returns A normalized error message string\n   */\n  private _normalizeErrorMessage(data: any): string {\n    // Handle array of error messages\n    if (Array.isArray(data)) {\n      return data[0] || \"Unknown error\";\n    }\n\n    // Handle object with error property\n    if (data && typeof data === \"object\") {\n      // Check for common error message patterns\n      if (data.error) {\n        return data.error;\n      }\n\n      // Handle nested error objects (like { name: ['has already been taken'] })\n      for (const key in data) {\n        if (Array.isArray(data[key])) {\n          return `${key}: ${data[key][0]}`;\n        }\n        if (typeof data[key] === \"string\") {\n          return `${key}: ${data[key]}`;\n        }\n      }\n\n      // If we have a slug, it might be an error message\n      if (data.slug) {\n        return data.slug;\n      }\n    }\n\n    // Fallback for unknown error structures\n    return \"Unknown error\";\n  }\n\n  private _statusHandler(res: ISbResponse): Promise<ISbResponse | ISbError> {\n    const statusOk = /20[0-6]/g;\n\n    return new Promise((resolve, reject) => {\n      if (statusOk.test(`${res.status}`)) {\n        return resolve(res);\n      }\n\n      const error: ISbError = {\n        message: this._normalizeErrorMessage(res.data),\n        status: res.status,\n        response: res,\n      };\n\n      reject(error);\n    });\n  }\n}\n\nexport default SbFetch;\n","const _METHOD = {\n  GET: \"get\",\n  DELETE: \"delete\",\n  POST: \"post\",\n  PUT: \"put\",\n  PATCH: \"patch\",\n} as const;\n\ntype ObjectValues<T> = T[keyof T];\ntype Method = ObjectValues<typeof _METHOD>;\n\nexport default Method;\n\nexport const StoryblokContentVersion = {\n  DRAFT: \"draft\",\n  PUBLISHED: \"published\",\n} as const;\n\nexport type StoryblokContentVersionKeys =\n  (typeof StoryblokContentVersion)[keyof typeof StoryblokContentVersion];\n\nexport const StoryblokContentVersionValues = Object.values(\n  StoryblokContentVersion,\n) as StoryblokContentVersionKeys[];\n\n/**\n * Default per_page value for Storyblok API requests\n */\nexport const DEFAULT_PER_PAGE = 25;\n\n/**\n * Per-page tier thresholds for rate limiting\n */\nexport const PER_PAGE_THRESHOLDS = {\n  SMALL: 25,\n  MEDIUM: 50,\n  LARGE: 75,\n} as const;\n","import type { ISbStoriesParams } from \"./interfaces\";\nimport { DEFAULT_PER_PAGE, PER_PAGE_THRESHOLDS } from \"./constants\";\n\nexport interface RateLimitConfig {\n  // User-provided rate limit\n  userRateLimit?: number;\n  // Rate limit determined from server response headers\n  serverHeadersRateLimit?: number;\n  // Whether this is a Management API client (uses oauthToken)\n  isManagementApi?: boolean;\n}\n\nexport interface RateLimitHeaders {\n  remaining?: number;\n  max?: number;\n}\n\n/**\n * Rate limit tiers based on per_page parameter\n * These limits apply to all CDN API requests regardless of version\n */\nconst RATE_LIMIT_TIERS = {\n  SINGLE_OR_SMALL: 50, // Single entries or listings ≤25 entries\n  MEDIUM: 15, // 26-50 entries\n  LARGE: 10, // 51-75 entries\n  VERY_LARGE: 6, // 76-100 entries\n} as const;\n\n/**\n * Maximum rate limit that should never be exceeded\n */\nconst MAX_RATE_LIMIT = 1000;\n\n/**\n * Default rate limit for Management API (when using oauthToken)\n */\nexport const MANAGEMENT_API_DEFAULT_RATE_LIMIT = 3;\n\n/**\n * Determines if a request is for a single story based on URL and params\n */\nfunction isSingleStoryRequest(url: string, params: ISbStoriesParams): boolean {\n  // Single story requests typically have a specific story slug/id in the URL\n  // or use find_by parameter\n  const isCdnStories = url.includes(\"/cdn/stories/\");\n  const hasSpecificPath = url.split(\"/\").length > 3 && !url.endsWith(\"/cdn/stories\");\n  const hasFindBy = \"find_by\" in params;\n\n  return (isCdnStories && hasSpecificPath) || hasFindBy;\n}\n\n/**\n * Calculates the appropriate rate limit tier based on the per_page parameter\n * These tiers match the backend rate limiting logic\n */\nfunction getRateLimitTier(perPage: number): number {\n  if (perPage <= PER_PAGE_THRESHOLDS.SMALL) {\n    return RATE_LIMIT_TIERS.SINGLE_OR_SMALL;\n  } else if (perPage <= PER_PAGE_THRESHOLDS.MEDIUM) {\n    return RATE_LIMIT_TIERS.MEDIUM;\n  } else if (perPage <= PER_PAGE_THRESHOLDS.LARGE) {\n    return RATE_LIMIT_TIERS.LARGE;\n  } else {\n    return RATE_LIMIT_TIERS.VERY_LARGE;\n  }\n}\n\n/**\n * Determines the appropriate rate limit for a request based on:\n * - Request type (single vs listing)\n * - Number of entries (per_page)\n * - User configuration\n * - Server headers\n *\n * Rate limits are based on per_page regardless of version (draft/published).\n * The backend enforces per_page-based rate limits on ALL requests before\n * checking the cache, so cached requests still count against rate limits.\n *\n * When url and params are not provided (Management API), uses the defaultRateLimit\n * as the fallback instead of automatic tier calculation.\n */\nexport function determineRateLimit(\n  url?: string,\n  params?: ISbStoriesParams,\n  config: RateLimitConfig = {},\n  defaultRateLimit?: number,\n): number {\n  // Priority order for all requests:\n  // 1. User-provided rate limit (highest priority, applies to all requests)\n  // 2. Server-provided rate limit (from response headers)\n  // 3. Default rate limit (Management API)\n  // 4. Automatic tier calculation based on per_page (CDN)\n\n  if (config.userRateLimit !== undefined) {\n    return Math.min(config.userRateLimit, MAX_RATE_LIMIT);\n  }\n\n  if (config.serverHeadersRateLimit !== undefined) {\n    return Math.min(config.serverHeadersRateLimit, MAX_RATE_LIMIT);\n  }\n\n  // If a default rate limit is provided (Management API), use it\n  if (defaultRateLimit !== undefined) {\n    return defaultRateLimit;\n  }\n\n  // For CDN API, calculate based on request type and per_page\n  // At this point, url and params should be defined for CDN API calls\n  if (!url || !params) {\n    return RATE_LIMIT_TIERS.SINGLE_OR_SMALL;\n  }\n\n  // Single story requests\n  if (isSingleStoryRequest(url, params)) {\n    return RATE_LIMIT_TIERS.SINGLE_OR_SMALL;\n  }\n\n  // For listings, determine tier based on per_page\n  const perPage = params.per_page || DEFAULT_PER_PAGE;\n  return getRateLimitTier(perPage);\n}\n\n/**\n * Parses X-RateLimit and X-RateLimit-Policy headers from the response\n *\n * Example headers:\n * X-RateLimit: \"concurrent-requests\";r=29\n * X-RateLimit-Policy: \"concurrent-requests\";q=30\n *\n * Where:\n * - r = remaining requests\n * - q = maximum requests allowed (quota)\n */\nexport function parseRateLimitHeaders(headers: any): RateLimitHeaders | null {\n  if (!headers) {\n    return null;\n  }\n\n  const rateLimitHeader = headers[\"x-ratelimit\"] || headers[\"X-RateLimit\"];\n  const rateLimitPolicyHeader = headers[\"x-ratelimit-policy\"] || headers[\"X-RateLimit-Policy\"];\n\n  if (!rateLimitHeader && !rateLimitPolicyHeader) {\n    return null;\n  }\n\n  const result: RateLimitHeaders = {};\n\n  // Parse remaining from X-RateLimit header\n  if (rateLimitHeader) {\n    const remainingMatch = rateLimitHeader.match(/r=(\\d+)/);\n    if (remainingMatch) {\n      result.remaining = Number.parseInt(remainingMatch[1], 10);\n    }\n  }\n\n  // Parse max from X-RateLimit-Policy header\n  if (rateLimitPolicyHeader) {\n    const maxMatch = rateLimitPolicyHeader.match(/q=(\\d+)/);\n    if (maxMatch) {\n      result.max = Number.parseInt(maxMatch[1], 10);\n    }\n  }\n\n  return Object.keys(result).length > 0 ? result : null;\n}\n\n/**\n * Creates a rate limit configuration object\n */\nexport function createRateLimitConfig(\n  userRateLimit?: number,\n  isManagementApi = false,\n): RateLimitConfig {\n  return {\n    userRateLimit,\n    serverHeadersRateLimit: undefined,\n    isManagementApi,\n  };\n}\n","import type { ISbThrottle } from \"./interfaces\";\n\nclass AbortError extends Error {\n  constructor(msg: string) {\n    super(msg);\n    this.name = \"AbortError\";\n  }\n}\n\n/**\n * Wraps `fn` in a per-second rate limiter. At most `limit` calls may start\n * within any rolling `interval` (default 1000ms); once the window is full,\n * further calls wait until the oldest call in it ages out. This matches how the\n * Storyblok API enforces its limits: a fixed number of requests per one-second\n * window, not a cap on the number of simultaneous requests.\n *\n * The limiter holds only a list of recent start timestamps, pruned against\n * `Date.now()` on every attempt, and every wait resolves the promise the caller\n * already awaits. It therefore keeps no counter that a scheduled callback must\n * decrement, and schedules no timer that outlives the awaited call. That is a\n * hard requirement on runtimes which suspend between requests and drop pending\n * timers (for example Cloudflare Workers): a shared limiter that released its\n * slots from a detached timer would leak its in-flight count across requests\n * until it deadlocked (see issues #533 and #319).\n *\n * A non-positive or non-finite `limit` or `interval` disables throttling and\n * lets every call through. Server-side rate limits remain enforced by the\n * client's 429 retry path.\n */\nfunction throttledQueue<T extends (...args: Parameters<T>) => ReturnType<T>>(\n  fn: T,\n  limit: number,\n  interval: number,\n): ISbThrottle<T> {\n  const isUnlimited =\n    !Number.isFinite(limit) || limit <= 0 || !Number.isFinite(interval) || interval <= 0;\n\n  // Start timestamps of the calls currently inside the rolling window.\n  const starts: number[] = [];\n  // Rejecters for calls waiting on the window, so abort() can settle them.\n  const pending = new Set<(reason: unknown) => void>();\n  let isAborted = false;\n\n  const acquire = (): Promise<void> => {\n    if (isUnlimited) {\n      return Promise.resolve();\n    }\n\n    return new Promise<void>((resolve, reject) => {\n      const attempt = () => {\n        if (isAborted) {\n          reject(new AbortError(\"Throttle function aborted\"));\n          return;\n        }\n\n        const now = Date.now();\n        while (starts.length > 0 && starts[0] <= now - interval) {\n          starts.shift();\n        }\n\n        if (starts.length < limit) {\n          starts.push(now);\n          resolve();\n          return;\n        }\n\n        // Window is full: retry once the oldest call ages out. The timer only\n        // resolves the promise the caller awaits, so it is never orphaned.\n        const wait = starts[0] + interval - now;\n        let reject_: (reason: unknown) => void;\n        const id = setTimeout(\n          () => {\n            pending.delete(reject_);\n            attempt();\n          },\n          wait > 0 ? wait : 0,\n        );\n        reject_ = (reason: unknown) => {\n          clearTimeout(id);\n          reject(reason);\n        };\n        pending.add(reject_);\n      };\n\n      attempt();\n    });\n  };\n\n  const throttled: ISbThrottle<T> = (...args) => {\n    if (isAborted) {\n      return Promise.reject(\n        new Error(\"Throttled function is already aborted and not accepting new promises\"),\n      );\n    }\n\n    return acquire().then(() => fn(...args));\n  };\n\n  throttled.abort = () => {\n    isAborted = true;\n    pending.forEach((reject_) => reject_(new AbortError(\"Throttle function aborted\")));\n    pending.clear();\n  };\n\n  return throttled;\n}\n\nexport default throttledQueue;\n","import throttledQueue from \"./throttlePromise\";\nimport type { ISbThrottle, ISbThrottledRequest } from \"./interfaces\";\n\n/**\n * Manages multiple throttle queues, each with different rate limits.\n * This ensures that requests with different rate limits don't interfere with each other.\n *\n * For example, cached requests (1000 req/s) and uncached requests (50 req/s)\n * will use separate queues, preventing the slower queue from affecting the faster one.\n */\nexport class ThrottleQueueManager {\n  private queues: Map<number, ISbThrottle<ISbThrottledRequest>>;\n  private interval: number;\n  private throttledRequestFn: ISbThrottledRequest;\n\n  constructor(throttledRequestFn: ISbThrottledRequest, interval = 1000) {\n    this.queues = new Map();\n    this.interval = interval;\n    this.throttledRequestFn = throttledRequestFn;\n  }\n\n  /**\n   * Gets or creates a throttle queue for the specified rate limit\n   */\n  private getQueue(rateLimit: number): ISbThrottle<ISbThrottledRequest> {\n    let queue = this.queues.get(rateLimit);\n\n    if (!queue) {\n      queue = throttledQueue(this.throttledRequestFn, rateLimit, this.interval);\n      this.queues.set(rateLimit, queue);\n    }\n\n    return queue;\n  }\n\n  /**\n   * Executes a request through the appropriate throttle queue based on rate limit\n   */\n  public execute(rateLimit: number, ...args: Parameters<ISbThrottledRequest>): Promise<unknown> {\n    const queue = this.getQueue(rateLimit);\n    return queue(...args);\n  }\n\n  /**\n   * Aborts all throttle queues\n   */\n  public abortAll(): void {\n    this.queues.forEach((queue) => {\n      queue.abort?.();\n    });\n    this.queues.clear();\n  }\n\n  /**\n   * Gets the number of active queues\n   */\n  public getQueueCount(): number {\n    return this.queues.size;\n  }\n}\n","import {\n  asyncMap,\n  decodeIfEncoded,\n  delay,\n  flatMap,\n  getOptionsPage,\n  getRegionURL,\n  isCDNUrl,\n  range,\n  stringify,\n} from \"./utils\";\nimport SbFetch from \"./sbFetch\";\nimport type Method from \"./constants\";\nimport type { StoryblokContentVersionKeys } from \"./constants\";\nimport { StoryblokContentVersion } from \"./constants\";\nimport {\n  createRateLimitConfig,\n  determineRateLimit,\n  MANAGEMENT_API_DEFAULT_RATE_LIMIT,\n  parseRateLimitHeaders,\n  type RateLimitConfig,\n} from \"./rateLimit\";\nimport { ThrottleQueueManager } from \"./throttleQueueManager\";\n\nimport type {\n  ICacheProvider,\n  IMemoryType,\n  ISbCache,\n  ISbComponentType,\n  ISbConfig,\n  ISbContentMangmntAPI,\n  ISbCustomFetch,\n  ISbField,\n  ISbLinksParams,\n  ISbLinksResult,\n  ISbLinkURLObject,\n  ISbResponse,\n  ISbResponseData,\n  ISbResult,\n  ISbStories,\n  ISbStoriesParams,\n  ISbStory,\n  ISbStoryData,\n  ISbStoryParams,\n} from \"./interfaces\";\n\nexport * from \"./interfaces\";\n\nlet memory: Partial<IMemoryType> = {};\n\nconst cacheVersions = {} as CachedVersions;\n\ninterface CachedVersions {\n  [key: string]: number;\n}\n\ninterface LinksType {\n  [key: string]: any;\n}\n\ninterface RelationsType {\n  [key: string]: any;\n}\n\ninterface ISbFlatMapped {\n  data: any;\n}\n\nconst _VERSION = {\n  V1: \"v1\",\n  V2: \"v2\",\n} as const;\n\ntype ObjectValues<T> = T[keyof T];\ntype Version = ObjectValues<typeof _VERSION>;\n\nexport class Storyblok {\n  private client: SbFetch;\n  private maxRetries: number;\n  private retriesDelay: number;\n  private throttleManager: ThrottleQueueManager;\n  private accessToken: string;\n  private cache: ISbCache;\n  private resolveCounter: number;\n  public relations: RelationsType;\n  public links: LinksType;\n  public version: StoryblokContentVersionKeys | undefined;\n  private rateLimitConfig: RateLimitConfig;\n  private cvMode: \"auto\" | \"manual\";\n  /**\n   * @deprecated This property is deprecated. Use the standalone `richTextResolver` from `@storyblok/richtext` instead.\n   * @see https://github.com/storyblok/richtext\n   */\n  public richTextResolver: unknown;\n  public resolveNestedRelations: boolean;\n  private stringifiedStoriesCache: Record<string, string>;\n  private inlineAssets: boolean;\n\n  /**\n   *\n   * @param config ISbConfig interface\n   * @param pEndpoint string, optional\n   */\n  public constructor(config: ISbConfig, pEndpoint?: string) {\n    let endpoint = config.endpoint || pEndpoint;\n\n    if (!endpoint) {\n      const protocol = config.https === false ? \"http\" : \"https\";\n\n      if (!config.oauthToken) {\n        endpoint = `${protocol}://${getRegionURL(config.region)}/${\"v2\" as Version}`;\n      } else {\n        endpoint = `${protocol}://${getRegionURL(config.region)}/${\"v1\" as Version}`;\n      }\n    }\n\n    const headers: Headers = new Headers();\n\n    // Skip Content-Type for GET browser CDN requests to avoid CORS preflight.\n    // https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/CORS#simple_requests\n    const isBrowserCdn = !config.oauthToken && typeof window !== \"undefined\";\n    if (!isBrowserCdn) {\n      headers.set(\"Content-Type\", \"application/json\");\n    }\n\n    headers.set(\"Accept\", \"application/json\");\n\n    if (config.headers) {\n      const entries =\n        config.headers.constructor.name === \"Headers\"\n          ? config.headers.entries().toArray()\n          : Object.entries(config.headers);\n\n      entries.forEach(([key, value]: [string, string]) => {\n        headers.set(key, value);\n      });\n    }\n\n    if (config.oauthToken) {\n      headers.set(\"Authorization\", config.oauthToken);\n    }\n\n    // Create rate limit config - user's rateLimit applies only to uncached requests\n    // Pass isManagementApi flag to handle Management API default rate limit\n    this.rateLimitConfig = createRateLimitConfig(config.rateLimit, !!config.oauthToken);\n\n    this.maxRetries = config.maxRetries || 10;\n    this.retriesDelay = config.retriesDelay ?? 300;\n\n    // Initialize throttle queue manager\n    this.throttleManager = new ThrottleQueueManager(this.throttledRequest.bind(this), 1000);\n\n    this.accessToken = config.accessToken || \"\";\n    this.relations = {} as RelationsType;\n    this.links = {} as LinksType;\n    this.cache = config.cache || { clear: \"manual\" };\n    this.cvMode = config.cache?.cv ?? \"auto\";\n    this.resolveCounter = 0;\n    this.resolveNestedRelations = config.resolveNestedRelations || true;\n    this.stringifiedStoriesCache = {} as Record<string, string>;\n    this.version = config.version || StoryblokContentVersion.PUBLISHED; // the default version is published as per API documentation\n    this.inlineAssets = config.inlineAssets || false;\n\n    this.client = new SbFetch({\n      baseURL: endpoint,\n      timeout: config.timeout || 0,\n      headers,\n      responseInterceptor: config.responseInterceptor,\n      fetch: config.fetch,\n    });\n  }\n\n  private parseParams(params: ISbStoriesParams): ISbStoriesParams {\n    if (!params.token) {\n      params.token = this.getToken();\n    }\n\n    if (!params.cv && this.cvMode === \"auto\") {\n      params.cv = cacheVersions[params.token];\n    }\n\n    if (Array.isArray(params.resolve_relations)) {\n      // Decode URL-encoded strings in array before joining\n      params.resolve_relations = params.resolve_relations.map(decodeIfEncoded).join(\",\");\n    } else if (typeof params.resolve_relations === \"string\") {\n      // Decode URL-encoded strings to prevent double-encoding\n      params.resolve_relations = decodeIfEncoded(params.resolve_relations);\n    }\n\n    if (typeof params.resolve_relations !== \"undefined\") {\n      params.resolve_level = 2;\n    }\n\n    return params;\n  }\n\n  private factoryParamOptions(url: string, params: ISbStoriesParams): ISbStoriesParams {\n    if (isCDNUrl(url)) {\n      return this.parseParams(params);\n    }\n\n    return params;\n  }\n\n  private makeRequest(\n    url: string,\n    params: ISbStoriesParams,\n    per_page: number,\n    page: number,\n    fetchOptions?: ISbCustomFetch,\n  ): Promise<ISbResult> {\n    const query = this.factoryParamOptions(url, getOptionsPage(params, per_page, page));\n\n    return this.cacheResponse(url, query, undefined, fetchOptions);\n  }\n\n  public get(\n    slug: \"cdn/links\",\n    params?: ISbLinksParams,\n    fetchOptions?: ISbCustomFetch,\n  ): Promise<ISbLinksResult>;\n\n  public get(\n    slug: string,\n    params?: ISbStoriesParams,\n    fetchOptions?: ISbCustomFetch,\n  ): Promise<ISbResult>;\n\n  public get(\n    slug: string,\n    params: ISbStoriesParams | ISbLinksParams = {},\n    fetchOptions?: ISbCustomFetch,\n  ): Promise<ISbResult | ISbLinksResult> {\n    if (!params) {\n      params = {} as ISbStoriesParams;\n    }\n    const url = `/${slug}`;\n\n    // Only add/keep version parameter for CDN URLs — strip it from MAPI requests\n    if (isCDNUrl(url)) {\n      params.version = params.version || this.version;\n    } else if (params.version) {\n      delete params.version;\n    }\n\n    const query = this.factoryParamOptions(url, params);\n\n    return this.cacheResponse(url, query, undefined, fetchOptions);\n  }\n\n  public async getAll(\n    slug: string,\n    params: ISbStoriesParams = {},\n    entity?: string,\n    fetchOptions?: ISbCustomFetch,\n  ): Promise<any[]> {\n    const perPage = params?.per_page || 25;\n    const url = `/${slug}`.replace(/\\/$/, \"\");\n    const e = entity ?? url.substring(url.lastIndexOf(\"/\") + 1);\n    params.version = params.version || this.version;\n\n    const firstPage = 1;\n    const firstRes = await this.makeRequest(url, params, perPage, firstPage, fetchOptions);\n    const lastPage = firstRes.total ? Math.ceil(firstRes.total / (firstRes.perPage || perPage)) : 1;\n\n    const restRes: any = await asyncMap(range(firstPage, lastPage), (i: number) => {\n      return this.makeRequest(url, params, perPage, i + 1, fetchOptions);\n    });\n\n    return flatMap([firstRes, ...restRes], (res: ISbFlatMapped) => Object.values(res.data[e]));\n  }\n\n  public post(\n    slug: string,\n    params: ISbStoriesParams | ISbContentMangmntAPI = {},\n    fetchOptions?: ISbCustomFetch,\n  ): Promise<ISbResponse> {\n    const url = `/${slug}`;\n\n    const rateLimit = determineRateLimit(\n      undefined,\n      undefined,\n      this.rateLimitConfig,\n      MANAGEMENT_API_DEFAULT_RATE_LIMIT,\n    );\n    return this.throttleManager.execute(\n      rateLimit,\n      \"post\",\n      url,\n      params,\n      fetchOptions,\n    ) as Promise<ISbResponse>;\n  }\n\n  public put(\n    slug: string,\n    params: ISbStoriesParams | ISbContentMangmntAPI = {},\n    fetchOptions?: ISbCustomFetch,\n  ): Promise<ISbResponse> {\n    const url = `/${slug}`;\n\n    const rateLimit = determineRateLimit(\n      undefined,\n      undefined,\n      this.rateLimitConfig,\n      MANAGEMENT_API_DEFAULT_RATE_LIMIT,\n    );\n    return this.throttleManager.execute(\n      rateLimit,\n      \"put\",\n      url,\n      params,\n      fetchOptions,\n    ) as Promise<ISbResponse>;\n  }\n\n  public patch(\n    slug: string,\n    params: ISbStoriesParams | ISbContentMangmntAPI = {},\n    fetchOptions?: ISbCustomFetch,\n  ): Promise<ISbResponse> {\n    const url = `/${slug}`;\n\n    const rateLimit = determineRateLimit(\n      undefined,\n      undefined,\n      this.rateLimitConfig,\n      MANAGEMENT_API_DEFAULT_RATE_LIMIT,\n    );\n    return this.throttleManager.execute(\n      rateLimit,\n      \"patch\",\n      url,\n      params,\n      fetchOptions,\n    ) as Promise<ISbResponse>;\n  }\n\n  public delete(\n    slug: string,\n    params: ISbStoriesParams | ISbContentMangmntAPI = {},\n    fetchOptions?: ISbCustomFetch,\n  ): Promise<ISbResponse> {\n    if (!params) {\n      params = {} as ISbStoriesParams;\n    }\n    const url = `/${slug}`;\n\n    const rateLimit = determineRateLimit(\n      undefined,\n      undefined,\n      this.rateLimitConfig,\n      MANAGEMENT_API_DEFAULT_RATE_LIMIT,\n    );\n    return this.throttleManager.execute(\n      rateLimit,\n      \"delete\",\n      url,\n      params,\n      fetchOptions,\n    ) as Promise<ISbResponse>;\n  }\n\n  public getStories(\n    params: ISbStoriesParams = {},\n    fetchOptions?: ISbCustomFetch,\n  ): Promise<ISbStories> {\n    this._addResolveLevel(params);\n\n    return this.get(\"cdn/stories\", params, fetchOptions);\n  }\n\n  public getStory(\n    slug: string,\n    params: ISbStoryParams = {},\n    fetchOptions?: ISbCustomFetch,\n  ): Promise<ISbStory> {\n    this._addResolveLevel(params);\n\n    return this.get(`cdn/stories/${slug}`, params, fetchOptions);\n  }\n\n  private getToken(): string {\n    return this.accessToken;\n  }\n\n  public ejectInterceptor(): void {\n    this.client.eject();\n  }\n\n  private _addResolveLevel(params: ISbStoriesParams | ISbStoryParams): void {\n    if (typeof params.resolve_relations !== \"undefined\") {\n      params.resolve_level = 2;\n    }\n  }\n\n  private _cleanCopy(value: LinksType): JSON {\n    return JSON.parse(JSON.stringify(value));\n  }\n\n  private _insertLinks(\n    jtree: ISbStoriesParams,\n    treeItem: keyof ISbStoriesParams,\n    resolveId: string,\n  ): void {\n    const node = jtree[treeItem];\n\n    if (\n      node &&\n      node.fieldtype === \"multilink\" &&\n      node.linktype === \"story\" &&\n      typeof node.id === \"string\" &&\n      this.links[resolveId][node.id]\n    ) {\n      node.story = this._cleanCopy(this.links[resolveId][node.id]);\n    } else if (\n      node &&\n      node.linktype === \"story\" &&\n      typeof node.uuid === \"string\" &&\n      this.links[resolveId][node.uuid]\n    ) {\n      node.story = this._cleanCopy(this.links[resolveId][node.uuid]);\n    }\n  }\n\n  /**\n   *\n   * @param resolveId A counter number as a string\n   * @param uuid The uuid of the story\n   * @returns string | object\n   */\n  private getStoryReference(resolveId: string, uuid: string): string | JSON {\n    const result = this.relations[resolveId][uuid]\n      ? JSON.parse(\n          this.stringifiedStoriesCache[uuid] || JSON.stringify(this.relations[resolveId][uuid]),\n        )\n      : uuid;\n    return result;\n  }\n\n  /**\n   * Resolves a field's value by replacing UUIDs with their corresponding story references\n   * @param jtree - The JSON tree object containing the field to resolve\n   * @param treeItem - The key of the field to resolve\n   * @param resolveId - The unique identifier for the current resolution context\n   *\n   * This method handles both single string UUIDs and arrays of UUIDs:\n   * - For single strings: directly replaces the UUID with the story reference\n   * - For arrays: maps through each UUID and replaces with corresponding story references\n   */\n  private _resolveField(\n    jtree: ISbStoriesParams,\n    treeItem: keyof ISbStoriesParams,\n    resolveId: string,\n  ): void {\n    const item = jtree[treeItem];\n    if (typeof item === \"string\") {\n      jtree[treeItem] = this.getStoryReference(resolveId, item);\n    } else if (Array.isArray(item)) {\n      jtree[treeItem] = item.map((uuid) => this.getStoryReference(resolveId, uuid)).filter(Boolean);\n    }\n  }\n\n  /**\n   * Inserts relations into the JSON tree by resolving references\n   * @param jtree - The JSON tree object to process\n   * @param treeItem - The current field being processed\n   * @param fields - The relation patterns to resolve (string or array of strings)\n   * @param resolveId - The unique identifier for the current resolution context\n   *\n   * This method handles two types of relation patterns:\n   * 1. Nested relations: matches fields that end with the current field name\n   *    Example: If treeItem is \"event_type\", it matches patterns like \"*.event_type\"\n   *\n   * 2. Direct component relations: matches exact component.field patterns\n   *    Example: \"event.event_type\" for component \"event\" and field \"event_type\"\n   *\n   * The method supports both string and array formats for the fields parameter,\n   * allowing flexible specification of relation patterns.\n   */\n  private _insertRelations(\n    jtree: ISbStoriesParams,\n    treeItem: keyof ISbStoriesParams,\n    fields: string | string[],\n    resolveId: string,\n  ): void {\n    // Check for nested relations (e.g., \"*.event_type\" or \"spots.event_type\")\n    const fieldPattern = Array.isArray(fields)\n      ? fields.find((f) => f.endsWith(`.${treeItem}`))\n      : fields.endsWith(`.${treeItem}`);\n\n    if (fieldPattern) {\n      // If we found a matching pattern, resolve this field\n      this._resolveField(jtree, treeItem, resolveId);\n      return;\n    }\n\n    // If no nested pattern matched, check for direct component.field pattern\n    // e.g., \"event.event_type\" for a field within its immediate parent component\n    const fieldPath = jtree.component ? `${jtree.component}.${treeItem}` : treeItem;\n    // Check if this exact pattern exists in the fields to resolve\n    if (Array.isArray(fields) ? fields.includes(fieldPath) : fields === fieldPath) {\n      this._resolveField(jtree, treeItem, resolveId);\n    }\n  }\n\n  /**\n   * Recursively traverses and resolves relations in the story content tree\n   * @param story - The story object containing the content to process\n   * @param fields - The relation patterns to resolve\n   * @param resolveId - The unique identifier for the current resolution context\n   */\n  private iterateTree(\n    story: ISbStoryData,\n    fields: string | Array<string>,\n    resolveId: string,\n  ): void {\n    // Internal recursive function to process each node in the tree\n    const enrich = (jtree: ISbStoriesParams | any, path = \"\") => {\n      // Skip processing if node is null/undefined or marked to stop resolving\n      if (!jtree || jtree._stopResolving) {\n        return;\n      }\n\n      // Handle arrays by recursively processing each element\n      // Maintains path context by adding array indices\n      if (Array.isArray(jtree)) {\n        jtree.forEach((item, index) => enrich(item, `${path}[${index}]`));\n      }\n      // Handle object nodes\n      else if (typeof jtree === \"object\") {\n        // Process each property in the object\n        for (const key in jtree) {\n          // Build the current path for the context\n          const newPath = path ? `${path}.${key}` : key;\n\n          // If this is a component (has component and _uid) or a link,\n          // attempt to resolve its relations and links\n          if ((jtree.component && jtree._uid) || jtree.type === \"link\") {\n            this._insertRelations(jtree, key as keyof ISbStoriesParams, fields, resolveId);\n            this._insertLinks(jtree, key as keyof ISbStoriesParams, resolveId);\n          }\n\n          // Continue traversing deeper into the tree\n          // This ensures we process nested components and their relations\n          enrich(jtree[key], newPath);\n        }\n      }\n    };\n\n    // Start the traversal from the story's content\n    enrich(story.content);\n  }\n\n  private async resolveLinks(\n    responseData: ISbResponseData,\n    params: ISbStoriesParams,\n    resolveId: string,\n  ): Promise<void> {\n    let links: (ISbStoryData | ISbLinkURLObject | string)[] = [];\n\n    if (responseData.link_uuids) {\n      const relSize = responseData.link_uuids.length;\n      const chunks = [];\n      const chunkSize = 50;\n\n      for (let i = 0; i < relSize; i += chunkSize) {\n        const end = Math.min(relSize, i + chunkSize);\n        chunks.push(responseData.link_uuids.slice(i, end));\n      }\n\n      for (let chunkIndex = 0; chunkIndex < chunks.length; chunkIndex++) {\n        const linksRes = await this.getStories({\n          per_page: chunkSize,\n          language: params.language,\n          version: params.version,\n          starts_with: params.starts_with,\n          by_uuids: chunks[chunkIndex].join(\",\"),\n        });\n\n        linksRes.data.stories.forEach((rel: ISbStoryData | ISbLinkURLObject | string) => {\n          links.push(rel);\n        });\n      }\n    } else {\n      links = responseData.links;\n    }\n\n    links.forEach((story: ISbStoryData | any) => {\n      this.links[resolveId][story.uuid] = {\n        ...story,\n        _stopResolving: true,\n      };\n    });\n  }\n\n  private async resolveRelations(\n    responseData: ISbResponseData,\n    params: ISbStoriesParams,\n    resolveId: string,\n  ): Promise<void> {\n    let relations: ISbStoryData<ISbComponentType<string> & { [index: string]: any }>[] = [];\n\n    if (responseData.rel_uuids) {\n      const relSize = responseData.rel_uuids.length;\n      const chunks = [];\n      const chunkSize = 50;\n\n      for (let i = 0; i < relSize; i += chunkSize) {\n        const end = Math.min(relSize, i + chunkSize);\n        chunks.push(responseData.rel_uuids.slice(i, end));\n      }\n\n      for (let chunkIndex = 0; chunkIndex < chunks.length; chunkIndex++) {\n        const relationsRes = await this.getStories({\n          per_page: chunkSize,\n          language: params.language,\n          version: params.version,\n          starts_with: params.starts_with,\n          by_uuids: chunks[chunkIndex].join(\",\"),\n          excluding_fields: params.excluding_fields,\n        });\n\n        relationsRes.data.stories.forEach((rel: ISbStoryData) => {\n          relations.push(rel);\n        });\n      }\n\n      // Replace rel_uuids with the fully resolved stories and clear it\n      if (relations.length > 0) {\n        responseData.rels = relations;\n        delete responseData.rel_uuids;\n      }\n    } else {\n      relations = responseData.rels;\n    }\n\n    if (relations && relations.length > 0) {\n      relations.forEach((story: ISbStoryData) => {\n        this.relations[resolveId][story.uuid] = {\n          ...story,\n          _stopResolving: true,\n        };\n      });\n    }\n  }\n\n  /**\n   *\n   * @param responseData\n   * @param params\n   * @param resolveId\n   * @description Resolves the relations and links of the stories\n   * @returns Promise<void>\n   *\n   */\n  private async resolveStories(\n    responseData: ISbResponseData,\n    params: ISbStoriesParams,\n    resolveId: string,\n  ): Promise<void> {\n    let relationParams: string[] = [];\n\n    this.links[resolveId] = {};\n    this.relations[resolveId] = {};\n\n    if (typeof params.resolve_relations !== \"undefined\" && params.resolve_relations.length > 0) {\n      if (typeof params.resolve_relations === \"string\") {\n        relationParams = params.resolve_relations.split(\",\");\n      }\n      await this.resolveRelations(responseData, params, resolveId);\n    }\n\n    if (\n      params.resolve_links &&\n      [\"1\", \"story\", \"url\", \"link\"].includes(params.resolve_links) &&\n      (responseData.links?.length || responseData.link_uuids?.length)\n    ) {\n      await this.resolveLinks(responseData, params, resolveId);\n    }\n\n    if (this.resolveNestedRelations) {\n      for (const relUuid in this.relations[resolveId]) {\n        this.iterateTree(this.relations[resolveId][relUuid], relationParams, resolveId);\n      }\n    }\n\n    if (responseData.story) {\n      this.iterateTree(responseData.story, relationParams, resolveId);\n    } else {\n      responseData.stories.forEach((story: ISbStoryData) => {\n        this.iterateTree(story, relationParams, resolveId);\n      });\n    }\n\n    this.stringifiedStoriesCache = {};\n\n    delete this.links[resolveId];\n    delete this.relations[resolveId];\n  }\n\n  private async cacheResponse(\n    url: string,\n    params: ISbStoriesParams,\n    retries?: number,\n    fetchOptions?: ISbCustomFetch,\n  ): Promise<ISbResult> {\n    const cacheKey = stringify({ url, params });\n    const provider = this.cacheProvider();\n\n    // Check in-memory cache first for published content\n    // If cached, skip API call and rate limiting entirely\n    if (params.version === \"published\" && url !== \"/cdn/spaces/me\") {\n      const cache = await provider.get(cacheKey);\n      if (cache) {\n        return Promise.resolve(cache);\n      }\n    }\n\n    // Calculate appropriate rate limit for this request\n    // For Management API requests (non-CDN URLs), use the MAPI rate limit\n    const isMapi = !isCDNUrl(url) && this.rateLimitConfig.isManagementApi;\n    const defaultLimit = isMapi ? MANAGEMENT_API_DEFAULT_RATE_LIMIT : undefined;\n    const rateLimit = determineRateLimit(url, params, this.rateLimitConfig, defaultLimit);\n\n    return new Promise(async (resolve, reject) => {\n      try {\n        // Execute through the appropriate throttle queue based on rate limit\n        const res = (await this.throttleManager.execute(\n          rateLimit,\n          \"get\",\n          url,\n          params,\n          fetchOptions,\n        )) as ISbResponse;\n        if (res.status !== 200) {\n          return reject(res);\n        }\n\n        let response = { data: res.data, headers: res.headers } as ISbResult;\n\n        // Parse rate limit headers and update config if present\n        const rateLimitHeaders = parseRateLimitHeaders(res.headers);\n        if (rateLimitHeaders?.max !== undefined) {\n          // Update server rate limit for subsequent requests\n          this.rateLimitConfig.serverHeadersRateLimit = rateLimitHeaders.max;\n        }\n\n        if (res.headers?.[\"per-page\"]) {\n          response = Object.assign({}, response, {\n            perPage: res.headers[\"per-page\"] ? Number.parseInt(res.headers[\"per-page\"]) : 0,\n            total: res.headers[\"per-page\"] ? Number.parseInt(res.headers.total) : 0,\n          });\n        }\n\n        if (response.data.story || response.data.stories) {\n          const resolveId = (this.resolveCounter = ++this.resolveCounter % 1000);\n          await this.resolveStories(response.data, params, `${resolveId}`);\n          response = await this.processInlineAssets(response);\n        }\n\n        if (params.version === \"published\" && url !== \"/cdn/spaces/me\") {\n          await provider.set(cacheKey, response);\n        }\n\n        const isCacheClearable =\n          (this.cache.clear === \"onpreview\" && params.version === \"draft\") ||\n          this.cache.clear === \"auto\";\n\n        if (params.token && response.data.cv) {\n          if (\n            isCacheClearable &&\n            cacheVersions[params.token] && // there is a cache\n            cacheVersions[params.token] !== response.data.cv // a new cv is incoming\n          ) {\n            await this.flushCache();\n          }\n          cacheVersions[params.token] = response.data.cv;\n        }\n\n        return resolve(response);\n      } catch (error: Error | any) {\n        if (error.response && error.status === 429) {\n          retries = typeof retries === \"undefined\" ? 0 : retries + 1;\n\n          if (retries < this.maxRetries) {\n            // eslint-disable-next-line no-console\n            console.log(`Hit rate limit. Retrying in ${this.retriesDelay / 1000} seconds.`);\n            await delay(this.retriesDelay);\n            // Give `fetchOptions` to the retry. If you do not give it, the\n            // retried request loses the per-request fetch configuration that\n            // the caller supplied.\n            return this.cacheResponse(url, params, retries, fetchOptions)\n              .then(resolve)\n              .catch(reject);\n          }\n        }\n        reject(error);\n      }\n    });\n  }\n\n  private throttledRequest(\n    type: Method,\n    url: string,\n    params: ISbStoriesParams,\n    fetchOptions?: ISbCustomFetch,\n  ): Promise<unknown> {\n    this.client.setFetchOptions(fetchOptions);\n    return this.client[type](url, params);\n  }\n\n  public cacheVersions(): CachedVersions {\n    return cacheVersions;\n  }\n\n  public cacheVersion(): number {\n    return cacheVersions[this.accessToken];\n  }\n\n  public setCacheVersion(cv: number): void {\n    if (this.accessToken) {\n      cacheVersions[this.accessToken] = cv;\n    }\n  }\n\n  public clearCacheVersion(): void {\n    if (this.accessToken) {\n      cacheVersions[this.accessToken] = 0;\n    }\n  }\n\n  public cacheProvider(): ICacheProvider {\n    switch (this.cache.type) {\n      case \"memory\":\n        return {\n          get(key: string) {\n            return Promise.resolve(memory[key]);\n          },\n          getAll() {\n            return Promise.resolve(memory as IMemoryType);\n          },\n          set(key: string, content: ISbResult) {\n            memory[key] = content;\n            return Promise.resolve(undefined);\n          },\n          flush() {\n            memory = {};\n            return Promise.resolve(undefined);\n          },\n        };\n      case \"custom\":\n        if (this.cache.custom) {\n          return this.cache.custom;\n        }\n      // eslint-disable-next-line no-fallthrough\n      default:\n        return {\n          get() {\n            return Promise.resolve();\n          },\n          getAll() {\n            return Promise.resolve(undefined);\n          },\n          set() {\n            return Promise.resolve(undefined);\n          },\n          flush() {\n            return Promise.resolve(undefined);\n          },\n        };\n    }\n  }\n\n  public async flushCache(): Promise<this> {\n    await this.cacheProvider().flush();\n    this.clearCacheVersion();\n    return this;\n  }\n\n  private async processInlineAssets(response: ISbResult): Promise<ISbResult> {\n    if (!this.inlineAssets) {\n      return response;\n    }\n\n    const processNode = (node: ISbField): unknown => {\n      if (!node || typeof node !== \"object\") {\n        return node;\n      }\n\n      if (Array.isArray(node)) {\n        return node.map((item) => processNode(item));\n      }\n\n      let processedNode = { ...node };\n      if (processedNode.fieldtype === \"asset\" && Array.isArray(response.data.assets)) {\n        // Enrich the asset with an actual asset object\n        processedNode = {\n          ...response.data.assets.find((asset: any) => asset.id === processedNode.id),\n          ...processedNode,\n        };\n      }\n\n      // Recursively process all properties\n      for (const key in processedNode) {\n        if (typeof processedNode[key] === \"object\") {\n          processedNode[key] = processNode(processedNode[key] as ISbField);\n        }\n      }\n\n      return processedNode;\n    };\n\n    // Process the story content\n    if (response.data.story) {\n      response.data.story.content = processNode(response.data.story.content);\n    }\n\n    // Process all stories if present\n    if (response.data.stories) {\n      response.data.stories = response.data.stories.map((story: any) => {\n        story.content = processNode(story.content);\n        return story;\n      });\n    }\n\n    return response;\n  }\n}\n\nexport default Storyblok;\n"],"mappings":"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"}