{"version":3,"file":"index.cjs","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 {\n  AsyncFn,\n  HtmlEscapes,\n  ISbResult,\n  ISbStoriesParams,\n} 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 = (\n  options: ISbStoriesParams,\n  perPage = 25,\n  page = 1,\n) => ({\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> =>\n  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) =>\n  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) =>\n  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    }\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 = (\n  params: ISbParams,\n  prefix?: string,\n  isArray?: boolean,\n): 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(\n        value,\n        prefix ? prefix + encodeURIComponent(`[${enkey}]`) : enkey,\n        Array.isArray(value),\n      );\n    }\n    else {\n      pair = `${\n        prefix ? prefix + encodeURIComponent(`[${enkey}]`) : enkey\n      }=${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 {\n  ISbCustomFetch,\n  ISbError,\n  ISbResponse,\n  ISbStoriesParams,\n} 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]) =>\n      $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(\n    method: Method,\n  ): 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    }\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(\n        fetchResponse,\n      )) as ISbResponse;\n\n      if (this.responseInterceptor && !this.ejectInterceptor) {\n        return this._statusHandler(this.responseInterceptor(response));\n      }\n      else {\n        return this._statusHandler(response);\n      }\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  }\n  else if (perPage <= PER_PAGE_THRESHOLDS.MEDIUM) {\n    return RATE_LIMIT_TIERS.MEDIUM;\n  }\n  else if (perPage <= PER_PAGE_THRESHOLDS.LARGE) {\n    return RATE_LIMIT_TIERS.LARGE;\n  }\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(userRateLimit?: number, isManagementApi = false): RateLimitConfig {\n  return {\n    userRateLimit,\n    serverHeadersRateLimit: undefined,\n    isManagementApi,\n  };\n}\n","import type { ISbThrottle, Queue } from './interfaces';\n\nclass AbortError extends Error {\n  constructor(msg: string) {\n    super(msg);\n    this.name = 'AbortError';\n  }\n}\n\nfunction throttledQueue<T extends (...args: Parameters<T>) => ReturnType<T>>(\n  fn: T,\n  limit: number,\n  interval: number,\n): ISbThrottle<T> {\n  if (!Number.isFinite(limit)) {\n    throw new TypeError('Expected `limit` to be a finite number');\n  }\n\n  if (!Number.isFinite(interval)) {\n    throw new TypeError('Expected `interval` to be a finite number');\n  }\n\n  const queue: Queue<Parameters<T>>[] = [];\n  let timeouts: ReturnType<typeof setTimeout>[] = [];\n  let activeCount = 0;\n  let isAborted = false;\n\n  const next = async () => {\n    activeCount++;\n\n    const x = queue.shift();\n    if (x) {\n      try {\n        const res = await fn(...x.args);\n        x.resolve(res);\n      }\n      catch (error) {\n        x.reject(error);\n      }\n    }\n\n    const id = setTimeout(() => {\n      activeCount--;\n\n      if (queue.length > 0) {\n        next();\n      }\n\n      timeouts = timeouts.filter(currentId => currentId !== id);\n    }, interval);\n\n    if (!timeouts.includes(id)) {\n      timeouts.push(id);\n    }\n  };\n\n  const throttled: ISbThrottle<T> = (...args) => {\n    if (isAborted) {\n      return Promise.reject(\n        new Error(\n          'Throttled function is already aborted and not accepting new promises',\n        ),\n      );\n    }\n\n    return new Promise((resolve, reject) => {\n      queue.push({\n        resolve,\n        reject,\n        args,\n      });\n\n      if (activeCount < limit) {\n        next();\n      }\n    });\n  };\n\n  throttled.abort = () => {\n    isAborted = true;\n    timeouts.forEach(clearTimeout);\n    timeouts = [];\n\n    queue.forEach(x =>\n      x.reject(() => new AbortError('Throttle function aborted')),\n    );\n    queue.length = 0;\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(\n        this.throttledRequestFn,\n        rateLimit,\n        this.interval,\n      );\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(\n    rateLimit: number,\n    ...args: Parameters<ISbThrottledRequest>\n  ): 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 { createRateLimitConfig, determineRateLimit, MANAGEMENT_API_DEFAULT_RATE_LIMIT, parseRateLimitHeaders, type RateLimitConfig } 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      }\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(\n      this.throttledRequest.bind(this),\n      1000,\n    );\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    }\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(\n    url: string,\n    params: ISbStoriesParams,\n  ): 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(\n      url,\n      getOptionsPage(params, per_page, page),\n    );\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 version parameter for CDN URLs\n    if (isCDNUrl(url)) {\n      params.version = params.version || this.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(\n      url,\n      params,\n      perPage,\n      firstPage,\n      fetchOptions,\n    );\n    const lastPage = firstRes.total ? Math.ceil(firstRes.total / (firstRes.perPage || perPage)) : 1;\n\n    const restRes: any = await asyncMap(\n      range(firstPage, lastPage),\n      (i: number) => {\n        return this.makeRequest(url, params, perPage, i + 1, fetchOptions);\n      },\n    );\n\n    return flatMap([firstRes, ...restRes], (res: ISbFlatMapped) =>\n      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(undefined, undefined, this.rateLimitConfig, MANAGEMENT_API_DEFAULT_RATE_LIMIT);\n    return this.throttleManager.execute(rateLimit, 'post', url, params, fetchOptions) 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(undefined, undefined, this.rateLimitConfig, MANAGEMENT_API_DEFAULT_RATE_LIMIT);\n    return this.throttleManager.execute(rateLimit, 'put', url, params, fetchOptions) 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(undefined, undefined, this.rateLimitConfig, MANAGEMENT_API_DEFAULT_RATE_LIMIT);\n    return this.throttleManager.execute(rateLimit, 'patch', url, params, fetchOptions) 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(undefined, undefined, this.rateLimitConfig, MANAGEMENT_API_DEFAULT_RATE_LIMIT);\n    return this.throttleManager.execute(rateLimit, 'delete', url, params, fetchOptions) 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    }\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(this.stringifiedStoriesCache[uuid] || JSON.stringify(this.relations[resolveId][uuid]))\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    }\n    else if (Array.isArray(item)) {\n      jtree[treeItem] = item.map(uuid =>\n        this.getStoryReference(resolveId, uuid),\n      ).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(\n          (rel: ISbStoryData | ISbLinkURLObject | string) => {\n            links.push(rel);\n          },\n        );\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    }\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 (\n      typeof params.resolve_relations !== 'undefined'\n      && params.resolve_relations.length > 0\n    ) {\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(\n          this.relations[resolveId][relUuid],\n          relationParams,\n          resolveId,\n        );\n      }\n    }\n\n    if (responseData.story) {\n      this.iterateTree(responseData.story, relationParams, resolveId);\n    }\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']\n              ? Number.parseInt(res.headers['per-page'])\n              : 0,\n            total: res.headers['per-page']\n              ? Number.parseInt(res.headers.total)\n              : 0,\n          });\n        }\n\n        if (response.data.story || response.data.stories) {\n          const resolveId = (this.resolveCounter\n            = ++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 = (this.cache.clear === 'onpreview' && params.version === 'draft')\n          || this.cache.clear === 'auto';\n\n        if (params.token && response.data.cv) {\n          if (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      }\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(\n              `Hit rate limit. Retrying in ${this.retriesDelay / 1000} seconds.`,\n            );\n            await delay(this.retriesDelay);\n            return this.cacheResponse(url, params, retries)\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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"}