@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,175 @@
1
+ import {
2
+ NgZone,
3
+ VERSION,
4
+ computed,
5
+ effect,
6
+ inject,
7
+ signal,
8
+ untracked,
9
+ } from '@angular/core'
10
+ import {
11
+ QueryClient,
12
+ notifyManager,
13
+ shouldThrowError,
14
+ } from '@tanstack/query-core'
15
+ import { signalProxy } from './signal-proxy'
16
+ import { injectIsRestoring } from './inject-is-restoring'
17
+ import { PENDING_TASKS } from './pending-tasks-compat'
18
+ import type { PendingTaskRef } from './pending-tasks-compat'
19
+ import type {
20
+ QueryKey,
21
+ QueryObserver,
22
+ QueryObserverResult,
23
+ } from '@tanstack/query-core'
24
+ import type { CreateBaseQueryOptions } from './types'
25
+
26
+ /**
27
+ * Base implementation for `injectQuery` and `injectInfiniteQuery`.
28
+ * @param optionsFn
29
+ * @param Observer
30
+ */
31
+ export function createBaseQuery<
32
+ TQueryFnData,
33
+ TError,
34
+ TData,
35
+ TQueryData,
36
+ TQueryKey extends QueryKey,
37
+ >(
38
+ optionsFn: () => CreateBaseQueryOptions<
39
+ TQueryFnData,
40
+ TError,
41
+ TData,
42
+ TQueryData,
43
+ TQueryKey
44
+ >,
45
+ Observer: typeof QueryObserver,
46
+ ) {
47
+ const ngZone = inject(NgZone)
48
+ const pendingTasks = inject(PENDING_TASKS)
49
+ const queryClient = inject(QueryClient)
50
+ const isRestoring = injectIsRestoring()
51
+
52
+ /**
53
+ * Signal that has the default options from query client applied
54
+ * computed() is used so signals can be inserted into the options
55
+ * making it reactive. Wrapping options in a function ensures embedded expressions
56
+ * are preserved and can keep being applied after signal changes
57
+ */
58
+ const defaultedOptionsSignal = computed(() => {
59
+ const defaultedOptions = queryClient.defaultQueryOptions(optionsFn())
60
+ defaultedOptions._optimisticResults = isRestoring()
61
+ ? 'isRestoring'
62
+ : 'optimistic'
63
+ return defaultedOptions
64
+ })
65
+
66
+ const observerSignal = (() => {
67
+ let instance: QueryObserver<
68
+ TQueryFnData,
69
+ TError,
70
+ TData,
71
+ TQueryData,
72
+ TQueryKey
73
+ > | null = null
74
+
75
+ return computed(() => {
76
+ return (instance ||= new Observer(queryClient, defaultedOptionsSignal()))
77
+ })
78
+ })()
79
+
80
+ const optimisticResultSignal = computed(() =>
81
+ observerSignal().getOptimisticResult(defaultedOptionsSignal()),
82
+ )
83
+
84
+ const resultFromSubscriberSignal = signal<QueryObserverResult<
85
+ TData,
86
+ TError
87
+ > | null>(null)
88
+
89
+ effect(
90
+ (onCleanup) => {
91
+ const observer = observerSignal()
92
+ const defaultedOptions = defaultedOptionsSignal()
93
+
94
+ untracked(() => {
95
+ observer.setOptions(defaultedOptions)
96
+ })
97
+ onCleanup(() => {
98
+ ngZone.run(() => resultFromSubscriberSignal.set(null))
99
+ })
100
+ },
101
+ {
102
+ // Set allowSignalWrites to support Angular < v19
103
+ // Set to undefined to avoid warning on newer versions
104
+ allowSignalWrites: VERSION.major < '19' || undefined,
105
+ },
106
+ )
107
+
108
+ effect((onCleanup) => {
109
+ // observer.trackResult is not used as this optimization is not needed for Angular
110
+ const observer = observerSignal()
111
+ let pendingTaskRef: PendingTaskRef | null = null
112
+
113
+ const unsubscribe = isRestoring()
114
+ ? () => undefined
115
+ : untracked(() =>
116
+ ngZone.runOutsideAngular(() => {
117
+ return observer.subscribe(
118
+ notifyManager.batchCalls((state) => {
119
+ ngZone.run(() => {
120
+ if (state.fetchStatus === 'fetching' && !pendingTaskRef) {
121
+ pendingTaskRef = pendingTasks.add()
122
+ }
123
+
124
+ if (state.fetchStatus === 'idle' && pendingTaskRef) {
125
+ pendingTaskRef()
126
+ pendingTaskRef = null
127
+ }
128
+
129
+ if (
130
+ state.isError &&
131
+ !state.isFetching &&
132
+ shouldThrowError(observer.options.throwOnError, [
133
+ state.error,
134
+ observer.getCurrentQuery(),
135
+ ])
136
+ ) {
137
+ ngZone.onError.emit(state.error)
138
+ throw state.error
139
+ }
140
+ resultFromSubscriberSignal.set(state)
141
+ })
142
+ }),
143
+ )
144
+ }),
145
+ )
146
+
147
+ onCleanup(() => {
148
+ if (pendingTaskRef) {
149
+ pendingTaskRef()
150
+ pendingTaskRef = null
151
+ }
152
+ unsubscribe()
153
+ })
154
+ })
155
+
156
+ return signalProxy(
157
+ computed(() => {
158
+ const subscriberResult = resultFromSubscriberSignal()
159
+ const optimisticResult = optimisticResultSignal()
160
+ const result = subscriberResult ?? optimisticResult
161
+
162
+ // Wrap methods to ensure observer has latest options before execution
163
+ const observer = observerSignal()
164
+
165
+ const originalRefetch = result.refetch
166
+ return {
167
+ ...result,
168
+ refetch: ((...args: Parameters<typeof originalRefetch>) => {
169
+ observer.setOptions(defaultedOptionsSignal())
170
+ return originalRefetch(...args)
171
+ }) as typeof originalRefetch,
172
+ }
173
+ }),
174
+ )
175
+ }
@@ -0,0 +1,8 @@
1
+ export type {
2
+ DevtoolsOptions,
3
+ WithDevtools,
4
+ WithDevtoolsFn,
5
+ WithDevtoolsOptions,
6
+ } from './types'
7
+
8
+ export { withDevtools } from './with-devtools'
@@ -0,0 +1 @@
1
+ export * from '..'
@@ -0,0 +1,7 @@
1
+ import type { WithDevtools } from './types'
2
+
3
+ // Stub which replaces `withDevtools` in production builds
4
+ export const withDevtools: WithDevtools = () => ({
5
+ ɵkind: 'Devtools',
6
+ ɵproviders: [],
7
+ })
@@ -0,0 +1,116 @@
1
+ import type { QueryClient } from '@tanstack/query-core'
2
+ import type {
3
+ DevtoolsButtonPosition,
4
+ DevtoolsErrorType,
5
+ DevtoolsPosition,
6
+ Theme,
7
+ } from '@tanstack/query-devtools'
8
+ import type { DevtoolsFeature } from '../providers'
9
+
10
+ /**
11
+ * Options for configuring withDevtools.
12
+ */
13
+ export interface WithDevtoolsOptions {
14
+ /**
15
+ * An array of dependencies to be injected and passed to the `withDevtoolsFn` function.
16
+ *
17
+ * **Example**
18
+ * ```ts
19
+ * export const appConfig: ApplicationConfig = {
20
+ * providers: [
21
+ * provideTanStackQuery(
22
+ * new QueryClient(),
23
+ * withDevtools(
24
+ * (devToolsOptionsManager: DevtoolsOptionsManager) => ({
25
+ * loadDevtools: devToolsOptionsManager.loadDevtools(),
26
+ * }),
27
+ * {
28
+ * deps: [DevtoolsOptionsManager],
29
+ * },
30
+ * ),
31
+ * ),
32
+ * ],
33
+ * }
34
+ * ```
35
+ */
36
+ deps?: Array<any>
37
+ }
38
+
39
+ /**
40
+ * Options for configuring the TanStack Query devtools.
41
+ */
42
+ export interface DevtoolsOptions {
43
+ /**
44
+ * Set this true if you want the devtools to default to being open
45
+ */
46
+ initialIsOpen?: boolean
47
+ /**
48
+ * The position of the TanStack logo to open and close the devtools panel.
49
+ * `top-left` | `top-right` | `bottom-left` | `bottom-right` | `relative`
50
+ *
51
+ * @defaultValue bottom-right
52
+ */
53
+ buttonPosition?: DevtoolsButtonPosition
54
+ /**
55
+ * The position of the Angular Query devtools panel.
56
+ * `top` | `bottom` | `left` | `right`
57
+ *
58
+ * @defaultValue bottom
59
+ */
60
+ position?: DevtoolsPosition
61
+ /**
62
+ * Custom instance of QueryClient
63
+ */
64
+ client?: QueryClient
65
+ /**
66
+ * Use this so you can define custom errors that can be shown in the devtools.
67
+ */
68
+ errorTypes?: Array<DevtoolsErrorType>
69
+ /**
70
+ * Use this to pass a nonce to the style tag that is added to the document head. This is useful if you are using a Content Security Policy (CSP) nonce to allow inline styles.
71
+ */
72
+ styleNonce?: string
73
+ /**
74
+ * Use this so you can attach the devtool's styles to a specific element in the DOM.
75
+ */
76
+ shadowDOMTarget?: ShadowRoot
77
+ /**
78
+ * Set this to true to hide disabled queries from the devtools panel.
79
+ */
80
+ hideDisabledQueries?: boolean
81
+ /**
82
+ * Set this to 'light', 'dark', or 'system' to change the theme of the devtools panel.
83
+ *
84
+ * @defaultValue system
85
+ */
86
+ theme?: Theme
87
+
88
+ /**
89
+ * Whether the developer tools should load.
90
+ * - `auto`- (Default) Lazily loads devtools when in development mode. Skips loading in production mode.
91
+ * - `true`- Always load the devtools, regardless of the environment.
92
+ * - `false`- Never load the devtools, regardless of the environment.
93
+ *
94
+ * You can use `true` and `false` to override loading developer tools from an environment file.
95
+ * For example, a test environment might run in production mode but you may want to load developer tools.
96
+ *
97
+ * Additionally, you can use a signal in the callback to dynamically load the devtools based on a condition. For example,
98
+ * a signal created from a RxJS observable that listens for a keyboard shortcut.
99
+ *
100
+ * **Example**
101
+ * ```ts
102
+ * withDevtools(() => ({
103
+ * initialIsOpen: true,
104
+ * loadDevtools: inject(ExampleService).loadDevtools()
105
+ * }))
106
+ * ```
107
+ */
108
+ loadDevtools?: 'auto' | boolean
109
+ }
110
+
111
+ export type WithDevtoolsFn = (...deps: Array<any>) => DevtoolsOptions
112
+
113
+ export type WithDevtools = (
114
+ withDevtoolsFn?: WithDevtoolsFn,
115
+ options?: WithDevtoolsOptions,
116
+ ) => DevtoolsFeature
@@ -0,0 +1,182 @@
1
+ import { isPlatformBrowser } from '@angular/common'
2
+ import {
3
+ DestroyRef,
4
+ ENVIRONMENT_INITIALIZER,
5
+ InjectionToken,
6
+ Injector,
7
+ PLATFORM_ID,
8
+ computed,
9
+ effect,
10
+ inject,
11
+ isDevMode,
12
+ } from '@angular/core'
13
+ import { QueryClient, noop, onlineManager } from '@tanstack/query-core'
14
+ import { queryFeature } from '../providers'
15
+ import type { Signal } from '@angular/core'
16
+ import type {
17
+ DevtoolsOptions,
18
+ WithDevtools,
19
+ WithDevtoolsFn,
20
+ WithDevtoolsOptions,
21
+ } from './types'
22
+ import type { TanstackQueryDevtools } from '@tanstack/query-devtools'
23
+
24
+ /**
25
+ * Internal token used to prevent double providing of devtools in child injectors
26
+ */
27
+ const DEVTOOLS_PROVIDED = new InjectionToken('', {
28
+ factory: () => ({
29
+ isProvided: false,
30
+ }),
31
+ })
32
+
33
+ /**
34
+ * Internal token for providing devtools options
35
+ */
36
+ const DEVTOOLS_OPTIONS_SIGNAL = new InjectionToken<Signal<DevtoolsOptions>>('')
37
+
38
+ /**
39
+ * Enables developer tools in Angular development builds.
40
+ *
41
+ * **Example**
42
+ *
43
+ * ```ts
44
+ * export const appConfig: ApplicationConfig = {
45
+ * providers: [
46
+ * provideTanStackQuery(new QueryClient(), withDevtools())
47
+ * ]
48
+ * }
49
+ * ```
50
+ * The devtools will be rendered in `<body>`.
51
+ *
52
+ * If you need more control over when devtools are loaded, you can use the `loadDevtools` option.
53
+ *
54
+ * If you need more control over where devtools are rendered, consider `injectDevtoolsPanel`. This allows rendering devtools inside your own devtools for example.
55
+ * @param withDevtoolsFn - A function that returns `DevtoolsOptions`.
56
+ * @param options - Additional options for configuring `withDevtools`.
57
+ * @returns A set of providers for use with `provideTanStackQuery`.
58
+ * @see {@link provideTanStackQuery}
59
+ * @see {@link DevtoolsOptions}
60
+ */
61
+ export const withDevtools: WithDevtools = (
62
+ withDevtoolsFn?: WithDevtoolsFn,
63
+ options: WithDevtoolsOptions = {},
64
+ ) =>
65
+ queryFeature('Devtools', [
66
+ {
67
+ provide: DEVTOOLS_OPTIONS_SIGNAL,
68
+ useFactory: (...deps: Array<any>) =>
69
+ computed(() => withDevtoolsFn?.(...deps) ?? {}),
70
+ deps: options.deps || [],
71
+ },
72
+ {
73
+ // Do not use provideEnvironmentInitializer while Angular < v19 is supported
74
+ provide: ENVIRONMENT_INITIALIZER,
75
+ multi: true,
76
+ useFactory: () => {
77
+ const devtoolsProvided = inject(DEVTOOLS_PROVIDED)
78
+ if (
79
+ !isPlatformBrowser(inject(PLATFORM_ID)) ||
80
+ devtoolsProvided.isProvided
81
+ )
82
+ return noop
83
+
84
+ devtoolsProvided.isProvided = true
85
+ let injectorIsDestroyed = false
86
+ inject(DestroyRef).onDestroy(() => (injectorIsDestroyed = true))
87
+
88
+ return () => {
89
+ const injectedClient = inject(QueryClient, {
90
+ optional: true,
91
+ })
92
+ const destroyRef = inject(DestroyRef)
93
+ const devtoolsOptions = inject(DEVTOOLS_OPTIONS_SIGNAL)
94
+ const injector = inject(Injector)
95
+
96
+ let devtools: TanstackQueryDevtools | null = null
97
+ let el: HTMLElement | null = null
98
+
99
+ const shouldLoadToolsSignal = computed(() => {
100
+ const { loadDevtools } = devtoolsOptions()
101
+ return typeof loadDevtools === 'boolean'
102
+ ? loadDevtools
103
+ : isDevMode()
104
+ })
105
+
106
+ const getResolvedQueryClient = () => {
107
+ const client = devtoolsOptions().client ?? injectedClient
108
+ if (!client) {
109
+ throw new Error('No QueryClient found')
110
+ }
111
+ return client
112
+ }
113
+
114
+ const destroyDevtools = () => {
115
+ devtools?.unmount()
116
+ el?.remove()
117
+ devtools = null
118
+ }
119
+
120
+ effect(
121
+ () => {
122
+ const shouldLoadTools = shouldLoadToolsSignal()
123
+ const {
124
+ client,
125
+ position,
126
+ errorTypes,
127
+ buttonPosition,
128
+ initialIsOpen,
129
+ theme,
130
+ } = devtoolsOptions()
131
+
132
+ if (!shouldLoadTools) {
133
+ // Destroy or do nothing
134
+ devtools && destroyDevtools()
135
+ return
136
+ }
137
+
138
+ if (devtools) {
139
+ // Update existing devtools config
140
+ client && devtools.setClient(client)
141
+ position && devtools.setPosition(position)
142
+ errorTypes && devtools.setErrorTypes(errorTypes)
143
+ buttonPosition && devtools.setButtonPosition(buttonPosition)
144
+ typeof initialIsOpen === 'boolean' &&
145
+ devtools.setInitialIsOpen(initialIsOpen)
146
+ theme && devtools.setTheme(theme)
147
+ return
148
+ }
149
+
150
+ // Create devtools
151
+ import('@tanstack/query-devtools')
152
+ .then((queryDevtools) => {
153
+ // As this code runs async, the injector could have been destroyed
154
+ if (injectorIsDestroyed) return
155
+
156
+ devtools = new queryDevtools.TanstackQueryDevtools({
157
+ ...devtoolsOptions(),
158
+ client: getResolvedQueryClient(),
159
+ queryFlavor: 'Angular Query',
160
+ version: '5',
161
+ onlineManager,
162
+ })
163
+
164
+ el = document.body.appendChild(document.createElement('div'))
165
+ el.classList.add('tsqd-parent-container')
166
+ devtools.mount(el)
167
+
168
+ destroyRef.onDestroy(destroyDevtools)
169
+ })
170
+ .catch((error) => {
171
+ console.error(
172
+ 'Install @tanstack/query-devtools or reinstall without --omit=optional.',
173
+ error,
174
+ )
175
+ })
176
+ },
177
+ { injector },
178
+ )
179
+ }
180
+ },
181
+ },
182
+ ])
@@ -0,0 +1,8 @@
1
+ export type {
2
+ InjectDevtoolsPanel,
3
+ DevtoolsPanelOptions,
4
+ InjectDevtoolsPanelOptions,
5
+ DevtoolsPanelRef,
6
+ } from './types'
7
+
8
+ export { injectDevtoolsPanel } from './inject-devtools-panel'
@@ -0,0 +1,110 @@
1
+ import {
2
+ DestroyRef,
3
+ Injector,
4
+ PLATFORM_ID,
5
+ assertInInjectionContext,
6
+ computed,
7
+ effect,
8
+ inject,
9
+ runInInjectionContext,
10
+ untracked,
11
+ } from '@angular/core'
12
+ import { QueryClient, onlineManager } from '@tanstack/query-core'
13
+ import { isPlatformBrowser } from '@angular/common'
14
+ import type { TanstackQueryDevtoolsPanel } from '@tanstack/query-devtools'
15
+ import type {
16
+ DevtoolsPanelOptions,
17
+ InjectDevtoolsPanel,
18
+ InjectDevtoolsPanelOptions,
19
+ } from './types'
20
+
21
+ /**
22
+ * Inject a TanStack Query devtools panel and render it in the DOM.
23
+ *
24
+ * Devtools panel allows programmatic control over the devtools, for example if you want to render
25
+ * the devtools as part of your own devtools.
26
+ *
27
+ * Consider `withDevtools` instead if you don't need this.
28
+ * @param injectDevtoolsPanelFn - A function that returns devtools panel options.
29
+ * @param options - Additional configuration
30
+ * @returns DevtoolsPanelRef
31
+ * @see https://tanstack.com/query/v5/docs/framework/angular/devtools
32
+ */
33
+ export const injectDevtoolsPanel: InjectDevtoolsPanel = (
34
+ injectDevtoolsPanelFn: () => DevtoolsPanelOptions,
35
+ options?: InjectDevtoolsPanelOptions,
36
+ ) => {
37
+ !options?.injector && assertInInjectionContext(injectDevtoolsPanel)
38
+ const currentInjector = options?.injector ?? inject(Injector)
39
+
40
+ return runInInjectionContext(currentInjector, () => {
41
+ const destroyRef = inject(DestroyRef)
42
+ const isBrowser = isPlatformBrowser(inject(PLATFORM_ID))
43
+ const injectedClient = inject(QueryClient, { optional: true })
44
+
45
+ const queryOptions = computed(injectDevtoolsPanelFn)
46
+ let devtools: TanstackQueryDevtoolsPanel | null = null
47
+
48
+ const destroy = () => {
49
+ devtools?.unmount()
50
+ devtools = null
51
+ }
52
+
53
+ if (!isBrowser)
54
+ return {
55
+ destroy,
56
+ }
57
+
58
+ effect(() => {
59
+ const {
60
+ client = injectedClient,
61
+ errorTypes = [],
62
+ styleNonce,
63
+ shadowDOMTarget,
64
+ onClose,
65
+ hostElement,
66
+ } = queryOptions()
67
+
68
+ untracked(() => {
69
+ if (!client) throw new Error('No QueryClient found')
70
+ if (!devtools && hostElement) {
71
+ import('@tanstack/query-devtools')
72
+ .then((queryDevtools) => {
73
+ devtools = new queryDevtools.TanstackQueryDevtoolsPanel({
74
+ client,
75
+ queryFlavor: 'Angular Query',
76
+ version: '5',
77
+ buttonPosition: 'bottom-left',
78
+ position: 'bottom',
79
+ initialIsOpen: true,
80
+ errorTypes,
81
+ styleNonce,
82
+ shadowDOMTarget,
83
+ onClose,
84
+ onlineManager,
85
+ })
86
+ devtools.mount(hostElement.nativeElement)
87
+ })
88
+ .catch((error) => {
89
+ console.error(
90
+ 'Install @tanstack/query-devtools or reinstall without --omit=optional.',
91
+ error,
92
+ )
93
+ })
94
+ } else if (devtools && hostElement) {
95
+ devtools.setClient(client)
96
+ devtools.setErrorTypes(errorTypes)
97
+ onClose && devtools.setOnClose(onClose)
98
+ } else if (devtools && !hostElement) {
99
+ destroy()
100
+ }
101
+ })
102
+ })
103
+
104
+ destroyRef.onDestroy(destroy)
105
+
106
+ return {
107
+ destroy,
108
+ }
109
+ })
110
+ }
@@ -0,0 +1 @@
1
+ export * from '..'
@@ -0,0 +1,7 @@
1
+ import { noop } from '@tanstack/query-core'
2
+ import type { InjectDevtoolsPanel } from './types'
3
+
4
+ // Stub which replaces `injectDevtoolsPanel` in production builds
5
+ export const injectDevtoolsPanel: InjectDevtoolsPanel = () => ({
6
+ destroy: noop,
7
+ })
@@ -0,0 +1,57 @@
1
+ import type { DevtoolsErrorType } from '@tanstack/query-devtools'
2
+ import type { ElementRef, Injector } from '@angular/core'
3
+ import type { QueryClient } from '@tanstack/query-core'
4
+
5
+ export interface InjectDevtoolsPanelOptions {
6
+ /**
7
+ * The `Injector` in which to create the devtools panel.
8
+ *
9
+ * If this is not provided, the current injection context will be used instead (via `inject`).
10
+ */
11
+ injector?: Injector
12
+ }
13
+
14
+ /**
15
+ * A devtools panel, which can be manually destroyed.
16
+ */
17
+ export interface DevtoolsPanelRef {
18
+ /**
19
+ * Destroy the panel, removing it from the DOM and stops listening to signal changes.
20
+ */
21
+ destroy: () => void
22
+ }
23
+
24
+ export interface DevtoolsPanelOptions {
25
+ /**
26
+ * Custom instance of QueryClient
27
+ */
28
+ client?: QueryClient
29
+ /**
30
+ * Use this so you can define custom errors that can be shown in the devtools.
31
+ */
32
+ errorTypes?: Array<DevtoolsErrorType>
33
+ /**
34
+ * Use this to pass a nonce to the style tag that is added to the document head. This is useful if you are using a Content Security Policy (CSP) nonce to allow inline styles.
35
+ */
36
+ styleNonce?: string
37
+ /**
38
+ * Use this so you can attach the devtool's styles to specific element in the DOM.
39
+ */
40
+ shadowDOMTarget?: ShadowRoot
41
+
42
+ /**
43
+ * Callback function that is called when the devtools panel is closed
44
+ */
45
+ onClose?: () => void
46
+
47
+ /**
48
+ * Element where to render the devtools panel. When set to undefined or null, the devtools panel will not be created, or destroyed if existing.
49
+ * If changed from undefined to an ElementRef, the devtools panel will be created.
50
+ */
51
+ hostElement?: ElementRef
52
+ }
53
+
54
+ export type InjectDevtoolsPanel = (
55
+ injectDevtoolsPanelFn: () => DevtoolsPanelOptions,
56
+ options?: InjectDevtoolsPanelOptions,
57
+ ) => DevtoolsPanelRef