@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,97 @@
1
+ import {
2
+ DestroyRef,
3
+ Injector,
4
+ NgZone,
5
+ assertInInjectionContext,
6
+ inject,
7
+ signal,
8
+ } from '@angular/core'
9
+ import { QueryClient, notifyManager } from '@tanstack/query-core'
10
+ import type { QueryFilters } from '@tanstack/query-core'
11
+ import type { Signal } from '@angular/core'
12
+
13
+ export interface InjectIsFetchingOptions {
14
+ /**
15
+ * The `Injector` in which to create the isFetching signal.
16
+ *
17
+ * If this is not provided, the current injection context will be used instead (via `inject`).
18
+ */
19
+ injector?: Injector
20
+ }
21
+
22
+ /**
23
+ * Injects a signal that tracks the number of queries that your application is loading or fetching in the
24
+ * background (useful for app-wide loading indicators).
25
+ *
26
+ * @param filters - The {@link QueryFilters} to narrow down the matched queries.
27
+ * @param options - Additional configuration
28
+ * @returns A `Signal` with the number of queries that your application is currently loading or fetching in
29
+ * the background.
30
+ *
31
+ * @example
32
+ * ```angular-ts
33
+ * @Component({
34
+ * selector: 'posts-fetching-indicator',
35
+ * template: `
36
+ * @if (isFetchingPosts()) {
37
+ * <span>Refreshing posts...</span>
38
+ * }
39
+ * `,
40
+ * })
41
+ * export class PostsFetchingIndicator {
42
+ * // How many queries matching the posts prefix are fetching?
43
+ * readonly isFetchingPosts = injectIsFetching({ queryKey: ['posts'] })
44
+ * }
45
+ * ```
46
+ *
47
+ * @example
48
+ * A global loading indicator for any query fetching in the background, not just the ones on screen:
49
+ * ```angular-ts
50
+ * @Component({
51
+ * selector: 'global-loading-indicator',
52
+ * template: `
53
+ * @if (isFetching()) {
54
+ * <div>Queries are fetching in the background...</div>
55
+ * }
56
+ * `,
57
+ * })
58
+ * export class GlobalLoadingIndicator {
59
+ * readonly isFetching = injectIsFetching()
60
+ * }
61
+ * ```
62
+ */
63
+ export function injectIsFetching(
64
+ filters?: QueryFilters,
65
+ options?: InjectIsFetchingOptions,
66
+ ): Signal<number> {
67
+ !options?.injector && assertInInjectionContext(injectIsFetching)
68
+ const injector = options?.injector ?? inject(Injector)
69
+ const destroyRef = injector.get(DestroyRef)
70
+ const ngZone = injector.get(NgZone)
71
+ const queryClient = injector.get(QueryClient)
72
+
73
+ const cache = queryClient.getQueryCache()
74
+ // isFetching is the prev value initialized on mount *
75
+ let isFetching = queryClient.isFetching(filters)
76
+
77
+ const result = signal(isFetching)
78
+
79
+ const unsubscribe = ngZone.runOutsideAngular(() =>
80
+ cache.subscribe(
81
+ notifyManager.batchCalls(() => {
82
+ const newIsFetching = queryClient.isFetching(filters)
83
+ if (isFetching !== newIsFetching) {
84
+ // * and update with each change
85
+ isFetching = newIsFetching
86
+ ngZone.run(() => {
87
+ result.set(isFetching)
88
+ })
89
+ }
90
+ }),
91
+ ),
92
+ )
93
+
94
+ destroyRef.onDestroy(unsubscribe)
95
+
96
+ return result
97
+ }
@@ -0,0 +1,80 @@
1
+ import {
2
+ DestroyRef,
3
+ Injector,
4
+ NgZone,
5
+ assertInInjectionContext,
6
+ inject,
7
+ signal,
8
+ } from '@angular/core'
9
+ import { QueryClient, notifyManager } from '@tanstack/query-core'
10
+ import type { MutationFilters } from '@tanstack/query-core'
11
+ import type { Signal } from '@angular/core'
12
+
13
+ export interface InjectIsMutatingOptions {
14
+ /**
15
+ * The `Injector` in which to create the isMutating signal.
16
+ *
17
+ * If this is not provided, the current injection context will be used instead (via `inject`).
18
+ */
19
+ injector?: Injector
20
+ }
21
+
22
+ /**
23
+ * Injects a signal that tracks the number of mutations that your application currently has `pending`
24
+ * (useful for app-wide loading indicators).
25
+ *
26
+ * @param filters - The {@link MutationFilters} to narrow down the matched mutations.
27
+ * @param options - Additional configuration
28
+ * @returns A `Signal` with the number of mutations that your application currently has `pending`.
29
+ *
30
+ * @example
31
+ * ```angular-ts
32
+ * @Component({
33
+ * selector: 'posts-mutating-indicator',
34
+ * template: `
35
+ * @if (isMutatingPosts()) {
36
+ * <span>Saving posts...</span>
37
+ * }
38
+ * `,
39
+ * })
40
+ * export class PostsMutatingIndicator {
41
+ * // How many mutations matching the posts prefix are in progress?
42
+ * readonly isMutatingPosts = injectIsMutating({ mutationKey: ['posts'] })
43
+ * }
44
+ * ```
45
+ */
46
+ export function injectIsMutating(
47
+ filters?: MutationFilters,
48
+ options?: InjectIsMutatingOptions,
49
+ ): Signal<number> {
50
+ !options?.injector && assertInInjectionContext(injectIsMutating)
51
+ const injector = options?.injector ?? inject(Injector)
52
+ const destroyRef = injector.get(DestroyRef)
53
+ const ngZone = injector.get(NgZone)
54
+ const queryClient = injector.get(QueryClient)
55
+
56
+ const cache = queryClient.getMutationCache()
57
+ // isMutating is the prev value initialized on mount *
58
+ let isMutating = queryClient.isMutating(filters)
59
+
60
+ const result = signal(isMutating)
61
+
62
+ const unsubscribe = ngZone.runOutsideAngular(() =>
63
+ cache.subscribe(
64
+ notifyManager.batchCalls(() => {
65
+ const newIsMutating = queryClient.isMutating(filters)
66
+ if (isMutating !== newIsMutating) {
67
+ // * and update with each change
68
+ isMutating = newIsMutating
69
+ ngZone.run(() => {
70
+ result.set(isMutating)
71
+ })
72
+ }
73
+ }),
74
+ ),
75
+ )
76
+
77
+ destroyRef.onDestroy(unsubscribe)
78
+
79
+ return result.asReadonly()
80
+ }
@@ -0,0 +1,53 @@
1
+ import {
2
+ InjectionToken,
3
+ Injector,
4
+ assertInInjectionContext,
5
+ inject,
6
+ signal,
7
+ } from '@angular/core'
8
+ import type { Provider, Signal } from '@angular/core'
9
+
10
+ /**
11
+ * Internal token used to track isRestoring state, accessible in public API through `injectIsRestoring` and set via `provideIsRestoring`
12
+ */
13
+ const IS_RESTORING = new InjectionToken('', {
14
+ // Default value when not provided
15
+ factory: () => signal(false).asReadonly(),
16
+ })
17
+
18
+ interface InjectIsRestoringOptions {
19
+ /**
20
+ * The `Injector` to use to get the isRestoring signal.
21
+ *
22
+ * If this is not provided, the current injection context will be used instead (via `inject`).
23
+ */
24
+ injector?: Injector
25
+ }
26
+
27
+ /**
28
+ * Injects a signal that tracks whether a restore (e.g. from a persisted client, wired up via
29
+ * `provideIsRestoring`) is currently in progress. `injectQuery` and friends also check this internally to
30
+ * avoid race conditions between the restore and initializing queries.
31
+ * @param options - Additional configuration
32
+ * @returns A readonly `Signal<boolean>` — `true` while a restore is in progress, `false` otherwise (the
33
+ * default when no `provideIsRestoring` provider is registered).
34
+ */
35
+ export function injectIsRestoring(options?: InjectIsRestoringOptions) {
36
+ !options?.injector && assertInInjectionContext(injectIsRestoring)
37
+ const injector = options?.injector ?? inject(Injector)
38
+ return injector.get(IS_RESTORING)
39
+ }
40
+
41
+ /**
42
+ * Registers a provider for the restore state read by `injectIsRestoring`. Wire this up wherever you drive a
43
+ * restore yourself — e.g. a persist-client integration — so `injectQuery` and friends can defer subscribing
44
+ * to their observer (avoiding a race with the restore) until the restore signal flips back to `false`.
45
+ * @param isRestoring - A readonly `Signal<boolean>` that tracks the restore state.
46
+ * @returns A provider for the `isRestoring` signal.
47
+ */
48
+ export function provideIsRestoring(isRestoring: Signal<boolean>): Provider {
49
+ return {
50
+ provide: IS_RESTORING,
51
+ useValue: isRestoring,
52
+ }
53
+ }
@@ -0,0 +1,167 @@
1
+ import {
2
+ DestroyRef,
3
+ Injector,
4
+ NgZone,
5
+ assertInInjectionContext,
6
+ computed,
7
+ inject,
8
+ signal,
9
+ } from '@angular/core'
10
+ import {
11
+ QueryClient,
12
+ notifyManager,
13
+ replaceEqualDeep,
14
+ } from '@tanstack/query-core'
15
+ import type { Signal } from '@angular/core'
16
+ import type {
17
+ Mutation,
18
+ MutationCache,
19
+ MutationFilters,
20
+ MutationState,
21
+ } from '@tanstack/query-core'
22
+
23
+ type MutationStateOptions<TResult = MutationState> = {
24
+ filters?: MutationFilters
25
+ select?: (mutation: Mutation) => TResult
26
+ }
27
+
28
+ function getResult<TResult = MutationState>(
29
+ mutationCache: MutationCache,
30
+ options: MutationStateOptions<TResult>,
31
+ ): Array<TResult> {
32
+ return mutationCache
33
+ .findAll(options.filters)
34
+ .map(
35
+ (mutation): TResult =>
36
+ (options.select ? options.select(mutation) : mutation.state) as TResult,
37
+ )
38
+ }
39
+
40
+ export interface InjectMutationStateOptions {
41
+ /**
42
+ * The `Injector` in which to create the mutation state signal.
43
+ *
44
+ * If this is not provided, the current injection context will be used instead (via `inject`).
45
+ */
46
+ injector?: Injector
47
+ }
48
+
49
+ /**
50
+ * Injects a signal that gives you access to all mutations in the `MutationCache`. You can pass `filters`
51
+ * ({@link MutationFilters}) to narrow down your mutations, and `select` to transform the mutation state.
52
+ *
53
+ * @param injectMutationStateFn - A function returning the `filters` to narrow down matched mutations, and an
54
+ * optional `select` to transform the mutation state. Similar to `computed` from Angular, this function runs
55
+ * in the reactive context, so signals read inside it re-narrow the matched mutations.
56
+ * @param options - Additional configuration
57
+ * @returns A `Signal` with an Array of whatever `select` returns for each matching mutation.
58
+ *
59
+ * @example
60
+ * Get all variables of all running mutations:
61
+ * ```angular-ts
62
+ * @Component({
63
+ * selector: 'pending-posts',
64
+ * template: `{{ pendingVariables().length }} posts saving...`,
65
+ * })
66
+ * export class PendingPosts {
67
+ * readonly pendingVariables = injectMutationState(() => ({
68
+ * filters: { status: 'pending' },
69
+ * select: (mutation) => mutation.state.variables,
70
+ * }))
71
+ * }
72
+ * ```
73
+ *
74
+ * @example
75
+ * Get all data for specific mutations via the `mutationKey`:
76
+ * ```angular-ts
77
+ * const mutationKey = ['posts']
78
+ *
79
+ * @Component({
80
+ * selector: 'posts',
81
+ * template: `
82
+ * <button (click)="createPost()">
83
+ * Create post ({{ savedPosts().length }} saved so far)
84
+ * </button>
85
+ * `,
86
+ * })
87
+ * export class Posts {
88
+ * // Some mutation that we want to get the state for
89
+ * readonly createPostMutation = injectMutation(() => ({
90
+ * mutationKey,
91
+ * mutationFn: createPosts,
92
+ * }))
93
+ *
94
+ * readonly savedPosts = injectMutationState(() => ({
95
+ * // this mutation key needs to match the mutation key of the given mutation (see above)
96
+ * filters: { mutationKey, status: 'success' },
97
+ * select: (mutation) => mutation.state.data,
98
+ * }))
99
+ *
100
+ * createPost() {
101
+ * this.createPostMutation.mutate(['New Post'])
102
+ * }
103
+ * }
104
+ * ```
105
+ */
106
+ export function injectMutationState<TResult = MutationState>(
107
+ injectMutationStateFn: () => MutationStateOptions<TResult> = () => ({}),
108
+ options?: InjectMutationStateOptions,
109
+ ): Signal<Array<TResult>> {
110
+ !options?.injector && assertInInjectionContext(injectMutationState)
111
+ const injector = options?.injector ?? inject(Injector)
112
+ const destroyRef = injector.get(DestroyRef)
113
+ const ngZone = injector.get(NgZone)
114
+ const queryClient = injector.get(QueryClient)
115
+ const mutationCache = queryClient.getMutationCache()
116
+
117
+ /**
118
+ * Computed signal that gets result from mutation cache based on passed options
119
+ * First element is the result, second element is the time when the result was set
120
+ */
121
+ const resultFromOptionsSignal = computed(() => {
122
+ return [
123
+ getResult(mutationCache, injectMutationStateFn()),
124
+ performance.now(),
125
+ ] as const
126
+ })
127
+
128
+ /**
129
+ * Signal that contains result set by subscriber
130
+ * First element is the result, second element is the time when the result was set
131
+ */
132
+ const resultFromSubscriberSignal = signal<[Array<TResult>, number] | null>(
133
+ null,
134
+ )
135
+
136
+ /**
137
+ * Returns the last result by either subscriber or options
138
+ */
139
+ const effectiveResultSignal = computed(() => {
140
+ const optionsResult = resultFromOptionsSignal()
141
+ const subscriberResult = resultFromSubscriberSignal()
142
+ return subscriberResult && subscriberResult[1] > optionsResult[1]
143
+ ? subscriberResult[0]
144
+ : optionsResult[0]
145
+ })
146
+
147
+ const unsubscribe = ngZone.runOutsideAngular(() =>
148
+ mutationCache.subscribe(
149
+ notifyManager.batchCalls(() => {
150
+ const [lastResult] = effectiveResultSignal()
151
+ const nextResult = replaceEqualDeep(
152
+ lastResult,
153
+ getResult(mutationCache, injectMutationStateFn()),
154
+ )
155
+ if (lastResult !== nextResult) {
156
+ ngZone.run(() => {
157
+ resultFromSubscriberSignal.set([nextResult, performance.now()])
158
+ })
159
+ }
160
+ }),
161
+ ),
162
+ )
163
+
164
+ destroyRef.onDestroy(unsubscribe)
165
+
166
+ return effectiveResultSignal
167
+ }