@tanstack/query-core 5.76.0 → 5.77.0
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/legacy/{hydration-BaHDIfRR.d.ts → hydration-B3ndIyL6.d.ts} +1 -0
- package/build/legacy/{hydration-n7FlH3vr.d.cts → hydration-GTiXepW_.d.cts} +1 -0
- package/build/legacy/hydration.cjs +48 -33
- package/build/legacy/hydration.cjs.map +1 -1
- package/build/legacy/hydration.d.cts +1 -1
- package/build/legacy/hydration.d.ts +1 -1
- package/build/legacy/hydration.js +48 -33
- package/build/legacy/hydration.js.map +1 -1
- package/build/legacy/index.d.cts +1 -1
- package/build/legacy/index.d.ts +1 -1
- package/build/legacy/infiniteQueryBehavior.d.cts +1 -1
- package/build/legacy/infiniteQueryBehavior.d.ts +1 -1
- package/build/legacy/infiniteQueryObserver.d.cts +1 -1
- package/build/legacy/infiniteQueryObserver.d.ts +1 -1
- package/build/legacy/mutation.d.cts +1 -1
- package/build/legacy/mutation.d.ts +1 -1
- package/build/legacy/mutationCache.d.cts +1 -1
- package/build/legacy/mutationCache.d.ts +1 -1
- package/build/legacy/mutationObserver.d.cts +1 -1
- package/build/legacy/mutationObserver.d.ts +1 -1
- package/build/legacy/queriesObserver.d.cts +1 -1
- package/build/legacy/queriesObserver.d.ts +1 -1
- package/build/legacy/query.d.cts +1 -1
- package/build/legacy/query.d.ts +1 -1
- package/build/legacy/queryCache.d.cts +1 -1
- package/build/legacy/queryCache.d.ts +1 -1
- package/build/legacy/queryClient.d.cts +1 -1
- package/build/legacy/queryClient.d.ts +1 -1
- package/build/legacy/queryObserver.d.cts +1 -1
- package/build/legacy/queryObserver.d.ts +1 -1
- package/build/legacy/retryer.d.cts +1 -1
- package/build/legacy/retryer.d.ts +1 -1
- package/build/legacy/streamedQuery.cjs +6 -4
- package/build/legacy/streamedQuery.cjs.map +1 -1
- package/build/legacy/streamedQuery.d.cts +8 -3
- package/build/legacy/streamedQuery.d.ts +8 -3
- package/build/legacy/streamedQuery.js +6 -4
- package/build/legacy/streamedQuery.js.map +1 -1
- package/build/legacy/thenable.cjs +17 -2
- package/build/legacy/thenable.cjs.map +1 -1
- package/build/legacy/thenable.d.cts +12 -1
- package/build/legacy/thenable.d.ts +12 -1
- package/build/legacy/thenable.js +15 -1
- package/build/legacy/thenable.js.map +1 -1
- package/build/legacy/types.d.cts +1 -1
- package/build/legacy/types.d.ts +1 -1
- package/build/legacy/utils.d.cts +1 -1
- package/build/legacy/utils.d.ts +1 -1
- package/build/modern/{hydration-BaHDIfRR.d.ts → hydration-B3ndIyL6.d.ts} +1 -0
- package/build/modern/{hydration-n7FlH3vr.d.cts → hydration-GTiXepW_.d.cts} +1 -0
- package/build/modern/hydration.cjs +47 -32
- package/build/modern/hydration.cjs.map +1 -1
- package/build/modern/hydration.d.cts +1 -1
- package/build/modern/hydration.d.ts +1 -1
- package/build/modern/hydration.js +47 -32
- package/build/modern/hydration.js.map +1 -1
- package/build/modern/index.d.cts +1 -1
- package/build/modern/index.d.ts +1 -1
- package/build/modern/infiniteQueryBehavior.d.cts +1 -1
- package/build/modern/infiniteQueryBehavior.d.ts +1 -1
- package/build/modern/infiniteQueryObserver.d.cts +1 -1
- package/build/modern/infiniteQueryObserver.d.ts +1 -1
- package/build/modern/mutation.d.cts +1 -1
- package/build/modern/mutation.d.ts +1 -1
- package/build/modern/mutationCache.d.cts +1 -1
- package/build/modern/mutationCache.d.ts +1 -1
- package/build/modern/mutationObserver.d.cts +1 -1
- package/build/modern/mutationObserver.d.ts +1 -1
- package/build/modern/queriesObserver.d.cts +1 -1
- package/build/modern/queriesObserver.d.ts +1 -1
- package/build/modern/query.d.cts +1 -1
- package/build/modern/query.d.ts +1 -1
- package/build/modern/queryCache.d.cts +1 -1
- package/build/modern/queryCache.d.ts +1 -1
- package/build/modern/queryClient.d.cts +1 -1
- package/build/modern/queryClient.d.ts +1 -1
- package/build/modern/queryObserver.d.cts +1 -1
- package/build/modern/queryObserver.d.ts +1 -1
- package/build/modern/retryer.d.cts +1 -1
- package/build/modern/retryer.d.ts +1 -1
- package/build/modern/streamedQuery.cjs +6 -4
- package/build/modern/streamedQuery.cjs.map +1 -1
- package/build/modern/streamedQuery.d.cts +8 -3
- package/build/modern/streamedQuery.d.ts +8 -3
- package/build/modern/streamedQuery.js +6 -4
- package/build/modern/streamedQuery.js.map +1 -1
- package/build/modern/thenable.cjs +16 -2
- package/build/modern/thenable.cjs.map +1 -1
- package/build/modern/thenable.d.cts +12 -1
- package/build/modern/thenable.d.ts +12 -1
- package/build/modern/thenable.js +14 -1
- package/build/modern/thenable.js.map +1 -1
- package/build/modern/types.d.cts +1 -1
- package/build/modern/types.d.ts +1 -1
- package/build/modern/utils.d.cts +1 -1
- package/build/modern/utils.d.ts +1 -1
- package/package.json +1 -1
- package/src/hydration.ts +73 -46
- package/src/streamedQuery.ts +11 -4
- package/src/thenable.ts +29 -0
package/package.json
CHANGED
package/src/hydration.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { tryResolveSync } from './thenable'
|
|
1
2
|
import type {
|
|
2
3
|
DefaultError,
|
|
3
4
|
MutationKey,
|
|
@@ -46,6 +47,10 @@ interface DehydratedQuery {
|
|
|
46
47
|
state: QueryState
|
|
47
48
|
promise?: Promise<unknown>
|
|
48
49
|
meta?: QueryMeta
|
|
50
|
+
// This is only optional because older versions of Query might have dehydrated
|
|
51
|
+
// without it which we need to handle for backwards compatibility.
|
|
52
|
+
// This should be changed to required in the future.
|
|
53
|
+
dehydratedAt?: number
|
|
49
54
|
}
|
|
50
55
|
|
|
51
56
|
export interface DehydratedState {
|
|
@@ -74,6 +79,7 @@ function dehydrateQuery(
|
|
|
74
79
|
shouldRedactErrors: (error: unknown) => boolean,
|
|
75
80
|
): DehydratedQuery {
|
|
76
81
|
return {
|
|
82
|
+
dehydratedAt: Date.now(),
|
|
77
83
|
state: {
|
|
78
84
|
...query.state,
|
|
79
85
|
...(query.state.data !== undefined && {
|
|
@@ -189,52 +195,73 @@ export function hydrate(
|
|
|
189
195
|
)
|
|
190
196
|
})
|
|
191
197
|
|
|
192
|
-
queries.forEach(
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
const
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
198
|
+
queries.forEach(
|
|
199
|
+
({ queryKey, state, queryHash, meta, promise, dehydratedAt }) => {
|
|
200
|
+
const syncData = promise ? tryResolveSync(promise) : undefined
|
|
201
|
+
const rawData = state.data === undefined ? syncData?.data : state.data
|
|
202
|
+
const data = rawData === undefined ? rawData : deserializeData(rawData)
|
|
203
|
+
|
|
204
|
+
let query = queryCache.get(queryHash)
|
|
205
|
+
const existingQueryIsPending = query?.state.status === 'pending'
|
|
206
|
+
|
|
207
|
+
// Do not hydrate if an existing query exists with newer data
|
|
208
|
+
if (query) {
|
|
209
|
+
const hasNewerSyncData =
|
|
210
|
+
syncData &&
|
|
211
|
+
// We only need this undefined check to handle older dehydration
|
|
212
|
+
// payloads that might not have dehydratedAt
|
|
213
|
+
dehydratedAt !== undefined &&
|
|
214
|
+
dehydratedAt > query.state.dataUpdatedAt
|
|
215
|
+
if (
|
|
216
|
+
state.dataUpdatedAt > query.state.dataUpdatedAt ||
|
|
217
|
+
hasNewerSyncData
|
|
218
|
+
) {
|
|
219
|
+
// omit fetchStatus from dehydrated state
|
|
220
|
+
// so that query stays in its current fetchStatus
|
|
221
|
+
const { fetchStatus: _ignored, ...serializedState } = state
|
|
222
|
+
query.setState({
|
|
223
|
+
...serializedState,
|
|
224
|
+
data,
|
|
225
|
+
})
|
|
226
|
+
}
|
|
227
|
+
} else {
|
|
228
|
+
// Restore query
|
|
229
|
+
query = queryCache.build(
|
|
230
|
+
client,
|
|
231
|
+
{
|
|
232
|
+
...client.getDefaultOptions().hydrate?.queries,
|
|
233
|
+
...options?.defaultOptions?.queries,
|
|
234
|
+
queryKey,
|
|
235
|
+
queryHash,
|
|
236
|
+
meta,
|
|
237
|
+
},
|
|
238
|
+
// Reset fetch status to idle to avoid
|
|
239
|
+
// query being stuck in fetching state upon hydration
|
|
240
|
+
{
|
|
241
|
+
...state,
|
|
242
|
+
data,
|
|
243
|
+
fetchStatus: 'idle',
|
|
244
|
+
status: data !== undefined ? 'success' : state.status,
|
|
245
|
+
},
|
|
246
|
+
)
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
if (
|
|
250
|
+
promise &&
|
|
251
|
+
!existingQueryIsPending &&
|
|
252
|
+
// Only hydrate if dehydration is newer than any existing data,
|
|
253
|
+
// this is always true for new queries
|
|
254
|
+
(dehydratedAt === undefined || dehydratedAt > query.state.dataUpdatedAt)
|
|
255
|
+
) {
|
|
256
|
+
// This doesn't actually fetch - it just creates a retryer
|
|
257
|
+
// which will re-use the passed `initialPromise`
|
|
258
|
+
// Note that we need to call these even when data was synchronously
|
|
259
|
+
// available, as we still need to set up the retryer
|
|
260
|
+
void query.fetch(undefined, {
|
|
261
|
+
// RSC transformed promises are not thenable
|
|
262
|
+
initialPromise: Promise.resolve(promise).then(deserializeData),
|
|
207
263
|
})
|
|
208
264
|
}
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
query = queryCache.build(
|
|
212
|
-
client,
|
|
213
|
-
{
|
|
214
|
-
...client.getDefaultOptions().hydrate?.queries,
|
|
215
|
-
...options?.defaultOptions?.queries,
|
|
216
|
-
queryKey,
|
|
217
|
-
queryHash,
|
|
218
|
-
meta,
|
|
219
|
-
},
|
|
220
|
-
// Reset fetch status to idle to avoid
|
|
221
|
-
// query being stuck in fetching state upon hydration
|
|
222
|
-
{
|
|
223
|
-
...state,
|
|
224
|
-
data,
|
|
225
|
-
fetchStatus: 'idle',
|
|
226
|
-
},
|
|
227
|
-
)
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
if (promise) {
|
|
231
|
-
// Note: `Promise.resolve` required cause
|
|
232
|
-
// RSC transformed promises are not thenable
|
|
233
|
-
const initialPromise = Promise.resolve(promise).then(deserializeData)
|
|
234
|
-
|
|
235
|
-
// this doesn't actually fetch - it just creates a retryer
|
|
236
|
-
// which will re-use the passed `initialPromise`
|
|
237
|
-
void query.fetch(undefined, { initialPromise })
|
|
238
|
-
}
|
|
239
|
-
})
|
|
265
|
+
},
|
|
266
|
+
)
|
|
240
267
|
}
|
package/src/streamedQuery.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { addToEnd } from './utils'
|
|
1
2
|
import type { QueryFunction, QueryFunctionContext, QueryKey } from './types'
|
|
2
3
|
|
|
3
4
|
/**
|
|
@@ -9,7 +10,11 @@ import type { QueryFunction, QueryFunctionContext, QueryKey } from './types'
|
|
|
9
10
|
* @param refetchMode - Defines how re-fetches are handled.
|
|
10
11
|
* Defaults to `'reset'`, erases all data and puts the query back into `pending` state.
|
|
11
12
|
* Set to `'append'` to append new data to the existing data.
|
|
12
|
-
* Set to `'replace'` to write
|
|
13
|
+
* Set to `'replace'` to write all data to the cache once the stream ends.
|
|
14
|
+
* @param maxChunks - The maximum number of chunks to keep in the cache.
|
|
15
|
+
* Defaults to `undefined`, meaning all chunks will be kept.
|
|
16
|
+
* If `undefined` or `0`, the number of chunks is unlimited.
|
|
17
|
+
* If the number of chunks exceeds this number, the oldest chunk will be removed.
|
|
13
18
|
*/
|
|
14
19
|
export function streamedQuery<
|
|
15
20
|
TQueryFnData = unknown,
|
|
@@ -17,11 +22,13 @@ export function streamedQuery<
|
|
|
17
22
|
>({
|
|
18
23
|
queryFn,
|
|
19
24
|
refetchMode = 'reset',
|
|
25
|
+
maxChunks,
|
|
20
26
|
}: {
|
|
21
27
|
queryFn: (
|
|
22
28
|
context: QueryFunctionContext<TQueryKey>,
|
|
23
29
|
) => AsyncIterable<TQueryFnData> | Promise<AsyncIterable<TQueryFnData>>
|
|
24
30
|
refetchMode?: 'append' | 'reset' | 'replace'
|
|
31
|
+
maxChunks?: number
|
|
25
32
|
}): QueryFunction<Array<TQueryFnData>, TQueryKey> {
|
|
26
33
|
return async (context) => {
|
|
27
34
|
const query = context.client
|
|
@@ -38,7 +45,7 @@ export function streamedQuery<
|
|
|
38
45
|
})
|
|
39
46
|
}
|
|
40
47
|
|
|
41
|
-
|
|
48
|
+
let result: Array<TQueryFnData> = []
|
|
42
49
|
const stream = await queryFn(context)
|
|
43
50
|
|
|
44
51
|
for await (const chunk of stream) {
|
|
@@ -51,11 +58,11 @@ export function streamedQuery<
|
|
|
51
58
|
context.client.setQueryData<Array<TQueryFnData>>(
|
|
52
59
|
context.queryKey,
|
|
53
60
|
(prev = []) => {
|
|
54
|
-
return prev
|
|
61
|
+
return addToEnd(prev, chunk, maxChunks)
|
|
55
62
|
},
|
|
56
63
|
)
|
|
57
64
|
}
|
|
58
|
-
result
|
|
65
|
+
result = addToEnd(result, chunk, maxChunks)
|
|
59
66
|
}
|
|
60
67
|
|
|
61
68
|
// finalize result: replace-refetching needs to write to the cache
|
package/src/thenable.ts
CHANGED
|
@@ -7,6 +7,8 @@
|
|
|
7
7
|
* @see https://github.com/facebook/react/blob/4f604941569d2e8947ce1460a0b2997e835f37b9/packages/react-debug-tools/src/ReactDebugHooks.js#L224-L227
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
|
+
import { noop } from './utils'
|
|
11
|
+
|
|
10
12
|
interface Fulfilled<T> {
|
|
11
13
|
status: 'fulfilled'
|
|
12
14
|
value: T
|
|
@@ -80,3 +82,30 @@ export function pendingThenable<T>(): PendingThenable<T> {
|
|
|
80
82
|
|
|
81
83
|
return thenable
|
|
82
84
|
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* This function takes a Promise-like input and detects whether the data
|
|
88
|
+
* is synchronously available or not.
|
|
89
|
+
*
|
|
90
|
+
* It does not inspect .status, .value or .reason properties of the promise,
|
|
91
|
+
* as those are not always available, and the .status of React's promises
|
|
92
|
+
* should not be considered part of the public API.
|
|
93
|
+
*/
|
|
94
|
+
export function tryResolveSync(promise: Promise<unknown> | Thenable<unknown>) {
|
|
95
|
+
let data: unknown
|
|
96
|
+
|
|
97
|
+
promise
|
|
98
|
+
.then((result) => {
|
|
99
|
+
data = result
|
|
100
|
+
return result
|
|
101
|
+
})
|
|
102
|
+
// .catch can be unavailable on certain kinds of thenable's
|
|
103
|
+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
|
104
|
+
?.catch(noop)
|
|
105
|
+
|
|
106
|
+
if (data !== undefined) {
|
|
107
|
+
return { data }
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
return undefined
|
|
111
|
+
}
|