@tanstack/solid-query 5.0.0-alpha.85 → 5.0.0-alpha.87

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 (40) hide show
  1. package/build/dev.cjs +354 -0
  2. package/build/dev.js +341 -0
  3. package/build/index.cjs +351 -0
  4. package/build/index.d.cts +142 -0
  5. package/build/index.d.ts +142 -0
  6. package/build/index.js +338 -0
  7. package/package.json +24 -18
  8. package/src/__tests__/createMutation.test.tsx +13 -14
  9. package/src/__tests__/createQuery.test.tsx +30 -64
  10. package/src/__tests__/utils.tsx +5 -2
  11. package/dist/cjs/index.cjs +0 -359
  12. package/dist/cjs/index.cjs.map +0 -1
  13. package/dist/esm/index.js +0 -342
  14. package/dist/esm/index.js.map +0 -1
  15. package/dist/source/QueryClient.js +0 -6
  16. package/dist/source/QueryClientProvider.jsx +0 -21
  17. package/dist/source/createBaseQuery.js +0 -177
  18. package/dist/source/createInfiniteQuery.js +0 -8
  19. package/dist/source/createMutation.js +0 -38
  20. package/dist/source/createQueries.js +0 -38
  21. package/dist/source/createQuery.js +0 -9
  22. package/dist/source/index.js +0 -15
  23. package/dist/source/setBatchUpdatesFn.js +0 -3
  24. package/dist/source/types.js +0 -2
  25. package/dist/source/useIsFetching.js +0 -12
  26. package/dist/source/useIsMutating.js +0 -12
  27. package/dist/source/utils.js +0 -7
  28. package/dist/types/QueryClient.d.ts +0 -29
  29. package/dist/types/QueryClientProvider.d.ts +0 -9
  30. package/dist/types/createBaseQuery.d.ts +0 -5
  31. package/dist/types/createInfiniteQuery.d.ts +0 -5
  32. package/dist/types/createMutation.d.ts +0 -5
  33. package/dist/types/createQueries.d.ts +0 -53
  34. package/dist/types/createQuery.d.ts +0 -14
  35. package/dist/types/index.d.ts +0 -13
  36. package/dist/types/setBatchUpdatesFn.d.ts +0 -1
  37. package/dist/types/types.d.ts +0 -34
  38. package/dist/types/useIsFetching.d.ts +0 -4
  39. package/dist/types/useIsMutating.d.ts +0 -4
  40. package/dist/types/utils.d.ts +0 -1
