@tanstack/angular-query-experimental 5.103.1 → 5.103.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (219) hide show
  1. package/dist/create-base-query.d.mts +169 -0
  2. package/dist/create-base-query.d.mts.map +1 -0
  3. package/dist/create-base-query.mjs +91 -0
  4. package/dist/create-base-query.mjs.map +1 -0
  5. package/dist/devtools/index.d.mts +3 -0
  6. package/dist/devtools/index.mjs +2 -0
  7. package/dist/devtools/production/index.d.mts +4 -0
  8. package/dist/devtools/production/index.mjs +2 -0
  9. package/dist/devtools/stub.d.mts +6 -0
  10. package/dist/devtools/stub.d.mts.map +1 -0
  11. package/dist/devtools/stub.mjs +9 -0
  12. package/dist/devtools/stub.mjs.map +1 -0
  13. package/dist/devtools/types.d.mts +107 -0
  14. package/dist/devtools/types.d.mts.map +1 -0
  15. package/dist/devtools/types.mjs +1 -0
  16. package/{devtools/with-devtools.d.ts → dist/devtools/with-devtools.d.mts} +6 -2
  17. package/dist/devtools/with-devtools.d.mts.map +1 -0
  18. package/dist/devtools/with-devtools.mjs +110 -0
  19. package/dist/devtools/with-devtools.mjs.map +1 -0
  20. package/dist/devtools-panel/index.d.mts +3 -0
  21. package/dist/devtools-panel/index.mjs +2 -0
  22. package/{devtools-panel/inject-devtools-panel.d.ts → dist/devtools-panel/inject-devtools-panel.d.mts} +6 -2
  23. package/dist/devtools-panel/inject-devtools-panel.d.mts.map +1 -0
  24. package/dist/devtools-panel/inject-devtools-panel.mjs +67 -0
  25. package/dist/devtools-panel/inject-devtools-panel.mjs.map +1 -0
  26. package/dist/devtools-panel/production/index.d.mts +4 -0
  27. package/dist/devtools-panel/production/index.mjs +2 -0
  28. package/dist/devtools-panel/stub.d.mts +6 -0
  29. package/dist/devtools-panel/stub.d.mts.map +1 -0
  30. package/dist/devtools-panel/stub.mjs +7 -0
  31. package/dist/devtools-panel/stub.mjs.map +1 -0
  32. package/dist/devtools-panel/types.d.mts +52 -0
  33. package/dist/devtools-panel/types.d.mts.map +1 -0
  34. package/dist/devtools-panel/types.mjs +1 -0
  35. package/dist/index.d.mts +16 -0
  36. package/{index.mjs → dist/index.mjs} +8 -21
  37. package/dist/index.mjs.map +1 -0
  38. package/{infinite-query-options.d.ts → dist/infinite-query-options.d.mts} +35 -31
  39. package/dist/infinite-query-options.d.mts.map +1 -0
  40. package/dist/infinite-query-options.mjs +8 -0
  41. package/dist/infinite-query-options.mjs.map +1 -0
  42. package/{inject-infinite-query.d.ts → dist/inject-infinite-query.d.mts} +18 -14
  43. package/dist/inject-infinite-query.d.mts.map +1 -0
  44. package/dist/inject-infinite-query.mjs +13 -0
  45. package/dist/inject-infinite-query.mjs.map +1 -0
  46. package/{inject-is-fetching.d.ts → dist/inject-is-fetching.d.mts} +14 -10
  47. package/dist/inject-is-fetching.d.mts.map +1 -0
  48. package/dist/inject-is-fetching.mjs +69 -0
  49. package/dist/inject-is-fetching.mjs.map +1 -0
  50. package/{inject-is-mutating.d.ts → dist/inject-is-mutating.d.mts} +14 -10
  51. package/dist/inject-is-mutating.d.mts.map +1 -0
  52. package/dist/inject-is-mutating.mjs +52 -0
  53. package/dist/inject-is-mutating.mjs.map +1 -0
  54. package/{inject-is-restoring.d.ts → dist/inject-is-restoring.d.mts} +13 -10
  55. package/dist/inject-is-restoring.d.mts.map +1 -0
  56. package/dist/inject-is-restoring.mjs +35 -0
  57. package/dist/inject-is-restoring.mjs.map +1 -0
  58. package/{inject-mutation-state.d.ts → dist/inject-mutation-state.d.mts} +16 -13
  59. package/dist/inject-mutation-state.d.mts.map +1 -0
  60. package/dist/inject-mutation-state.mjs +103 -0
  61. package/dist/inject-mutation-state.mjs.map +1 -0
  62. package/{inject-mutation.d.ts → dist/inject-mutation.d.mts} +15 -11
  63. package/dist/inject-mutation.d.mts.map +1 -0
  64. package/dist/inject-mutation.mjs +226 -0
  65. package/dist/inject-mutation.mjs.map +1 -0
  66. package/dist/inject-queries-experimental/index.d.mts +2 -0
  67. package/dist/inject-queries-experimental/index.mjs +2 -0
  68. package/{inject-queries.d.ts → dist/inject-queries.d.mts} +36 -55
  69. package/dist/inject-queries.d.mts.map +1 -0
  70. package/dist/inject-queries.mjs +203 -0
  71. package/dist/inject-queries.mjs.map +1 -0
  72. package/{inject-query-client.d.ts → dist/inject-query-client.d.mts} +8 -4
  73. package/dist/inject-query-client.d.mts.map +1 -0
  74. package/dist/inject-query-client.mjs +23 -0
  75. package/dist/inject-query-client.mjs.map +1 -0
  76. package/{inject-query.d.ts → dist/inject-query.d.mts} +18 -14
  77. package/dist/inject-query.d.mts.map +1 -0
  78. package/dist/inject-query.mjs +12 -0
  79. package/dist/inject-query.mjs.map +1 -0
  80. package/{mutation-options.d.ts → dist/mutation-options.d.mts} +8 -4
  81. package/dist/mutation-options.d.mts.map +1 -0
  82. package/dist/mutation-options.mjs +8 -0
  83. package/dist/mutation-options.mjs.map +1 -0
  84. package/dist/pending-tasks-compat.d.mts +10 -0
  85. package/dist/pending-tasks-compat.d.mts.map +1 -0
  86. package/dist/pending-tasks-compat.mjs +13 -0
  87. package/dist/pending-tasks-compat.mjs.map +1 -0
  88. package/{providers.d.ts → dist/providers.d.mts} +16 -13
  89. package/dist/providers.d.mts.map +1 -0
  90. package/dist/providers.mjs +124 -0
  91. package/dist/providers.mjs.map +1 -0
  92. package/{query-options.d.ts → dist/query-options.d.mts} +41 -37
  93. package/dist/query-options.d.mts.map +1 -0
  94. package/dist/query-options.mjs +8 -0
  95. package/dist/query-options.mjs.map +1 -0
  96. package/dist/signal-proxy.d.mts +13 -0
  97. package/dist/signal-proxy.d.mts.map +1 -0
  98. package/dist/signal-proxy.mjs +35 -0
  99. package/dist/signal-proxy.mjs.map +1 -0
  100. package/{types.d.ts → dist/types.d.mts} +36 -37
  101. package/dist/types.d.mts.map +1 -0
  102. package/dist/types.mjs +6 -0
  103. package/dist/types.mjs.map +1 -0
  104. package/package.json +48 -20
  105. package/src/__tests__/infinite-query-options.test-d.ts +314 -0
  106. package/src/__tests__/infinite-query-options.test.ts +19 -0
  107. package/src/__tests__/inject-devtools-panel.test.ts +196 -0
  108. package/src/__tests__/inject-infinite-query.test-d.ts +66 -0
  109. package/src/__tests__/inject-infinite-query.test.ts +227 -0
  110. package/src/__tests__/inject-is-fetching.test.ts +108 -0
  111. package/src/__tests__/inject-is-mutating.test.ts +113 -0
  112. package/src/__tests__/inject-is-restoring.test.ts +93 -0
  113. package/src/__tests__/inject-mutation-state.test-d.ts +22 -0
  114. package/src/__tests__/inject-mutation-state.test.ts +198 -0
  115. package/src/__tests__/inject-mutation.test-d.ts +158 -0
  116. package/src/__tests__/inject-mutation.test.ts +1161 -0
  117. package/src/__tests__/inject-queries.test-d.ts +196 -0
  118. package/src/__tests__/inject-queries.test.ts +240 -0
  119. package/src/__tests__/inject-query.test-d.ts +357 -0
  120. package/src/__tests__/inject-query.test.ts +700 -0
  121. package/src/__tests__/mutation-options.test-d.ts +234 -0
  122. package/src/__tests__/mutation-options.test.ts +344 -0
  123. package/src/__tests__/pending-tasks.test.ts +644 -0
  124. package/src/__tests__/provide-query-client.test.ts +38 -0
  125. package/src/__tests__/provide-tanstack-query.test.ts +38 -0
  126. package/src/__tests__/query-options.test-d.ts +262 -0
  127. package/src/__tests__/query-options.test.ts +14 -0
  128. package/src/__tests__/signal-proxy.test.ts +27 -0
  129. package/src/__tests__/test-utils.ts +77 -0
  130. package/src/__tests__/with-devtools.test.ts +674 -0
  131. package/src/create-base-query.ts +175 -0
  132. package/src/devtools/index.ts +8 -0
  133. package/src/devtools/production/index.ts +1 -0
  134. package/src/devtools/stub.ts +7 -0
  135. package/src/devtools/types.ts +116 -0
  136. package/src/devtools/with-devtools.ts +182 -0
  137. package/src/devtools-panel/index.ts +8 -0
  138. package/src/devtools-panel/inject-devtools-panel.ts +110 -0
  139. package/src/devtools-panel/production/index.ts +1 -0
  140. package/src/devtools-panel/stub.ts +7 -0
  141. package/src/devtools-panel/types.ts +57 -0
  142. package/src/index.ts +60 -0
  143. package/src/infinite-query-options.ts +354 -0
  144. package/src/inject-infinite-query.ts +296 -0
  145. package/src/inject-is-fetching.ts +97 -0
  146. package/src/inject-is-mutating.ts +80 -0
  147. package/src/inject-is-restoring.ts +53 -0
  148. package/src/inject-mutation-state.ts +167 -0
  149. package/src/inject-mutation.ts +328 -0
  150. package/src/inject-queries-experimental/index.ts +1 -0
  151. package/src/inject-queries.ts +479 -0
  152. package/src/inject-query-client.ts +22 -0
  153. package/src/inject-query.ts +208 -0
  154. package/src/mutation-options.ts +121 -0
  155. package/src/pending-tasks-compat.ts +27 -0
  156. package/src/providers.ts +170 -0
  157. package/src/query-options.ts +292 -0
  158. package/src/signal-proxy.ts +46 -0
  159. package/src/types.ts +429 -0
  160. package/create-base-query.d.ts +0 -164
  161. package/create-base-query.mjs +0 -99
  162. package/create-base-query.mjs.map +0 -1
  163. package/devtools/index.d.ts +0 -2
  164. package/devtools/index.mjs +0 -5
  165. package/devtools/index.mjs.map +0 -1
  166. package/devtools/production/index.d.ts +0 -1
  167. package/devtools/stub.d.ts +0 -2
  168. package/devtools/stub.mjs +0 -8
  169. package/devtools/stub.mjs.map +0 -1
  170. package/devtools/types.d.ts +0 -100
  171. package/devtools/with-devtools.mjs +0 -106
  172. package/devtools/with-devtools.mjs.map +0 -1
  173. package/devtools-panel/index.d.ts +0 -2
  174. package/devtools-panel/index.mjs +0 -5
  175. package/devtools-panel/index.mjs.map +0 -1
  176. package/devtools-panel/inject-devtools-panel.mjs +0 -72
  177. package/devtools-panel/inject-devtools-panel.mjs.map +0 -1
  178. package/devtools-panel/production/index.d.ts +0 -1
  179. package/devtools-panel/stub.d.ts +0 -2
  180. package/devtools-panel/stub.mjs +0 -8
  181. package/devtools-panel/stub.mjs.map +0 -1
  182. package/devtools-panel/types.d.ts +0 -48
  183. package/index.d.ts +0 -25
  184. package/index.mjs.map +0 -1
  185. package/infinite-query-options.mjs +0 -7
  186. package/infinite-query-options.mjs.map +0 -1
  187. package/inject-infinite-query.mjs +0 -18
  188. package/inject-infinite-query.mjs.map +0 -1
  189. package/inject-is-fetching.mjs +0 -31
  190. package/inject-is-fetching.mjs.map +0 -1
  191. package/inject-is-mutating.mjs +0 -31
  192. package/inject-is-mutating.mjs.map +0 -1
  193. package/inject-is-restoring.mjs +0 -21
  194. package/inject-is-restoring.mjs.map +0 -1
  195. package/inject-mutation-state.mjs +0 -51
  196. package/inject-mutation-state.mjs.map +0 -1
  197. package/inject-mutation.mjs +0 -94
  198. package/inject-mutation.mjs.map +0 -1
  199. package/inject-queries-experimental/index.d.ts +0 -1
  200. package/inject-queries-experimental/index.mjs +0 -5
  201. package/inject-queries-experimental/index.mjs.map +0 -1
  202. package/inject-queries.mjs +0 -82
  203. package/inject-queries.mjs.map +0 -1
  204. package/inject-query-client.mjs +0 -9
  205. package/inject-query-client.mjs.map +0 -1
  206. package/inject-query.mjs +0 -14
  207. package/inject-query.mjs.map +0 -1
  208. package/mutation-options.mjs +0 -7
  209. package/mutation-options.mjs.map +0 -1
  210. package/pending-tasks-compat.d.ts +0 -7
  211. package/pending-tasks-compat.mjs +0 -19
  212. package/pending-tasks-compat.mjs.map +0 -1
  213. package/providers.mjs +0 -32
  214. package/providers.mjs.map +0 -1
  215. package/query-options.mjs +0 -7
  216. package/query-options.mjs.map +0 -1
  217. package/signal-proxy.d.ts +0 -11
  218. package/signal-proxy.mjs +0 -29
  219. package/signal-proxy.mjs.map +0 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"inject-is-fetching.mjs","names":[],"sources":["../src/inject-is-fetching.ts"],"sourcesContent":["import {\n DestroyRef,\n Injector,\n NgZone,\n assertInInjectionContext,\n inject,\n signal,\n} from '@angular/core'\nimport { QueryClient, notifyManager } from '@tanstack/query-core'\nimport type { QueryFilters } from '@tanstack/query-core'\nimport type { Signal } from '@angular/core'\n\nexport interface InjectIsFetchingOptions {\n /**\n * The `Injector` in which to create the isFetching signal.\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 signal that tracks the number of queries that your application is loading or fetching in the\n * background (useful for app-wide loading indicators).\n *\n * @param filters - The {@link QueryFilters} to narrow down the matched queries.\n * @param options - Additional configuration\n * @returns A `Signal` with the number of queries that your application is currently loading or fetching in\n * the background.\n *\n * @example\n * ```angular-ts\n * @Component({\n * selector: 'posts-fetching-indicator',\n * template: `\n * @if (isFetchingPosts()) {\n * <span>Refreshing posts...</span>\n * }\n * `,\n * })\n * export class PostsFetchingIndicator {\n * // How many queries matching the posts prefix are fetching?\n * readonly isFetchingPosts = injectIsFetching({ queryKey: ['posts'] })\n * }\n * ```\n *\n * @example\n * A global loading indicator for any query fetching in the background, not just the ones on screen:\n * ```angular-ts\n * @Component({\n * selector: 'global-loading-indicator',\n * template: `\n * @if (isFetching()) {\n * <div>Queries are fetching in the background...</div>\n * }\n * `,\n * })\n * export class GlobalLoadingIndicator {\n * readonly isFetching = injectIsFetching()\n * }\n * ```\n */\nexport function injectIsFetching(\n filters?: QueryFilters,\n options?: InjectIsFetchingOptions,\n): Signal<number> {\n !options?.injector && assertInInjectionContext(injectIsFetching)\n const injector = options?.injector ?? inject(Injector)\n const destroyRef = injector.get(DestroyRef)\n const ngZone = injector.get(NgZone)\n const queryClient = injector.get(QueryClient)\n\n const cache = queryClient.getQueryCache()\n // isFetching is the prev value initialized on mount *\n let isFetching = queryClient.isFetching(filters)\n\n const result = signal(isFetching)\n\n const unsubscribe = ngZone.runOutsideAngular(() =>\n cache.subscribe(\n notifyManager.batchCalls(() => {\n const newIsFetching = queryClient.isFetching(filters)\n if (isFetching !== newIsFetching) {\n // * and update with each change\n isFetching = newIsFetching\n ngZone.run(() => {\n result.set(isFetching)\n })\n }\n }),\n ),\n )\n\n destroyRef.onDestroy(unsubscribe)\n\n return result\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA8DA,SAAgB,iBACd,SACA,SACgB;CAChB,CAAC,SAAS,YAAY,yBAAyB,gBAAgB;CAC/D,MAAM,WAAW,SAAS,YAAY,OAAO,QAAQ;CACrD,MAAM,aAAa,SAAS,IAAI,UAAU;CAC1C,MAAM,SAAS,SAAS,IAAI,MAAM;CAClC,MAAM,cAAc,SAAS,IAAI,WAAW;CAE5C,MAAM,QAAQ,YAAY,cAAc;CAExC,IAAI,aAAa,YAAY,WAAW,OAAO;CAE/C,MAAM,SAAS,OAAO,UAAU;CAEhC,MAAM,cAAc,OAAO,wBACzB,MAAM,UACJ,cAAc,iBAAiB;EAC7B,MAAM,gBAAgB,YAAY,WAAW,OAAO;EACpD,IAAI,eAAe,eAAe;GAEhC,aAAa;GACb,OAAO,UAAU;IACf,OAAO,IAAI,UAAU;GACvB,CAAC;EACH;CACF,CAAC,CACH,CACF;CAEA,WAAW,UAAU,WAAW;CAEhC,OAAO;AACT"}
