{"version":3,"file":"mutationCache.cjs","names":["Subscribable","Mutation","matchMutation","notifyManager","noop"],"sources":["../../src/mutationCache.ts"],"sourcesContent":["import { notifyManager } from './notifyManager'\nimport { Mutation } from './mutation'\nimport { matchMutation, noop } from './utils'\nimport { Subscribable } from './subscribable'\nimport type { MutationObserver } from './mutationObserver'\nimport type {\n  DefaultError,\n  MutationFunctionContext,\n  MutationOptions,\n  NotifyEvent,\n} from './types'\nimport type { QueryClient } from './queryClient'\nimport type { Action, MutationState } from './mutation'\nimport type { MutationFilters } from './utils'\n\n// TYPES\n\n/**\n * Global callbacks that fire for every mutation handled by a `MutationCache`, regardless of which\n * component or observer triggered it. They differ from the `defaultOptions` provided to a\n * `QueryClient` in two ways: `defaultOptions` can be overridden by each mutation, while these\n * callbacks are always called, and `onMutate` here does not allow returning a result.\n *\n * If a callback returns a promise, it will be awaited before the mutation continues.\n */\nexport interface MutationCacheConfig {\n  /** Called when any mutation in the cache encounters an error. */\n  onError?: (\n    error: DefaultError,\n    variables: unknown,\n    onMutateResult: unknown,\n    mutation: Mutation<unknown, unknown, unknown>,\n    context: MutationFunctionContext,\n  ) => Promise<unknown> | unknown\n  /** Called when any mutation in the cache is successful. */\n  onSuccess?: (\n    data: unknown,\n    variables: unknown,\n    onMutateResult: unknown,\n    mutation: Mutation<unknown, unknown, unknown>,\n    context: MutationFunctionContext,\n  ) => Promise<unknown> | unknown\n  /** Called before any mutation in the cache executes. */\n  onMutate?: (\n    variables: unknown,\n    mutation: Mutation<unknown, unknown, unknown>,\n    context: MutationFunctionContext,\n  ) => Promise<unknown> | unknown\n  /** Called when any mutation in the cache is settled, either successfully or with an error. */\n  onSettled?: (\n    data: unknown | undefined,\n    error: DefaultError | null,\n    variables: unknown,\n    onMutateResult: unknown,\n    mutation: Mutation<unknown, unknown, unknown>,\n    context: MutationFunctionContext,\n  ) => Promise<unknown> | unknown\n}\n\ninterface NotifyEventMutationAdded extends NotifyEvent {\n  type: 'added'\n  mutation: Mutation<any, any, any, any>\n}\ninterface NotifyEventMutationRemoved extends NotifyEvent {\n  type: 'removed'\n  mutation: Mutation<any, any, any, any>\n}\n\ninterface NotifyEventMutationObserverAdded extends NotifyEvent {\n  type: 'observerAdded'\n  mutation: Mutation<any, any, any, any>\n  observer: MutationObserver<any, any, any>\n}\n\ninterface NotifyEventMutationObserverRemoved extends NotifyEvent {\n  type: 'observerRemoved'\n  mutation: Mutation<any, any, any, any>\n  observer: MutationObserver<any, any, any>\n}\n\ninterface NotifyEventMutationObserverOptionsUpdated extends NotifyEvent {\n  type: 'observerOptionsUpdated'\n  mutation?: Mutation<any, any, any, any>\n  observer: MutationObserver<any, any, any, any>\n}\n\ninterface NotifyEventMutationUpdated extends NotifyEvent {\n  type: 'updated'\n  mutation: Mutation<any, any, any, any>\n  action: Action<any, any, any, any>\n}\n\n/**\n * The event passed to a `MutationCache` subscriber. Fired whenever a mutation is added or removed\n * from the cache, its state is updated, or one of its observers is added, removed, or has its\n * options updated.\n */\nexport type MutationCacheNotifyEvent =\n  | NotifyEventMutationAdded\n  | NotifyEventMutationRemoved\n  | NotifyEventMutationObserverAdded\n  | NotifyEventMutationObserverRemoved\n  | NotifyEventMutationObserverOptionsUpdated\n  | NotifyEventMutationUpdated\n\ntype MutationCacheListener = (event: MutationCacheNotifyEvent) => void\n\n// CLASS\n\n/**\n * The `MutationCache` is the storage for mutations.\n *\n * Normally, you will not interact with the `MutationCache` directly and instead use a\n * `QueryClient`. You can subscribe to it (inherited from `Subscribable`) to be informed of\n * safe/known updates to the cache, such as mutations being added, removed, or updated.\n * @example\n * ```ts\n * const unsubscribe = mutationCache.subscribe((event) => {\n *   console.log(event.type, event.mutation)\n * })\n * ```\n */\nexport class MutationCache extends Subscribable<MutationCacheListener> {\n  #mutations: Set<Mutation<any, any, any, any>>\n  #scopes: Map<string, Array<Mutation<any, any, any, any>>>\n  #mutationId: number\n\n  constructor(public config: MutationCacheConfig = {}) {\n    super()\n    this.#mutations = new Set()\n    this.#scopes = new Map()\n    this.#mutationId = 0\n  }\n\n  /**\n   * Creates a mutation and adds it to the cache.\n   * @internal\n   * @param client - The client the mutation belongs to, used to default its options.\n   * @param options - The mutation options. They are defaulted with {@link\n   * QueryClient#defaultMutationOptions}.\n   * @param state - The initial state of the mutation, e.g. when restoring a dehydrated mutation.\n   * @returns The new mutation, already added to the cache.\n   */\n  build<TData, TError, TVariables, TOnMutateResult>(\n    client: QueryClient,\n    options: MutationOptions<TData, TError, TVariables, TOnMutateResult>,\n    state?: MutationState<TData, TError, TVariables, TOnMutateResult>,\n  ): Mutation<TData, TError, TVariables, TOnMutateResult> {\n    const mutation = new Mutation({\n      client,\n      mutationCache: this,\n      mutationId: ++this.#mutationId,\n      options: client.defaultMutationOptions(options),\n      state,\n    })\n\n    this.add(mutation)\n\n    return mutation\n  }\n\n  /**\n   * Adds a mutation to the cache.\n   * @internal\n   * @param mutation - The mutation to add. If it has a `scope`, it is queued in that scope.\n   */\n  add(mutation: Mutation<any, any, any, any>): void {\n    this.#mutations.add(mutation)\n    const scope = scopeFor(mutation)\n    if (typeof scope === 'string') {\n      const scopedMutations = this.#scopes.get(scope)\n      if (scopedMutations) {\n        scopedMutations.push(mutation)\n      } else {\n        this.#scopes.set(scope, [mutation])\n      }\n    }\n    this.notify({ type: 'added', mutation })\n  }\n\n  /**\n   * Removes a mutation from the cache.\n   * @internal\n   * @param mutation - The mutation to remove, also from its scope's queue.\n   */\n  remove(mutation: Mutation<any, any, any, any>): void {\n    if (this.#mutations.delete(mutation)) {\n      const scope = scopeFor(mutation)\n      if (typeof scope === 'string') {\n        const scopedMutations = this.#scopes.get(scope)\n        if (scopedMutations) {\n          if (scopedMutations.length > 1) {\n            const index = scopedMutations.indexOf(mutation)\n            if (index !== -1) {\n              scopedMutations.splice(index, 1)\n            }\n          } else if (scopedMutations[0] === mutation) {\n            this.#scopes.delete(scope)\n          }\n        }\n      }\n    }\n\n    // Currently we notify the removal even if the mutation was already removed.\n    // Consider making this an error or not notifying of the removal depending on the desired semantics.\n    this.notify({ type: 'removed', mutation })\n  }\n\n  /**\n   * Checks whether a mutation can run now, given the other mutations in its `scope`.\n   * @internal\n   * @param mutation - The mutation to check.\n   * @returns `true` if the mutation has no `scope`, or no other mutation in its scope is pending\n   * ahead of it.\n   */\n  canRun(mutation: Mutation<any, any, any, any>): boolean {\n    const scope = scopeFor(mutation)\n    if (typeof scope === 'string') {\n      const mutationsWithSameScope = this.#scopes.get(scope)\n      const firstPendingMutation = mutationsWithSameScope?.find(\n        (m) => m.state.status === 'pending',\n      )\n      // we can run if there is no current pending mutation (start use-case)\n      // or if WE are the first pending mutation (continue use-case)\n      return !firstPendingMutation || firstPendingMutation === mutation\n    } else {\n      // For unscoped mutations there are never any pending mutations in front of the\n      // current mutation\n      return true\n    }\n  }\n\n  /**\n   * Continues the next paused mutation in the same `scope` after a mutation finishes.\n   * @internal\n   * @param mutation - The mutation that finished.\n   * @returns A promise that resolves once the next paused mutation in the same scope has continued,\n   * or immediately if there is none.\n   */\n  runNext(mutation: Mutation<any, any, any, any>): Promise<unknown> {\n    const scope = scopeFor(mutation)\n    if (typeof scope === 'string') {\n      const foundMutation = this.#scopes\n        .get(scope)\n        ?.find((m) => m !== mutation && m.state.isPaused)\n\n      return foundMutation?.continue() ?? Promise.resolve()\n    } else {\n      return Promise.resolve()\n    }\n  }\n\n  /**\n   * Removes all mutations from the cache.\n   * @example\n   * ```ts\n   * const mutationCache = queryClient.getMutationCache()\n   *\n   * mutationCache.clear()\n   * ```\n   */\n  clear(): void {\n    notifyManager.batch(() => {\n      const mutations = this.getAll()\n      this.#mutations.clear()\n      this.#scopes.clear()\n      mutations.forEach((mutation) => {\n        this.notify({ type: 'removed', mutation })\n      })\n    })\n  }\n\n  /**\n   * Returns all mutations within the cache.\n   *\n   * This is not typically needed for most applications, but can come in handy when needing more\n   * information about a mutation in rare scenarios.\n   * @returns Every mutation in the cache.\n   * @example\n   * ```ts\n   * const mutationCache = queryClient.getMutationCache()\n   *\n   * const mutations = mutationCache.getAll()\n   * ```\n   */\n  getAll(): Array<Mutation> {\n    return Array.from(this.#mutations)\n  }\n\n  /**\n   * A slightly more advanced method that can be used to get an existing mutation instance from\n   * the cache. If the mutation does not exist, `undefined` is returned.\n   *\n   * This is not typically needed for most applications, but can come in handy when needing more\n   * information about a mutation in rare scenarios.\n   * @param filters - The filters to match. `exact` defaults to `true`.\n   * @returns The first matching mutation, or `undefined`.\n   * @see {@link MutationCache#findAll}\n   * @example\n   * ```ts\n   * const mutationCache = queryClient.getMutationCache()\n   *\n   * const mutation = mutationCache.find({ mutationKey: ['addPost'] })\n   * ```\n   */\n  find<\n    TData = unknown,\n    TError = DefaultError,\n    TVariables = any,\n    TOnMutateResult = unknown,\n  >(\n    filters: MutationFilters,\n  ): Mutation<TData, TError, TVariables, TOnMutateResult> | undefined {\n    const defaultedFilters = { exact: true, ...filters }\n\n    return this.getAll().find((mutation) =>\n      matchMutation(defaultedFilters, mutation),\n    ) as Mutation<TData, TError, TVariables, TOnMutateResult> | undefined\n  }\n\n  /**\n   * An even more advanced method that can be used to get existing mutation instances from the\n   * cache that match the given filters. If no mutations match, an empty array is returned.\n   *\n   * This is not typically needed for most applications, but can come in handy when needing more\n   * information about mutations in rare scenarios.\n   * @param filters - The filters to match. Without filters, every mutation is returned.\n   * @returns The matching mutations.\n   * @see {@link MutationCache#find}\n   * @example\n   * ```ts\n   * const mutationCache = queryClient.getMutationCache()\n   *\n   * const mutations = mutationCache.findAll({ mutationKey: ['addPost'] })\n   * ```\n   */\n  findAll(filters: MutationFilters = {}): Array<Mutation> {\n    return this.getAll().filter((mutation) => matchMutation(filters, mutation))\n  }\n\n  /**\n   * Notifies every cache listener of an event, in one batch.\n   * @internal\n   * @param event - The event passed to every listener.\n   */\n  notify(event: MutationCacheNotifyEvent) {\n    notifyManager.batch(() => {\n      this.listeners.forEach((listener) => {\n        listener(event)\n      })\n    })\n  }\n\n  /**\n   * Continues every paused mutation, e.g. when the app comes back online.\n   * @internal\n   * @returns A promise that resolves once every paused mutation has continued and settled.\n   */\n  resumePausedMutations(): Promise<unknown> {\n    const pausedMutations = this.getAll().filter((x) => x.state.isPaused)\n\n    return notifyManager.batch(() =>\n      Promise.all(\n        pausedMutations.map((mutation) => mutation.continue().catch(noop)),\n      ),\n    )\n  }\n}\n\n/**\n * Returns the scope id of a mutation, used to run mutations with the same scope one after another.\n * @param mutation - The mutation to read the scope of.\n * @returns The mutation's `scope.id`, or `undefined` if it has no scope.\n */\nfunction scopeFor(mutation: Mutation<any, any, any, any>) {\n  return mutation.options.scope?.id\n}\n"],"mappings":"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"}