{"version":3,"file":"getCachedPromise.cjs","sources":["../../../src/utils/getCachedPromise.ts"],"sourcesContent":["import { type LogContext } from '@grafana/faro-web-sdk';\n\nimport { createMonitoringLogger, type MonitoringLogger } from './logging';\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nconst cache: Map<string, Promise<any>> = new Map();\nexport const MAX_CACHE_SIZE = 500;\n\ninterface OnErrorArgs {\n  error: unknown;\n  invalidate: () => void;\n}\n\ntype PromiseFunction<T> = () => Promise<T>;\n\ninterface CachedPromiseOptions<T> {\n  cacheKey?: string;\n  defaultValue?: T;\n  invalidate?: boolean;\n  onError?: (args: OnErrorArgs) => Promise<T>;\n}\n\ninterface CachePromiseWithoutCatchArgs<T> {\n  key: string;\n  promise: PromiseFunction<T>;\n}\n\ninterface CachePromiseWithDefaultArgs<T> {\n  key: string;\n  promise: PromiseFunction<T>;\n  defaultValue: T;\n}\n\ninterface CachePromiseWithCallbackArgs<T> {\n  key: string;\n  promise: PromiseFunction<T>;\n  onError: (args: OnErrorArgs) => Promise<T>;\n}\n\ninterface LogErrorArgs {\n  error: unknown;\n  key: string;\n}\n\nlet logger: MonitoringLogger;\n\nfunction getLogger() {\n  if (!logger) {\n    logger = createMonitoringLogger('get-cached-promise-logs');\n  }\n\n  return logger;\n}\n\nexport function setLogger(override: MonitoringLogger) {\n  if (process.env.NODE_ENV !== 'test') {\n    throw new Error('setLogger function can only be called from tests.');\n  }\n\n  logger = override;\n}\n\nfunction logError({ error, key }: LogErrorArgs): void {\n  const err = error instanceof Error ? error : new Error(String(error));\n\n  const context: LogContext = { message: err.message, key };\n  if (err.stack) {\n    context.stack = err.stack;\n  }\n\n  getLogger().logError(new Error(`Something failed while resolving a cached promise`), context);\n}\n\nfunction checkCacheSize() {\n  if (cache.size <= MAX_CACHE_SIZE) {\n    return;\n  }\n  cache.clear();\n}\n\nfunction addToCache<T>(key: string, cached: Promise<T>) {\n  checkCacheSize();\n  cache.set(key, cached);\n}\n\nfunction cachePromiseWithoutCatch<T>({ key, promise }: CachePromiseWithoutCatchArgs<T>): Promise<T> {\n  const cached = promise();\n  addToCache(key, cached);\n\n  return cached;\n}\n\nfunction cachePromiseWithDefaultValue<T>({ defaultValue, key, promise }: CachePromiseWithDefaultArgs<T>): Promise<T> {\n  const cached = promise().catch((error) => {\n    logError({ error, key });\n    cache.delete(key);\n    return defaultValue;\n  });\n  addToCache(key, cached);\n\n  return cached;\n}\n\nfunction cachePromiseWithCallback<T>({ key, promise, onError }: CachePromiseWithCallbackArgs<T>): Promise<T> {\n  const invalidate = () => cache.delete(key);\n  const cached = promise().catch((error) => onError({ error, invalidate }));\n  addToCache(key, cached);\n\n  return cached;\n}\n\n/**\n * This utility function will safely handle concurrent requests for the same resource by caching the promise.\n * Caches the result of a promise based on the name of the promise function or cacheKey. If a cached promise exists for the given key,\n * it returns the cached promise. Otherwise, it executes the promise function and caches the result.\n * It also provides options for handling errors, including returning a defaultValue value or invoking a custom error handler.\n * If neither defaultValue nor onError is provided, errors will propagate as usual.\n *\n * @template T - The type of the resolved promise value\n * @param promise - Function that returns the promise to be cached\n * @param options - Options object for error behaviors\n * @param options.cacheKey - Optional cache key to use as key instead of the function name\n * @param options.defaultValue - Optional default value to return if the promise rejects\n * @param options.invalidate - Optionally invalidates the cache for the given function name or cacheKey\n * @param options.onError - Optional error handler that receives the error and an invalidate function\n * @returns A promise that resolves to the cached or newly computed value\n */\nexport function getCachedPromise<T>(promise: PromiseFunction<T>, options?: CachedPromiseOptions<T>): Promise<T> {\n  const { cacheKey, defaultValue, onError, invalidate = false } = options ?? {};\n  const key = cacheKey ?? promise.name;\n\n  if (!key) {\n    return Promise.reject(new Error(`getCachedPromise function must be invoked with a named function or cacheKey`));\n  }\n\n  if (invalidate) {\n    cache.delete(key);\n  }\n\n  const cached = cache.get(key);\n\n  if (cached) {\n    return cached;\n  }\n\n  if (onError) {\n    return cachePromiseWithCallback({ key, onError, promise });\n  }\n\n  if (defaultValue !== undefined) {\n    return cachePromiseWithDefaultValue({ defaultValue, key, promise });\n  }\n\n  return cachePromiseWithoutCatch({ key, promise });\n}\n\nexport function invalidateCache() {\n  if (process.env.NODE_ENV !== 'test') {\n    throw new Error('invalidateCache function can only be called from tests.');\n  }\n\n  cache.clear();\n}\n"],"names":["createMonitoringLogger"],"mappings":"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"}