package/build/index.js ADDED
@@ -0,0 +1,338 @@
1
+ import { notifyManager, QueryClient as QueryClient$1, MutationObserver, QueriesObserver, hydrate, QueryObserver, InfiniteQueryObserver } from '@tanstack/query-core';
2
+ export * from '@tanstack/query-core';
3
+ import { batch, createContext, useContext, onMount, onCleanup, createMemo, createSignal, createComputed, on, createResource } from 'solid-js';
4
+ import { createComponent, isServer } from 'solid-js/web';
5
+ import { createStore, unwrap, reconcile } from 'solid-js/store';
6
+
7
+ // src/setBatchUpdatesFn.ts
8
+ notifyManager.setBatchNotifyFunction(batch);
9
+ var QueryClient = class extends QueryClient$1 {
10
+ constructor(config = {}) {
11
+ super(config);
12
+ }
13
+ };
14
+ var QueryClientContext = createContext(void 0);
15
+ var useQueryClient = (queryClient) => {
16
+ if (queryClient) {
17
+ return queryClient;
18
+ }
19
+ const client = useContext(QueryClientContext);
20
+ if (!client) {
21
+ throw new Error("No QueryClient set, use QueryClientProvider to set one");
22
+ }
23
+ return client;
24
+ };
25
+ var QueryClientProvider = (props) => {
26
+ onMount(() => {
27
+ props.client.mount();
28
+ });
29
+ onCleanup(() => props.client.unmount());
30
+ return createComponent(QueryClientContext.Provider, {
31
+ get value() {
32
+ return props.client;
33
+ },
34
+ get children() {
35
+ return props.children;
36
+ }
37
+ });
38
+ };
39
+
40
+ // src/utils.ts
41
+ function shouldThrowError(throwError, params) {
42
+ if (typeof throwError === "function") {
43
+ return throwError(...params);
44
+ }
45
+ return !!throwError;
46
+ }
47
+
48
+ // src/createBaseQuery.ts
49
+ function reconcileFn(store, result, reconcileOption) {
50
+ if (reconcileOption === false)
51
+ return result;
52
+ if (typeof reconcileOption === "function") {
53
+ const newData2 = reconcileOption(store.data, result.data);
54
+ return { ...result, data: newData2 };
55
+ }
56
+ const newData = reconcile(result.data, { key: reconcileOption })(store.data);
57
+ return { ...result, data: newData };
58
+ }
59
+ function createBaseQuery(options, Observer, queryClient) {
60
+ const client = createMemo(() => useQueryClient(queryClient?.()));
61
+ const defaultedOptions = client().defaultQueryOptions(options());
62
+ defaultedOptions._optimisticResults = "optimistic";
63
+ defaultedOptions.structuralSharing = false;
64
+ if (isServer) {
65
+ defaultedOptions.retry = false;
66
+ defaultedOptions.throwOnError = true;
67
+ }
68
+ const observer = new Observer(client(), defaultedOptions);
69
+ const [state, setState] = createStore(
70
+ observer.getOptimisticResult(defaultedOptions)
71
+ );
72
+ const createServerSubscriber = (resolve, reject) => {
73
+ return observer.subscribe((result) => {
74
+ notifyManager.batchCalls(() => {
75
+ const query = observer.getCurrentQuery();
76
+ const { refetch: refetch2, ...rest } = unwrap(result);
77
+ const unwrappedResult = {
78
+ ...rest,
79
+ // hydrate() expects a QueryState object, which is similar but not
80
+ // quite the same as a QueryObserverResult object. Thus, for now, we're
81
+ // copying over the missing properties from state in order to support hydration
82
+ dataUpdateCount: query.state.dataUpdateCount,
83
+ fetchFailureCount: query.state.fetchFailureCount,
84
+ // Removing these properties since they might not be serializable
85
+ // fetchFailureReason: query.state.fetchFailureReason,
86
+ // fetchMeta: query.state.fetchMeta,
87
+ isInvalidated: query.state.isInvalidated
88
+ };
89
+ if (unwrappedResult.isError) {
90
+ reject(unwrappedResult.error);
91
+ }
92
+ if (unwrappedResult.isSuccess) {
93
+ resolve(unwrappedResult);
94
+ }
95
+ })();
96
+ });
97
+ };
98
+ const createClientSubscriber = () => {
99
+ return observer.subscribe((result) => {
100
+ notifyManager.batchCalls(() => {
101
+ const reconcileOptions = observer.options.reconcile;
102
+ if (queryResource()?.data && result.data && !queryResource.loading) {
103
+ setState((store) => {
104
+ return reconcileFn(
105
+ store,
106
+ result,
107
+ reconcileOptions === void 0 ? "id" : reconcileOptions
108
+ );
109
+ });
110
+ mutate(state);
111
+ } else {
112
+ setState((store) => {
113
+ return reconcileFn(
114
+ store,
115
+ result,
116
+ reconcileOptions === void 0 ? "id" : reconcileOptions
117
+ );
118
+ });
119
+ refetch();
120
+ }
121
+ })();
122
+ });
123
+ };
124
+ let unsubscribe = null;
125
+ const [queryResource, { refetch, mutate }] = createResource(
126
+ () => {
127
+ return new Promise((resolve, reject) => {
128
+ if (isServer) {
129
+ unsubscribe = createServerSubscriber(resolve, reject);
130
+ } else {
131
+ if (!unsubscribe) {
132
+ unsubscribe = createClientSubscriber();
133
+ }
134
+ }
135
+ if (!state.isLoading) {
136
+ resolve(state);
137
+ }
138
+ });
139
+ },
140
+ {
141
+ initialValue: state,
142
+ // If initialData is provided, we resolve the resource immediately
143
+ ssrLoadFrom: options().initialData ? "initial" : "server",
144
+ get deferStream() {
145
+ return options().deferStream;
146
+ },
147
+ /**
148
+ * If this resource was populated on the server (either sync render, or streamed in over time), onHydrated
149
+ * will be called. This is the point at which we can hydrate the query cache state, and setup the query subscriber.
150
+ *
151
+ * Leveraging onHydrated allows us to plug into the async and streaming support that solidjs resources already support.
152
+ *
153
+ * Note that this is only invoked on the client, for queries that were originally run on the server.
154
+ */
155
+ onHydrated(_k, info) {
156
+ if (info.value) {
157
+ hydrate(client(), {
158
+ queries: [
159
+ {
160
+ queryKey: defaultedOptions.queryKey,
161
+ queryHash: defaultedOptions.queryHash,
162
+ state: info.value
163
+ }
164
+ ]
165
+ });
166
+ }
167
+ if (!unsubscribe) {
168
+ const newOptions = { ...defaultedOptions };
169
+ if (defaultedOptions.staleTime || !defaultedOptions.initialData) {
170
+ newOptions.refetchOnMount = false;
171
+ }
172
+ observer.setOptions(newOptions);
173
+ setState(observer.getOptimisticResult(newOptions));
174
+ unsubscribe = createClientSubscriber();
175
+ }
176
+ }
177
+ }
178
+ );
179
+ onCleanup(() => {
180
+ if (unsubscribe) {
181
+ unsubscribe();
182
+ unsubscribe = null;
183
+ }
184
+ });
185
+ createComputed(
186
+ on(
187
+ () => client().defaultQueryOptions(options()),
188
+ () => observer.setOptions(client().defaultQueryOptions(options())),
189
+ {
190
+ // Defer because we don't need to trigger on first render
191
+ // This only cares about changes to options after the observer is created
192
+ defer: true
193
+ }
194
+ )
195
+ );
196
+ createComputed(
197
+ on(
198
+ () => state.status,
199
+ () => {
200
+ if (state.isError && !state.isFetching && shouldThrowError(observer.options.throwOnError, [
201
+ state.error,
202
+ observer.getCurrentQuery()
203
+ ])) {
204
+ throw state.error;
205
+ }
206
+ }
207
+ )
208
+ );
209
+ const handler = {
210
+ get(target, prop) {
211
+ const val = queryResource()?.[prop];
212
+ return val !== void 0 ? val : Reflect.get(target, prop);
213
+ }
214
+ };
215
+ return new Proxy(state, handler);
216
+ }
217
+
218
+ // src/createQuery.ts
219
+ function queryOptions(options) {
220
+ return options;
221
+ }
222
+ function createQuery(options, queryClient) {
223
+ return createBaseQuery(
224
+ createMemo(() => options()),
225
+ QueryObserver,
226
+ queryClient
227
+ );
228
+ }
229
+ function useIsFetching(filters, queryClient) {
230
+ const client = createMemo(() => useQueryClient(queryClient?.()));
231
+ const queryCache = createMemo(() => client().getQueryCache());
232
+ const [fetches, setFetches] = createSignal(client().isFetching(filters?.()));
233
+ const unsubscribe = queryCache().subscribe(() => {
234
+ setFetches(client().isFetching(filters?.()));
235
+ });
236
+ onCleanup(unsubscribe);
237
+ return fetches;
238
+ }
239
+ function createInfiniteQuery(options, queryClient) {
240
+ return createBaseQuery(
241
+ createMemo(() => options()),
242
+ // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion
243
+ InfiniteQueryObserver,
244
+ queryClient
245
+ );
246
+ }
247
+ function createMutation(options, queryClient) {
248
+ const client = useQueryClient(queryClient?.());
249
+ const observer = new MutationObserver(
250
+ client,
251
+ options()
252
+ );
253
+ const mutate = (variables, mutateOptions) => {
254
+ observer.mutate(variables, mutateOptions).catch(noop);
255
+ };
256
+ const [state, setState] = createStore({
257
+ ...observer.getCurrentResult(),
258
+ mutate,
259
+ mutateAsync: observer.getCurrentResult().mutate
260
+ });
261
+ createComputed(() => {
262
+ observer.setOptions(options());
263
+ });
264
+ createComputed(
265
+ on(
266
+ () => state.status,
267
+ () => {
268
+ if (state.isError && shouldThrowError(observer.options.throwOnError, [state.error])) {
269
+ throw state.error;
270
+ }
271
+ }
272
+ )
273
+ );
274
+ const unsubscribe = observer.subscribe((result) => {
275
+ setState({
276
+ ...result,
277
+ mutate,
278
+ mutateAsync: result.mutate
279
+ });
280
+ });
281
+ onCleanup(unsubscribe);
282
+ return state;
283
+ }
284
+ function noop() {
285
+ }
286
+ function useIsMutating(filters, queryClient) {
287
+ const client = createMemo(() => useQueryClient(queryClient?.()));
288
+ const mutationCache = createMemo(() => client().getMutationCache());
289
+ const [mutations, setMutations] = createSignal(
290
+ client().isMutating(filters?.())
291
+ );
292
+ const unsubscribe = mutationCache().subscribe((_result) => {
293
+ setMutations(client().isMutating(filters?.()));
294
+ });
295
+ onCleanup(unsubscribe);
296
+ return mutations;
297
+ }
298
+ function createQueries(queriesOptions, queryClient) {
299
+ const client = useQueryClient(queryClient?.());
300
+ const defaultedQueries = queriesOptions().queries.map((options) => {
301
+ const defaultedOptions = client.defaultQueryOptions(options);
302
+ defaultedOptions._optimisticResults = "optimistic";
303
+ return defaultedOptions;
304
+ });
305
+ const observer = new QueriesObserver(
306
+ client,
307
+ defaultedQueries,
308
+ queriesOptions().combine ? {
309
+ combine: queriesOptions().combine
310
+ } : void 0
311
+ );
312
+ const [state, setState] = createStore(
313
+ observer.getOptimisticResult(defaultedQueries)[1]()
314
+ );
315
+ const unsubscribe = observer.subscribe((result) => {
316
+ notifyManager.batchCalls(() => {
317
+ setState(unwrap(result));
318
+ })();
319
+ });
320
+ onCleanup(unsubscribe);
321
+ createComputed(() => {
322
+ const updatedQueries = queriesOptions().queries.map((options) => {
323
+ const defaultedOptions = client.defaultQueryOptions(options);
324
+ defaultedOptions._optimisticResults = "optimistic";
325
+ return defaultedOptions;
326
+ });
327
+ observer.setQueries(
328
+ updatedQueries,
329
+ queriesOptions().combine ? {
330
+ combine: queriesOptions().combine
331
+ } : void 0,
332
+ { listeners: false }
333
+ );
334
+ });
335
+ return state;
336
+ }
337
+
338
+ export { QueryClient, QueryClientContext, QueryClientProvider, createInfiniteQuery, createMutation, createQueries, createQuery, queryOptions, useIsFetching, useIsMutating, useQueryClient };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tanstack/solid-query",
3
- "version": "5.0.0-alpha.85",
3
+ "version": "5.0.0-alpha.87",
4
4
  "description": "Primitives for managing, caching and syncing asynchronous and remote data in Solid",