@@ -1,12 +1,13 @@
1
- import { Injector, Signal } from '@angular/core';
2
- import { MutationFilters } from '@tanstack/query-core';
3
- export interface InjectIsMutatingOptions {
4
- /**
5
- * The `Injector` in which to create the isMutating signal.
6
- *
7
- * If this is not provided, the current injection context will be used instead (via `inject`).
8
- */
9
- injector?: Injector;
1
+ import { Injector, Signal } from "@angular/core";
2
+ import { MutationFilters } from "@tanstack/query-core";
3
+ //#region src/inject-is-mutating.d.ts
4
+ interface InjectIsMutatingOptions {
5
+ /**
6
+ * The `Injector` in which to create the isMutating signal.
7
+ *
8
+ * If this is not provided, the current injection context will be used instead (via `inject`).
9
+ */
10
+ injector?: Injector;
10
11
  }
11
12
  /**
12
13
  * Injects a signal that tracks the number of mutations that your application currently has `pending`
@@ -32,4 +33,7 @@ export interface InjectIsMutatingOptions {
32
33
  * }
33
34
  * ```
34
35
  */
35
- export declare function injectIsMutating(filters?: MutationFilters, options?: InjectIsMutatingOptions): Signal<number>;
36
+ declare function injectIsMutating(filters?: MutationFilters, options?: InjectIsMutatingOptions): Signal<number>;
37
+ //#endregion
38
+ export { InjectIsMutatingOptions, injectIsMutating };
39
+ //# sourceMappingURL=inject-is-mutating.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"inject-is-mutating.d.mts","names":[],"sources":["../src/inject-is-mutating.ts"],"mappings":";;;UAYiB;;;;;;EAMf,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;iBA2BG,iBACd,UAAU,iBACV,UAAU,0BACT"}
@@ -0,0 +1,52 @@
1
+ import { DestroyRef, Injector, NgZone, assertInInjectionContext, inject, signal } from "@angular/core";
2
+ import { QueryClient, notifyManager } from "@tanstack/query-core";
3
+ //#region src/inject-is-mutating.ts
4
+ /**
5
+ * Injects a signal that tracks the number of mutations that your application currently has `pending`
6
+ * (useful for app-wide loading indicators).
7
+ *
8
+ * @param filters - The {@link MutationFilters} to narrow down the matched mutations.
9
+ * @param options - Additional configuration
10
+ * @returns A `Signal` with the number of mutations that your application currently has `pending`.
11
+ *
12
+ * @example
13
+ * ```angular-ts
14
+ * @Component({
15
+ * selector: 'posts-mutating-indicator',
16
+ * template: `
17
+ * @if (isMutatingPosts()) {
18
+ * <span>Saving posts...</span>
19
+ * }
20
+ * `,
21
+ * })
22
+ * export class PostsMutatingIndicator {
23
+ * // How many mutations matching the posts prefix are in progress?
24
+ * readonly isMutatingPosts = injectIsMutating({ mutationKey: ['posts'] })
25
+ * }
26
+ * ```
27
+ */
28
+ function injectIsMutating(filters, options) {
29
+ !options?.injector && assertInInjectionContext(injectIsMutating);
30
+ const injector = options?.injector ?? inject(Injector);
31
+ const destroyRef = injector.get(DestroyRef);
32
+ const ngZone = injector.get(NgZone);
33
+ const queryClient = injector.get(QueryClient);
34
+ const cache = queryClient.getMutationCache();
35
+ let isMutating = queryClient.isMutating(filters);
36
+ const result = signal(isMutating);
37
+ const unsubscribe = ngZone.runOutsideAngular(() => cache.subscribe(notifyManager.batchCalls(() => {
38
+ const newIsMutating = queryClient.isMutating(filters);
39
+ if (isMutating !== newIsMutating) {
40
+ isMutating = newIsMutating;
41
+ ngZone.run(() => {
42
+ result.set(isMutating);
43
+ });
44
+ }
45
+ })));
46
+ destroyRef.onDestroy(unsubscribe);
47
+ return result.asReadonly();
48
+ }
49
+ //#endregion
50
+ export { injectIsMutating };
51
+
52
+ //# sourceMappingURL=inject-is-mutating.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"inject-is-mutating.mjs","names":[],"sources":["../src/inject-is-mutating.ts"],"sourcesContent":["import {\n DestroyRef,\n Injector,\n NgZone,\n assertInInjectionContext,\n inject,\n signal,\n} from '@angular/core'\nimport { QueryClient, notifyManager } from '@tanstack/query-core'\nimport type { MutationFilters } from '@tanstack/query-core'\nimport type { Signal } from '@angular/core'\n\nexport interface InjectIsMutatingOptions {\n /**\n * The `Injector` in which to create the isMutating signal.\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 signal that tracks the number of mutations that your application currently has `pending`\n * (useful for app-wide loading indicators).\n *\n * @param filters - The {@link MutationFilters} to narrow down the matched mutations.\n * @param options - Additional configuration\n * @returns A `Signal` with the number of mutations that your application currently has `pending`.\n *\n * @example\n * ```angular-ts\n * @Component({\n * selector: 'posts-mutating-indicator',\n * template: `\n * @if (isMutatingPosts()) {\n * <span>Saving posts...</span>\n * }\n * `,\n * })\n * export class PostsMutatingIndicator {\n * // How many mutations matching the posts prefix are in progress?\n * readonly isMutatingPosts = injectIsMutating({ mutationKey: ['posts'] })\n * }\n * ```\n */\nexport function injectIsMutating(\n filters?: MutationFilters,\n options?: InjectIsMutatingOptions,\n): Signal<number> {\n !options?.injector && assertInInjectionContext(injectIsMutating)\n const injector = options?.injector ?? inject(Injector)\n const destroyRef = injector.get(DestroyRef)\n const ngZone = injector.get(NgZone)\n const queryClient = injector.get(QueryClient)\n\n const cache = queryClient.getMutationCache()\n // isMutating is the prev value initialized on mount *\n let isMutating = queryClient.isMutating(filters)\n\n const result = signal(isMutating)\n\n const unsubscribe = ngZone.runOutsideAngular(() =>\n cache.subscribe(\n notifyManager.batchCalls(() => {\n const newIsMutating = queryClient.isMutating(filters)\n if (isMutating !== newIsMutating) {\n // * and update with each change\n isMutating = newIsMutating\n ngZone.run(() => {\n result.set(isMutating)\n })\n }\n }),\n ),\n )\n\n destroyRef.onDestroy(unsubscribe)\n\n return result.asReadonly()\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;AA6CA,SAAgB,iBACd,SACA,SACgB;CAChB,CAAC,SAAS,YAAY,yBAAyB,gBAAgB;CAC/D,MAAM,WAAW,SAAS,YAAY,OAAO,QAAQ;CACrD,MAAM,aAAa,SAAS,IAAI,UAAU;CAC1C,MAAM,SAAS,SAAS,IAAI,MAAM;CAClC,MAAM,cAAc,SAAS,IAAI,WAAW;CAE5C,MAAM,QAAQ,YAAY,iBAAiB;CAE3C,IAAI,aAAa,YAAY,WAAW,OAAO;CAE/C,MAAM,SAAS,OAAO,UAAU;CAEhC,MAAM,cAAc,OAAO,wBACzB,MAAM,UACJ,cAAc,iBAAiB;EAC7B,MAAM,gBAAgB,YAAY,WAAW,OAAO;EACpD,IAAI,eAAe,eAAe;GAEhC,aAAa;GACb,OAAO,UAAU;IACf,OAAO,IAAI,UAAU;GACvB,CAAC;EACH;CACF,CAAC,CACH,CACF;CAEA,WAAW,UAAU,WAAW;CAEhC,OAAO,OAAO,WAAW;AAC3B"}
@@ -1,11 +1,12 @@
1
- import { Injector, Provider, Signal } from '@angular/core';
1
+ import { Injector, Provider, Signal } from "@angular/core";
2
+ //#region src/inject-is-restoring.d.ts
2
3
  interface InjectIsRestoringOptions {
3
- /**
4
- * The `Injector` to use to get the isRestoring signal.
5
- *
6
- * If this is not provided, the current injection context will be used instead (via `inject`).
7
- */
8
- injector?: Injector;
4
+ /**
5
+ * The `Injector` to use to get the isRestoring signal.
6
+ *
7
+ * If this is not provided, the current injection context will be used instead (via `inject`).
8
+ */
9
+ injector?: Injector;
9
10
  }
10
11
  /**
11
12
  * Injects a signal that tracks whether a restore (e.g. from a persisted client, wired up via
@@ -15,7 +16,7 @@ interface InjectIsRestoringOptions {
15
16
  * @returns A readonly `Signal<boolean>` — `true` while a restore is in progress, `false` otherwise (the
16
17
  * default when no `provideIsRestoring` provider is registered).
17
18
  */
18
- export declare function injectIsRestoring(options?: InjectIsRestoringOptions): Signal<boolean>;
19
+ declare function injectIsRestoring(options?: InjectIsRestoringOptions): Signal<boolean>;
19
20
  /**
20
21
  * Registers a provider for the restore state read by `injectIsRestoring`. Wire this up wherever you drive a
21
22
  * restore yourself — e.g. a persist-client integration — so `injectQuery` and friends can defer subscribing
@@ -23,5 +24,7 @@ export declare function injectIsRestoring(options?: InjectIsRestoringOptions): S
23
24
  * @param isRestoring - A readonly `Signal<boolean>` that tracks the restore state.
24
25
  * @returns A provider for the `isRestoring` signal.
25
26
  */
26
- export declare function provideIsRestoring(isRestoring: Signal<boolean>): Provider;
27
- export {};
27
+ declare function provideIsRestoring(isRestoring: Signal<boolean>): Provider;
28
+ //#endregion
29
+ export { injectIsRestoring, provideIsRestoring };
30
+ //# sourceMappingURL=inject-is-restoring.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"inject-is-restoring.d.mts","names":[],"sources":["../src/inject-is-restoring.ts"],"mappings":";;UAiBU;;;;;;EAMR,WAAW;;;;;;;;;;iBAWG,kBAAkB,UAAU,2BAAwB;;;;;;;;iBAapD,mBAAmB,aAAa,kBAAkB"}
@@ -0,0 +1,35 @@
1
+ import { InjectionToken, Injector, assertInInjectionContext, inject, signal } from "@angular/core";
2
+ //#region src/inject-is-restoring.ts
3
+ /**
4
+ * Internal token used to track isRestoring state, accessible in public API through `injectIsRestoring` and set via `provideIsRestoring`
5
+ */
6
+ const IS_RESTORING = new InjectionToken("", { factory: () => signal(false).asReadonly() });
7
+ /**
8
+ * Injects a signal that tracks whether a restore (e.g. from a persisted client, wired up via
9
+ * `provideIsRestoring`) is currently in progress. `injectQuery` and friends also check this internally to
10
+ * avoid race conditions between the restore and initializing queries.
11
+ * @param options - Additional configuration
12
+ * @returns A readonly `Signal<boolean>` — `true` while a restore is in progress, `false` otherwise (the
13
+ * default when no `provideIsRestoring` provider is registered).
14
+ */
15
+ function injectIsRestoring(options) {
16
+ !options?.injector && assertInInjectionContext(injectIsRestoring);
17
+ return (options?.injector ?? inject(Injector)).get(IS_RESTORING);
18
+ }
19
+ /**
20
+ * Registers a provider for the restore state read by `injectIsRestoring`. Wire this up wherever you drive a
21
+ * restore yourself — e.g. a persist-client integration — so `injectQuery` and friends can defer subscribing
22
+ * to their observer (avoiding a race with the restore) until the restore signal flips back to `false`.
23
+ * @param isRestoring - A readonly `Signal<boolean>` that tracks the restore state.
24
+ * @returns A provider for the `isRestoring` signal.
25
+ */
26
+ function provideIsRestoring(isRestoring) {
27
+ return {
28
+ provide: IS_RESTORING,
29
+ useValue: isRestoring
30
+ };
31
+ }
32
+ //#endregion
33
+ export { injectIsRestoring, provideIsRestoring };
34
+
35
+ //# sourceMappingURL=inject-is-restoring.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"inject-is-restoring.mjs","names":[],"sources":["../src/inject-is-restoring.ts"],"sourcesContent":["import {\n InjectionToken,\n Injector,\n assertInInjectionContext,\n inject,\n signal,\n} from '@angular/core'\nimport type { Provider, Signal } from '@angular/core'\n\n/**\n * Internal token used to track isRestoring state, accessible in public API through `injectIsRestoring` and set via `provideIsRestoring`\n */\nconst IS_RESTORING = new InjectionToken('', {\n // Default value when not provided\n factory: () => signal(false).asReadonly(),\n})\n\ninterface InjectIsRestoringOptions {\n /**\n * The `Injector` to use to get the isRestoring signal.\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 signal that tracks whether a restore (e.g. from a persisted client, wired up via\n * `provideIsRestoring`) is currently in progress. `injectQuery` and friends also check this internally to\n * avoid race conditions between the restore and initializing queries.\n * @param options - Additional configuration\n * @returns A readonly `Signal<boolean>` — `true` while a restore is in progress, `false` otherwise (the\n * default when no `provideIsRestoring` provider is registered).\n */\nexport function injectIsRestoring(options?: InjectIsRestoringOptions) {\n !options?.injector && assertInInjectionContext(injectIsRestoring)\n const injector = options?.injector ?? inject(Injector)\n return injector.get(IS_RESTORING)\n}\n\n/**\n * Registers a provider for the restore state read by `injectIsRestoring`. Wire this up wherever you drive a\n * restore yourself — e.g. a persist-client integration — so `injectQuery` and friends can defer subscribing\n * to their observer (avoiding a race with the restore) until the restore signal flips back to `false`.\n * @param isRestoring - A readonly `Signal<boolean>` that tracks the restore state.\n * @returns A provider for the `isRestoring` signal.\n */\nexport function provideIsRestoring(isRestoring: Signal<boolean>): Provider {\n return {\n provide: IS_RESTORING,\n useValue: isRestoring,\n }\n}\n"],"mappings":";;;;;AAYA,MAAM,eAAe,IAAI,eAAe,IAAI,EAE1C,eAAe,OAAO,KAAK,CAAC,CAAC,WAAW,EAC1C,CAAC;;;;;;;;;AAmBD,SAAgB,kBAAkB,SAAoC;CACpE,CAAC,SAAS,YAAY,yBAAyB,iBAAiB;CAEhE,QADiB,SAAS,YAAY,OAAO,QAAQ,EAAA,CACrC,IAAI,YAAY;AAClC;;;;;;;;AASA,SAAgB,mBAAmB,aAAwC;CACzE,OAAO;EACL,SAAS;EACT,UAAU;CACZ;AACF"}
@@ -1,16 +1,17 @@
1
- import { Injector, Signal } from '@angular/core';
2
- import { Mutation, MutationFilters, MutationState } from '@tanstack/query-core';
1
+ import { Injector, Signal } from "@angular/core";
2
+ import { Mutation, MutationFilters, MutationState } from "@tanstack/query-core";
3
+ //#region src/inject-mutation-state.d.ts
3
4
  type MutationStateOptions<TResult = MutationState> = {
4
- filters?: MutationFilters;
5
- select?: (mutation: Mutation) => TResult;
5
+ filters?: MutationFilters;
6
+ select?: (mutation: Mutation) => TResult;
6
7
  };
7
- export interface InjectMutationStateOptions {
8
- /**
9
- * The `Injector` in which to create the mutation state signal.
10
- *
11
- * If this is not provided, the current injection context will be used instead (via `inject`).
12
- */
13
- injector?: Injector;
8
+ interface InjectMutationStateOptions {
9
+ /**
10
+ * The `Injector` in which to create the mutation state signal.
11
+ *
12
+ * If this is not provided, the current injection context will be used instead (via `inject`).
13
+ */
14
+ injector?: Injector;
14
15
  }
15
16
  /**
16
17
  * Injects a signal that gives you access to all mutations in the `MutationCache`. You can pass `filters`
@@ -69,5 +70,7 @@ export interface InjectMutationStateOptions {
69
70
  * }
70
71
  * ```
71
72
  */
72
- export declare function injectMutationState<TResult = MutationState>(injectMutationStateFn?: () => MutationStateOptions<TResult>, options?: InjectMutationStateOptions): Signal<Array<TResult>>;
73
- export {};
73
+ declare function injectMutationState<TResult = MutationState>(injectMutationStateFn?: () => MutationStateOptions<TResult>, options?: InjectMutationStateOptions): Signal<Array<TResult>>;
74
+ //#endregion
75
+ export { InjectMutationStateOptions, injectMutationState };
76
+ //# sourceMappingURL=inject-mutation-state.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"inject-mutation-state.d.mts","names":[],"sources":["../src/inject-mutation-state.ts"],"mappings":";;;KAsBK,qBAAqB,UAAU;EAClC,UAAU;EACV,UAAU,UAAU,aAAa;;UAelB;;;;;;EAMf,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBA4DG,oBAAoB,UAAU,eAC5C,8BAA6B,qBAAqB,UAClD,UAAU,6BACT,OAAO,MAAM"}
@@ -0,0 +1,103 @@
1
+ import { DestroyRef, Injector, NgZone, assertInInjectionContext, computed, inject, signal } from "@angular/core";
2
+ import { QueryClient, notifyManager, replaceEqualDeep } from "@tanstack/query-core";
3
+ //#region src/inject-mutation-state.ts
4
+ function getResult(mutationCache, options) {
5
+ return mutationCache.findAll(options.filters).map((mutation) => options.select ? options.select(mutation) : mutation.state);
6
+ }
7
+ /**
8
+ * Injects a signal that gives you access to all mutations in the `MutationCache`. You can pass `filters`
9
+ * ({@link MutationFilters}) to narrow down your mutations, and `select` to transform the mutation state.
10
+ *
11
+ * @param injectMutationStateFn - A function returning the `filters` to narrow down matched mutations, and an
12
+ * optional `select` to transform the mutation state. Similar to `computed` from Angular, this function runs
13
+ * in the reactive context, so signals read inside it re-narrow the matched mutations.
14
+ * @param options - Additional configuration
15
+ * @returns A `Signal` with an Array of whatever `select` returns for each matching mutation.
16
+ *
17
+ * @example
18
+ * Get all variables of all running mutations:
19
+ * ```angular-ts
20
+ * @Component({
21
+ * selector: 'pending-posts',
22
+ * template: `{{ pendingVariables().length }} posts saving...`,
23
+ * })
24
+ * export class PendingPosts {
25
+ * readonly pendingVariables = injectMutationState(() => ({
26
+ * filters: { status: 'pending' },
27
+ * select: (mutation) => mutation.state.variables,
28
+ * }))
29
+ * }
30
+ * ```
31
+ *
32
+ * @example
33
+ * Get all data for specific mutations via the `mutationKey`:
34
+ * ```angular-ts
35
+ * const mutationKey = ['posts']
36
+ *
37
+ * @Component({
38
+ * selector: 'posts',
39
+ * template: `
40
+ * <button (click)="createPost()">
41
+ * Create post ({{ savedPosts().length }} saved so far)
42
+ * </button>
43
+ * `,
44
+ * })
45
+ * export class Posts {
46
+ * // Some mutation that we want to get the state for
47
+ * readonly createPostMutation = injectMutation(() => ({
48
+ * mutationKey,
49
+ * mutationFn: createPosts,
50
+ * }))
51
+ *
52
+ * readonly savedPosts = injectMutationState(() => ({
53
+ * // this mutation key needs to match the mutation key of the given mutation (see above)
54
+ * filters: { mutationKey, status: 'success' },
55
+ * select: (mutation) => mutation.state.data,
56
+ * }))
57
+ *
58
+ * createPost() {
59
+ * this.createPostMutation.mutate(['New Post'])
60
+ * }
61
+ * }
62
+ * ```
63
+ */
64
+ function injectMutationState(injectMutationStateFn = () => ({}), options) {
65
+ !options?.injector && assertInInjectionContext(injectMutationState);
66
+ const injector = options?.injector ?? inject(Injector);
67
+ const destroyRef = injector.get(DestroyRef);
68
+ const ngZone = injector.get(NgZone);
69
+ const mutationCache = injector.get(QueryClient).getMutationCache();
70
+ /**
71
+ * Computed signal that gets result from mutation cache based on passed options
72
+ * First element is the result, second element is the time when the result was set
73
+ */
74
+ const resultFromOptionsSignal = computed(() => {
75
+ return [getResult(mutationCache, injectMutationStateFn()), performance.now()];
76
+ });
77
+ /**
78
+ * Signal that contains result set by subscriber
79
+ * First element is the result, second element is the time when the result was set
80
+ */
81
+ const resultFromSubscriberSignal = signal(null);
82
+ /**
83
+ * Returns the last result by either subscriber or options
84
+ */
85
+ const effectiveResultSignal = computed(() => {
86
+ const optionsResult = resultFromOptionsSignal();
87
+ const subscriberResult = resultFromSubscriberSignal();
88
+ return subscriberResult && subscriberResult[1] > optionsResult[1] ? subscriberResult[0] : optionsResult[0];
89
+ });
90
+ const unsubscribe = ngZone.runOutsideAngular(() => mutationCache.subscribe(notifyManager.batchCalls(() => {
91
+ const [lastResult] = effectiveResultSignal();
92
+ const nextResult = replaceEqualDeep(lastResult, getResult(mutationCache, injectMutationStateFn()));
93
+ if (lastResult !== nextResult) ngZone.run(() => {
94
+ resultFromSubscriberSignal.set([nextResult, performance.now()]);
95
+ });
96
+ })));
97
+ destroyRef.onDestroy(unsubscribe);
98
+ return effectiveResultSignal;
99
+ }
100
+ //#endregion
101
+ export { injectMutationState };
102
+
103
+ //# sourceMappingURL=inject-mutation-state.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"inject-mutation-state.mjs","names":[],"sources":["../src/inject-mutation-state.ts"],"sourcesContent":["import {\n DestroyRef,\n Injector,\n NgZone,\n assertInInjectionContext,\n computed,\n inject,\n signal,\n} from '@angular/core'\nimport {\n QueryClient,\n notifyManager,\n replaceEqualDeep,\n} from '@tanstack/query-core'\nimport type { Signal } from '@angular/core'\nimport type {\n Mutation,\n MutationCache,\n MutationFilters,\n MutationState,\n} from '@tanstack/query-core'\n\ntype MutationStateOptions<TResult = MutationState> = {\n filters?: MutationFilters\n select?: (mutation: Mutation) => TResult\n}\n\nfunction getResult<TResult = MutationState>(\n mutationCache: MutationCache,\n options: MutationStateOptions<TResult>,\n): Array<TResult> {\n return mutationCache\n .findAll(options.filters)\n .map(\n (mutation): TResult =>\n (options.select ? options.select(mutation) : mutation.state) as TResult,\n )\n}\n\nexport interface InjectMutationStateOptions {\n /**\n * The `Injector` in which to create the mutation state signal.\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 signal that gives you access to all mutations in the `MutationCache`. You can pass `filters`\n * ({@link MutationFilters}) to narrow down your mutations, and `select` to transform the mutation state.\n *\n * @param injectMutationStateFn - A function returning the `filters` to narrow down matched mutations, and an\n * optional `select` to transform the mutation state. Similar to `computed` from Angular, this function runs\n * in the reactive context, so signals read inside it re-narrow the matched mutations.\n * @param options - Additional configuration\n * @returns A `Signal` with an Array of whatever `select` returns for each matching mutation.\n *\n * @example\n * Get all variables of all running mutations:\n * ```angular-ts\n * @Component({\n * selector: 'pending-posts',\n * template: `{{ pendingVariables().length }} posts saving...`,\n * })\n * export class PendingPosts {\n * readonly pendingVariables = injectMutationState(() => ({\n * filters: { status: 'pending' },\n * select: (mutation) => mutation.state.variables,\n * }))\n * }\n * ```\n *\n * @example\n * Get all data for specific mutations via the `mutationKey`:\n * ```angular-ts\n * const mutationKey = ['posts']\n *\n * @Component({\n * selector: 'posts',\n * template: `\n * <button (click)=\"createPost()\">\n * Create post ({{ savedPosts().length }} saved so far)\n * </button>\n * `,\n * })\n * export class Posts {\n * // Some mutation that we want to get the state for\n * readonly createPostMutation = injectMutation(() => ({\n * mutationKey,\n * mutationFn: createPosts,\n * }))\n *\n * readonly savedPosts = injectMutationState(() => ({\n * // this mutation key needs to match the mutation key of the given mutation (see above)\n * filters: { mutationKey, status: 'success' },\n * select: (mutation) => mutation.state.data,\n * }))\n *\n * createPost() {\n * this.createPostMutation.mutate(['New Post'])\n * }\n * }\n * ```\n */\nexport function injectMutationState<TResult = MutationState>(\n injectMutationStateFn: () => MutationStateOptions<TResult> = () => ({}),\n options?: InjectMutationStateOptions,\n): Signal<Array<TResult>> {\n !options?.injector && assertInInjectionContext(injectMutationState)\n const injector = options?.injector ?? inject(Injector)\n const destroyRef = injector.get(DestroyRef)\n const ngZone = injector.get(NgZone)\n const queryClient = injector.get(QueryClient)\n const mutationCache = queryClient.getMutationCache()\n\n /**\n * Computed signal that gets result from mutation cache based on passed options\n * First element is the result, second element is the time when the result was set\n */\n const resultFromOptionsSignal = computed(() => {\n return [\n getResult(mutationCache, injectMutationStateFn()),\n performance.now(),\n ] as const\n })\n\n /**\n * Signal that contains result set by subscriber\n * First element is the result, second element is the time when the result was set\n */\n const resultFromSubscriberSignal = signal<[Array<TResult>, number] | null>(\n null,\n )\n\n /**\n * Returns the last result by either subscriber or options\n */\n const effectiveResultSignal = computed(() => {\n const optionsResult = resultFromOptionsSignal()\n const subscriberResult = resultFromSubscriberSignal()\n return subscriberResult && subscriberResult[1] > optionsResult[1]\n ? subscriberResult[0]\n : optionsResult[0]\n })\n\n const unsubscribe = ngZone.runOutsideAngular(() =>\n mutationCache.subscribe(\n notifyManager.batchCalls(() => {\n const [lastResult] = effectiveResultSignal()\n const nextResult = replaceEqualDeep(\n lastResult,\n getResult(mutationCache, injectMutationStateFn()),\n )\n if (lastResult !== nextResult) {\n ngZone.run(() => {\n resultFromSubscriberSignal.set([nextResult, performance.now()])\n })\n }\n }),\n ),\n )\n\n destroyRef.onDestroy(unsubscribe)\n\n return effectiveResultSignal\n}\n"],"mappings":";;;AA2BA,SAAS,UACP,eACA,SACgB;CAChB,OAAO,cACJ,QAAQ,QAAQ,OAAO,CAAC,CACxB,KACE,aACE,QAAQ,SAAS,QAAQ,OAAO,QAAQ,IAAI,SAAS,KAC1D;AACJ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAoEA,SAAgB,oBACd,+BAAoE,CAAC,IACrE,SACwB;CACxB,CAAC,SAAS,YAAY,yBAAyB,mBAAmB;CAClE,MAAM,WAAW,SAAS,YAAY,OAAO,QAAQ;CACrD,MAAM,aAAa,SAAS,IAAI,UAAU;CAC1C,MAAM,SAAS,SAAS,IAAI,MAAM;CAElC,MAAM,gBADc,SAAS,IAAI,WACD,CAAC,CAAC,iBAAiB;;;;;CAMnD,MAAM,0BAA0B,eAAe;EAC7C,OAAO,CACL,UAAU,eAAe,sBAAsB,CAAC,GAChD,YAAY,IAAI,CAClB;CACF,CAAC;;;;;CAMD,MAAM,6BAA6B,OACjC,IACF;;;;CAKA,MAAM,wBAAwB,eAAe;EAC3C,MAAM,gBAAgB,wBAAwB;EAC9C,MAAM,mBAAmB,2BAA2B;EACpD,OAAO,oBAAoB,iBAAiB,KAAK,cAAc,KAC3D,iBAAiB,KACjB,cAAc;CACpB,CAAC;CAED,MAAM,cAAc,OAAO,wBACzB,cAAc,UACZ,cAAc,iBAAiB;EAC7B,MAAM,CAAC,cAAc,sBAAsB;EAC3C,MAAM,aAAa,iBACjB,YACA,UAAU,eAAe,sBAAsB,CAAC,CAClD;EACA,IAAI,eAAe,YACjB,OAAO,UAAU;GACf,2BAA2B,IAAI,CAAC,YAAY,YAAY,IAAI,CAAC,CAAC;EAChE,CAAC;CAEL,CAAC,CACH,CACF;CAEA,WAAW,UAAU,WAAW;CAEhC,OAAO;AACT"}
@@ -1,13 +1,14 @@
1
- import { Injector } from '@angular/core';
2
- import { DefaultError } from '@tanstack/query-core';
3
- import { CreateMutationOptions, CreateMutationResult } from './types.js';
4
- export interface InjectMutationOptions {
5
- /**
6
- * The `Injector` in which to create the mutation.
7
- *
8
- * If this is not provided, the current injection context will be used instead (via `inject`).
9
- */
10
- injector?: Injector;
1
+ import { CreateMutationOptions, CreateMutationResult } from "./types.mjs";
2
+ import { Injector } from "@angular/core";
3
+ import { DefaultError } from "@tanstack/query-core";
4
+ //#region src/inject-mutation.d.ts
5
+ interface InjectMutationOptions {
6
+ /**
7
+ * The `Injector` in which to create the mutation.
8
+ *
9
+ * If this is not provided, the current injection context will be used instead (via `inject`).
10
+ */
11
+ injector?: Injector;
11
12
  }
12
13
  /**
13
14
  * Unlike queries, mutations are typically used to create/update/delete data or perform server side-effects.
@@ -146,4 +147,7 @@ export interface InjectMutationOptions {
146
147
  * }
147
148
  * ```
148
149
  */
149
- export declare function injectMutation<TData = unknown, TError = DefaultError, TVariables = void, TOnMutateResult = unknown>(injectMutationFn: () => CreateMutationOptions<TData, TError, TVariables, TOnMutateResult>, options?: InjectMutationOptions): CreateMutationResult<TData, TError, TVariables, TOnMutateResult>;
150
+ declare function injectMutation<TData = unknown, TError = DefaultError, TVariables = void, TOnMutateResult = unknown>(injectMutationFn: () => CreateMutationOptions<TData, TError, TVariables, TOnMutateResult>, options?: InjectMutationOptions): CreateMutationResult<TData, TError, TVariables, TOnMutateResult>;
151
+ //#endregion
152
+ export { InjectMutationOptions, injectMutation };
153
+ //# sourceMappingURL=inject-mutation.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"inject-mutation.d.mts","names":[],"sources":["../src/inject-mutation.ts"],"mappings":";;;;UA2BiB;;;;;;EAMf,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBA4IG,eACd,iBACA,SAAS,cACT,mBACA,2BAEA,wBAAwB,sBACtB,OACA,QACA,YACA,kBAEF,UAAU,wBACT,qBAAqB,OAAO,QAAQ,YAAY"}
@@ -0,0 +1,226 @@
1
+ import { signalProxy } from "./signal-proxy.mjs";
2
+ import { PENDING_TASKS } from "./pending-tasks-compat.mjs";
3
+ import { Injector, NgZone, assertInInjectionContext, computed, effect, inject, signal, untracked } from "@angular/core";
4
+ import { MutationObserver, QueryClient, noop, notifyManager, shouldThrowError } from "@tanstack/query-core";
5
+ //#region src/inject-mutation.ts
6
+ /**
7
+ * Unlike queries, mutations are typically used to create/update/delete data or perform server side-effects.
8
+ * `injectMutation` is the function for that. Unlike queries, mutations are not run automatically.
9
+ *
10
+ * @remarks `mutate`/`mutateAsync` also accept per-call `onSuccess`/`onError`/`onSettled` callbacks as a
11
+ * second argument, useful for triggering call-site side effects (e.g. navigation) without coupling them to
12
+ * the shared mutation definition. Callbacks defined in `injectMutationFn` fire for every mutation; per-call
13
+ * callbacks fire only for the latest call you've made — `mutateAsync` gives you a promise per call instead,
14
+ * so you can await `Promise.all`/`Promise.allSettled` over several calls and see each one's outcome.
15
+ * @see {@link mutationOptions} to share these options across multiple `injectMutation` call sites, or to look
16
+ * the mutation up elsewhere via its `mutationKey` (e.g. with `injectMutationState`).
17
+ * @param injectMutationFn - A function that returns mutation options. Similar to `computed` from Angular,
18
+ * this function runs in the reactive context, so signals read inside it drive the mutation's options.
19
+ * @param options - Additional configuration
20
+ * @returns The mutation result. Value fields are exposed as a `Signal` — read `data`/`error` by calling them
21
+ * (e.g. `mutation.data()`) — while function fields (`mutate`, `mutateAsync`, `reset`) are called directly,
22
+ * unchanged. `isSuccess`/`isError`/`isPending`/`isIdle` are type-guard methods you can call to narrow whether
23
+ * `data` is defined.
24
+ *
25
+ * @example
26
+ * ```angular-ts
27
+ * @Component({
28
+ * selector: 'todos',
29
+ * template: `
30
+ * @if (addMutation.isPending()) {
31
+ * <span>Adding todo...</span>
32
+ * } @else if (addMutation.isError()) {
33
+ * <div>An error occurred: {{ addMutation.error()?.message }}</div>
34
+ * }
35
+ * <button (click)="addMutation.mutate('Item')">Add</button>
36
+ * `,
37
+ * })
38
+ * export class Todos {
39
+ * readonly #queryClient = inject(QueryClient)
40
+ *
41
+ * readonly addMutation = injectMutation(() => ({
42
+ * mutationFn: addTodo,
43
+ * onSuccess: () => this.#queryClient.invalidateQueries({ queryKey: ['todos'] }),
44
+ * }))
45
+ * }
46
+ * ```
47
+ *
48
+ * @example
49
+ * Optimistic update via `onMutate`, rolling back on `onError`:
50
+ * ```angular-ts
51
+ * @Component({
52
+ * selector: 'todos',
53
+ * template: `<button (click)="addMutation.mutate('Item')">Add</button>`,
54
+ * })
55
+ * export class Todos {
56
+ * readonly #queryClient = inject(QueryClient)
57
+ *
58
+ * readonly addMutation = injectMutation(() => ({
59
+ * mutationFn: addTodo,
60
+ * onMutate: async (newTodo) => {
61
+ * await this.#queryClient.cancelQueries({ queryKey: ['todos'] })
62
+ * const previousTodos = this.#queryClient.getQueryData<Array<string>>(['todos'])
63
+ *
64
+ * this.#queryClient.setQueryData<Array<string>>(['todos'], (old) => [
65
+ * ...(old ?? []),
66
+ * newTodo,
67
+ * ])
68
+ *
69
+ * // Passed to `onError` as `onMutateResult` if the mutation fails.
70
+ * return { previousTodos }
71
+ * },
72
+ * onError: (_err, _newTodo, onMutateResult) => {
73
+ * this.#queryClient.setQueryData(['todos'], onMutateResult?.previousTodos)
74
+ * },
75
+ * onSettled: () => {
76
+ * this.#queryClient.invalidateQueries({ queryKey: ['todos'] })
77
+ * },
78
+ * }))
79
+ * }
80
+ * ```
81
+ *
82
+ * @example
83
+ * Callbacks passed per call to `mutate` only fire for the last call — `mutateAsync` gives you a promise per
84
+ * call instead, so you can wait for all of them when they succeed:
85
+ * ```angular-ts
86
+ * @Component({
87
+ * selector: 'todos',
88
+ * template: `
89
+ * <button (click)="handleAddAll(['Todo 1', 'Todo 2', 'Todo 3'])">Add all</button>
90
+ * `,
91
+ * })
92
+ * export class Todos {
93
+ * readonly #queryClient = inject(QueryClient)
94
+ *
95
+ * readonly addMutation = injectMutation(() => ({
96
+ * mutationFn: addTodo,
97
+ * onSuccess: () => this.#queryClient.invalidateQueries({ queryKey: ['todos'] }),
98
+ * }))
99
+ *
100
+ * async handleAddAll(todos: Array<string>) {
101
+ * try {
102
+ * await Promise.all(todos.map((todo) => this.addMutation.mutateAsync(todo)))
103
+ * } catch (error) {
104
+ * console.error('Failed to add todos:', error)
105
+ * }
106
+ * }
107
+ * }
108
+ * ```
109
+ *
110
+ * @example
111
+ * If some of the mutations above can fail independently of the others, and you want to know which ones did —
112
+ * rather than losing that information the moment the first one rejects — swap `Promise.all` for
113
+ * `Promise.allSettled`:
114
+ * ```angular-ts
115
+ * @Component({
116
+ * selector: 'todos',
117
+ * template: `
118
+ * <button (click)="handleAddAll(['Todo 1', 'Todo 2', 'Todo 3'])">Add all</button>
119
+ * `,
120
+ * })
121
+ * export class Todos {
122
+ * readonly #queryClient = inject(QueryClient)
123
+ *
124
+ * readonly addMutation = injectMutation(() => ({
125
+ * mutationFn: addTodo,
126
+ * onSuccess: () => this.#queryClient.invalidateQueries({ queryKey: ['todos'] }),
127
+ * }))
128
+ *
129
+ * async handleAddAll(todos: Array<string>) {
130
+ * const addResults = await Promise.allSettled(
131
+ * todos.map((todo) => this.addMutation.mutateAsync(todo)),
132
+ * )
133
+ *
134
+ * addResults.forEach((addResult, index) => {
135
+ * if (addResult.status === 'rejected') {
136
+ * console.error(`Failed to add "${todos[index]}":`, addResult.reason)
137
+ * }
138
+ * })
139
+ * }
140
+ * }
141
+ * ```
142
+ */
143
+ function injectMutation(injectMutationFn, options) {
144
+ !options?.injector && assertInInjectionContext(injectMutation);
145
+ const injector = options?.injector ?? inject(Injector);
146
+ const ngZone = injector.get(NgZone);
147
+ const pendingTasks = injector.get(PENDING_TASKS);
148
+ const queryClient = injector.get(QueryClient);
149
+ /**
150
+ * computed() is used so signals can be inserted into the options
151
+ * making it reactive. Wrapping options in a function ensures embedded expressions
152
+ * are preserved and can keep being applied after signal changes
153
+ */
154
+ const optionsSignal = computed(injectMutationFn);
155
+ const observerSignal = (() => {
156
+ let instance = null;
157
+ return computed(() => {
158
+ return instance ||= new MutationObserver(queryClient, optionsSignal());
159
+ });
160
+ })();
161
+ const mutateFnSignal = computed(() => {
162
+ const observer = observerSignal();
163
+ return (...args) => {
164
+ observer.mutate(args[0], args[1]).catch(noop);
165
+ };
166
+ });
167
+ /**
168
+ * Computed signal that gets result from mutation cache based on passed options
169
+ */
170
+ const resultFromInitialOptionsSignal = computed(() => {
171
+ return observerSignal().getCurrentResult();
172
+ });
173
+ /**
174
+ * Signal that contains result set by subscriber
175
+ */
176
+ const resultFromSubscriberSignal = signal(null);
177
+ effect(() => {
178
+ const observer = observerSignal();
179
+ const observerOptions = optionsSignal();
180
+ untracked(() => {
181
+ observer.setOptions(observerOptions);
182
+ });
183
+ }, { injector });
184
+ effect((onCleanup) => {
185
+ const observer = observerSignal();
186
+ let pendingTaskRef = null;
187
+ untracked(() => {
188
+ const unsubscribe = ngZone.runOutsideAngular(() => observer.subscribe(notifyManager.batchCalls((state) => {
189
+ ngZone.run(() => {
190
+ if (state.isPending && !pendingTaskRef) pendingTaskRef = pendingTasks.add();
191
+ if (!state.isPending && pendingTaskRef) {
192
+ pendingTaskRef();
193
+ pendingTaskRef = null;
194
+ }
195
+ if (state.isError && shouldThrowError(observer.options.throwOnError, [state.error])) {
196
+ ngZone.onError.emit(state.error);
197
+ throw state.error;
198
+ }
199
+ resultFromSubscriberSignal.set(state);
200
+ });
201
+ })));
202
+ onCleanup(() => {
203
+ if (pendingTaskRef) {
204
+ pendingTaskRef();
205
+ pendingTaskRef = null;
206
+ }
207
+ unsubscribe();
208
+ });
209
+ });
210
+ }, { injector });
211
+ const resultSignal = computed(() => {
212
+ const resultFromSubscriber = resultFromSubscriberSignal();
213
+ const resultFromInitialOptions = resultFromInitialOptionsSignal();
214
+ const result = resultFromSubscriber ?? resultFromInitialOptions;
215
+ return {
216
+ ...result,
217
+ mutate: mutateFnSignal(),
218
+ mutateAsync: result.mutate
219
+ };
220
+ });
221
+ return signalProxy(resultSignal);
222
+ }
223
+ //#endregion
224
+ export { injectMutation };
225
+
226
+ //# sourceMappingURL=inject-mutation.mjs.map