@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,208 @@
1
+ import { QueryObserver } from '@tanstack/query-core'
2
+ import {
3
+ Injector,
4
+ assertInInjectionContext,
5
+ inject,
6
+ runInInjectionContext,
7
+ } from '@angular/core'
8
+ import { createBaseQuery } from './create-base-query'
9
+ import type { DefaultError, QueryKey } from '@tanstack/query-core'
10
+ import type {
11
+ CreateQueryOptions,
12
+ CreateQueryResult,
13
+ DefinedCreateQueryResult,
14
+ } from './types'
15
+ import type {
16
+ DefinedInitialDataOptions,
17
+ UndefinedInitialDataOptions,
18
+ } from './query-options'
19
+
20
+ export interface InjectQueryOptions {
21
+ /**
22
+ * The `Injector` in which to create the query.
23
+ *
24
+ * If this is not provided, the current injection context will be used instead (via `inject`).
25
+ */
26
+ injector?: Injector
27
+ }
28
+
29
+ /**
30
+ * This overload is selected when `initialData` is set on the options returned by `injectQueryFn`, so the
31
+ * resulting `data` signal is never `undefined` (unless a `select` changes `TData` to include `undefined`).
32
+ *
33
+ * @see https://tanstack.com/query/latest/docs/framework/angular/guides/queries
34
+ * @see {@link queryOptions} to share these options between `injectQuery` and imperative APIs like
35
+ * `queryClient.fetchQuery`.
36
+ * @param injectQueryFn - A function returning the {@link DefinedInitialDataOptions} to use — everything you
37
+ * can pass to `injectQuery`, with `initialData` set. Similar to `computed` from Angular, this function runs
38
+ * in the reactive context, so signals read inside it (in `queryKey`, `enabled`, etc.) drive the query.
39
+ * @param options - Additional configuration
40
+ * @returns The query result, typed so that `data` is never `undefined` (unless a `select` changes `TData` to
41
+ * include `undefined`).
42
+ *
43
+ * @example
44
+ * ```angular-ts
45
+ * @Component({
46
+ * selector: 'posts',
47
+ * template: `
48
+ * <!-- `postsQuery.data()` is `Post[]`, never `undefined`, thanks to `initialData` — even if a
49
+ * refetch fails, so the list stays visible alongside the error. -->
50
+ * @if (postsQuery.isError()) {
51
+ * <span>Error: {{ postsQuery.error()?.message }}</span>
52
+ * }
53
+ * <ul>
54
+ * @for (post of postsQuery.data(); track post.id) {
55
+ * <li>{{ post.title }}</li>
56
+ * }
57
+ * </ul>
58
+ * `,
59
+ * })
60
+ * export class Posts {
61
+ * readonly postsQuery = injectQuery(() => ({
62
+ * queryKey: ['posts'],
63
+ * queryFn: fetchPosts,
64
+ * initialData: [],
65
+ * }))
66
+ * }
67
+ * ```
68
+ */
69
+ export function injectQuery<
70
+ TQueryFnData = unknown,
71
+ TError = DefaultError,
72
+ TData = TQueryFnData,
73
+ TQueryKey extends QueryKey = QueryKey,
74
+ >(
75
+ injectQueryFn: () => DefinedInitialDataOptions<
76
+ TQueryFnData,
77
+ TError,
78
+ TData,
79
+ TQueryKey
80
+ >,
81
+ options?: InjectQueryOptions,
82
+ ): DefinedCreateQueryResult<TData, TError>
83
+
84
+ /**
85
+ * Injects a query: a declarative dependency on an asynchronous source of data that is tied to a unique key.
86
+ *
87
+ * @see https://tanstack.com/query/latest/docs/framework/angular/guides/queries
88
+ * @see {@link queryOptions} to share these options between `injectQuery` and imperative APIs like
89
+ * `queryClient.fetchQuery`.
90
+ * @param injectQueryFn - A function returning the {@link UndefinedInitialDataOptions} to use — everything
91
+ * you can pass to `injectQuery`. Similar to `computed` from Angular, this function runs in the reactive
92
+ * context, so signals read inside it (in `queryKey`, `enabled`, etc.) drive the query.
93
+ * @param options - Additional configuration
94
+ * @returns The query result. `status()` is `'pending'` if there is no cached data to display, `'error'` if
95
+ * the last fetch attempt failed, or `'success'` if the query has data to display. `isPending`/`isSuccess`/
96
+ * `isError` are type-guard methods for convenience.
97
+ *
98
+ * @example
99
+ * ```angular-ts
100
+ * @Component({
101
+ * selector: 'posts',
102
+ * template: `
103
+ * @if (postsQuery.isPending()) {
104
+ * Loading...
105
+ * } @else if (postsQuery.isError()) {
106
+ * <span>Error: {{ postsQuery.error()?.message }}</span>
107
+ * } @else {
108
+ * <ul>
109
+ * @for (post of postsQuery.data(); track post.id) {
110
+ * <li>{{ post.title }}</li>
111
+ * }
112
+ * </ul>
113
+ * }
114
+ * `,
115
+ * })
116
+ * export class Posts {
117
+ * readonly postsQuery = injectQuery(() => ({
118
+ * queryKey: ['posts'],
119
+ * queryFn: fetchPosts,
120
+ * }))
121
+ * }
122
+ * ```
123
+ *
124
+ * @example
125
+ * Similar to `computed` from Angular, the function passed to `injectQuery` runs in the reactive context. In
126
+ * the example below, the query is automatically enabled and executed when the filter signal changes to a
127
+ * truthy value. When the filter signal changes back to a falsy value, the query is disabled.
128
+ * ```angular-ts
129
+ * @Component({
130
+ * selector: 'posts',
131
+ * template: `
132
+ * <input [ngModel]="filter()" (ngModelChange)="filter.set($event)" />
133
+ * @if (postsQuery.isPending()) {
134
+ * Loading...
135
+ * } @else if (postsQuery.isError()) {
136
+ * <span>Error: {{ postsQuery.error()?.message }}</span>
137
+ * } @else {
138
+ * <ul>
139
+ * @for (post of postsQuery.data(); track post.id) {
140
+ * <li>{{ post.title }}</li>
141
+ * }
142
+ * </ul>
143
+ * }
144
+ * `,
145
+ * })
146
+ * export class Posts {
147
+ * readonly filter = signal('')
148
+ *
149
+ * readonly postsQuery = injectQuery(() => ({
150
+ * queryKey: ['posts', this.filter()],
151
+ * queryFn: () => fetchPosts(this.filter()),
152
+ * // Signals can be combined with expressions
153
+ * enabled: !!this.filter(),
154
+ * }))
155
+ * }
156
+ * ```
157
+ */
158
+ export function injectQuery<
159
+ TQueryFnData = unknown,
160
+ TError = DefaultError,
161
+ TData = TQueryFnData,
162
+ TQueryKey extends QueryKey = QueryKey,
163
+ >(
164
+ injectQueryFn: () => UndefinedInitialDataOptions<
165
+ TQueryFnData,
166
+ TError,
167
+ TData,
168
+ TQueryKey
169
+ >,
170
+ options?: InjectQueryOptions,
171
+ ): CreateQueryResult<TData, TError>
172
+
173
+ /**
174
+ * This overload accepts the general {@link CreateQueryOptions} shape rather than the `initialData`-aware
175
+ * overloads above, so whether `data` is defined can't be inferred from the call site — useful when wrapping
176
+ * `injectQuery` in your own helper function that forwards caller-provided options.
177
+ *
178
+ * @see https://tanstack.com/query/latest/docs/framework/angular/guides/queries
179
+ * @param injectQueryFn - A function that returns query options. Similar to `computed` from Angular, this
180
+ * function runs in the reactive context, so signals read inside it (in `queryKey`, `enabled`, etc.) drive
181
+ * the query.
182
+ * @param options - Additional configuration
183
+ * @returns The query result.
184
+ */
185
+ export function injectQuery<
186
+ TQueryFnData = unknown,
187
+ TError = DefaultError,
188
+ TData = TQueryFnData,
189
+ TQueryKey extends QueryKey = QueryKey,
190
+ >(
191
+ injectQueryFn: () => CreateQueryOptions<
192
+ TQueryFnData,
193
+ TError,
194
+ TData,
195
+ TQueryKey
196
+ >,
197
+ options?: InjectQueryOptions,
198
+ ): CreateQueryResult<TData, TError>
199
+
200
+ export function injectQuery(
201
+ injectQueryFn: () => CreateQueryOptions,
202
+ options?: InjectQueryOptions,
203
+ ) {
204
+ !options?.injector && assertInInjectionContext(injectQuery)
205
+ return runInInjectionContext(options?.injector ?? inject(Injector), () =>
206
+ createBaseQuery(injectQueryFn, QueryObserver),
207
+ ) as unknown as CreateQueryResult
208
+ }
@@ -0,0 +1,121 @@
1
+ import type { DefaultError, WithRequired } from '@tanstack/query-core'
2
+ import type { CreateMutationOptions } from './types'
3
+
4
+ /**
5
+ * You can generally pass everything to `mutationOptions` that you can also pass to `injectMutation`. A
6
+ * `mutationKey` is required on this overload so the mutation can be looked up later, e.g. with
7
+ * `injectMutationState`.
8
+ *
9
+ * @see {@link injectMutation} to run the mutation these options describe.
10
+ * @param options - The mutation options to use, identical to what you'd pass to `injectMutation`, with a
11
+ * required `mutationKey`.
12
+ * @returns The same options object, unchanged.
13
+ *
14
+ * @example
15
+ * Looking the mutation up elsewhere via its `mutationKey`, e.g. for a global "saving…" indicator:
16
+ * ```angular-ts
17
+ * import { mutationOptions, injectMutationState } from '@tanstack/angular-query-experimental'
18
+ *
19
+ * const createPostOptions = mutationOptions({
20
+ * mutationKey: ['posts', 'create'],
21
+ * mutationFn: createPost,
22
+ * })
23
+ *
24
+ * @Component({
25
+ * selector: 'saving-indicator',
26
+ * template: `
27
+ * @if (isCreatingPost()) {
28
+ * <span>Saving…</span>
29
+ * }
30
+ * `,
31
+ * })
32
+ * export class SavingIndicator {
33
+ * readonly #pendingCreates = injectMutationState(() => ({
34
+ * filters: { mutationKey: createPostOptions.mutationKey, status: 'pending' },
35
+ * }))
36
+ * readonly isCreatingPost = computed(() => this.#pendingCreates().length > 0)
37
+ * }
38
+ * ```
39
+ */
40
+ export function mutationOptions<
41
+ TData = unknown,
42
+ TError = DefaultError,
43
+ TVariables = void,
44
+ TOnMutateResult = unknown,
45
+ >(
46
+ options: WithRequired<
47
+ CreateMutationOptions<TData, TError, TVariables, TOnMutateResult>,
48
+ 'mutationKey'
49
+ >,
50
+ ): WithRequired<
51
+ CreateMutationOptions<TData, TError, TVariables, TOnMutateResult>,
52
+ 'mutationKey'
53
+ >
54
+ /**
55
+ * You can generally pass everything to `mutationOptions` that you can also pass to `injectMutation`. No
56
+ * `mutationKey` is required on this overload — use this when you don't need to target the mutation via a
57
+ * `mutationKey` filter later (e.g. with `injectMutationState`); it can still be observed through other
58
+ * filters, such as `status`.
59
+ *
60
+ * @see {@link injectMutation} to run the mutation these options describe.
61
+ * @param options - The mutation options to use, identical to what you'd pass to `injectMutation`, without a
62
+ * `mutationKey`.
63
+ * @returns The same options object, unchanged.
64
+ * @remarks See the other overload's example for looking a mutation up via `injectMutationState`.
65
+ *
66
+ * @example
67
+ * Sharing options across services, so `QueriesService` stays the single place a mutation is defined:
68
+ * ```angular-ts
69
+ * import { mutationOptions, injectMutation } from '@tanstack/angular-query-experimental'
70
+ *
71
+ * @Injectable({ providedIn: 'root' })
72
+ * export class QueriesService {
73
+ * readonly #queryClient = inject(QueryClient)
74
+ *
75
+ * updatePost(id: number) {
76
+ * return mutationOptions({
77
+ * mutationFn: (post: Partial<Post>) => putPost(id, post),
78
+ * onSuccess: (newPost) => this.#queryClient.setQueryData(['posts', id], newPost),
79
+ * })
80
+ * }
81
+ * }
82
+ *
83
+ * @Component({
84
+ * selector: 'post',
85
+ * template: `<button (click)="save()">Save</button>`,
86
+ * })
87
+ * export class Post {
88
+ * readonly queries = inject(QueriesService)
89
+ * readonly id = signal(0)
90
+ * readonly updatePostMutation = injectMutation(() => this.queries.updatePost(this.id()))
91
+ *
92
+ * save() {
93
+ * this.updatePostMutation.mutate({ title: 'New Title' })
94
+ * }
95
+ * }
96
+ * ```
97
+ */
98
+ export function mutationOptions<
99
+ TData = unknown,
100
+ TError = DefaultError,
101
+ TVariables = void,
102
+ TOnMutateResult = unknown,
103
+ >(
104
+ options: Omit<
105
+ CreateMutationOptions<TData, TError, TVariables, TOnMutateResult>,
106
+ 'mutationKey'
107
+ >,
108
+ ): Omit<
109
+ CreateMutationOptions<TData, TError, TVariables, TOnMutateResult>,
110
+ 'mutationKey'
111
+ >
112
+ export function mutationOptions<
113
+ TData = unknown,
114
+ TError = DefaultError,
115
+ TVariables = void,
116
+ TOnMutateResult = unknown,
117
+ >(
118
+ options: CreateMutationOptions<TData, TError, TVariables, TOnMutateResult>,
119
+ ): CreateMutationOptions<TData, TError, TVariables, TOnMutateResult> {
120
+ return options
121
+ }
@@ -0,0 +1,27 @@
1
+ import { InjectionToken, inject } from '@angular/core'
2
+ import * as ng from '@angular/core'
3
+ import { noop } from '@tanstack/query-core'
4
+
5
+ type PendingTasksCompat = { add: () => PendingTaskRef }
6
+
7
+ export type PendingTaskRef = () => void
8
+
9
+ export const PENDING_TASKS = new InjectionToken<PendingTasksCompat>(
10
+ 'PENDING_TASKS',
11
+ {
12
+ factory: (): PendingTasksCompat => {
13
+ // Access via Reflect so bundlers stay quiet when the token is absent (Angular < 19).
14
+ const token = Reflect.get(ng, 'PendingTasks') as unknown as
15
+ Parameters<typeof inject>[0] | undefined
16
+
17
+ const svc: PendingTasksCompat | null = token
18
+ ? (inject(token, { optional: true }) as PendingTasksCompat | null)
19
+ : null
20
+
21
+ // Without PendingTasks we fall back to a stable no-op shim.
22
+ return {
23
+ add: svc ? () => svc.add() : () => noop,
24
+ }
25
+ },
26
+ },
27
+ )
@@ -0,0 +1,170 @@
1
+ import { DestroyRef, InjectionToken, inject } from '@angular/core'
2
+ import { QueryClient } from '@tanstack/query-core'
3
+ import type { Provider } from '@angular/core'
4
+
5
+ /**
6
+ * Usually {@link provideTanStackQuery} is used once to set up TanStack Query and the
7
+ * [`QueryClient`](https://tanstack.com/query/latest/docs/reference/QueryClient) for the entire application —
8
+ * it calls `provideQueryClient` internally. Use `provideQueryClient` directly to provide a different
9
+ * `QueryClient` instance for part of the application, or for unit testing.
10
+ * @param queryClient - A `QueryClient` instance, or an `InjectionToken` which provides a `QueryClient`.
11
+ * @returns A provider object that can be used to provide the `QueryClient` instance.
12
+ *
13
+ * @example
14
+ * Providing a test-only `QueryClient` in a component test, without wiring up `provideTanStackQuery`'s other
15
+ * defaults:
16
+ * ```ts
17
+ * TestBed.configureTestingModule({
18
+ * providers: [provideQueryClient(new QueryClient())],
19
+ * })
20
+ * ```
21
+ */
22
+ export function provideQueryClient(
23
+ queryClient: QueryClient | InjectionToken<QueryClient>,
24
+ ): Provider {
25
+ return {
26
+ provide: QueryClient,
27
+ useFactory: () => {
28
+ const client =
29
+ queryClient instanceof InjectionToken
30
+ ? inject(queryClient)
31
+ : queryClient
32
+ // Unmount the query client on injector destroy
33
+ inject(DestroyRef).onDestroy(() => client.unmount())
34
+ client.mount()
35
+ return client
36
+ },
37
+ }
38
+ }
39
+
40
+ /**
41
+ * Sets up providers necessary to enable TanStack Query functionality for Angular applications. Allows
42
+ * configuring a `QueryClient` and optional features such as developer tools.
43
+ *
44
+ * @see https://tanstack.com/query/v5/docs/framework/angular/quick-start
45
+ * @see {@link withDevtools}
46
+ * @param queryClient - A `QueryClient` instance, or an `InjectionToken` which provides a `QueryClient`.
47
+ * @param features - Optional features to configure additional Query functionality.
48
+ * @returns A set of providers to set up TanStack Query.
49
+ *
50
+ * @example
51
+ * ```ts
52
+ * import { provideTanStackQuery, QueryClient } from '@tanstack/angular-query-experimental'
53
+ *
54
+ * bootstrapApplication(AppComponent, {
55
+ * providers: [provideTanStackQuery(new QueryClient())],
56
+ * })
57
+ * ```
58
+ *
59
+ * @example
60
+ * The same, in an `NgModule`-based application:
61
+ * ```ts
62
+ * import { provideTanStackQuery, QueryClient } from '@tanstack/angular-query-experimental'
63
+ *
64
+ * @NgModule({
65
+ * declarations: [AppComponent],
66
+ * imports: [BrowserModule],
67
+ * providers: [provideTanStackQuery(new QueryClient())],
68
+ * bootstrap: [AppComponent],
69
+ * })
70
+ * export class AppModule {}
71
+ * ```
72
+ *
73
+ * @example
74
+ * Enabling optional developer tools by adding `withDevtools` — by default, the tools are then loaded when
75
+ * your app is in development mode:
76
+ * ```ts
77
+ * import {
78
+ * provideTanStackQuery,
79
+ * withDevtools,
80
+ * QueryClient,
81
+ * } from '@tanstack/angular-query-experimental'
82
+ *
83
+ * bootstrapApplication(AppComponent, {
84
+ * providers: [provideTanStackQuery(new QueryClient(), withDevtools())],
85
+ * })
86
+ * ```
87
+ *
88
+ * @example
89
+ * Using an `InjectionToken` for the `QueryClient` — an advanced optimization that lets TanStack Query be
90
+ * absent from the main application bundle, useful for including it on lazy-loaded routes only while still
91
+ * sharing a `QueryClient`. This is a small optimization; for most applications it's preferable to provide
92
+ * the `QueryClient` in the main application config, as in the examples above:
93
+ * ```ts
94
+ * export const MY_QUERY_CLIENT = new InjectionToken('', {
95
+ * factory: () => new QueryClient(),
96
+ * })
97
+ *
98
+ * // In a lazy loaded route or lazy loaded component's providers array:
99
+ * providers: [provideTanStackQuery(MY_QUERY_CLIENT)]
100
+ * ```
101
+ */
102
+ export function provideTanStackQuery(
103
+ queryClient: QueryClient | InjectionToken<QueryClient>,
104
+ ...features: Array<QueryFeatures>
105
+ ): Array<Provider> {
106
+ return [
107
+ provideQueryClient(queryClient),
108
+ features.map((feature) => feature.ɵproviders),
109
+ ]
110
+ }
111
+
112
+ /**
113
+ * Sets up providers necessary to enable TanStack Query functionality for Angular applications.
114
+ *
115
+ * Allows configuring a `QueryClient`.
116
+ * @see https://tanstack.com/query/v5/docs/framework/angular/quick-start
117
+ * @param queryClient - A `QueryClient` instance.
118
+ * @returns A set of providers to set up TanStack Query.
119
+ * @deprecated Use `provideTanStackQuery` instead.
120
+ */
121
+ export function provideAngularQuery(queryClient: QueryClient): Array<Provider> {
122
+ return provideTanStackQuery(queryClient)
123
+ }
124
+
125
+ const queryFeatures = ['Devtools', 'PersistQueryClient'] as const
126
+
127
+ type QueryFeatureKind = (typeof queryFeatures)[number]
128
+
129
+ /**
130
+ * Helper type to represent a Query feature.
131
+ */
132
+ export interface QueryFeature<TFeatureKind extends QueryFeatureKind> {
133
+ ɵkind: TFeatureKind
134
+ ɵproviders: Array<Provider>
135
+ }
136
+
137
+ /**
138
+ * Helper function to create an object that represents a Query feature.
139
+ * @param kind - The kind of feature, e.g. `'Devtools'`.
140
+ * @param providers - The Angular providers this feature contributes to `provideTanStackQuery`.
141
+ * @returns A Query feature.
142
+ */
143
+ export function queryFeature<TFeatureKind extends QueryFeatureKind>(
144
+ kind: TFeatureKind,
145
+ providers: Array<Provider>,
146
+ ): QueryFeature<TFeatureKind> {
147
+ return { ɵkind: kind, ɵproviders: providers }
148
+ }
149
+
150
+ /**
151
+ * A type alias that represents a feature which enables developer tools.
152
+ * The type is used to describe the return value of the `withDevtools` function.
153
+ * @see {@link withDevtools}
154
+ */
155
+ export type DevtoolsFeature = QueryFeature<'Devtools'>
156
+
157
+ /**
158
+ * A type alias that represents a feature which enables persistence.
159
+ * The type is used to describe the return value of the `withPersistQueryClient` function.
160
+ */
161
+ export type PersistQueryClientFeature = QueryFeature<'PersistQueryClient'>
162
+
163
+ /**
164
+ * A type alias that represents all Query features available for use with `provideTanStackQuery`.
165
+ * Features can be enabled by adding special functions to the `provideTanStackQuery` call.
166
+ * See documentation for each symbol to find corresponding function name. See also `provideTanStackQuery`
167
+ * documentation on how to use those functions.
168
+ * @see {@link provideTanStackQuery}
169
+ */
170
+ export type QueryFeatures = DevtoolsFeature | PersistQueryClientFeature