snapshot of https://github.com/TanStack/query.git (main, 2026-09-16; blobs > 131072B omitted)
Some checks failed
autofix.ci / autofix (push) Failing after 4s
Release / Release (push) Has been skipped
GitHub Actions Security Analysis / Run zizmor (push) Failing after 2s

This commit is contained in:
upstream-mirror
2026-09-16 01:13:08 +05:00
commit 3a013ccdfe
3570 changed files with 490194 additions and 0 deletions

View File

@@ -0,0 +1,307 @@
# @tanstack/react-query-next-experimental
## 5.102.8
### Patch Changes
- Updated dependencies []:
- @tanstack/react-query@5.102.8
## 5.102.7
### Patch Changes
- Updated dependencies []:
- @tanstack/react-query@5.102.7
## 5.102.6
### Patch Changes
- Updated dependencies [[`ac2b612`](https://github.com/TanStack/query/commit/ac2b61230ea35b90b177ba35dc030598bac9c9a6)]:
- @tanstack/react-query@5.102.6
## 5.102.5
### Patch Changes
- Updated dependencies []:
- @tanstack/react-query@5.102.5
## 5.102.4
### Patch Changes
- Updated dependencies []:
- @tanstack/react-query@5.102.4
## 5.102.3
### Patch Changes
- Updated dependencies []:
- @tanstack/react-query@5.102.3
## 5.102.2
### Patch Changes
- Updated dependencies []:
- @tanstack/react-query@5.102.2
## 5.102.1
### Patch Changes
- Updated dependencies []:
- @tanstack/react-query@5.102.1
## 5.102.0
### Patch Changes
- Updated dependencies [[`37127db`](https://github.com/TanStack/query/commit/37127dbe479a4892dbbe28ac8ceabf8832b5f1a3), [`6e3d521`](https://github.com/TanStack/query/commit/6e3d521fe54f78624e53c1c6f9cadd678504bee8), [`294d4e6`](https://github.com/TanStack/query/commit/294d4e62c4f7d674574a4903eef2a1bc3dd1413b), [`cb6c9d3`](https://github.com/TanStack/query/commit/cb6c9d3725db0fed94fb5133820e41b7c326d2ef), [`2215bb0`](https://github.com/TanStack/query/commit/2215bb031139cdc8a84751b37a485c38ca9d2b6e), [`1ef4208`](https://github.com/TanStack/query/commit/1ef42087c9a266c2137d2ef645cbcc662f60ac93), [`fb6c3fa`](https://github.com/TanStack/query/commit/fb6c3fabda4cb6b291cccc6651ed88a7db901915), [`8834267`](https://github.com/TanStack/query/commit/88342670eca6e4949416aab832b1f81cc7b881f8), [`b866a95`](https://github.com/TanStack/query/commit/b866a95adde7e8465462526df5870ebc12340b36), [`e546d03`](https://github.com/TanStack/query/commit/e546d03bef116c66a05dbf42ccfd70b6d8600a8f), [`e674826`](https://github.com/TanStack/query/commit/e6748265c86294704f6c872e6f435d9ec5a92b28)]:
- @tanstack/react-query@5.102.0
## 5.101.4
### Patch Changes
- Updated dependencies []:
- @tanstack/react-query@5.101.4
## 5.101.3
### Patch Changes
- Updated dependencies []:
- @tanstack/react-query@5.101.3
## 5.101.2
### Patch Changes
- Updated dependencies []:
- @tanstack/react-query@5.101.2
## 5.101.1
### Patch Changes
- Updated dependencies []:
- @tanstack/react-query@5.101.1
## 5.101.0
### Patch Changes
- [#10857](https://github.com/TanStack/query/pull/10857) [`7cf5923`](https://github.com/TanStack/query/commit/7cf5923308fb91f3eff0fe952d8c64676e2bdad7) - fix(react-query-next-experimental): replace deprecated 'isServer' with 'environmentManager.isServer()'
- Updated dependencies []:
- @tanstack/react-query@5.101.0
## 5.100.14
### Patch Changes
- Updated dependencies [[`ed20b6d`](https://github.com/TanStack/query/commit/ed20b6d7541c908033acfcad92b0cd112930d1c3)]:
- @tanstack/react-query@5.100.14
## 5.100.13
### Patch Changes
- Updated dependencies []:
- @tanstack/react-query@5.100.13
## 5.100.12
### Patch Changes
- Updated dependencies []:
- @tanstack/react-query@5.100.12
## 5.100.11
### Patch Changes
- Updated dependencies []:
- @tanstack/react-query@5.100.11
## 5.100.10
### Patch Changes
- Updated dependencies []:
- @tanstack/react-query@5.100.10
## 5.100.9
### Patch Changes
- Updated dependencies []:
- @tanstack/react-query@5.100.9
## 5.100.8
### Patch Changes
- Updated dependencies []:
- @tanstack/react-query@5.100.8
## 5.100.7
### Patch Changes
- Updated dependencies []:
- @tanstack/react-query@5.100.7
## 5.100.6
### Patch Changes
- Updated dependencies []:
- @tanstack/react-query@5.100.6
## 5.100.5
### Patch Changes
- Updated dependencies []:
- @tanstack/react-query@5.100.5
## 5.100.4
### Patch Changes
- Updated dependencies []:
- @tanstack/react-query@5.100.4
## 5.100.3
### Patch Changes
- Updated dependencies [[`f85d825`](https://github.com/TanStack/query/commit/f85d825e02efbbff02e2081528ed28f5e5382f7a)]:
- @tanstack/react-query@5.100.3
## 5.100.2
### Patch Changes
- Updated dependencies []:
- @tanstack/react-query@5.100.2
## 5.100.1
### Patch Changes
- Updated dependencies []:
- @tanstack/react-query@5.100.1
## 5.100.0
### Patch Changes
- Updated dependencies []:
- @tanstack/react-query@5.100.0
## 5.99.2
### Patch Changes
- Updated dependencies []:
- @tanstack/react-query@5.99.2
## 5.99.1
### Patch Changes
- Updated dependencies []:
- @tanstack/react-query@5.99.1
## 5.99.0
### Patch Changes
- Updated dependencies []:
- @tanstack/react-query@5.99.0
## 5.98.0
### Patch Changes
- Updated dependencies []:
- @tanstack/react-query@5.98.0
## 5.97.0
### Patch Changes
- Updated dependencies []:
- @tanstack/react-query@5.97.0
## 5.96.2
### Patch Changes
- Updated dependencies []:
- @tanstack/react-query@5.96.2
## 5.96.1
### Patch Changes
- Updated dependencies []:
- @tanstack/react-query@5.96.1
## 5.96.0
### Patch Changes
- Updated dependencies []:
- @tanstack/react-query@5.96.0
## 5.95.2
### Patch Changes
- Updated dependencies []:
- @tanstack/react-query@5.95.2
## 5.95.1
### Patch Changes
- Updated dependencies []:
- @tanstack/react-query@5.95.1
## 5.95.0
### Patch Changes
- Updated dependencies []:
- @tanstack/react-query@5.95.0
## 5.94.5
### Patch Changes
- fix(\*): resolve issue about excluded build directory ([#10312](https://github.com/TanStack/query/pull/10312))
- Updated dependencies [[`4b6536d`](https://github.com/TanStack/query/commit/4b6536dfce99036f4e37f52943c6fed3ad0e0a18)]:
- @tanstack/react-query@5.94.5
## 5.94.4
### Patch Changes
- chore: fixed version ([#10064](https://github.com/TanStack/query/pull/10064))
- Updated dependencies [[`4c75210`](https://github.com/TanStack/query/commit/4c75210ce8235fe3d39b67e1029eff11278927cc)]:
- @tanstack/react-query@5.94.4
## 5.91.0
### Minor Changes
- feat(react-query-next-experimental): support Next.js 16 ([#9868](https://github.com/TanStack/query/pull/9868))

View File

@@ -0,0 +1,22 @@
// @ts-check
import pluginReact from '@eslint-react/eslint-plugin'
import reactHooks from 'eslint-plugin-react-hooks'
import rootConfig from './root.eslint.config.js'
export default [
...rootConfig,
// @ts-expect-error wtf
...reactHooks.configs['recommended-latest'],
{
files: ['**/*.{ts,tsx}'],
...pluginReact.configs.recommended,
rules: {
'@eslint-react/no-context-provider': 'off', // We need to be React 18 compatible
'react-hooks/exhaustive-deps': 'error',
'react-hooks/rules-of-hooks': 'error',
'react-hooks/unsupported-syntax': 'error',
'react-hooks/incompatible-library': 'error',
},
},
]

View File

@@ -0,0 +1,68 @@
{
"name": "@tanstack/react-query-next-experimental",
"version": "5.102.8",
"description": "Hydration utils for React Query in the NextJs app directory",
"author": "tannerlinsley",
"license": "MIT",
"repository": {
"type": "git",
"url": "git+https://github.com/TanStack/query.git",
"directory": "packages/react-query-next-experimental"
},
"homepage": "https://tanstack.com/query",
"funding": {
"type": "github",
"url": "https://github.com/sponsors/tannerlinsley"
},
"scripts": {
"clean": "premove ./build ./coverage ./dist-ts ./.cache/test-types",
"compile": "tsc --project tsconfig.json",
"test:eslint": "eslint --concurrency=auto ./src",
"test:types": "npm-run-all --serial test:types:*",
"test:types:ts56": "node ../../node_modules/typescript56/lib/tsc.js --project tsconfig.legacy.json --outDir .cache/test-types/ts56 --tsBuildInfoFile .cache/test-types/ts56.tsbuildinfo",
"test:types:ts57": "node ../../node_modules/typescript57/lib/tsc.js --project tsconfig.legacy.json --outDir .cache/test-types/ts57 --tsBuildInfoFile .cache/test-types/ts57.tsbuildinfo",
"test:types:ts58": "node ../../node_modules/typescript58/lib/tsc.js --project tsconfig.legacy.json --outDir .cache/test-types/ts58 --tsBuildInfoFile .cache/test-types/ts58.tsbuildinfo",
"test:types:ts59": "node ../../node_modules/typescript59/lib/tsc.js --project tsconfig.legacy.json --outDir .cache/test-types/ts59 --tsBuildInfoFile .cache/test-types/ts59.tsbuildinfo",
"test:types:tscurrent": "tsc --project tsconfig.json --outDir .cache/test-types/tscurrent --tsBuildInfoFile .cache/test-types/tscurrent.tsbuildinfo",
"test:types:ts70": "node ../../node_modules/typescript70/lib/tsc.js --project tsconfig.json --outDir .cache/test-types/ts70 --tsBuildInfoFile .cache/test-types/ts70.tsbuildinfo",
"test:build": "publint --strict && attw --pack",
"build": "tsdown --tsconfig tsconfig.prod.json"
},
"type": "module",
"types": "build/legacy/index.d.ts",
"main": "build/legacy/index.cjs",
"module": "build/legacy/index.js",
"exports": {
".": {
"@tanstack/custom-condition": "./src/index.ts",
"import": {
"types": "./build/modern/index.d.ts",
"default": "./build/modern/index.js"
},
"require": {
"types": "./build/modern/index.d.cts",
"default": "./build/modern/index.cjs"
}
},
"./package.json": "./package.json"
},
"sideEffects": false,
"files": [
"build",
"src",
"!src/__tests__"
],
"devDependencies": {
"@tanstack/react-query": "workspace:*",
"@types/react": "^19.2.7",
"@vitejs/plugin-react": "^4.3.4",
"next": "^16.0.1",
"npm-run-all2": "^5.0.0",
"react": "^19.2.1"
},
"peerDependencies": {
"@tanstack/react-query": "workspace:^",
"next": "^13 || ^14 || ^15 || ^16",
"react": "^18 || ^19"
}
}

View File

@@ -0,0 +1 @@
../../eslint.config.js

View File

@@ -0,0 +1 @@
../../scripts/getTsdownConfig.js

View File

@@ -0,0 +1,192 @@
'use client'
import { environmentManager } from '@tanstack/react-query'
import { useServerInsertedHTML } from 'next/navigation'
import * as React from 'react'
import { htmlEscapeJsonString } from './htmlescape'
const serializedSymbol = Symbol('serialized')
interface DataTransformer {
serialize: (object: any) => any
deserialize: (object: any) => any
}
type Serialized<TData> = unknown & {
[serializedSymbol]: TData
}
interface TypedDataTransformer<TData> {
serialize: (obj: TData) => Serialized<TData>
deserialize: (obj: Serialized<TData>) => TData
}
interface HydrationStreamContext<TShape> {
id: string
stream: {
/**
* **Server method**
* Push a new entry to the stream
* Will be ignored on the client
*/
push: (...shape: Array<TShape>) => void
}
}
export interface HydrationStreamProviderProps<TShape> {
children: React.ReactNode
/**
* Optional transformer to serialize/deserialize the data
* Example devalue, superjson et al
*/
transformer?: DataTransformer
/**
* **Client method**
* Called in the browser when new entries are received
*/
onEntries: (entries: Array<TShape>) => void
/**
* **Server method**
* onFlush is called on the server when the cache is flushed
*/
onFlush?: () => Array<TShape>
/**
* A nonce that'll allow the inline script to be executed when Content Security Policy is enforced
*/
nonce?: string
}
export function createHydrationStreamProvider<TShape>() {
const context = React.createContext<HydrationStreamContext<TShape>>(
null as any,
)
/**
* 1. (Happens on server): `useServerInsertedHTML()` is called **on the server** whenever a `Suspense`-boundary completes
* - This means that we might have some new entries in the cache that needs to be flushed
* - We pass these to the client by inserting a `<script>`-tag where we do `window[id].push(serializedVersionOfCache)`
* 2. (Happens in browser) In `useEffect()`:
* - We check if `window[id]` is set to an array and call `push()` on all the entries which will call `onEntries()` with the new entries
* - We replace `window[id]` with a `push()`-method that will be called whenever new entries are received
**/
function UseClientHydrationStreamProvider(props: {
children: React.ReactNode
/**
* Optional transformer to serialize/deserialize the data
* Example devalue, superjson et al
*/
transformer?: DataTransformer
/**
* **Client method**
* Called in the browser when new entries are received
*/
onEntries: (entries: Array<TShape>) => void
/**
* **Server method**
* onFlush is called on the server when the cache is flushed
*/
onFlush?: () => Array<TShape>
/**
* A nonce that'll allow the inline script to be executed when Content Security Policy is enforced
*/
nonce?: string
}) {
// unique id for the cache provider
const id = `__RQ${React.useId()}`
const idJSON = htmlEscapeJsonString(JSON.stringify(id))
const [transformer] = React.useState(
() =>
(props.transformer ?? {
// noop
serialize: (obj: any) => obj,
deserialize: (obj: any) => obj,
}) as unknown as TypedDataTransformer<TShape>,
)
// <server stuff>
const [stream] = React.useState<Array<TShape>>(() => {
if (!environmentManager.isServer()) {
return {
push() {
// no-op on the client
},
} as unknown as Array<TShape>
}
return []
})
const count = React.useRef(0)
useServerInsertedHTML(() => {
// This only happens on the server
stream.push(...(props.onFlush?.() ?? []))
if (!stream.length) {
return null
}
// console.log(`pushing ${stream.length} entries`)
const serializedCacheArgs = stream
.map((entry) => transformer.serialize(entry))
.map((entry) => JSON.stringify(entry))
.join(',')
// Flush stream
// eslint-disable-next-line react-hooks/immutability
stream.length = 0
const html: Array<string> = [
`window[${idJSON}] = window[${idJSON}] || [];`,
`window[${idJSON}].push(${htmlEscapeJsonString(serializedCacheArgs)});`,
]
return (
<script
key={count.current++}
nonce={props.nonce}
dangerouslySetInnerHTML={{
__html: html.join(''),
}}
/>
)
})
// </server stuff>
// <client stuff>
// Setup and run the onEntries handler on the client only, but do it during
// the initial render so children have access to the data immediately
// This is important to avoid the client suspending during the initial render
// if the data has not yet been hydrated.
if (!environmentManager.isServer()) {
const win = window as any
if (!win[id]?.initialized) {
// Client: consume cache:
const onEntries = (...serializedEntries: Array<Serialized<TShape>>) => {
const entries = serializedEntries.map((serialized) =>
transformer.deserialize(serialized),
)
props.onEntries(entries)
}
const winStream: Array<Serialized<TShape>> = win[id] ?? []
onEntries(...winStream)
// eslint-disable-next-line react-hooks/immutability
win[id] = {
initialized: true,
push: onEntries,
}
}
}
// </client stuff>
return (
<context.Provider value={{ stream, id }}>
{props.children}
</context.Provider>
)
}
return {
Provider: UseClientHydrationStreamProvider,
context,
}
}

View File

@@ -0,0 +1,96 @@
'use client'
import {
defaultShouldDehydrateQuery,
dehydrate,
environmentManager,
hydrate,
useQueryClient,
} from '@tanstack/react-query'
import * as React from 'react'
import { createHydrationStreamProvider } from './HydrationStreamProvider'
import type { HydrationStreamProviderProps } from './HydrationStreamProvider'
import type {
DehydrateOptions,
DehydratedState,
HydrateOptions,
QueryClient,
} from '@tanstack/react-query'
const stream = createHydrationStreamProvider<DehydratedState>()
/**
* This component is responsible for:
* - hydrating the query client on the server
* - dehydrating the query client on the server
*/
export function ReactQueryStreamedHydration(props: {
children: React.ReactNode
queryClient?: QueryClient
nonce?: string
options?: {
hydrate?: HydrateOptions
dehydrate?: DehydrateOptions
}
transformer?: HydrationStreamProviderProps<DehydratedState>['transformer']
}) {
const queryClient = useQueryClient(props.queryClient)
/**
* We need to track which queries were added/updated during the render
*/
const [trackedKeys] = React.useState(() => new Set<string>())
// <server only>
if (environmentManager.isServer()) {
// Do we need to care about unsubscribing? I don't think so to be honest
queryClient.getQueryCache().subscribe((event) => {
switch (event.type) {
case 'added':
case 'updated':
// console.log('tracking', event.query.queryHash, 'b/c of a', event.type)
trackedKeys.add(event.query.queryHash)
}
})
}
// </server only>
return (
<stream.Provider
// Happens on server:
onFlush={() => {
/**
* Dehydrated state of the client where we only include the queries that were added/updated since the last flush
*/
const shouldDehydrate =
props.options?.dehydrate?.shouldDehydrateQuery ??
defaultShouldDehydrateQuery
const dehydratedState = dehydrate(queryClient, {
...props.options?.dehydrate,
shouldDehydrateQuery(query) {
return trackedKeys.has(query.queryHash) && shouldDehydrate(query)
},
})
trackedKeys.clear()
if (!dehydratedState.queries.length) {
return []
}
return [dehydratedState]
}}
// Happens in browser:
onEntries={(entries) => {
for (const hydratedState of entries) {
hydrate(queryClient, hydratedState, props.options?.hydrate)
}
}}
// Handle BigInts etc using superjson
transformer={props.transformer}
nonce={props.nonce}
>
{props.children}
</stream.Provider>
)
}

View File

@@ -0,0 +1,24 @@
// --------------------------------------------------------------------------------
//
// copied from
// https://github.com/vercel/next.js/blob/6bc07792a4462a4bf921a72ab30dc4ab2c4e1bda/packages/next/src/server/htmlescape.ts
// License: https://github.com/vercel/next.js/blob/6bc07792a4462a4bf921a72ab30dc4ab2c4e1bda/packages/next/license.md
//
// --------------------------------------------------------------------------------
// This utility is based on https://github.com/zertosh/htmlescape
// License: https://github.com/zertosh/htmlescape/blob/0527ca7156a524d256101bb310a9f970f63078ad/LICENSE
const ESCAPE_LOOKUP: Record<string, string> = {
'&': '\\u0026',
'>': '\\u003e',
'<': '\\u003c',
'\u2028': '\\u2028',
'\u2029': '\\u2029',
}
export const ESCAPE_REGEX = /[&><\u2028\u2029]/g
export function htmlEscapeJsonString(str: string): string {
return str.replace(ESCAPE_REGEX, (match) => ESCAPE_LOOKUP[match]!)
}

View File

@@ -0,0 +1 @@
export { ReactQueryStreamedHydration } from './ReactQueryStreamedHydration'

View File

@@ -0,0 +1,10 @@
{
"extends": "../../tsconfig.json",
"compilerOptions": {
"outDir": "./dist-ts",
"rootDir": ".",
"jsx": "react-jsx"
},
"include": ["src", "*.config.ts", "*.config.js", "package.json"],
"references": [{ "path": "../react-query" }]
}

View File

@@ -0,0 +1,10 @@
{
"extends": "./tsconfig.json",
"compilerOptions": {
"jsx": "react-jsx",
"outDir": "./dist-ts/legacy"
},
"include": ["src"],
"exclude": ["src/__tests__"],
"references": [{ "path": "../react-query" }]
}

View File

@@ -0,0 +1,10 @@
{
"extends": "./tsconfig.json",
"compilerOptions": {
"incremental": false,
"composite": false,
"rootDir": "../../"
},
"include": ["src"],
"exclude": ["src/__tests__"]
}

View File

@@ -0,0 +1,7 @@
import { defineConfig } from 'tsdown'
import { legacyConfig, modernConfig } from './root.tsdown.config.js'
export default defineConfig([
modernConfig({ entry: ['src/*.ts', 'src/*.tsx'] }),
legacyConfig({ entry: ['src/*.ts', 'src/*.tsx'] }),
])

View File

@@ -0,0 +1,17 @@
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
export default defineConfig({
plugins: [react()],
// fix from https://github.com/vitest-dev/vitest/issues/6992#issuecomment-2509408660
resolve: {
conditions: ['@tanstack/custom-condition'],
},
environments: {
ssr: {
resolve: {
conditions: ['@tanstack/custom-condition'],
},
},
},
})