5
5
  "author": "tannerlinsley",
6
6
  "license": "MIT",
@@ -11,46 +11,52 @@
11
11
  "url": "https://github.com/sponsors/tannerlinsley"
12
12
  },
13
13
  "type": "module",
14
- "types": "dist/types/index.d.ts",
15
- "main": "dist/cjs/index.cjs",
16
- "module": "dist/esm/index.js",
14
+ "main": "./build/index.cjs",
15
+ "module": "./build/index.js",
16
+ "types": "./build/index.d.ts",
17
+ "browser": {},
17
18
  "exports": {
18
- ".": {
19
- "types": "./dist/types/index.d.ts",
20
- "solid": "./dist/source/index.js",
21
- "import": "./dist/esm/index.js",
22
- "browser": {
23
- "import": "./dist/esm/index.js",
24
- "require": "./dist/cjs/index.cjs"
19
+ "solid": {
20
+ "development": "./build/dev.js",
21
+ "import": "./build/index.js"
22
+ },
23
+ "development": {
24
+ "import": {
25
+ "types": "./build/index.d.ts",
26
+ "default": "./build/dev.js"
25
27
  },
26
- "require": "./dist/cjs/index.cjs",
27
- "node": "./dist/cjs/index.cjs"
28
+ "require": "./build/dev.cjs"
29
+ },
30
+ "import": {
31
+ "types": "./build/index.d.ts",
32
+ "default": "./build/index.js"
28
33
  },
29
- "./package.json": "./package.json"
34
+ "require": "./build/index.cjs"
30
35
  },
31
36
  "sideEffects": [
32
37
  "./src/setBatchUpdatesFn.ts"
33
38
  ],
34
39
  "files": [
35
- "dist",
40
+ "build",
36
41
  "src"
37
42
  ],
38
43
  "dependencies": {
39
- "@tanstack/query-core": "5.0.0-alpha.85"
44
+ "@tanstack/query-core": "5.0.0-alpha.87"
40
45
  },
41
46
  "devDependencies": {
47
+ "tsup-preset-solid": "^0.1.8",
42
48
  "vite-plugin-solid": "^2.5.0"
43
49
  },
44
50
  "peerDependencies": {
45
51
  "solid-js": "^1.6.13"
46
52
  },
47
53
  "scripts": {
48
- "clean": "rimraf ./dist && rimraf ./coverage",
54
+ "clean": "rimraf ./build && rimraf ./coverage",
49
55
  "test:eslint": "eslint --ext .ts,.tsx ./src",
50
56
  "test:types": "tsc --noEmit",
51
57
  "test:lib": "vitest run --coverage",
52
58
  "test:lib:dev": "pnpm run test:lib --watch",
53
59
  "test:build": "publint --strict",
54
- "build": "rollup --config rollup.config.js"
60
+ "build": "tsup"
55
61
  }
56
62
  }
@@ -15,7 +15,7 @@ import {
15
15
  } from '..'
16
16
  import {
17
17
  createQueryClient,
18
- mockNavigatorOnLine,
18
+ mockOnlineManagerIsOnline,
19
19
  queryKey,
20
20
  setActTimeout,
21
21
  sleep,
@@ -495,7 +495,7 @@ describe('createMutation', () => {
495
495
  })
496
496
 
497
497
  it('should not retry mutations while offline', async () => {
498
- const onlineMock = mockNavigatorOnLine(false)
498
+ const onlineMock = mockOnlineManagerIsOnline(false)
499
499
 
500
500
  let count = 0
501
501
 
@@ -535,6 +535,8 @@ describe('createMutation', () => {
535
535
  ).toBeInTheDocument()
536
536
  })
537
537
 
538
+ window.dispatchEvent(new Event('offline'))
539
+
538
540
  fireEvent.click(screen.getByRole('button', { name: /mutate/i }))
539
541
 
540
542
  await waitFor(() => {
@@ -545,7 +547,7 @@ describe('createMutation', () => {
545
547
 
546
548
  expect(count).toBe(0)
547
549
 
548
- onlineMock.mockReturnValue(true)
550
+ onlineMock.mockRestore()
549
551
  window.dispatchEvent(new Event('online'))
550
552
 
551
553
  await sleep(100)
@@ -557,12 +559,10 @@ describe('createMutation', () => {
557
559
  })
558
560
 
559
561
  expect(count).toBe(2)
560
-
561
- onlineMock.mockRestore()
562
562
  })
563
563
 
564
564
  it('should call onMutate even if paused', async () => {
565
- const onlineMock = mockNavigatorOnLine(false)
565
+ const onlineMock = mockOnlineManagerIsOnline(false)
566
566
  const onMutate = vi.fn()
567
567
  let count = 0
568
568
 
@@ -595,6 +595,8 @@ describe('createMutation', () => {
595
595
 
596
596
  await screen.findByText('data: null, status: idle, isPaused: false')
597
597
 
598
+ window.dispatchEvent(new Event('offline'))
599
+
598
600
  fireEvent.click(screen.getByRole('button', { name: /mutate/i }))
599
601
 
600
602
  await screen.findByText('data: null, status: pending, isPaused: true')
@@ -602,19 +604,17 @@ describe('createMutation', () => {
602
604
  expect(onMutate).toHaveBeenCalledTimes(1)
603
605
  expect(onMutate).toHaveBeenCalledWith('todo')
604
606
 
605
- onlineMock.mockReturnValue(true)
607
+ onlineMock.mockRestore()
606
608
  window.dispatchEvent(new Event('online'))
607
609
 
608
610
  await screen.findByText('data: 1, status: success, isPaused: false')
609
611
 
610
612
  expect(onMutate).toHaveBeenCalledTimes(1)
611
613
  expect(count).toBe(1)
612
-
613
- onlineMock.mockRestore()
614
614
  })
615
615
 
616
616
  it('should optimistically go to paused state if offline', async () => {
617
- const onlineMock = mockNavigatorOnLine(false)
617
+ const onlineMock = mockOnlineManagerIsOnline(false)
618
618
  let count = 0
619
619
  const states: Array<string> = []
620
620
 
@@ -667,7 +667,7 @@ describe('createMutation', () => {
667
667
  })
668
668
 
669
669
  it('should be able to retry a mutation when online', async () => {
670
- const onlineMock = mockNavigatorOnLine(false)
670
+ const onlineMock = mockOnlineManagerIsOnline(false)
671
671
 
672
672
  let count = 0
673
673
  const states: CreateMutationResult<any, any, any, any>[] = []
@@ -693,6 +693,7 @@ describe('createMutation', () => {
693
693
  createEffect(() => {
694
694
  const { mutate } = mutation
695
695
  setActTimeout(() => {
696
+ window.dispatchEvent(new Event('offline'))
696
697
  mutate('todo')
697
698
  }, 10)
698
699
  })
@@ -734,7 +735,7 @@ describe('createMutation', () => {
734
735
  failureReason: new Error('oops'),
735
736
  })
736
737
 
737
- onlineMock.mockReturnValue(true)
738
+ onlineMock.mockRestore()
738
739
  window.dispatchEvent(new Event('online'))
739
740
 
740
741
  await sleep(50)
@@ -753,8 +754,6 @@ describe('createMutation', () => {
753
754
  failureReason: null,
754
755
  data: 'data',
755
756
  })
756
-
757
- onlineMock.mockRestore()
758
757
  })
759
758
 
760
759
  it('should not change state if unmounted', async () => {