@tanstack/solid-query 6.0.0-rc.1 → 6.0.0-rc.2
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.
- package/build/_tsup-dts-rollup.d.cts +60 -2
- package/build/_tsup-dts-rollup.d.ts +60 -2
- package/build/dev.cjs +48 -11
- package/build/dev.d.cts +2 -0
- package/build/dev.d.ts +2 -0
- package/build/dev.js +49 -13
- package/build/index.cjs +48 -11
- package/build/index.d.cts +2 -0
- package/build/index.d.ts +2 -0
- package/build/index.js +49 -13
- package/package.json +5 -4
- package/src/QueryClientProvider.tsx +63 -4
- package/src/dehydrateSettled.ts +42 -0
- package/src/index.ts +2 -0
- package/src/useMutation.ts +39 -25
|
@@ -251,6 +251,33 @@ export { DehydratedState }
|
|
|
251
251
|
|
|
252
252
|
export { DehydrateOptions }
|
|
253
253
|
|
|
254
|
+
/**
|
|
255
|
+
* Waits for every fetch the client has in flight to settle, then
|
|
256
|
+
* dehydrates. This is the extraction half of a single-flight collector:
|
|
257
|
+
* after route data functions run for the mutation's target URL, loaders
|
|
258
|
+
* commonly kick off prefetches without awaiting them — plain
|
|
259
|
+
* `dehydrate()` would snapshot those mid-fetch and ship nothing.
|
|
260
|
+
*
|
|
261
|
+
* ```ts
|
|
262
|
+
* registerFlightDataSource(FLIGHT_DATA_SOURCE, (event, outcome) =>
|
|
263
|
+
* loadFlightTarget({
|
|
264
|
+
* router,
|
|
265
|
+
* event,
|
|
266
|
+
* outcome,
|
|
267
|
+
* collect: () => dehydrateSettled(queryClient),
|
|
268
|
+
* }),
|
|
269
|
+
* )
|
|
270
|
+
* ```
|
|
271
|
+
*
|
|
272
|
+
* Settling is chased to quiescence — awaiting one batch of fetches can
|
|
273
|
+
* dispatch more (dependent queries keyed off a first result) — so an
|
|
274
|
+
* unconditionally self-refetching query would keep this pending; that's
|
|
275
|
+
* an app bug mirrored, not guarded.
|
|
276
|
+
*/
|
|
277
|
+
declare function dehydrateSettled(client: QueryClient, options?: DehydrateOptions): Promise<DehydratedState>;
|
|
278
|
+
export { dehydrateSettled }
|
|
279
|
+
export { dehydrateSettled as dehydrateSettled_alias_1 }
|
|
280
|
+
|
|
254
281
|
export { DistributiveOmit }
|
|
255
282
|
|
|
256
283
|
export { EnsureInfiniteQueryDataOptions }
|
|
@@ -271,6 +298,31 @@ export { FetchQueryOptions }
|
|
|
271
298
|
|
|
272
299
|
export { FetchStatus }
|
|
273
300
|
|
|
301
|
+
/**
|
|
302
|
+
* The query cache's single-flight source id. Mutation responses can fold
|
|
303
|
+
* fresh data for multiple caches at once (Solid's multi-source
|
|
304
|
+
* single-flight protocol); this is the slice the query cache claims — the
|
|
305
|
+
* provider subscribes its consumer under it, and server collectors
|
|
306
|
+
* register under it to produce the data:
|
|
307
|
+
*
|
|
308
|
+
* ```ts
|
|
309
|
+
* import { registerFlightDataSource } from '@solidjs/web/server-functions/server'
|
|
310
|
+
* import { FLIGHT_DATA_SOURCE, dehydrate } from '@tanstack/solid-query'
|
|
311
|
+
*
|
|
312
|
+
* registerFlightDataSource(FLIGHT_DATA_SOURCE, async (event, outcome) => {
|
|
313
|
+
* // rebuild the data for outcome.targetUrl into a QueryClient, then
|
|
314
|
+
* return dehydrate(queryClient)
|
|
315
|
+
* })
|
|
316
|
+
* ```
|
|
317
|
+
*
|
|
318
|
+
* The slice's payload is a `DehydratedState`; the provider consumes it
|
|
319
|
+
* with `hydrate()`, so every mounted query on those keys updates before
|
|
320
|
+
* the mutation's promise resolves — no follow-up refetches.
|
|
321
|
+
*/
|
|
322
|
+
declare const FLIGHT_DATA_SOURCE = "sq";
|
|
323
|
+
export { FLIGHT_DATA_SOURCE }
|
|
324
|
+
export { FLIGHT_DATA_SOURCE as FLIGHT_DATA_SOURCE_alias_1 }
|
|
325
|
+
|
|
274
326
|
export { focusManager }
|
|
275
327
|
|
|
276
328
|
export { GetNextPageParamFunction }
|
|
@@ -555,8 +607,14 @@ export { QueryClientContext as QueryClientContext_alias_1 }
|
|
|
555
607
|
/**
|
|
556
608
|
* Provides the QueryClient and manages its mount lifecycle. On the server
|
|
557
609
|
* it also registers the cache serializer above; on the client, hooks prime
|
|
558
|
-
* the cache from their hash-keyed registry entries themselves
|
|
559
|
-
* `useBaseQuery
|
|
610
|
+
* the cache from their hash-keyed registry entries themselves (see
|
|
611
|
+
* `useBaseQuery`) and the provider subscribes the cache's single-flight
|
|
612
|
+
* consumer: mutation responses carrying a `FLIGHT_DATA_SOURCE` slice (a
|
|
613
|
+
* `DehydratedState` produced by a server collector registered under the
|
|
614
|
+
* same id) hydrate this client before the mutation's promise resolves.
|
|
615
|
+
* Subscribing is inert when no server collector exists — the server just
|
|
616
|
+
* folds nothing — so it is unconditional. One consumer per source: with
|
|
617
|
+
* nested providers, the innermost mounted one owns the slice.
|
|
560
618
|
*/
|
|
561
619
|
declare const QueryClientProvider: (props: QueryClientProviderProps) => JSX.Element;
|
|
562
620
|
export { QueryClientProvider }
|
|
@@ -251,6 +251,33 @@ export { DehydratedState }
|
|
|
251
251
|
|
|
252
252
|
export { DehydrateOptions }
|
|
253
253
|
|
|
254
|
+
/**
|
|
255
|
+
* Waits for every fetch the client has in flight to settle, then
|
|
256
|
+
* dehydrates. This is the extraction half of a single-flight collector:
|
|
257
|
+
* after route data functions run for the mutation's target URL, loaders
|
|
258
|
+
* commonly kick off prefetches without awaiting them — plain
|
|
259
|
+
* `dehydrate()` would snapshot those mid-fetch and ship nothing.
|
|
260
|
+
*
|
|
261
|
+
* ```ts
|
|
262
|
+
* registerFlightDataSource(FLIGHT_DATA_SOURCE, (event, outcome) =>
|
|
263
|
+
* loadFlightTarget({
|
|
264
|
+
* router,
|
|
265
|
+
* event,
|
|
266
|
+
* outcome,
|
|
267
|
+
* collect: () => dehydrateSettled(queryClient),
|
|
268
|
+
* }),
|
|
269
|
+
* )
|
|
270
|
+
* ```
|
|
271
|
+
*
|
|
272
|
+
* Settling is chased to quiescence — awaiting one batch of fetches can
|
|
273
|
+
* dispatch more (dependent queries keyed off a first result) — so an
|
|
274
|
+
* unconditionally self-refetching query would keep this pending; that's
|
|
275
|
+
* an app bug mirrored, not guarded.
|
|
276
|
+
*/
|
|
277
|
+
declare function dehydrateSettled(client: QueryClient, options?: DehydrateOptions): Promise<DehydratedState>;
|
|
278
|
+
export { dehydrateSettled }
|
|
279
|
+
export { dehydrateSettled as dehydrateSettled_alias_1 }
|
|
280
|
+
|
|
254
281
|
export { DistributiveOmit }
|
|
255
282
|
|
|
256
283
|
export { EnsureInfiniteQueryDataOptions }
|
|
@@ -271,6 +298,31 @@ export { FetchQueryOptions }
|
|
|
271
298
|
|
|
272
299
|
export { FetchStatus }
|
|
273
300
|
|
|
301
|
+
/**
|
|
302
|
+
* The query cache's single-flight source id. Mutation responses can fold
|
|
303
|
+
* fresh data for multiple caches at once (Solid's multi-source
|
|
304
|
+
* single-flight protocol); this is the slice the query cache claims — the
|
|
305
|
+
* provider subscribes its consumer under it, and server collectors
|
|
306
|
+
* register under it to produce the data:
|
|
307
|
+
*
|
|
308
|
+
* ```ts
|
|
309
|
+
* import { registerFlightDataSource } from '@solidjs/web/server-functions/server'
|
|
310
|
+
* import { FLIGHT_DATA_SOURCE, dehydrate } from '@tanstack/solid-query'
|
|
311
|
+
*
|
|
312
|
+
* registerFlightDataSource(FLIGHT_DATA_SOURCE, async (event, outcome) => {
|
|
313
|
+
* // rebuild the data for outcome.targetUrl into a QueryClient, then
|
|
314
|
+
* return dehydrate(queryClient)
|
|
315
|
+
* })
|
|
316
|
+
* ```
|
|
317
|
+
*
|
|
318
|
+
* The slice's payload is a `DehydratedState`; the provider consumes it
|
|
319
|
+
* with `hydrate()`, so every mounted query on those keys updates before
|
|
320
|
+
* the mutation's promise resolves — no follow-up refetches.
|
|
321
|
+
*/
|
|
322
|
+
declare const FLIGHT_DATA_SOURCE = "sq";
|
|
323
|
+
export { FLIGHT_DATA_SOURCE }
|
|
324
|
+
export { FLIGHT_DATA_SOURCE as FLIGHT_DATA_SOURCE_alias_1 }
|
|
325
|
+
|
|
274
326
|
export { focusManager }
|
|
275
327
|
|
|
276
328
|
export { GetNextPageParamFunction }
|
|
@@ -555,8 +607,14 @@ export { QueryClientContext as QueryClientContext_alias_1 }
|
|
|
555
607
|
/**
|
|
556
608
|
* Provides the QueryClient and manages its mount lifecycle. On the server
|
|
557
609
|
* it also registers the cache serializer above; on the client, hooks prime
|
|
558
|
-
* the cache from their hash-keyed registry entries themselves
|
|
559
|
-
* `useBaseQuery
|
|
610
|
+
* the cache from their hash-keyed registry entries themselves (see
|
|
611
|
+
* `useBaseQuery`) and the provider subscribes the cache's single-flight
|
|
612
|
+
* consumer: mutation responses carrying a `FLIGHT_DATA_SOURCE` slice (a
|
|
613
|
+
* `DehydratedState` produced by a server collector registered under the
|
|
614
|
+
* same id) hydrate this client before the mutation's promise resolves.
|
|
615
|
+
* Subscribing is inert when no server collector exists — the server just
|
|
616
|
+
* folds nothing — so it is unconditional. One consumer per source: with
|
|
617
|
+
* nested providers, the innermost mounted one owns the slice.
|
|
560
618
|
*/
|
|
561
619
|
declare const QueryClientProvider: (props: QueryClientProviderProps) => JSX.Element;
|
|
562
620
|
export { QueryClientProvider }
|
package/build/dev.cjs
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
var queryCore = require('@tanstack/query-core');
|
|
4
4
|
var solidJs = require('solid-js');
|
|
5
5
|
var web = require('@solidjs/web');
|
|
6
|
+
var serverFunctions = require('@solidjs/web/server-functions');
|
|
6
7
|
|
|
7
8
|
// src/index.ts
|
|
8
9
|
exports.QueryClient = class QueryClient extends queryCore.QueryClient {
|
|
@@ -12,6 +13,7 @@ exports.QueryClient = class QueryClient extends queryCore.QueryClient {
|
|
|
12
13
|
};
|
|
13
14
|
var isServer = typeof window === "undefined";
|
|
14
15
|
var HYDRATION_KEY_PREFIX = "sq:";
|
|
16
|
+
exports.FLIGHT_DATA_SOURCE = "sq";
|
|
15
17
|
exports.QueryClientContext = solidJs.createContext(null);
|
|
16
18
|
exports.useQueryClient = (queryClient) => {
|
|
17
19
|
if (queryClient) {
|
|
@@ -27,9 +29,11 @@ function serializeCacheOnServer(client) {
|
|
|
27
29
|
const ctx = solidJs.sharedConfig.context;
|
|
28
30
|
if (!ctx || !ctx.async || ctx.noHydrate) return;
|
|
29
31
|
const cache = client.getQueryCache();
|
|
32
|
+
const shouldDehydrateQuery = client.getDefaultOptions().dehydrate?.shouldDehydrateQuery;
|
|
30
33
|
const seen = /* @__PURE__ */ new Set();
|
|
31
34
|
const serializeQuery = (query) => {
|
|
32
35
|
if (seen.has(query.queryHash)) return;
|
|
36
|
+
if (shouldDehydrateQuery && !shouldDehydrateQuery(query)) return;
|
|
33
37
|
const state = query.state;
|
|
34
38
|
if (state.status === "success") {
|
|
35
39
|
seen.add(query.queryHash);
|
|
@@ -53,7 +57,17 @@ function serializeCacheOnServer(client) {
|
|
|
53
57
|
exports.QueryClientProvider = (props) => {
|
|
54
58
|
props.client.mount();
|
|
55
59
|
solidJs.onCleanup(() => props.client.unmount());
|
|
56
|
-
if (isServer)
|
|
60
|
+
if (isServer) {
|
|
61
|
+
serializeCacheOnServer(props.client);
|
|
62
|
+
solidJs.onCleanup(() => {
|
|
63
|
+
props.client.cancelQueries().catch(() => void 0);
|
|
64
|
+
props.client.clear();
|
|
65
|
+
});
|
|
66
|
+
} else {
|
|
67
|
+
solidJs.onCleanup(serverFunctions.subscribeFlightData(exports.FLIGHT_DATA_SOURCE, (data) => {
|
|
68
|
+
queryCore.hydrate(props.client, data);
|
|
69
|
+
}));
|
|
70
|
+
}
|
|
57
71
|
return web.createComponent(exports.QueryClientContext, {
|
|
58
72
|
value: () => props.client,
|
|
59
73
|
get children() {
|
|
@@ -432,6 +446,15 @@ function useQuery(options, queryClient) {
|
|
|
432
446
|
function queryOptions(options) {
|
|
433
447
|
return options;
|
|
434
448
|
}
|
|
449
|
+
async function dehydrateSettled(client, options) {
|
|
450
|
+
const cache = client.getQueryCache();
|
|
451
|
+
for (; ; ) {
|
|
452
|
+
const pending = cache.getAll().filter((query) => query.state.fetchStatus !== "idle").map((query) => query.promise);
|
|
453
|
+
if (pending.length === 0) break;
|
|
454
|
+
await Promise.allSettled(pending);
|
|
455
|
+
}
|
|
456
|
+
return queryCore.dehydrate(client, options);
|
|
457
|
+
}
|
|
435
458
|
var isServer3 = typeof window === "undefined";
|
|
436
459
|
function createCacheAggregate(subscribe, read, empty) {
|
|
437
460
|
const hydratedMount = !isServer3 && solidJs.sharedConfig.hydrating === true;
|
|
@@ -592,15 +615,13 @@ function useMutation(options, queryClient) {
|
|
|
592
615
|
const [flight, setFlight] = solidJs.createOptimistic(null);
|
|
593
616
|
const [settled, setSettled] = solidJs.createSignal(IDLE);
|
|
594
617
|
let activeMutation = null;
|
|
618
|
+
let unsubscribeFlight = null;
|
|
595
619
|
const [flightVersion, setFlightVersion] = solidJs.createSignal(0);
|
|
596
|
-
if (!isServer4)
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
}
|
|
620
|
+
if (!isServer4)
|
|
621
|
+
solidJs.onCleanup(() => {
|
|
622
|
+
unsubscribeFlight?.();
|
|
623
|
+
unsubscribeFlight = null;
|
|
601
624
|
});
|
|
602
|
-
solidJs.onCleanup(unsubscribe);
|
|
603
|
-
}
|
|
604
625
|
async function* run(variables) {
|
|
605
626
|
const opts = solidJs.untrack(options);
|
|
606
627
|
const callbackContext = {
|
|
@@ -610,7 +631,8 @@ function useMutation(options, queryClient) {
|
|
|
610
631
|
};
|
|
611
632
|
if (!isServer4) setFlight({ variables });
|
|
612
633
|
opts.onMutate?.(variables, callbackContext);
|
|
613
|
-
const
|
|
634
|
+
const c = solidJs.untrack(client);
|
|
635
|
+
const mutation = c.getMutationCache().build(c, {
|
|
614
636
|
...opts,
|
|
615
637
|
// Options-level callbacks re-run below, inside the transaction —
|
|
616
638
|
// executing them here (inside the await gap) would let their
|
|
@@ -621,6 +643,20 @@ function useMutation(options, queryClient) {
|
|
|
621
643
|
onSettled: void 0
|
|
622
644
|
});
|
|
623
645
|
activeMutation = mutation;
|
|
646
|
+
if (!isServer4) {
|
|
647
|
+
unsubscribeFlight?.();
|
|
648
|
+
unsubscribeFlight = c.getMutationCache().subscribe((event) => {
|
|
649
|
+
if ("mutation" in event && event.mutation === activeMutation) {
|
|
650
|
+
setFlightVersion((v) => v + 1);
|
|
651
|
+
}
|
|
652
|
+
});
|
|
653
|
+
}
|
|
654
|
+
const settleFlight = () => {
|
|
655
|
+
if (activeMutation !== mutation) return;
|
|
656
|
+
activeMutation = null;
|
|
657
|
+
unsubscribeFlight?.();
|
|
658
|
+
unsubscribeFlight = null;
|
|
659
|
+
};
|
|
624
660
|
async function* settleFailure(error) {
|
|
625
661
|
try {
|
|
626
662
|
if (opts.onError)
|
|
@@ -648,7 +684,7 @@ function useMutation(options, queryClient) {
|
|
|
648
684
|
variables,
|
|
649
685
|
submittedAt: mutation.state.submittedAt
|
|
650
686
|
});
|
|
651
|
-
|
|
687
|
+
settleFlight();
|
|
652
688
|
throw error;
|
|
653
689
|
}
|
|
654
690
|
let result2;
|
|
@@ -688,7 +724,7 @@ function useMutation(options, queryClient) {
|
|
|
688
724
|
variables,
|
|
689
725
|
submittedAt: mutation.state.submittedAt
|
|
690
726
|
});
|
|
691
|
-
|
|
727
|
+
settleFlight();
|
|
692
728
|
return result2;
|
|
693
729
|
}
|
|
694
730
|
const invoke = isServer4 ? (variables) => drain(run(variables)) : solidJs.action(run);
|
|
@@ -826,6 +862,7 @@ function useQueries(queriesOptions, queryClient) {
|
|
|
826
862
|
});
|
|
827
863
|
}
|
|
828
864
|
|
|
865
|
+
exports.dehydrateSettled = dehydrateSettled;
|
|
829
866
|
exports.infiniteQueryOptions = infiniteQueryOptions;
|
|
830
867
|
exports.mutationOptions = mutationOptions;
|
|
831
868
|
exports.queryOptions = queryOptions;
|
package/build/dev.d.cts
CHANGED
|
@@ -23,10 +23,12 @@ export { useQuery } from './_tsup-dts-rollup.cjs';
|
|
|
23
23
|
export { queryOptions } from './_tsup-dts-rollup.cjs';
|
|
24
24
|
export { DefinedInitialDataOptions } from './_tsup-dts-rollup.cjs';
|
|
25
25
|
export { UndefinedInitialDataOptions } from './_tsup-dts-rollup.cjs';
|
|
26
|
+
export { FLIGHT_DATA_SOURCE_alias_1 as FLIGHT_DATA_SOURCE } from './_tsup-dts-rollup.cjs';
|
|
26
27
|
export { QueryClientContext_alias_1 as QueryClientContext } from './_tsup-dts-rollup.cjs';
|
|
27
28
|
export { QueryClientProvider_alias_1 as QueryClientProvider } from './_tsup-dts-rollup.cjs';
|
|
28
29
|
export { useQueryClient_alias_1 as useQueryClient } from './_tsup-dts-rollup.cjs';
|
|
29
30
|
export { QueryClientProviderProps_alias_1 as QueryClientProviderProps } from './_tsup-dts-rollup.cjs';
|
|
31
|
+
export { dehydrateSettled_alias_1 as dehydrateSettled } from './_tsup-dts-rollup.cjs';
|
|
30
32
|
export { useIsFetching } from './_tsup-dts-rollup.cjs';
|
|
31
33
|
export { useInfiniteQuery } from './_tsup-dts-rollup.cjs';
|
|
32
34
|
export { infiniteQueryOptions } from './_tsup-dts-rollup.cjs';
|
package/build/dev.d.ts
CHANGED
|
@@ -23,10 +23,12 @@ export { useQuery } from './_tsup-dts-rollup.js';
|
|
|
23
23
|
export { queryOptions } from './_tsup-dts-rollup.js';
|
|
24
24
|
export { DefinedInitialDataOptions } from './_tsup-dts-rollup.js';
|
|
25
25
|
export { UndefinedInitialDataOptions } from './_tsup-dts-rollup.js';
|
|
26
|
+
export { FLIGHT_DATA_SOURCE_alias_1 as FLIGHT_DATA_SOURCE } from './_tsup-dts-rollup.js';
|
|
26
27
|
export { QueryClientContext_alias_1 as QueryClientContext } from './_tsup-dts-rollup.js';
|
|
27
28
|
export { QueryClientProvider_alias_1 as QueryClientProvider } from './_tsup-dts-rollup.js';
|
|
28
29
|
export { useQueryClient_alias_1 as useQueryClient } from './_tsup-dts-rollup.js';
|
|
29
30
|
export { QueryClientProviderProps_alias_1 as QueryClientProviderProps } from './_tsup-dts-rollup.js';
|
|
31
|
+
export { dehydrateSettled_alias_1 as dehydrateSettled } from './_tsup-dts-rollup.js';
|
|
30
32
|
export { useIsFetching } from './_tsup-dts-rollup.js';
|
|
31
33
|
export { useInfiniteQuery } from './_tsup-dts-rollup.js';
|
|
32
34
|
export { infiniteQueryOptions } from './_tsup-dts-rollup.js';
|
package/build/dev.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import { noop, QueryClient as QueryClient$1, shouldThrowError, InfiniteQueryObserver,
|
|
1
|
+
import { noop, QueryClient as QueryClient$1, hydrate, dehydrate, shouldThrowError, InfiniteQueryObserver, QueryObserver, replaceEqualDeep } from '@tanstack/query-core';
|
|
2
2
|
export * from '@tanstack/query-core';
|
|
3
3
|
import { createContext, useContext, onCleanup, createMemo, createOptimistic, createSignal, action, createRenderEffect, untrack, repeat, $TRACK, sharedConfig, createEffect, createProjection, runWithOwner, isPending, resolve } from 'solid-js';
|
|
4
4
|
import { createComponent } from '@solidjs/web';
|
|
5
|
+
import { subscribeFlightData } from '@solidjs/web/server-functions';
|
|
5
6
|
|
|
6
7
|
// src/index.ts
|
|
7
8
|
var QueryClient = class extends QueryClient$1 {
|
|
@@ -11,6 +12,7 @@ var QueryClient = class extends QueryClient$1 {
|
|
|
11
12
|
};
|
|
12
13
|
var isServer = typeof window === "undefined";
|
|
13
14
|
var HYDRATION_KEY_PREFIX = "sq:";
|
|
15
|
+
var FLIGHT_DATA_SOURCE = "sq";
|
|
14
16
|
var QueryClientContext = createContext(null);
|
|
15
17
|
var useQueryClient = (queryClient) => {
|
|
16
18
|
if (queryClient) {
|
|
@@ -26,9 +28,11 @@ function serializeCacheOnServer(client) {
|
|
|
26
28
|
const ctx = sharedConfig.context;
|
|
27
29
|
if (!ctx || !ctx.async || ctx.noHydrate) return;
|
|
28
30
|
const cache = client.getQueryCache();
|
|
31
|
+
const shouldDehydrateQuery = client.getDefaultOptions().dehydrate?.shouldDehydrateQuery;
|
|
29
32
|
const seen = /* @__PURE__ */ new Set();
|
|
30
33
|
const serializeQuery = (query) => {
|
|
31
34
|
if (seen.has(query.queryHash)) return;
|
|
35
|
+
if (shouldDehydrateQuery && !shouldDehydrateQuery(query)) return;
|
|
32
36
|
const state = query.state;
|
|
33
37
|
if (state.status === "success") {
|
|
34
38
|
seen.add(query.queryHash);
|
|
@@ -52,7 +56,17 @@ function serializeCacheOnServer(client) {
|
|
|
52
56
|
var QueryClientProvider = (props) => {
|
|
53
57
|
props.client.mount();
|
|
54
58
|
onCleanup(() => props.client.unmount());
|
|
55
|
-
if (isServer)
|
|
59
|
+
if (isServer) {
|
|
60
|
+
serializeCacheOnServer(props.client);
|
|
61
|
+
onCleanup(() => {
|
|
62
|
+
props.client.cancelQueries().catch(() => void 0);
|
|
63
|
+
props.client.clear();
|
|
64
|
+
});
|
|
65
|
+
} else {
|
|
66
|
+
onCleanup(subscribeFlightData(FLIGHT_DATA_SOURCE, (data) => {
|
|
67
|
+
hydrate(props.client, data);
|
|
68
|
+
}));
|
|
69
|
+
}
|
|
56
70
|
return createComponent(QueryClientContext, {
|
|
57
71
|
value: () => props.client,
|
|
58
72
|
get children() {
|
|
@@ -431,6 +445,15 @@ function useQuery(options, queryClient) {
|
|
|
431
445
|
function queryOptions(options) {
|
|
432
446
|
return options;
|
|
433
447
|
}
|
|
448
|
+
async function dehydrateSettled(client, options) {
|
|
449
|
+
const cache = client.getQueryCache();
|
|
450
|
+
for (; ; ) {
|
|
451
|
+
const pending = cache.getAll().filter((query) => query.state.fetchStatus !== "idle").map((query) => query.promise);
|
|
452
|
+
if (pending.length === 0) break;
|
|
453
|
+
await Promise.allSettled(pending);
|
|
454
|
+
}
|
|
455
|
+
return dehydrate(client, options);
|
|
456
|
+
}
|
|
434
457
|
var isServer3 = typeof window === "undefined";
|
|
435
458
|
function createCacheAggregate(subscribe, read, empty) {
|
|
436
459
|
const hydratedMount = !isServer3 && sharedConfig.hydrating === true;
|
|
@@ -591,15 +614,13 @@ function useMutation(options, queryClient) {
|
|
|
591
614
|
const [flight, setFlight] = createOptimistic(null);
|
|
592
615
|
const [settled, setSettled] = createSignal(IDLE);
|
|
593
616
|
let activeMutation = null;
|
|
617
|
+
let unsubscribeFlight = null;
|
|
594
618
|
const [flightVersion, setFlightVersion] = createSignal(0);
|
|
595
|
-
if (!isServer4)
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
}
|
|
619
|
+
if (!isServer4)
|
|
620
|
+
onCleanup(() => {
|
|
621
|
+
unsubscribeFlight?.();
|
|
622
|
+
unsubscribeFlight = null;
|
|
600
623
|
});
|
|
601
|
-
onCleanup(unsubscribe);
|
|
602
|
-
}
|
|
603
624
|
async function* run(variables) {
|
|
604
625
|
const opts = untrack(options);
|
|
605
626
|
const callbackContext = {
|
|
@@ -609,7 +630,8 @@ function useMutation(options, queryClient) {
|
|
|
609
630
|
};
|
|
610
631
|
if (!isServer4) setFlight({ variables });
|
|
611
632
|
opts.onMutate?.(variables, callbackContext);
|
|
612
|
-
const
|
|
633
|
+
const c = untrack(client);
|
|
634
|
+
const mutation = c.getMutationCache().build(c, {
|
|
613
635
|
...opts,
|
|
614
636
|
// Options-level callbacks re-run below, inside the transaction —
|
|
615
637
|
// executing them here (inside the await gap) would let their
|
|
@@ -620,6 +642,20 @@ function useMutation(options, queryClient) {
|
|
|
620
642
|
onSettled: void 0
|
|
621
643
|
});
|
|
622
644
|
activeMutation = mutation;
|
|
645
|
+
if (!isServer4) {
|
|
646
|
+
unsubscribeFlight?.();
|
|
647
|
+
unsubscribeFlight = c.getMutationCache().subscribe((event) => {
|
|
648
|
+
if ("mutation" in event && event.mutation === activeMutation) {
|
|
649
|
+
setFlightVersion((v) => v + 1);
|
|
650
|
+
}
|
|
651
|
+
});
|
|
652
|
+
}
|
|
653
|
+
const settleFlight = () => {
|
|
654
|
+
if (activeMutation !== mutation) return;
|
|
655
|
+
activeMutation = null;
|
|
656
|
+
unsubscribeFlight?.();
|
|
657
|
+
unsubscribeFlight = null;
|
|
658
|
+
};
|
|
623
659
|
async function* settleFailure(error) {
|
|
624
660
|
try {
|
|
625
661
|
if (opts.onError)
|
|
@@ -647,7 +683,7 @@ function useMutation(options, queryClient) {
|
|
|
647
683
|
variables,
|
|
648
684
|
submittedAt: mutation.state.submittedAt
|
|
649
685
|
});
|
|
650
|
-
|
|
686
|
+
settleFlight();
|
|
651
687
|
throw error;
|
|
652
688
|
}
|
|
653
689
|
let result2;
|
|
@@ -687,7 +723,7 @@ function useMutation(options, queryClient) {
|
|
|
687
723
|
variables,
|
|
688
724
|
submittedAt: mutation.state.submittedAt
|
|
689
725
|
});
|
|
690
|
-
|
|
726
|
+
settleFlight();
|
|
691
727
|
return result2;
|
|
692
728
|
}
|
|
693
729
|
const invoke = isServer4 ? (variables) => drain(run(variables)) : action(run);
|
|
@@ -825,4 +861,4 @@ function useQueries(queriesOptions, queryClient) {
|
|
|
825
861
|
});
|
|
826
862
|
}
|
|
827
863
|
|
|
828
|
-
export { IsRestoringContext, QueryClient, QueryClientContext, QueryClientProvider, infiniteQueryOptions, mutationOptions, queryOptions, useInfiniteQuery, useIsFetching, useIsMutating, useIsRestoring, useMutation, useMutationState, useQueries, useQuery, useQueryClient };
|
|
864
|
+
export { FLIGHT_DATA_SOURCE, IsRestoringContext, QueryClient, QueryClientContext, QueryClientProvider, dehydrateSettled, infiniteQueryOptions, mutationOptions, queryOptions, useInfiniteQuery, useIsFetching, useIsMutating, useIsRestoring, useMutation, useMutationState, useQueries, useQuery, useQueryClient };
|
package/build/index.cjs
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
var queryCore = require('@tanstack/query-core');
|
|
4
4
|
var solidJs = require('solid-js');
|
|
5
5
|
var web = require('@solidjs/web');
|
|
6
|
+
var serverFunctions = require('@solidjs/web/server-functions');
|
|
6
7
|
|
|
7
8
|
// src/index.ts
|
|
8
9
|
exports.QueryClient = class QueryClient extends queryCore.QueryClient {
|
|
@@ -12,6 +13,7 @@ exports.QueryClient = class QueryClient extends queryCore.QueryClient {
|
|
|
12
13
|
};
|
|
13
14
|
var isServer = typeof window === "undefined";
|
|
14
15
|
var HYDRATION_KEY_PREFIX = "sq:";
|
|
16
|
+
exports.FLIGHT_DATA_SOURCE = "sq";
|
|
15
17
|
exports.QueryClientContext = solidJs.createContext(null);
|
|
16
18
|
exports.useQueryClient = (queryClient) => {
|
|
17
19
|
if (queryClient) {
|
|
@@ -27,9 +29,11 @@ function serializeCacheOnServer(client) {
|
|
|
27
29
|
const ctx = solidJs.sharedConfig.context;
|
|
28
30
|
if (!ctx || !ctx.async || ctx.noHydrate) return;
|
|
29
31
|
const cache = client.getQueryCache();
|
|
32
|
+
const shouldDehydrateQuery = client.getDefaultOptions().dehydrate?.shouldDehydrateQuery;
|
|
30
33
|
const seen = /* @__PURE__ */ new Set();
|
|
31
34
|
const serializeQuery = (query) => {
|
|
32
35
|
if (seen.has(query.queryHash)) return;
|
|
36
|
+
if (shouldDehydrateQuery && !shouldDehydrateQuery(query)) return;
|
|
33
37
|
const state = query.state;
|
|
34
38
|
if (state.status === "success") {
|
|
35
39
|
seen.add(query.queryHash);
|
|
@@ -53,7 +57,17 @@ function serializeCacheOnServer(client) {
|
|
|
53
57
|
exports.QueryClientProvider = (props) => {
|
|
54
58
|
props.client.mount();
|
|
55
59
|
solidJs.onCleanup(() => props.client.unmount());
|
|
56
|
-
if (isServer)
|
|
60
|
+
if (isServer) {
|
|
61
|
+
serializeCacheOnServer(props.client);
|
|
62
|
+
solidJs.onCleanup(() => {
|
|
63
|
+
props.client.cancelQueries().catch(() => void 0);
|
|
64
|
+
props.client.clear();
|
|
65
|
+
});
|
|
66
|
+
} else {
|
|
67
|
+
solidJs.onCleanup(serverFunctions.subscribeFlightData(exports.FLIGHT_DATA_SOURCE, (data) => {
|
|
68
|
+
queryCore.hydrate(props.client, data);
|
|
69
|
+
}));
|
|
70
|
+
}
|
|
57
71
|
return web.createComponent(exports.QueryClientContext, {
|
|
58
72
|
value: () => props.client,
|
|
59
73
|
get children() {
|
|
@@ -432,6 +446,15 @@ function useQuery(options, queryClient) {
|
|
|
432
446
|
function queryOptions(options) {
|
|
433
447
|
return options;
|
|
434
448
|
}
|
|
449
|
+
async function dehydrateSettled(client, options) {
|
|
450
|
+
const cache = client.getQueryCache();
|
|
451
|
+
for (; ; ) {
|
|
452
|
+
const pending = cache.getAll().filter((query) => query.state.fetchStatus !== "idle").map((query) => query.promise);
|
|
453
|
+
if (pending.length === 0) break;
|
|
454
|
+
await Promise.allSettled(pending);
|
|
455
|
+
}
|
|
456
|
+
return queryCore.dehydrate(client, options);
|
|
457
|
+
}
|
|
435
458
|
var isServer3 = typeof window === "undefined";
|
|
436
459
|
function createCacheAggregate(subscribe, read, empty) {
|
|
437
460
|
const hydratedMount = !isServer3 && solidJs.sharedConfig.hydrating === true;
|
|
@@ -592,15 +615,13 @@ function useMutation(options, queryClient) {
|
|
|
592
615
|
const [flight, setFlight] = solidJs.createOptimistic(null);
|
|
593
616
|
const [settled, setSettled] = solidJs.createSignal(IDLE);
|
|
594
617
|
let activeMutation = null;
|
|
618
|
+
let unsubscribeFlight = null;
|
|
595
619
|
const [flightVersion, setFlightVersion] = solidJs.createSignal(0);
|
|
596
|
-
if (!isServer4)
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
}
|
|
620
|
+
if (!isServer4)
|
|
621
|
+
solidJs.onCleanup(() => {
|
|
622
|
+
unsubscribeFlight?.();
|
|
623
|
+
unsubscribeFlight = null;
|
|
601
624
|
});
|
|
602
|
-
solidJs.onCleanup(unsubscribe);
|
|
603
|
-
}
|
|
604
625
|
async function* run(variables) {
|
|
605
626
|
const opts = solidJs.untrack(options);
|
|
606
627
|
const callbackContext = {
|
|
@@ -610,7 +631,8 @@ function useMutation(options, queryClient) {
|
|
|
610
631
|
};
|
|
611
632
|
if (!isServer4) setFlight({ variables });
|
|
612
633
|
opts.onMutate?.(variables, callbackContext);
|
|
613
|
-
const
|
|
634
|
+
const c = solidJs.untrack(client);
|
|
635
|
+
const mutation = c.getMutationCache().build(c, {
|
|
614
636
|
...opts,
|
|
615
637
|
// Options-level callbacks re-run below, inside the transaction —
|
|
616
638
|
// executing them here (inside the await gap) would let their
|
|
@@ -621,6 +643,20 @@ function useMutation(options, queryClient) {
|
|
|
621
643
|
onSettled: void 0
|
|
622
644
|
});
|
|
623
645
|
activeMutation = mutation;
|
|
646
|
+
if (!isServer4) {
|
|
647
|
+
unsubscribeFlight?.();
|
|
648
|
+
unsubscribeFlight = c.getMutationCache().subscribe((event) => {
|
|
649
|
+
if ("mutation" in event && event.mutation === activeMutation) {
|
|
650
|
+
setFlightVersion((v) => v + 1);
|
|
651
|
+
}
|
|
652
|
+
});
|
|
653
|
+
}
|
|
654
|
+
const settleFlight = () => {
|
|
655
|
+
if (activeMutation !== mutation) return;
|
|
656
|
+
activeMutation = null;
|
|
657
|
+
unsubscribeFlight?.();
|
|
658
|
+
unsubscribeFlight = null;
|
|
659
|
+
};
|
|
624
660
|
async function* settleFailure(error) {
|
|
625
661
|
try {
|
|
626
662
|
if (opts.onError)
|
|
@@ -648,7 +684,7 @@ function useMutation(options, queryClient) {
|
|
|
648
684
|
variables,
|
|
649
685
|
submittedAt: mutation.state.submittedAt
|
|
650
686
|
});
|
|
651
|
-
|
|
687
|
+
settleFlight();
|
|
652
688
|
throw error;
|
|
653
689
|
}
|
|
654
690
|
let result2;
|
|
@@ -688,7 +724,7 @@ function useMutation(options, queryClient) {
|
|
|
688
724
|
variables,
|
|
689
725
|
submittedAt: mutation.state.submittedAt
|
|
690
726
|
});
|
|
691
|
-
|
|
727
|
+
settleFlight();
|
|
692
728
|
return result2;
|
|
693
729
|
}
|
|
694
730
|
const invoke = isServer4 ? (variables) => drain(run(variables)) : solidJs.action(run);
|
|
@@ -826,6 +862,7 @@ function useQueries(queriesOptions, queryClient) {
|
|
|
826
862
|
});
|
|
827
863
|
}
|
|
828
864
|
|
|
865
|
+
exports.dehydrateSettled = dehydrateSettled;
|
|
829
866
|
exports.infiniteQueryOptions = infiniteQueryOptions;
|
|
830
867
|
exports.mutationOptions = mutationOptions;
|
|
831
868
|
exports.queryOptions = queryOptions;
|
package/build/index.d.cts
CHANGED
|
@@ -23,10 +23,12 @@ export { useQuery } from './_tsup-dts-rollup.cjs';
|
|
|
23
23
|
export { queryOptions } from './_tsup-dts-rollup.cjs';
|
|
24
24
|
export { DefinedInitialDataOptions } from './_tsup-dts-rollup.cjs';
|
|
25
25
|
export { UndefinedInitialDataOptions } from './_tsup-dts-rollup.cjs';
|
|
26
|
+
export { FLIGHT_DATA_SOURCE_alias_1 as FLIGHT_DATA_SOURCE } from './_tsup-dts-rollup.cjs';
|
|
26
27
|
export { QueryClientContext_alias_1 as QueryClientContext } from './_tsup-dts-rollup.cjs';
|
|
27
28
|
export { QueryClientProvider_alias_1 as QueryClientProvider } from './_tsup-dts-rollup.cjs';
|
|
28
29
|
export { useQueryClient_alias_1 as useQueryClient } from './_tsup-dts-rollup.cjs';
|
|
29
30
|
export { QueryClientProviderProps_alias_1 as QueryClientProviderProps } from './_tsup-dts-rollup.cjs';
|
|
31
|
+
export { dehydrateSettled_alias_1 as dehydrateSettled } from './_tsup-dts-rollup.cjs';
|
|
30
32
|
export { useIsFetching } from './_tsup-dts-rollup.cjs';
|
|
31
33
|
export { useInfiniteQuery } from './_tsup-dts-rollup.cjs';
|
|
32
34
|
export { infiniteQueryOptions } from './_tsup-dts-rollup.cjs';
|
package/build/index.d.ts
CHANGED
|
@@ -23,10 +23,12 @@ export { useQuery } from './_tsup-dts-rollup.js';
|
|
|
23
23
|
export { queryOptions } from './_tsup-dts-rollup.js';
|
|
24
24
|
export { DefinedInitialDataOptions } from './_tsup-dts-rollup.js';
|
|
25
25
|
export { UndefinedInitialDataOptions } from './_tsup-dts-rollup.js';
|
|
26
|
+
export { FLIGHT_DATA_SOURCE_alias_1 as FLIGHT_DATA_SOURCE } from './_tsup-dts-rollup.js';
|
|
26
27
|
export { QueryClientContext_alias_1 as QueryClientContext } from './_tsup-dts-rollup.js';
|
|
27
28
|
export { QueryClientProvider_alias_1 as QueryClientProvider } from './_tsup-dts-rollup.js';
|
|
28
29
|
export { useQueryClient_alias_1 as useQueryClient } from './_tsup-dts-rollup.js';
|
|
29
30
|
export { QueryClientProviderProps_alias_1 as QueryClientProviderProps } from './_tsup-dts-rollup.js';
|
|
31
|
+
export { dehydrateSettled_alias_1 as dehydrateSettled } from './_tsup-dts-rollup.js';
|
|
30
32
|
export { useIsFetching } from './_tsup-dts-rollup.js';
|
|
31
33
|
export { useInfiniteQuery } from './_tsup-dts-rollup.js';
|
|
32
34
|
export { infiniteQueryOptions } from './_tsup-dts-rollup.js';
|
package/build/index.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import { noop, QueryClient as QueryClient$1, shouldThrowError, InfiniteQueryObserver,
|
|
1
|
+
import { noop, QueryClient as QueryClient$1, hydrate, dehydrate, shouldThrowError, InfiniteQueryObserver, QueryObserver, replaceEqualDeep } from '@tanstack/query-core';
|
|
2
2
|
export * from '@tanstack/query-core';
|
|
3
3
|
import { createContext, useContext, onCleanup, createMemo, createOptimistic, createSignal, action, createRenderEffect, untrack, repeat, $TRACK, sharedConfig, createEffect, createProjection, runWithOwner, isPending, resolve } from 'solid-js';
|
|
4
4
|
import { createComponent } from '@solidjs/web';
|
|
5
|
+
import { subscribeFlightData } from '@solidjs/web/server-functions';
|
|
5
6
|
|
|
6
7
|
// src/index.ts
|
|
7
8
|
var QueryClient = class extends QueryClient$1 {
|
|
@@ -11,6 +12,7 @@ var QueryClient = class extends QueryClient$1 {
|
|
|
11
12
|
};
|
|
12
13
|
var isServer = typeof window === "undefined";
|
|
13
14
|
var HYDRATION_KEY_PREFIX = "sq:";
|
|
15
|
+
var FLIGHT_DATA_SOURCE = "sq";
|
|
14
16
|
var QueryClientContext = createContext(null);
|
|
15
17
|
var useQueryClient = (queryClient) => {
|
|
16
18
|
if (queryClient) {
|
|
@@ -26,9 +28,11 @@ function serializeCacheOnServer(client) {
|
|
|
26
28
|
const ctx = sharedConfig.context;
|
|
27
29
|
if (!ctx || !ctx.async || ctx.noHydrate) return;
|
|
28
30
|
const cache = client.getQueryCache();
|
|
31
|
+
const shouldDehydrateQuery = client.getDefaultOptions().dehydrate?.shouldDehydrateQuery;
|
|
29
32
|
const seen = /* @__PURE__ */ new Set();
|
|
30
33
|
const serializeQuery = (query) => {
|
|
31
34
|
if (seen.has(query.queryHash)) return;
|
|
35
|
+
if (shouldDehydrateQuery && !shouldDehydrateQuery(query)) return;
|
|
32
36
|
const state = query.state;
|
|
33
37
|
if (state.status === "success") {
|
|
34
38
|
seen.add(query.queryHash);
|
|
@@ -52,7 +56,17 @@ function serializeCacheOnServer(client) {
|
|
|
52
56
|
var QueryClientProvider = (props) => {
|
|
53
57
|
props.client.mount();
|
|
54
58
|
onCleanup(() => props.client.unmount());
|
|
55
|
-
if (isServer)
|
|
59
|
+
if (isServer) {
|
|
60
|
+
serializeCacheOnServer(props.client);
|
|
61
|
+
onCleanup(() => {
|
|
62
|
+
props.client.cancelQueries().catch(() => void 0);
|
|
63
|
+
props.client.clear();
|
|
64
|
+
});
|
|
65
|
+
} else {
|
|
66
|
+
onCleanup(subscribeFlightData(FLIGHT_DATA_SOURCE, (data) => {
|
|
67
|
+
hydrate(props.client, data);
|
|
68
|
+
}));
|
|
69
|
+
}
|
|
56
70
|
return createComponent(QueryClientContext, {
|
|
57
71
|
value: () => props.client,
|
|
58
72
|
get children() {
|
|
@@ -431,6 +445,15 @@ function useQuery(options, queryClient) {
|
|
|
431
445
|
function queryOptions(options) {
|
|
432
446
|
return options;
|
|
433
447
|
}
|
|
448
|
+
async function dehydrateSettled(client, options) {
|
|
449
|
+
const cache = client.getQueryCache();
|
|
450
|
+
for (; ; ) {
|
|
451
|
+
const pending = cache.getAll().filter((query) => query.state.fetchStatus !== "idle").map((query) => query.promise);
|
|
452
|
+
if (pending.length === 0) break;
|
|
453
|
+
await Promise.allSettled(pending);
|
|
454
|
+
}
|
|
455
|
+
return dehydrate(client, options);
|
|
456
|
+
}
|
|
434
457
|
var isServer3 = typeof window === "undefined";
|
|
435
458
|
function createCacheAggregate(subscribe, read, empty) {
|
|
436
459
|
const hydratedMount = !isServer3 && sharedConfig.hydrating === true;
|
|
@@ -591,15 +614,13 @@ function useMutation(options, queryClient) {
|
|
|
591
614
|
const [flight, setFlight] = createOptimistic(null);
|
|
592
615
|
const [settled, setSettled] = createSignal(IDLE);
|
|
593
616
|
let activeMutation = null;
|
|
617
|
+
let unsubscribeFlight = null;
|
|
594
618
|
const [flightVersion, setFlightVersion] = createSignal(0);
|
|
595
|
-
if (!isServer4)
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
}
|
|
619
|
+
if (!isServer4)
|
|
620
|
+
onCleanup(() => {
|
|
621
|
+
unsubscribeFlight?.();
|
|
622
|
+
unsubscribeFlight = null;
|
|
600
623
|
});
|
|
601
|
-
onCleanup(unsubscribe);
|
|
602
|
-
}
|
|
603
624
|
async function* run(variables) {
|
|
604
625
|
const opts = untrack(options);
|
|
605
626
|
const callbackContext = {
|
|
@@ -609,7 +630,8 @@ function useMutation(options, queryClient) {
|
|
|
609
630
|
};
|
|
610
631
|
if (!isServer4) setFlight({ variables });
|
|
611
632
|
opts.onMutate?.(variables, callbackContext);
|
|
612
|
-
const
|
|
633
|
+
const c = untrack(client);
|
|
634
|
+
const mutation = c.getMutationCache().build(c, {
|
|
613
635
|
...opts,
|
|
614
636
|
// Options-level callbacks re-run below, inside the transaction —
|
|
615
637
|
// executing them here (inside the await gap) would let their
|
|
@@ -620,6 +642,20 @@ function useMutation(options, queryClient) {
|
|
|
620
642
|
onSettled: void 0
|
|
621
643
|
});
|
|
622
644
|
activeMutation = mutation;
|
|
645
|
+
if (!isServer4) {
|
|
646
|
+
unsubscribeFlight?.();
|
|
647
|
+
unsubscribeFlight = c.getMutationCache().subscribe((event) => {
|
|
648
|
+
if ("mutation" in event && event.mutation === activeMutation) {
|
|
649
|
+
setFlightVersion((v) => v + 1);
|
|
650
|
+
}
|
|
651
|
+
});
|
|
652
|
+
}
|
|
653
|
+
const settleFlight = () => {
|
|
654
|
+
if (activeMutation !== mutation) return;
|
|
655
|
+
activeMutation = null;
|
|
656
|
+
unsubscribeFlight?.();
|
|
657
|
+
unsubscribeFlight = null;
|
|
658
|
+
};
|
|
623
659
|
async function* settleFailure(error) {
|
|
624
660
|
try {
|
|
625
661
|
if (opts.onError)
|
|
@@ -647,7 +683,7 @@ function useMutation(options, queryClient) {
|
|
|
647
683
|
variables,
|
|
648
684
|
submittedAt: mutation.state.submittedAt
|
|
649
685
|
});
|
|
650
|
-
|
|
686
|
+
settleFlight();
|
|
651
687
|
throw error;
|
|
652
688
|
}
|
|
653
689
|
let result2;
|
|
@@ -687,7 +723,7 @@ function useMutation(options, queryClient) {
|
|
|
687
723
|
variables,
|
|
688
724
|
submittedAt: mutation.state.submittedAt
|
|
689
725
|
});
|
|
690
|
-
|
|
726
|
+
settleFlight();
|
|
691
727
|
return result2;
|
|
692
728
|
}
|
|
693
729
|
const invoke = isServer4 ? (variables) => drain(run(variables)) : action(run);
|
|
@@ -825,4 +861,4 @@ function useQueries(queriesOptions, queryClient) {
|
|
|
825
861
|
});
|
|
826
862
|
}
|
|
827
863
|
|
|
828
|
-
export { IsRestoringContext, QueryClient, QueryClientContext, QueryClientProvider, infiniteQueryOptions, mutationOptions, queryOptions, useInfiniteQuery, useIsFetching, useIsMutating, useIsRestoring, useMutation, useMutationState, useQueries, useQuery, useQueryClient };
|
|
864
|
+
export { FLIGHT_DATA_SOURCE, IsRestoringContext, QueryClient, QueryClientContext, QueryClientProvider, dehydrateSettled, infiniteQueryOptions, mutationOptions, queryOptions, useInfiniteQuery, useIsFetching, useIsMutating, useIsRestoring, useMutation, useMutationState, useQueries, useQuery, useQueryClient };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tanstack/solid-query",
|
|
3
|
-
"version": "6.0.0-rc.
|
|
3
|
+
"version": "6.0.0-rc.2",
|
|
4
4
|
"description": "Primitives for managing, caching and syncing asynchronous and remote data in Solid",
|
|
5
5
|
"author": "tannerlinsley",
|
|
6
6
|
"license": "MIT",
|
|
@@ -53,15 +53,16 @@
|
|
|
53
53
|
"@babel/preset-typescript": "^7.18.6",
|
|
54
54
|
"@solidjs/testing-library": "^0.8.10",
|
|
55
55
|
"@solidjs/vite-plugin": "^3.0.0-next.27",
|
|
56
|
-
"@solidjs/web": "^2.0.0-rc.
|
|
56
|
+
"@solidjs/web": "^2.0.0-rc.6",
|
|
57
57
|
"babel-preset-solid": "^2.0.0-rc.2",
|
|
58
58
|
"npm-run-all2": "^5.0.0",
|
|
59
|
-
"solid-js": "^2.0.0-rc.
|
|
59
|
+
"solid-js": "^2.0.0-rc.6",
|
|
60
60
|
"tsup-preset-solid": "^2.2.0",
|
|
61
61
|
"@tanstack/query-test-utils": "0.0.0"
|
|
62
62
|
},
|
|
63
63
|
"peerDependencies": {
|
|
64
|
-
"
|
|
64
|
+
"@solidjs/web": ">=2.0.0-rc.6 <3.0.0",
|
|
65
|
+
"solid-js": ">=2.0.0-rc.6 <3.0.0"
|
|
65
66
|
},
|
|
66
67
|
"scripts": {
|
|
67
68
|
"clean": "premove ./build ./coverage ./dist-ts",
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { createContext, onCleanup, sharedConfig, useContext } from 'solid-js'
|
|
2
|
-
import
|
|
2
|
+
import { hydrate } from '@tanstack/query-core'
|
|
3
|
+
import { subscribeFlightData } from '@solidjs/web/server-functions'
|
|
4
|
+
import type { DehydratedState, Query } from '@tanstack/query-core'
|
|
3
5
|
import type { QueryClient } from './QueryClient'
|
|
4
6
|
import type { JSX } from '@solidjs/web'
|
|
5
7
|
|
|
@@ -13,6 +15,29 @@ const isServer = typeof window === 'undefined'
|
|
|
13
15
|
*/
|
|
14
16
|
export const HYDRATION_KEY_PREFIX = 'sq:'
|
|
15
17
|
|
|
18
|
+
/**
|
|
19
|
+
* The query cache's single-flight source id. Mutation responses can fold
|
|
20
|
+
* fresh data for multiple caches at once (Solid's multi-source
|
|
21
|
+
* single-flight protocol); this is the slice the query cache claims — the
|
|
22
|
+
* provider subscribes its consumer under it, and server collectors
|
|
23
|
+
* register under it to produce the data:
|
|
24
|
+
*
|
|
25
|
+
* ```ts
|
|
26
|
+
* import { registerFlightDataSource } from '@solidjs/web/server-functions/server'
|
|
27
|
+
* import { FLIGHT_DATA_SOURCE, dehydrate } from '@tanstack/solid-query'
|
|
28
|
+
*
|
|
29
|
+
* registerFlightDataSource(FLIGHT_DATA_SOURCE, async (event, outcome) => {
|
|
30
|
+
* // rebuild the data for outcome.targetUrl into a QueryClient, then
|
|
31
|
+
* return dehydrate(queryClient)
|
|
32
|
+
* })
|
|
33
|
+
* ```
|
|
34
|
+
*
|
|
35
|
+
* The slice's payload is a `DehydratedState`; the provider consumes it
|
|
36
|
+
* with `hydrate()`, so every mounted query on those keys updates before
|
|
37
|
+
* the mutation's promise resolves — no follow-up refetches.
|
|
38
|
+
*/
|
|
39
|
+
export const FLIGHT_DATA_SOURCE = 'sq'
|
|
40
|
+
|
|
16
41
|
export const QueryClientContext = createContext<(() => QueryClient) | null>(
|
|
17
42
|
null,
|
|
18
43
|
)
|
|
@@ -64,9 +89,18 @@ function serializeCacheOnServer(client: QueryClient): void {
|
|
|
64
89
|
if (!ctx || !ctx.async || ctx.noHydrate) return
|
|
65
90
|
|
|
66
91
|
const cache = client.getQueryCache()
|
|
92
|
+
// The standard dehydrate filter gates the wire here too, so apps keep
|
|
93
|
+
// sensitive or oversized queries out of the HTML with the same option
|
|
94
|
+
// they'd pass any other transport.
|
|
95
|
+
const shouldDehydrateQuery =
|
|
96
|
+
client.getDefaultOptions().dehydrate?.shouldDehydrateQuery
|
|
67
97
|
const seen = new Set<string>()
|
|
68
98
|
const serializeQuery = (query: Query<any, any, any, any>) => {
|
|
69
99
|
if (seen.has(query.queryHash)) return
|
|
100
|
+
// Consulted per cache event until it passes, so a filter that rejects
|
|
101
|
+
// pending queries (e.g. the core default) still admits the settled
|
|
102
|
+
// value if it lands while the request's serialization context is live.
|
|
103
|
+
if (shouldDehydrateQuery && !shouldDehydrateQuery(query)) return
|
|
70
104
|
const state = query.state
|
|
71
105
|
if (state.status === 'success') {
|
|
72
106
|
seen.add(query.queryHash)
|
|
@@ -97,15 +131,40 @@ function serializeCacheOnServer(client: QueryClient): void {
|
|
|
97
131
|
/**
|
|
98
132
|
* Provides the QueryClient and manages its mount lifecycle. On the server
|
|
99
133
|
* it also registers the cache serializer above; on the client, hooks prime
|
|
100
|
-
* the cache from their hash-keyed registry entries themselves
|
|
101
|
-
* `useBaseQuery
|
|
134
|
+
* the cache from their hash-keyed registry entries themselves (see
|
|
135
|
+
* `useBaseQuery`) and the provider subscribes the cache's single-flight
|
|
136
|
+
* consumer: mutation responses carrying a `FLIGHT_DATA_SOURCE` slice (a
|
|
137
|
+
* `DehydratedState` produced by a server collector registered under the
|
|
138
|
+
* same id) hydrate this client before the mutation's promise resolves.
|
|
139
|
+
* Subscribing is inert when no server collector exists — the server just
|
|
140
|
+
* folds nothing — so it is unconditional. One consumer per source: with
|
|
141
|
+
* nested providers, the innermost mounted one owns the slice.
|
|
102
142
|
*/
|
|
103
143
|
export const QueryClientProvider = (
|
|
104
144
|
props: QueryClientProviderProps,
|
|
105
145
|
): JSX.Element => {
|
|
106
146
|
props.client.mount()
|
|
107
147
|
onCleanup(() => props.client.unmount())
|
|
108
|
-
if (isServer)
|
|
148
|
+
if (isServer) {
|
|
149
|
+
serializeCacheOnServer(props.client)
|
|
150
|
+
// Render disposal ends the request: abort what's still in flight and
|
|
151
|
+
// drop the cache so user-configured finite gcTime timers can't pin
|
|
152
|
+
// the per-request client (and whatever its queries closed over) until
|
|
153
|
+
// they fire. Serialized promises are already in seroval's hands, so
|
|
154
|
+
// clearing here can't affect the streamed payload.
|
|
155
|
+
onCleanup(() => {
|
|
156
|
+
props.client.cancelQueries().catch(() => undefined)
|
|
157
|
+
props.client.clear()
|
|
158
|
+
})
|
|
159
|
+
} else {
|
|
160
|
+
// Client-only: the server's consumer registry is module state shared
|
|
161
|
+
// across requests — registering there would leak between them.
|
|
162
|
+
onCleanup(
|
|
163
|
+
subscribeFlightData<DehydratedState>(FLIGHT_DATA_SOURCE, (data) => {
|
|
164
|
+
hydrate(props.client, data)
|
|
165
|
+
}),
|
|
166
|
+
)
|
|
167
|
+
}
|
|
109
168
|
|
|
110
169
|
return (
|
|
111
170
|
<QueryClientContext value={() => props.client}>
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { dehydrate } from '@tanstack/query-core'
|
|
2
|
+
import type { DehydrateOptions, DehydratedState } from '@tanstack/query-core'
|
|
3
|
+
import type { QueryClient } from './QueryClient'
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Waits for every fetch the client has in flight to settle, then
|
|
7
|
+
* dehydrates. This is the extraction half of a single-flight collector:
|
|
8
|
+
* after route data functions run for the mutation's target URL, loaders
|
|
9
|
+
* commonly kick off prefetches without awaiting them — plain
|
|
10
|
+
* `dehydrate()` would snapshot those mid-fetch and ship nothing.
|
|
11
|
+
*
|
|
12
|
+
* ```ts
|
|
13
|
+
* registerFlightDataSource(FLIGHT_DATA_SOURCE, (event, outcome) =>
|
|
14
|
+
* loadFlightTarget({
|
|
15
|
+
* router,
|
|
16
|
+
* event,
|
|
17
|
+
* outcome,
|
|
18
|
+
* collect: () => dehydrateSettled(queryClient),
|
|
19
|
+
* }),
|
|
20
|
+
* )
|
|
21
|
+
* ```
|
|
22
|
+
*
|
|
23
|
+
* Settling is chased to quiescence — awaiting one batch of fetches can
|
|
24
|
+
* dispatch more (dependent queries keyed off a first result) — so an
|
|
25
|
+
* unconditionally self-refetching query would keep this pending; that's
|
|
26
|
+
* an app bug mirrored, not guarded.
|
|
27
|
+
*/
|
|
28
|
+
export async function dehydrateSettled(
|
|
29
|
+
client: QueryClient,
|
|
30
|
+
options?: DehydrateOptions,
|
|
31
|
+
): Promise<DehydratedState> {
|
|
32
|
+
const cache = client.getQueryCache()
|
|
33
|
+
for (;;) {
|
|
34
|
+
const pending = cache
|
|
35
|
+
.getAll()
|
|
36
|
+
.filter((query) => query.state.fetchStatus !== 'idle')
|
|
37
|
+
.map((query) => query.promise)
|
|
38
|
+
if (pending.length === 0) break
|
|
39
|
+
await Promise.allSettled(pending)
|
|
40
|
+
}
|
|
41
|
+
return dehydrate(client, options)
|
|
42
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -39,11 +39,13 @@ export type {
|
|
|
39
39
|
UndefinedInitialDataOptions,
|
|
40
40
|
} from './queryOptions'
|
|
41
41
|
export {
|
|
42
|
+
FLIGHT_DATA_SOURCE,
|
|
42
43
|
QueryClientContext,
|
|
43
44
|
QueryClientProvider,
|
|
44
45
|
useQueryClient,
|
|
45
46
|
} from './QueryClientProvider'
|
|
46
47
|
export type { QueryClientProviderProps } from './QueryClientProvider'
|
|
48
|
+
export { dehydrateSettled } from './dehydrateSettled'
|
|
47
49
|
export { useIsFetching } from './useIsFetching'
|
|
48
50
|
export { useInfiniteQuery } from './useInfiniteQuery'
|
|
49
51
|
export { infiniteQueryOptions } from './infiniteQueryOptions'
|
package/src/useMutation.ts
CHANGED
|
@@ -114,20 +114,20 @@ export function useMutation<
|
|
|
114
114
|
* Flight metadata (retry failures, offline pause) lives on the Mutation
|
|
115
115
|
* instance and changes during the await gap; a version bump per cache
|
|
116
116
|
* event for the active mutation keeps reads current without cloning
|
|
117
|
-
* observer results.
|
|
117
|
+
* observer results. The subscription is per-flight, created in `run`
|
|
118
|
+
* against the same client the mutation is built on: nothing reactive is
|
|
119
|
+
* read at setup (no client read to untrack), the listener and the
|
|
120
|
+
* mutation can never sit on different clients, and an idle hook holds no
|
|
121
|
+
* cache subscription at all.
|
|
118
122
|
*/
|
|
119
123
|
let activeMutation: Mutation<TData, TError, TVariables> | null = null
|
|
124
|
+
let unsubscribeFlight: (() => void) | null = null
|
|
120
125
|
const [flightVersion, setFlightVersion] = createSignal(0)
|
|
121
|
-
if (!isServer)
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
setFlightVersion((v) => v + 1)
|
|
127
|
-
}
|
|
128
|
-
})
|
|
129
|
-
onCleanup(unsubscribe)
|
|
130
|
-
}
|
|
126
|
+
if (!isServer)
|
|
127
|
+
onCleanup(() => {
|
|
128
|
+
unsubscribeFlight?.()
|
|
129
|
+
unsubscribeFlight = null
|
|
130
|
+
})
|
|
131
131
|
|
|
132
132
|
async function* run(
|
|
133
133
|
variables: TVariables,
|
|
@@ -144,19 +144,33 @@ export function useMutation<
|
|
|
144
144
|
if (!isServer) setFlight({ variables })
|
|
145
145
|
opts.onMutate?.(variables, callbackContext)
|
|
146
146
|
|
|
147
|
-
const
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
}) as unknown as Mutation<TData, TError, TVariables>
|
|
147
|
+
const c = untrack(client)
|
|
148
|
+
const mutation = c.getMutationCache().build(c, {
|
|
149
|
+
...opts,
|
|
150
|
+
// Options-level callbacks re-run below, inside the transaction —
|
|
151
|
+
// executing them here (inside the await gap) would let their
|
|
152
|
+
// cache writes and invalidations escape the atomic settle.
|
|
153
|
+
onMutate: undefined,
|
|
154
|
+
onSuccess: undefined,
|
|
155
|
+
onError: undefined,
|
|
156
|
+
onSettled: undefined,
|
|
157
|
+
}) as unknown as Mutation<TData, TError, TVariables>
|
|
159
158
|
activeMutation = mutation
|
|
159
|
+
if (!isServer) {
|
|
160
|
+
// A rapid re-mutate replaces the previous flight's listener.
|
|
161
|
+
unsubscribeFlight?.()
|
|
162
|
+
unsubscribeFlight = c.getMutationCache().subscribe((event) => {
|
|
163
|
+
if ('mutation' in event && event.mutation === activeMutation) {
|
|
164
|
+
setFlightVersion((v) => v + 1)
|
|
165
|
+
}
|
|
166
|
+
})
|
|
167
|
+
}
|
|
168
|
+
const settleFlight = () => {
|
|
169
|
+
if (activeMutation !== mutation) return
|
|
170
|
+
activeMutation = null
|
|
171
|
+
unsubscribeFlight?.()
|
|
172
|
+
unsubscribeFlight = null
|
|
173
|
+
}
|
|
160
174
|
|
|
161
175
|
/**
|
|
162
176
|
* Failure settle, shared by both paths. Callback routing mirrors
|
|
@@ -202,7 +216,7 @@ export function useMutation<
|
|
|
202
216
|
variables,
|
|
203
217
|
submittedAt: mutation.state.submittedAt,
|
|
204
218
|
})
|
|
205
|
-
|
|
219
|
+
settleFlight()
|
|
206
220
|
throw error
|
|
207
221
|
}
|
|
208
222
|
|
|
@@ -250,7 +264,7 @@ export function useMutation<
|
|
|
250
264
|
variables,
|
|
251
265
|
submittedAt: mutation.state.submittedAt,
|
|
252
266
|
})
|
|
253
|
-
|
|
267
|
+
settleFlight()
|
|
254
268
|
return result
|
|
255
269
|
}
|
|
256
270
|
|