{"version":3,"sources":["../src/Cache.ts","../src/models/Subscribable.ts","../src/utils/isPlainObject.ts","../src/utils/hashCacheKey.ts"],"sourcesContent":["import { Subscribable } from './models/Subscribable'\nimport type { CacheKey, CacheOptions } from './types'\nimport type { ExtractPartial } from './utility-types/ExtractPartial'\nimport { hashCacheKey } from './utils'\n\nconst enum CacheStatus {\n  Idle = 'idle',\n  Pending = 'pending',\n  Resolved = 'resolved',\n  Rejected = 'rejected',\n}\n\nexport type AllStatusCached<TData, TCacheKey extends CacheKey = CacheKey> =\n  | {\n      status: CacheStatus.Idle\n      promiseToSuspend: undefined\n      cacheKey: TCacheKey\n      hashedCacheKey: ReturnType<typeof hashCacheKey>\n      state: {\n        promise: undefined\n        data: undefined\n        error: undefined\n      }\n    }\n  | {\n      status: CacheStatus.Pending\n      promiseToSuspend: Promise<void>\n      cacheKey: TCacheKey\n      hashedCacheKey: ReturnType<typeof hashCacheKey>\n      state: {\n        promise: Promise<TData>\n        data: undefined\n        error: undefined\n      }\n    }\n  | {\n      status: CacheStatus.Resolved\n      promiseToSuspend: Promise<void>\n      cacheKey: TCacheKey\n      hashedCacheKey: ReturnType<typeof hashCacheKey>\n      state: {\n        promise: Promise<TData>\n        data: TData\n        error: undefined\n      }\n    }\n  | {\n      status: CacheStatus.Rejected\n      promiseToSuspend: Promise<void>\n      cacheKey: TCacheKey\n      hashedCacheKey: ReturnType<typeof hashCacheKey>\n      state: {\n        promise: Promise<TData>\n        data: undefined\n        error: unknown\n      }\n    }\n\nexport type IdleCached<TData, TCacheKey extends CacheKey = CacheKey> = ExtractPartial<\n  AllStatusCached<TData, TCacheKey>,\n  { status: CacheStatus.Idle }\n>\nexport type PendingCached<TData, TCacheKey extends CacheKey = CacheKey> = ExtractPartial<\n  AllStatusCached<TData, TCacheKey>,\n  { status: CacheStatus.Pending }\n>\nexport type ResolvedCached<TData, TCacheKey extends CacheKey = CacheKey> = ExtractPartial<\n  AllStatusCached<TData, TCacheKey>,\n  { status: CacheStatus.Resolved }\n>\nexport type RejectedCached<TData, TCacheKey extends CacheKey = CacheKey> = ExtractPartial<\n  AllStatusCached<TData, TCacheKey>,\n  { status: CacheStatus.Rejected }\n>\n\nexport type Cached<TData, TCacheKey extends CacheKey = CacheKey> =\n  | IdleCached<TData, TCacheKey>\n  | PendingCached<TData, TCacheKey>\n  | ResolvedCached<TData, TCacheKey>\n  | RejectedCached<TData, TCacheKey>\n\n/**\n * @experimental This is experimental feature.\n */\nexport class Cache extends Subscribable<() => void> {\n  private cache = new Map<ReturnType<typeof hashCacheKey>, Cached<unknown>>()\n\n  public reset = (options?: Pick<CacheOptions<unknown, CacheKey>, 'cacheKey'>) => {\n    if (typeof options?.cacheKey === 'undefined' || options.cacheKey.length === 0) {\n      this.cache.clear()\n      this.notify()\n      return\n    }\n\n    const hashedCacheKey = hashCacheKey(options.cacheKey)\n\n    if (this.cache.has(hashedCacheKey)) {\n      this.cache.delete(hashedCacheKey)\n    }\n\n    this.notify()\n  }\n\n  public remove = (options: Pick<CacheOptions<unknown, CacheKey>, 'cacheKey'>) => {\n    const hashedCacheKey = hashCacheKey(options.cacheKey)\n\n    if (this.cache.has(hashedCacheKey)) {\n      this.cache.delete(hashedCacheKey)\n    }\n  }\n\n  public clearError = (options?: Pick<CacheOptions<unknown, CacheKey>, 'cacheKey'>) => {\n    if (options?.cacheKey === undefined || options.cacheKey.length === 0) {\n      this.cache.forEach((cached, hashedCacheKey, cache) => {\n        cache.set(hashedCacheKey, {\n          ...cached,\n          status: CacheStatus.Idle,\n          promiseToSuspend: undefined,\n          state: {\n            promise: undefined,\n            error: undefined,\n            data: undefined,\n          },\n        })\n      })\n      return\n    }\n\n    const hashedCacheKey = hashCacheKey(options.cacheKey)\n    const cached = this.cache.get(hashedCacheKey)\n    if (cached) {\n      this.cache.set(hashedCacheKey, {\n        ...cached,\n        status: CacheStatus.Idle,\n        promiseToSuspend: undefined,\n        state: {\n          promise: undefined,\n          error: undefined,\n          data: undefined,\n        },\n      })\n    }\n  }\n\n  public suspend = <TData, TCacheKey extends CacheKey = CacheKey>({\n    cacheKey,\n    cacheFn,\n  }: CacheOptions<TData, TCacheKey>): ResolvedCached<TData, TCacheKey> => {\n    const hashedCacheKey = hashCacheKey(cacheKey)\n    const cached = this.cache.get(hashedCacheKey)\n    if (cached && cached.status !== CacheStatus.Idle) {\n      if (cached.status === CacheStatus.Rejected) {\n        throw cached.state.error\n      }\n      if (cached.status === CacheStatus.Resolved) {\n        return cached as ResolvedCached<TData, TCacheKey>\n      }\n      // eslint-disable-next-line @typescript-eslint/only-throw-error\n      throw cached.promiseToSuspend\n    }\n\n    const promise = cacheFn({ cacheKey })\n    const newCached: Cached<TData, TCacheKey> = {\n      cacheKey,\n      hashedCacheKey,\n      status: CacheStatus.Pending,\n      state: {\n        promise,\n        data: undefined,\n        error: undefined,\n      },\n      promiseToSuspend: promise.then(\n        (data) => {\n          newCached.status = CacheStatus.Resolved\n          newCached.state.data = data\n          newCached.state.error = undefined\n        },\n        (error: unknown) => {\n          newCached.status = CacheStatus.Rejected\n          newCached.state.data = undefined\n          newCached.state.error = error\n        }\n      ),\n    }\n\n    this.cache.set(hashedCacheKey, newCached)\n    // eslint-disable-next-line @typescript-eslint/only-throw-error\n    throw newCached.promiseToSuspend\n  }\n\n  public getData = (options: Pick<CacheOptions<unknown, CacheKey>, 'cacheKey'>) =>\n    this.cache.get(hashCacheKey(options.cacheKey))?.state.data\n  public getError = (options: Pick<CacheOptions<unknown, CacheKey>, 'cacheKey'>) =>\n    this.cache.get(hashCacheKey(options.cacheKey))?.state.error\n}\n","type Listener = (...args: any[]) => unknown\n\ntype Unsubscribe = () => void\ntype Subscribe<TListener extends Listener> = (listener: TListener) => Unsubscribe\n\nexport class Subscribable<TListener extends Listener> {\n  protected listeners = new Set<TListener>()\n\n  public subscribe: Subscribe<TListener> = (listener) => {\n    this.listeners.add(listener)\n\n    const unsubscribe = (): void => {\n      this.listeners.delete(listener)\n    }\n    return unsubscribe\n  }\n\n  protected notify = (): void => this.listeners.forEach((listener) => listener())\n}\n","export type PlainObject = Record<string, any>\n\nexport const isPlainObject = (value: any): value is PlainObject => {\n  if (!hasObjectPrototype(value)) {\n    return false\n  }\n\n  // If has modified constructor\n  const ctor = value.constructor\n  if (typeof ctor === 'undefined') {\n    return true\n  }\n\n  // If has modified prototype\n  const prot = ctor.prototype\n  if (!hasObjectPrototype(prot)) {\n    return false\n  }\n\n  // If constructor does not have an Object-specific method\n  if (!Object.prototype.hasOwnProperty.call(prot, 'isPrototypeOf')) {\n    return false\n  }\n\n  // Most likely a plain Object\n  return true\n}\n\nconst hasObjectPrototype = (value: any) => Object.prototype.toString.call(value) === '[object Object]'\n","import type { CacheKey } from '../types'\nimport { type PlainObject, isPlainObject } from './isPlainObject'\n\nexport const hashCacheKey = (key: CacheKey) =>\n  JSON.stringify(key, (_, val: unknown) =>\n    isPlainObject(val)\n      ? Object.keys(val)\n          .sort()\n          .reduce((acc: PlainObject, cur) => {\n            acc[cur] = val[cur]\n            return acc\n          }, {})\n      : val\n  )\n"],"mappings":"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","names":["cached","hashedCacheKey"]}