{"version":3,"file":"inject-mutation.mjs","sources":["../src/inject-mutation.ts"],"sourcesContent":["import {\n  Injector,\n  NgZone,\n  assertInInjectionContext,\n  computed,\n  effect,\n  inject,\n  signal,\n  untracked,\n} from '@angular/core'\nimport {\n  MutationObserver,\n  QueryClient,\n  noop,\n  notifyManager,\n  shouldThrowError,\n} from '@tanstack/query-core'\nimport { signalProxy } from './signal-proxy'\nimport { PENDING_TASKS } from './pending-tasks-compat'\nimport type { PendingTaskRef } from './pending-tasks-compat'\nimport type { DefaultError, MutationObserverResult } from '@tanstack/query-core'\nimport type {\n  CreateMutateFunction,\n  CreateMutationOptions,\n  CreateMutationResult,\n} from './types'\n\nexport interface InjectMutationOptions {\n  /**\n   * The `Injector` in which to create the mutation.\n   *\n   * If this is not provided, the current injection context will be used instead (via `inject`).\n   */\n  injector?: Injector\n}\n\n/**\n * Injects a mutation: an imperative function that can be invoked which typically performs server side effects.\n *\n * Unlike queries, mutations are not run automatically.\n * @param injectMutationFn - A function that returns mutation options.\n * @param options - Additional configuration\n * @returns The mutation.\n */\nexport function injectMutation<\n  TData = unknown,\n  TError = DefaultError,\n  TVariables = void,\n  TOnMutateResult = unknown,\n>(\n  injectMutationFn: () => CreateMutationOptions<\n    TData,\n    TError,\n    TVariables,\n    TOnMutateResult\n  >,\n  options?: InjectMutationOptions,\n): CreateMutationResult<TData, TError, TVariables, TOnMutateResult> {\n  !options?.injector && assertInInjectionContext(injectMutation)\n  const injector = options?.injector ?? inject(Injector)\n  const ngZone = injector.get(NgZone)\n  const pendingTasks = injector.get(PENDING_TASKS)\n  const queryClient = injector.get(QueryClient)\n\n  /**\n   * computed() is used so signals can be inserted into the options\n   * making it reactive. Wrapping options in a function ensures embedded expressions\n   * are preserved and can keep being applied after signal changes\n   */\n  const optionsSignal = computed(injectMutationFn)\n\n  const observerSignal = (() => {\n    let instance: MutationObserver<\n      TData,\n      TError,\n      TVariables,\n      TOnMutateResult\n    > | null = null\n\n    return computed(() => {\n      return (instance ||= new MutationObserver(queryClient, optionsSignal()))\n    })\n  })()\n\n  const mutateFnSignal = computed<\n    CreateMutateFunction<TData, TError, TVariables, TOnMutateResult>\n  >(() => {\n    const observer = observerSignal()\n    return (variables, mutateOptions) => {\n      observer.mutate(variables, mutateOptions).catch(noop)\n    }\n  })\n\n  /**\n   * Computed signal that gets result from mutation cache based on passed options\n   */\n  const resultFromInitialOptionsSignal = computed(() => {\n    const observer = observerSignal()\n    return observer.getCurrentResult()\n  })\n\n  /**\n   * Signal that contains result set by subscriber\n   */\n  const resultFromSubscriberSignal = signal<MutationObserverResult<\n    TData,\n    TError,\n    TVariables,\n    TOnMutateResult\n  > | null>(null)\n\n  effect(\n    () => {\n      const observer = observerSignal()\n      const observerOptions = optionsSignal()\n\n      untracked(() => {\n        observer.setOptions(observerOptions)\n      })\n    },\n    {\n      injector,\n    },\n  )\n\n  effect(\n    (onCleanup) => {\n      // observer.trackResult is not used as this optimization is not needed for Angular\n      const observer = observerSignal()\n      let pendingTaskRef: PendingTaskRef | null = null\n\n      untracked(() => {\n        const unsubscribe = ngZone.runOutsideAngular(() =>\n          observer.subscribe(\n            notifyManager.batchCalls((state) => {\n              ngZone.run(() => {\n                // Track pending task when mutation is pending\n                if (state.isPending && !pendingTaskRef) {\n                  pendingTaskRef = pendingTasks.add()\n                }\n\n                // Clear pending task when mutation is no longer pending\n                if (!state.isPending && pendingTaskRef) {\n                  pendingTaskRef()\n                  pendingTaskRef = null\n                }\n\n                if (\n                  state.isError &&\n                  shouldThrowError(observer.options.throwOnError, [state.error])\n                ) {\n                  ngZone.onError.emit(state.error)\n                  throw state.error\n                }\n\n                resultFromSubscriberSignal.set(state)\n              })\n            }),\n          ),\n        )\n        onCleanup(() => {\n          // Clean up any pending task on destroy\n          if (pendingTaskRef) {\n            pendingTaskRef()\n            pendingTaskRef = null\n          }\n          unsubscribe()\n        })\n      })\n    },\n    {\n      injector,\n    },\n  )\n\n  const resultSignal = computed(() => {\n    const resultFromSubscriber = resultFromSubscriberSignal()\n    const resultFromInitialOptions = resultFromInitialOptionsSignal()\n\n    const result = resultFromSubscriber ?? resultFromInitialOptions\n\n    return {\n      ...result,\n      mutate: mutateFnSignal(),\n      mutateAsync: result.mutate,\n    }\n  })\n\n  return signalProxy(resultSignal) as CreateMutationResult<\n    TData,\n    TError,\n    TVariables,\n    TOnMutateResult\n  >\n}\n"],"names":[],"mappings":";;;;AA4CO,SAAS,eAMd,kBAMA,SACkE;AAClE,IAAC,mCAAS,aAAY,yBAAyB,cAAc;AAC7D,QAAM,YAAW,mCAAS,aAAY,OAAO,QAAQ;AACrD,QAAM,SAAS,SAAS,IAAI,MAAM;AAClC,QAAM,eAAe,SAAS,IAAI,aAAa;AAC/C,QAAM,cAAc,SAAS,IAAI,WAAW;AAO5C,QAAM,gBAAgB,SAAS,gBAAgB;AAE/C,QAAM,kBAAkB,MAAM;AAC5B,QAAI,WAKO;AAEX,WAAO,SAAS,MAAM;AACpB,aAAQ,wBAAa,IAAI,iBAAiB,aAAa,eAAe;AAAA,IACxE,CAAC;AAAA,EACH,GAAA;AAEA,QAAM,iBAAiB,SAErB,MAAM;AACN,UAAM,WAAW,eAAA;AACjB,WAAO,CAAC,WAAW,kBAAkB;AACnC,eAAS,OAAO,WAAW,aAAa,EAAE,MAAM,IAAI;AAAA,IACtD;AAAA,EACF,CAAC;AAKD,QAAM,iCAAiC,SAAS,MAAM;AACpD,UAAM,WAAW,eAAA;AACjB,WAAO,SAAS,iBAAA;AAAA,EAClB,CAAC;AAKD,QAAM,6BAA6B,OAKzB,IAAI;AAEd;AAAA,IACE,MAAM;AACJ,YAAM,WAAW,eAAA;AACjB,YAAM,kBAAkB,cAAA;AAExB,gBAAU,MAAM;AACd,iBAAS,WAAW,eAAe;AAAA,MACrC,CAAC;AAAA,IACH;AAAA,IACA;AAAA,MACE;AAAA,IAAA;AAAA,EACF;AAGF;AAAA,IACE,CAAC,cAAc;AAEb,YAAM,WAAW,eAAA;AACjB,UAAI,iBAAwC;AAE5C,gBAAU,MAAM;AACd,cAAM,cAAc,OAAO;AAAA,UAAkB,MAC3C,SAAS;AAAA,YACP,cAAc,WAAW,CAAC,UAAU;AAClC,qBAAO,IAAI,MAAM;AAEf,oBAAI,MAAM,aAAa,CAAC,gBAAgB;AACtC,mCAAiB,aAAa,IAAA;AAAA,gBAChC;AAGA,oBAAI,CAAC,MAAM,aAAa,gBAAgB;AACtC,iCAAA;AACA,mCAAiB;AAAA,gBACnB;AAEA,oBACE,MAAM,WACN,iBAAiB,SAAS,QAAQ,cAAc,CAAC,MAAM,KAAK,CAAC,GAC7D;AACA,yBAAO,QAAQ,KAAK,MAAM,KAAK;AAC/B,wBAAM,MAAM;AAAA,gBACd;AAEA,2CAA2B,IAAI,KAAK;AAAA,cACtC,CAAC;AAAA,YACH,CAAC;AAAA,UAAA;AAAA,QACH;AAEF,kBAAU,MAAM;AAEd,cAAI,gBAAgB;AAClB,2BAAA;AACA,6BAAiB;AAAA,UACnB;AACA,sBAAA;AAAA,QACF,CAAC;AAAA,MACH,CAAC;AAAA,IACH;AAAA,IACA;AAAA,MACE;AAAA,IAAA;AAAA,EACF;AAGF,QAAM,eAAe,SAAS,MAAM;AAClC,UAAM,uBAAuB,2BAAA;AAC7B,UAAM,2BAA2B,+BAAA;AAEjC,UAAM,SAAS,wBAAwB;AAEvC,WAAO;AAAA,MACL,GAAG;AAAA,MACH,QAAQ,eAAA;AAAA,MACR,aAAa,OAAO;AAAA,IAAA;AAAA,EAExB,CAAC;AAED,SAAO,YAAY,YAAY;AAMjC;"}