@tanstack/router-ssr-query-core 1.167.0 → 1.168.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.
@@ -3,7 +3,7 @@ let _tanstack_query_core = require("@tanstack/query-core");
3
3
  let _tanstack_router_core = require("@tanstack/router-core");
4
4
  let _tanstack_router_core_isServer = require("@tanstack/router-core/isServer");
5
5
  //#region src/index.ts
6
- function setupCoreRouterSsrQueryIntegration({ router, queryClient, handleRedirects = true }) {
6
+ function setupCoreRouterSsrQueryIntegration({ router, queryClient, dehydrateOptions, hydrateOptions, handleRedirects = true }) {
7
7
  const ogHydrate = router.options.hydrate;
8
8
  const ogDehydrate = router.options.dehydrate;
9
9
  if (_tanstack_router_core_isServer.isServer ?? router.isServer) {
@@ -20,7 +20,7 @@ function setupCoreRouterSsrQueryIntegration({ router, queryClient, handleRedirec
20
20
  ...await ogDehydrate?.(),
21
21
  queryStream: queryStream.stream
22
22
  };
23
- const dehydratedQueryClient = (0, _tanstack_query_core.dehydrate)(queryClient);
23
+ const dehydratedQueryClient = (0, _tanstack_query_core.dehydrate)(queryClient, dehydrateOptions);
24
24
  if (dehydratedQueryClient.queries.length > 0) {
25
25
  dehydratedQueryClient.queries.forEach((query) => {
26
26
  sentQueries.add(query.queryHash);
@@ -45,19 +45,24 @@ function setupCoreRouterSsrQueryIntegration({ router, queryClient, handleRedirec
45
45
  console.warn(`tried to stream query ${event.query.queryHash} after stream was already closed`);
46
46
  return;
47
47
  }
48
+ const dehydratedQuery = (0, _tanstack_query_core.dehydrate)(queryClient, {
49
+ ...dehydrateOptions,
50
+ shouldDehydrateQuery: (query) => {
51
+ if (query.queryHash !== event.query.queryHash) return false;
52
+ return (ogClientOptions.dehydrate?.shouldDehydrateQuery?.(query) ?? true) && (dehydrateOptions?.shouldDehydrateQuery?.(query) ?? true);
53
+ }
54
+ });
55
+ if (dehydratedQuery.queries.length === 0) return;
48
56
  sentQueries.add(event.query.queryHash);
49
- queryStream.enqueue((0, _tanstack_query_core.dehydrate)(queryClient, { shouldDehydrateQuery: (query) => {
50
- if (query.queryHash === event.query.queryHash) return ogClientOptions.dehydrate?.shouldDehydrateQuery?.(query) ?? true;
51
- return false;
52
- } }));
57
+ queryStream.enqueue(dehydratedQuery);
53
58
  });
54
59
  } else {
55
60
  router.options.hydrate = async (dehydrated) => {
56
61
  await ogHydrate?.(dehydrated);
57
- if (dehydrated.dehydratedQueryClient) (0, _tanstack_query_core.hydrate)(queryClient, dehydrated.dehydratedQueryClient);
62
+ if (dehydrated.dehydratedQueryClient) (0, _tanstack_query_core.hydrate)(queryClient, dehydrated.dehydratedQueryClient, hydrateOptions);
58
63
  const reader = dehydrated.queryStream.getReader();
59
64
  reader.read().then(async function handle({ done, value }) {
60
- (0, _tanstack_query_core.hydrate)(queryClient, value);
65
+ (0, _tanstack_query_core.hydrate)(queryClient, value, hydrateOptions);
61
66
  if (done) return;
62
67
  return handle(await reader.read());
63
68
  }).catch((err) => {
@@ -70,7 +75,7 @@ function setupCoreRouterSsrQueryIntegration({ router, queryClient, handleRedirec
70
75
  ...ogMutationCacheConfig,
71
76
  onError: (error, ...rest) => {
72
77
  if ((0, _tanstack_router_core.isRedirect)(error)) {
73
- error.options._fromLocation = router.stores.location.state;
78
+ error.options._fromLocation = router.stores.location.get();
74
79
  return router.navigate(router.resolveRedirect(error).options);
75
80
  }
76
81
  return ogMutationCacheConfig.onError?.(error, ...rest);
@@ -81,7 +86,7 @@ function setupCoreRouterSsrQueryIntegration({ router, queryClient, handleRedirec
81
86
  ...ogQueryCacheConfig,
82
87
  onError: (error, ...rest) => {
83
88
  if ((0, _tanstack_router_core.isRedirect)(error)) {
84
- error.options._fromLocation = router.stores.location.state;
89
+ error.options._fromLocation = router.stores.location.get();
85
90
  return router.navigate(router.resolveRedirect(error).options);
86
91
  }
87
92
  return ogQueryCacheConfig.onError?.(error, ...rest);
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","names":[],"sources":["../../src/index.ts"],"sourcesContent":["import {\n dehydrate as queryDehydrate,\n hydrate as queryHydrate,\n} from '@tanstack/query-core'\nimport { isRedirect } from '@tanstack/router-core'\nimport { isServer } from '@tanstack/router-core/isServer'\nimport type { AnyRouter } from '@tanstack/router-core'\nimport type {\n QueryClient,\n DehydratedState as QueryDehydratedState,\n} from '@tanstack/query-core'\n\nexport type RouterSsrQueryOptions<TRouter extends AnyRouter> = {\n router: TRouter\n queryClient: QueryClient\n\n /**\n * If `true`, the QueryClient will handle errors thrown by `redirect()` inside of mutations and queries.\n *\n * @default true\n * @link [Guide](https://tanstack.com/router/latest/docs/framework/react/api/router/redirectFunction)\n */\n handleRedirects?: boolean\n}\n\ntype DehydratedRouterQueryState = {\n dehydratedQueryClient?: QueryDehydratedState\n queryStream: ReadableStream<QueryDehydratedState>\n}\n\nexport function setupCoreRouterSsrQueryIntegration<TRouter extends AnyRouter>({\n router,\n queryClient,\n handleRedirects = true,\n}: RouterSsrQueryOptions<TRouter>) {\n const ogHydrate = router.options.hydrate\n const ogDehydrate = router.options.dehydrate\n\n if (isServer ?? router.isServer) {\n const sentQueries = new Set<string>()\n const queryStream = createPushableStream()\n let unsubscribe: (() => void) | undefined = undefined\n router.options.dehydrate =\n async (): Promise<DehydratedRouterQueryState> => {\n router.serverSsr!.onRenderFinished(() => {\n queryStream.close()\n unsubscribe?.()\n unsubscribe = undefined\n })\n const ogDehydrated = await ogDehydrate?.()\n\n const dehydratedRouter = {\n ...ogDehydrated,\n // prepare the stream for queries coming up during rendering\n queryStream: queryStream.stream,\n }\n\n const dehydratedQueryClient = queryDehydrate(queryClient)\n if (dehydratedQueryClient.queries.length > 0) {\n dehydratedQueryClient.queries.forEach((query) => {\n sentQueries.add(query.queryHash)\n })\n dehydratedRouter.dehydratedQueryClient = dehydratedQueryClient\n }\n\n return dehydratedRouter\n }\n\n const ogClientOptions = queryClient.getDefaultOptions()\n queryClient.setDefaultOptions({\n ...ogClientOptions,\n dehydrate: {\n shouldDehydrateQuery: () => true,\n ...ogClientOptions.dehydrate,\n },\n })\n\n unsubscribe = queryClient.getQueryCache().subscribe((event) => {\n // before rendering starts, we do not stream individual queries\n // instead we dehydrate the entire query client in router's dehydrate()\n // if attachRouterServerSsrUtils() has not been called yet, `router.serverSsr` will be undefined and we also do not stream\n if (!router.serverSsr?.isDehydrated()) {\n return\n }\n if (sentQueries.has(event.query.queryHash)) {\n return\n }\n // promise not yet set on the query, so we cannot stream it yet\n if (!event.query.promise) {\n return\n }\n if (queryStream.isClosed()) {\n console.warn(\n `tried to stream query ${event.query.queryHash} after stream was already closed`,\n )\n return\n }\n sentQueries.add(event.query.queryHash)\n queryStream.enqueue(\n queryDehydrate(queryClient, {\n shouldDehydrateQuery: (query) => {\n if (query.queryHash === event.query.queryHash) {\n return (\n ogClientOptions.dehydrate?.shouldDehydrateQuery?.(query) ?? true\n )\n }\n return false\n },\n }),\n )\n })\n // on the client\n } else {\n router.options.hydrate = async (dehydrated: DehydratedRouterQueryState) => {\n await ogHydrate?.(dehydrated)\n // hydrate the query client with the dehydrated data (if it was dehydrated on the server)\n if (dehydrated.dehydratedQueryClient) {\n queryHydrate(queryClient, dehydrated.dehydratedQueryClient)\n }\n\n // read the query stream and hydrate the queries as they come in\n const reader = dehydrated.queryStream.getReader()\n reader\n .read()\n .then(async function handle({ done, value }) {\n queryHydrate(queryClient, value)\n if (done) {\n return\n }\n const result = await reader.read()\n return handle(result)\n })\n .catch((err) => {\n console.error('Error reading query stream:', err)\n })\n }\n if (handleRedirects) {\n const ogMutationCacheConfig = queryClient.getMutationCache().config\n queryClient.getMutationCache().config = {\n ...ogMutationCacheConfig,\n onError: (error, ...rest) => {\n if (isRedirect(error)) {\n error.options._fromLocation = router.stores.location.state\n return router.navigate(router.resolveRedirect(error).options)\n }\n\n return ogMutationCacheConfig.onError?.(error, ...rest)\n },\n }\n\n const ogQueryCacheConfig = queryClient.getQueryCache().config\n queryClient.getQueryCache().config = {\n ...ogQueryCacheConfig,\n onError: (error, ...rest) => {\n if (isRedirect(error)) {\n error.options._fromLocation = router.stores.location.state\n return router.navigate(router.resolveRedirect(error).options)\n }\n\n return ogQueryCacheConfig.onError?.(error, ...rest)\n },\n }\n }\n }\n}\n\ntype PushableStream = {\n stream: ReadableStream\n enqueue: (chunk: unknown) => void\n close: () => void\n isClosed: () => boolean\n error: (err: unknown) => void\n}\n\nfunction createPushableStream(): PushableStream {\n let controllerRef: ReadableStreamDefaultController\n const stream = new ReadableStream({\n start(controller) {\n controllerRef = controller\n },\n })\n let _isClosed = false\n\n return {\n stream,\n enqueue: (chunk) => controllerRef.enqueue(chunk),\n close: () => {\n controllerRef.close()\n _isClosed = true\n },\n isClosed: () => _isClosed,\n error: (err: unknown) => controllerRef.error(err),\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.cjs","names":[],"sources":["../../src/index.ts"],"sourcesContent":["import {\n dehydrate as queryDehydrate,\n hydrate as queryHydrate,\n} from '@tanstack/query-core'\nimport { isRedirect } from '@tanstack/router-core'\nimport { isServer } from '@tanstack/router-core/isServer'\nimport type { AnyRouter } from '@tanstack/router-core'\nimport type {\n DehydrateOptions,\n HydrateOptions,\n QueryClient,\n DehydratedState as QueryDehydratedState,\n} from '@tanstack/query-core'\n\nexport type RouterSsrQueryOptions<TRouter extends AnyRouter> = {\n router: TRouter\n queryClient: QueryClient\n dehydrateOptions?: DehydrateOptions\n hydrateOptions?: HydrateOptions\n\n /**\n * If `true`, the QueryClient will handle errors thrown by `redirect()` inside of mutations and queries.\n *\n * @default true\n * @link [Guide](https://tanstack.com/router/latest/docs/framework/react/api/router/redirectFunction)\n */\n handleRedirects?: boolean\n}\n\ntype DehydratedRouterQueryState = {\n dehydratedQueryClient?: QueryDehydratedState\n queryStream: ReadableStream<QueryDehydratedState>\n}\n\nexport function setupCoreRouterSsrQueryIntegration<TRouter extends AnyRouter>({\n router,\n queryClient,\n dehydrateOptions,\n hydrateOptions,\n handleRedirects = true,\n}: RouterSsrQueryOptions<TRouter>) {\n const ogHydrate = router.options.hydrate\n const ogDehydrate = router.options.dehydrate\n\n if (isServer ?? router.isServer) {\n const sentQueries = new Set<string>()\n const queryStream = createPushableStream()\n let unsubscribe: (() => void) | undefined = undefined\n router.options.dehydrate =\n async (): Promise<DehydratedRouterQueryState> => {\n router.serverSsr!.onRenderFinished(() => {\n queryStream.close()\n unsubscribe?.()\n unsubscribe = undefined\n })\n const ogDehydrated = await ogDehydrate?.()\n\n const dehydratedRouter = {\n ...ogDehydrated,\n // prepare the stream for queries coming up during rendering\n queryStream: queryStream.stream,\n }\n\n const dehydratedQueryClient = queryDehydrate(\n queryClient,\n dehydrateOptions,\n )\n if (dehydratedQueryClient.queries.length > 0) {\n dehydratedQueryClient.queries.forEach((query) => {\n sentQueries.add(query.queryHash)\n })\n dehydratedRouter.dehydratedQueryClient = dehydratedQueryClient\n }\n\n return dehydratedRouter\n }\n\n const ogClientOptions = queryClient.getDefaultOptions()\n queryClient.setDefaultOptions({\n ...ogClientOptions,\n dehydrate: {\n shouldDehydrateQuery: () => true,\n ...ogClientOptions.dehydrate,\n },\n })\n\n unsubscribe = queryClient.getQueryCache().subscribe((event) => {\n // before rendering starts, we do not stream individual queries\n // instead we dehydrate the entire query client in router's dehydrate()\n // if attachRouterServerSsrUtils() has not been called yet, `router.serverSsr` will be undefined and we also do not stream\n if (!router.serverSsr?.isDehydrated()) {\n return\n }\n if (sentQueries.has(event.query.queryHash)) {\n return\n }\n // promise not yet set on the query, so we cannot stream it yet\n if (!event.query.promise) {\n return\n }\n if (queryStream.isClosed()) {\n console.warn(\n `tried to stream query ${event.query.queryHash} after stream was already closed`,\n )\n return\n }\n const dehydratedQuery = queryDehydrate(queryClient, {\n ...dehydrateOptions,\n shouldDehydrateQuery: (query) => {\n if (query.queryHash !== event.query.queryHash) {\n return false\n }\n\n return (\n (ogClientOptions.dehydrate?.shouldDehydrateQuery?.(query) ??\n true) &&\n (dehydrateOptions?.shouldDehydrateQuery?.(query) ?? true)\n )\n },\n })\n\n if (dehydratedQuery.queries.length === 0) {\n return\n }\n\n sentQueries.add(event.query.queryHash)\n queryStream.enqueue(dehydratedQuery)\n })\n // on the client\n } else {\n router.options.hydrate = async (dehydrated: DehydratedRouterQueryState) => {\n await ogHydrate?.(dehydrated)\n // hydrate the query client with the dehydrated data (if it was dehydrated on the server)\n if (dehydrated.dehydratedQueryClient) {\n queryHydrate(\n queryClient,\n dehydrated.dehydratedQueryClient,\n hydrateOptions,\n )\n }\n\n // read the query stream and hydrate the queries as they come in\n const reader = dehydrated.queryStream.getReader()\n reader\n .read()\n .then(async function handle({ done, value }) {\n queryHydrate(queryClient, value, hydrateOptions)\n if (done) {\n return\n }\n const result = await reader.read()\n return handle(result)\n })\n .catch((err) => {\n console.error('Error reading query stream:', err)\n })\n }\n if (handleRedirects) {\n const ogMutationCacheConfig = queryClient.getMutationCache().config\n queryClient.getMutationCache().config = {\n ...ogMutationCacheConfig,\n onError: (error, ...rest) => {\n if (isRedirect(error)) {\n error.options._fromLocation = router.stores.location.get()\n return router.navigate(router.resolveRedirect(error).options)\n }\n\n return ogMutationCacheConfig.onError?.(error, ...rest)\n },\n }\n\n const ogQueryCacheConfig = queryClient.getQueryCache().config\n queryClient.getQueryCache().config = {\n ...ogQueryCacheConfig,\n onError: (error, ...rest) => {\n if (isRedirect(error)) {\n error.options._fromLocation = router.stores.location.get()\n return router.navigate(router.resolveRedirect(error).options)\n }\n\n return ogQueryCacheConfig.onError?.(error, ...rest)\n },\n }\n }\n }\n}\n\ntype PushableStream = {\n stream: ReadableStream\n enqueue: (chunk: unknown) => void\n close: () => void\n isClosed: () => boolean\n error: (err: unknown) => void\n}\n\nfunction createPushableStream(): PushableStream {\n let controllerRef: ReadableStreamDefaultController\n const stream = new ReadableStream({\n start(controller) {\n controllerRef = controller\n },\n })\n let _isClosed = false\n\n return {\n stream,\n enqueue: (chunk) => controllerRef.enqueue(chunk),\n close: () => {\n controllerRef.close()\n _isClosed = true\n },\n isClosed: () => _isClosed,\n error: (err: unknown) => controllerRef.error(err),\n }\n}\n"],"mappings":"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"}
@@ -1,8 +1,10 @@
1
1
  import { AnyRouter } from '@tanstack/router-core';
2
- import { QueryClient } from '@tanstack/query-core';
2
+ import { DehydrateOptions, HydrateOptions, QueryClient } from '@tanstack/query-core';
3
3
  export type RouterSsrQueryOptions<TRouter extends AnyRouter> = {
4
4
  router: TRouter;
5
5
  queryClient: QueryClient;
6
+ dehydrateOptions?: DehydrateOptions;
7
+ hydrateOptions?: HydrateOptions;
6
8
  /**
7
9
  * If `true`, the QueryClient will handle errors thrown by `redirect()` inside of mutations and queries.
8
10
  *
@@ -11,4 +13,4 @@ export type RouterSsrQueryOptions<TRouter extends AnyRouter> = {
11
13
  */
12
14
  handleRedirects?: boolean;
13
15
  };
14
- export declare function setupCoreRouterSsrQueryIntegration<TRouter extends AnyRouter>({ router, queryClient, handleRedirects, }: RouterSsrQueryOptions<TRouter>): void;
16
+ export declare function setupCoreRouterSsrQueryIntegration<TRouter extends AnyRouter>({ router, queryClient, dehydrateOptions, hydrateOptions, handleRedirects, }: RouterSsrQueryOptions<TRouter>): void;
@@ -1,8 +1,10 @@
1
1
  import { AnyRouter } from '@tanstack/router-core';
2
- import { QueryClient } from '@tanstack/query-core';
2
+ import { DehydrateOptions, HydrateOptions, QueryClient } from '@tanstack/query-core';
3
3
  export type RouterSsrQueryOptions<TRouter extends AnyRouter> = {
4
4
  router: TRouter;
5
5
  queryClient: QueryClient;
6
+ dehydrateOptions?: DehydrateOptions;
7
+ hydrateOptions?: HydrateOptions;
6
8
  /**
7
9
  * If `true`, the QueryClient will handle errors thrown by `redirect()` inside of mutations and queries.
8
10
  *
@@ -11,4 +13,4 @@ export type RouterSsrQueryOptions<TRouter extends AnyRouter> = {
11
13
  */
12
14
  handleRedirects?: boolean;
13
15
  };
14
- export declare function setupCoreRouterSsrQueryIntegration<TRouter extends AnyRouter>({ router, queryClient, handleRedirects, }: RouterSsrQueryOptions<TRouter>): void;
16
+ export declare function setupCoreRouterSsrQueryIntegration<TRouter extends AnyRouter>({ router, queryClient, dehydrateOptions, hydrateOptions, handleRedirects, }: RouterSsrQueryOptions<TRouter>): void;
package/dist/esm/index.js CHANGED
@@ -2,7 +2,7 @@ import { dehydrate, hydrate } from "@tanstack/query-core";
2
2
  import { isRedirect } from "@tanstack/router-core";
3
3
  import { isServer } from "@tanstack/router-core/isServer";
4
4
  //#region src/index.ts
5
- function setupCoreRouterSsrQueryIntegration({ router, queryClient, handleRedirects = true }) {
5
+ function setupCoreRouterSsrQueryIntegration({ router, queryClient, dehydrateOptions, hydrateOptions, handleRedirects = true }) {
6
6
  const ogHydrate = router.options.hydrate;
7
7
  const ogDehydrate = router.options.dehydrate;
8
8
  if (isServer ?? router.isServer) {
@@ -19,7 +19,7 @@ function setupCoreRouterSsrQueryIntegration({ router, queryClient, handleRedirec
19
19
  ...await ogDehydrate?.(),
20
20
  queryStream: queryStream.stream
21
21
  };
22
- const dehydratedQueryClient = dehydrate(queryClient);
22
+ const dehydratedQueryClient = dehydrate(queryClient, dehydrateOptions);
23
23
  if (dehydratedQueryClient.queries.length > 0) {
24
24
  dehydratedQueryClient.queries.forEach((query) => {
25
25
  sentQueries.add(query.queryHash);
@@ -44,19 +44,24 @@ function setupCoreRouterSsrQueryIntegration({ router, queryClient, handleRedirec
44
44
  console.warn(`tried to stream query ${event.query.queryHash} after stream was already closed`);
45
45
  return;
46
46
  }
47
+ const dehydratedQuery = dehydrate(queryClient, {
48
+ ...dehydrateOptions,
49
+ shouldDehydrateQuery: (query) => {
50
+ if (query.queryHash !== event.query.queryHash) return false;
51
+ return (ogClientOptions.dehydrate?.shouldDehydrateQuery?.(query) ?? true) && (dehydrateOptions?.shouldDehydrateQuery?.(query) ?? true);
52
+ }
53
+ });
54
+ if (dehydratedQuery.queries.length === 0) return;
47
55
  sentQueries.add(event.query.queryHash);
48
- queryStream.enqueue(dehydrate(queryClient, { shouldDehydrateQuery: (query) => {
49
- if (query.queryHash === event.query.queryHash) return ogClientOptions.dehydrate?.shouldDehydrateQuery?.(query) ?? true;
50
- return false;
51
- } }));
56
+ queryStream.enqueue(dehydratedQuery);
52
57
  });
53
58
  } else {
54
59
  router.options.hydrate = async (dehydrated) => {
55
60
  await ogHydrate?.(dehydrated);
56
- if (dehydrated.dehydratedQueryClient) hydrate(queryClient, dehydrated.dehydratedQueryClient);
61
+ if (dehydrated.dehydratedQueryClient) hydrate(queryClient, dehydrated.dehydratedQueryClient, hydrateOptions);
57
62
  const reader = dehydrated.queryStream.getReader();
58
63
  reader.read().then(async function handle({ done, value }) {
59
- hydrate(queryClient, value);
64
+ hydrate(queryClient, value, hydrateOptions);
60
65
  if (done) return;
61
66
  return handle(await reader.read());
62
67
  }).catch((err) => {
@@ -69,7 +74,7 @@ function setupCoreRouterSsrQueryIntegration({ router, queryClient, handleRedirec
69
74
  ...ogMutationCacheConfig,
70
75
  onError: (error, ...rest) => {
71
76
  if (isRedirect(error)) {
72
- error.options._fromLocation = router.stores.location.state;
77
+ error.options._fromLocation = router.stores.location.get();
73
78
  return router.navigate(router.resolveRedirect(error).options);
74
79
  }
75
80
  return ogMutationCacheConfig.onError?.(error, ...rest);
@@ -80,7 +85,7 @@ function setupCoreRouterSsrQueryIntegration({ router, queryClient, handleRedirec
80
85
  ...ogQueryCacheConfig,
81
86
  onError: (error, ...rest) => {
82
87
  if (isRedirect(error)) {
83
- error.options._fromLocation = router.stores.location.state;
88
+ error.options._fromLocation = router.stores.location.get();
84
89
  return router.navigate(router.resolveRedirect(error).options);
85
90
  }
86
91
  return ogQueryCacheConfig.onError?.(error, ...rest);
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../../src/index.ts"],"sourcesContent":["import {\n dehydrate as queryDehydrate,\n hydrate as queryHydrate,\n} from '@tanstack/query-core'\nimport { isRedirect } from '@tanstack/router-core'\nimport { isServer } from '@tanstack/router-core/isServer'\nimport type { AnyRouter } from '@tanstack/router-core'\nimport type {\n QueryClient,\n DehydratedState as QueryDehydratedState,\n} from '@tanstack/query-core'\n\nexport type RouterSsrQueryOptions<TRouter extends AnyRouter> = {\n router: TRouter\n queryClient: QueryClient\n\n /**\n * If `true`, the QueryClient will handle errors thrown by `redirect()` inside of mutations and queries.\n *\n * @default true\n * @link [Guide](https://tanstack.com/router/latest/docs/framework/react/api/router/redirectFunction)\n */\n handleRedirects?: boolean\n}\n\ntype DehydratedRouterQueryState = {\n dehydratedQueryClient?: QueryDehydratedState\n queryStream: ReadableStream<QueryDehydratedState>\n}\n\nexport function setupCoreRouterSsrQueryIntegration<TRouter extends AnyRouter>({\n router,\n queryClient,\n handleRedirects = true,\n}: RouterSsrQueryOptions<TRouter>) {\n const ogHydrate = router.options.hydrate\n const ogDehydrate = router.options.dehydrate\n\n if (isServer ?? router.isServer) {\n const sentQueries = new Set<string>()\n const queryStream = createPushableStream()\n let unsubscribe: (() => void) | undefined = undefined\n router.options.dehydrate =\n async (): Promise<DehydratedRouterQueryState> => {\n router.serverSsr!.onRenderFinished(() => {\n queryStream.close()\n unsubscribe?.()\n unsubscribe = undefined\n })\n const ogDehydrated = await ogDehydrate?.()\n\n const dehydratedRouter = {\n ...ogDehydrated,\n // prepare the stream for queries coming up during rendering\n queryStream: queryStream.stream,\n }\n\n const dehydratedQueryClient = queryDehydrate(queryClient)\n if (dehydratedQueryClient.queries.length > 0) {\n dehydratedQueryClient.queries.forEach((query) => {\n sentQueries.add(query.queryHash)\n })\n dehydratedRouter.dehydratedQueryClient = dehydratedQueryClient\n }\n\n return dehydratedRouter\n }\n\n const ogClientOptions = queryClient.getDefaultOptions()\n queryClient.setDefaultOptions({\n ...ogClientOptions,\n dehydrate: {\n shouldDehydrateQuery: () => true,\n ...ogClientOptions.dehydrate,\n },\n })\n\n unsubscribe = queryClient.getQueryCache().subscribe((event) => {\n // before rendering starts, we do not stream individual queries\n // instead we dehydrate the entire query client in router's dehydrate()\n // if attachRouterServerSsrUtils() has not been called yet, `router.serverSsr` will be undefined and we also do not stream\n if (!router.serverSsr?.isDehydrated()) {\n return\n }\n if (sentQueries.has(event.query.queryHash)) {\n return\n }\n // promise not yet set on the query, so we cannot stream it yet\n if (!event.query.promise) {\n return\n }\n if (queryStream.isClosed()) {\n console.warn(\n `tried to stream query ${event.query.queryHash} after stream was already closed`,\n )\n return\n }\n sentQueries.add(event.query.queryHash)\n queryStream.enqueue(\n queryDehydrate(queryClient, {\n shouldDehydrateQuery: (query) => {\n if (query.queryHash === event.query.queryHash) {\n return (\n ogClientOptions.dehydrate?.shouldDehydrateQuery?.(query) ?? true\n )\n }\n return false\n },\n }),\n )\n })\n // on the client\n } else {\n router.options.hydrate = async (dehydrated: DehydratedRouterQueryState) => {\n await ogHydrate?.(dehydrated)\n // hydrate the query client with the dehydrated data (if it was dehydrated on the server)\n if (dehydrated.dehydratedQueryClient) {\n queryHydrate(queryClient, dehydrated.dehydratedQueryClient)\n }\n\n // read the query stream and hydrate the queries as they come in\n const reader = dehydrated.queryStream.getReader()\n reader\n .read()\n .then(async function handle({ done, value }) {\n queryHydrate(queryClient, value)\n if (done) {\n return\n }\n const result = await reader.read()\n return handle(result)\n })\n .catch((err) => {\n console.error('Error reading query stream:', err)\n })\n }\n if (handleRedirects) {\n const ogMutationCacheConfig = queryClient.getMutationCache().config\n queryClient.getMutationCache().config = {\n ...ogMutationCacheConfig,\n onError: (error, ...rest) => {\n if (isRedirect(error)) {\n error.options._fromLocation = router.stores.location.state\n return router.navigate(router.resolveRedirect(error).options)\n }\n\n return ogMutationCacheConfig.onError?.(error, ...rest)\n },\n }\n\n const ogQueryCacheConfig = queryClient.getQueryCache().config\n queryClient.getQueryCache().config = {\n ...ogQueryCacheConfig,\n onError: (error, ...rest) => {\n if (isRedirect(error)) {\n error.options._fromLocation = router.stores.location.state\n return router.navigate(router.resolveRedirect(error).options)\n }\n\n return ogQueryCacheConfig.onError?.(error, ...rest)\n },\n }\n }\n }\n}\n\ntype PushableStream = {\n stream: ReadableStream\n enqueue: (chunk: unknown) => void\n close: () => void\n isClosed: () => boolean\n error: (err: unknown) => void\n}\n\nfunction createPushableStream(): PushableStream {\n let controllerRef: ReadableStreamDefaultController\n const stream = new ReadableStream({\n start(controller) {\n controllerRef = controller\n },\n })\n let _isClosed = false\n\n return {\n stream,\n enqueue: (chunk) => controllerRef.enqueue(chunk),\n close: () => {\n controllerRef.close()\n _isClosed = true\n },\n isClosed: () => _isClosed,\n error: (err: unknown) => controllerRef.error(err),\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../src/index.ts"],"sourcesContent":["import {\n dehydrate as queryDehydrate,\n hydrate as queryHydrate,\n} from '@tanstack/query-core'\nimport { isRedirect } from '@tanstack/router-core'\nimport { isServer } from '@tanstack/router-core/isServer'\nimport type { AnyRouter } from '@tanstack/router-core'\nimport type {\n DehydrateOptions,\n HydrateOptions,\n QueryClient,\n DehydratedState as QueryDehydratedState,\n} from '@tanstack/query-core'\n\nexport type RouterSsrQueryOptions<TRouter extends AnyRouter> = {\n router: TRouter\n queryClient: QueryClient\n dehydrateOptions?: DehydrateOptions\n hydrateOptions?: HydrateOptions\n\n /**\n * If `true`, the QueryClient will handle errors thrown by `redirect()` inside of mutations and queries.\n *\n * @default true\n * @link [Guide](https://tanstack.com/router/latest/docs/framework/react/api/router/redirectFunction)\n */\n handleRedirects?: boolean\n}\n\ntype DehydratedRouterQueryState = {\n dehydratedQueryClient?: QueryDehydratedState\n queryStream: ReadableStream<QueryDehydratedState>\n}\n\nexport function setupCoreRouterSsrQueryIntegration<TRouter extends AnyRouter>({\n router,\n queryClient,\n dehydrateOptions,\n hydrateOptions,\n handleRedirects = true,\n}: RouterSsrQueryOptions<TRouter>) {\n const ogHydrate = router.options.hydrate\n const ogDehydrate = router.options.dehydrate\n\n if (isServer ?? router.isServer) {\n const sentQueries = new Set<string>()\n const queryStream = createPushableStream()\n let unsubscribe: (() => void) | undefined = undefined\n router.options.dehydrate =\n async (): Promise<DehydratedRouterQueryState> => {\n router.serverSsr!.onRenderFinished(() => {\n queryStream.close()\n unsubscribe?.()\n unsubscribe = undefined\n })\n const ogDehydrated = await ogDehydrate?.()\n\n const dehydratedRouter = {\n ...ogDehydrated,\n // prepare the stream for queries coming up during rendering\n queryStream: queryStream.stream,\n }\n\n const dehydratedQueryClient = queryDehydrate(\n queryClient,\n dehydrateOptions,\n )\n if (dehydratedQueryClient.queries.length > 0) {\n dehydratedQueryClient.queries.forEach((query) => {\n sentQueries.add(query.queryHash)\n })\n dehydratedRouter.dehydratedQueryClient = dehydratedQueryClient\n }\n\n return dehydratedRouter\n }\n\n const ogClientOptions = queryClient.getDefaultOptions()\n queryClient.setDefaultOptions({\n ...ogClientOptions,\n dehydrate: {\n shouldDehydrateQuery: () => true,\n ...ogClientOptions.dehydrate,\n },\n })\n\n unsubscribe = queryClient.getQueryCache().subscribe((event) => {\n // before rendering starts, we do not stream individual queries\n // instead we dehydrate the entire query client in router's dehydrate()\n // if attachRouterServerSsrUtils() has not been called yet, `router.serverSsr` will be undefined and we also do not stream\n if (!router.serverSsr?.isDehydrated()) {\n return\n }\n if (sentQueries.has(event.query.queryHash)) {\n return\n }\n // promise not yet set on the query, so we cannot stream it yet\n if (!event.query.promise) {\n return\n }\n if (queryStream.isClosed()) {\n console.warn(\n `tried to stream query ${event.query.queryHash} after stream was already closed`,\n )\n return\n }\n const dehydratedQuery = queryDehydrate(queryClient, {\n ...dehydrateOptions,\n shouldDehydrateQuery: (query) => {\n if (query.queryHash !== event.query.queryHash) {\n return false\n }\n\n return (\n (ogClientOptions.dehydrate?.shouldDehydrateQuery?.(query) ??\n true) &&\n (dehydrateOptions?.shouldDehydrateQuery?.(query) ?? true)\n )\n },\n })\n\n if (dehydratedQuery.queries.length === 0) {\n return\n }\n\n sentQueries.add(event.query.queryHash)\n queryStream.enqueue(dehydratedQuery)\n })\n // on the client\n } else {\n router.options.hydrate = async (dehydrated: DehydratedRouterQueryState) => {\n await ogHydrate?.(dehydrated)\n // hydrate the query client with the dehydrated data (if it was dehydrated on the server)\n if (dehydrated.dehydratedQueryClient) {\n queryHydrate(\n queryClient,\n dehydrated.dehydratedQueryClient,\n hydrateOptions,\n )\n }\n\n // read the query stream and hydrate the queries as they come in\n const reader = dehydrated.queryStream.getReader()\n reader\n .read()\n .then(async function handle({ done, value }) {\n queryHydrate(queryClient, value, hydrateOptions)\n if (done) {\n return\n }\n const result = await reader.read()\n return handle(result)\n })\n .catch((err) => {\n console.error('Error reading query stream:', err)\n })\n }\n if (handleRedirects) {\n const ogMutationCacheConfig = queryClient.getMutationCache().config\n queryClient.getMutationCache().config = {\n ...ogMutationCacheConfig,\n onError: (error, ...rest) => {\n if (isRedirect(error)) {\n error.options._fromLocation = router.stores.location.get()\n return router.navigate(router.resolveRedirect(error).options)\n }\n\n return ogMutationCacheConfig.onError?.(error, ...rest)\n },\n }\n\n const ogQueryCacheConfig = queryClient.getQueryCache().config\n queryClient.getQueryCache().config = {\n ...ogQueryCacheConfig,\n onError: (error, ...rest) => {\n if (isRedirect(error)) {\n error.options._fromLocation = router.stores.location.get()\n return router.navigate(router.resolveRedirect(error).options)\n }\n\n return ogQueryCacheConfig.onError?.(error, ...rest)\n },\n }\n }\n }\n}\n\ntype PushableStream = {\n stream: ReadableStream\n enqueue: (chunk: unknown) => void\n close: () => void\n isClosed: () => boolean\n error: (err: unknown) => void\n}\n\nfunction createPushableStream(): PushableStream {\n let controllerRef: ReadableStreamDefaultController\n const stream = new ReadableStream({\n start(controller) {\n controllerRef = controller\n },\n })\n let _isClosed = false\n\n return {\n stream,\n enqueue: (chunk) => controllerRef.enqueue(chunk),\n close: () => {\n controllerRef.close()\n _isClosed = true\n },\n isClosed: () => _isClosed,\n error: (err: unknown) => controllerRef.error(err),\n }\n}\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tanstack/router-ssr-query-core",
3
- "version": "1.167.0",
3
+ "version": "1.168.0",
4
4
  "description": "Modern and scalable routing for React applications",
5
5
  "author": "Tanner Linsley",
6
6
  "license": "MIT",
@@ -49,7 +49,7 @@
49
49
  "node": ">=20.19"
50
50
  },
51
51
  "devDependencies": {
52
- "@tanstack/router-core": ">=1.168.0",
52
+ "@tanstack/router-core": ">=1.168.10",
53
53
  "@tanstack/query-core": ">=5.90.0",
54
54
  "vite": "*"
55
55
  },
@@ -61,12 +61,12 @@
61
61
  "clean": "rimraf ./dist && rimraf ./coverage",
62
62
  "test:eslint": "eslint ./src",
63
63
  "test:types": "pnpm run \"/^test:types:ts[0-9]{2}$/\"",
64
- "test:types:ts54": "node ../../node_modules/typescript54/lib/tsc.js",
65
64
  "test:types:ts55": "node ../../node_modules/typescript55/lib/tsc.js",
66
65
  "test:types:ts56": "node ../../node_modules/typescript56/lib/tsc.js",
67
66
  "test:types:ts57": "node ../../node_modules/typescript57/lib/tsc.js",
68
67
  "test:types:ts58": "node ../../node_modules/typescript58/lib/tsc.js",
69
- "test:types:ts59": "tsc",
68
+ "test:types:ts59": "node ../../node_modules/typescript59/lib/tsc.js",
69
+ "test:types:ts60": "tsc",
70
70
  "test:unit": "exit 0; vitest",
71
71
  "test:unit:dev": "pnpm run test:unit --watch",
72
72
  "test:build": "publint --strict && attw --ignore-rules no-resolution --pack .",
package/src/index.ts CHANGED
@@ -6,6 +6,8 @@ import { isRedirect } from '@tanstack/router-core'
6
6
  import { isServer } from '@tanstack/router-core/isServer'
7
7
  import type { AnyRouter } from '@tanstack/router-core'
8
8
  import type {
9
+ DehydrateOptions,
10
+ HydrateOptions,
9
11
  QueryClient,
10
12
  DehydratedState as QueryDehydratedState,
11
13
  } from '@tanstack/query-core'
@@ -13,6 +15,8 @@ import type {
13
15
  export type RouterSsrQueryOptions<TRouter extends AnyRouter> = {
14
16
  router: TRouter
15
17
  queryClient: QueryClient
18
+ dehydrateOptions?: DehydrateOptions
19
+ hydrateOptions?: HydrateOptions
16
20
 
17
21
  /**
18
22
  * If `true`, the QueryClient will handle errors thrown by `redirect()` inside of mutations and queries.
@@ -31,6 +35,8 @@ type DehydratedRouterQueryState = {
31
35
  export function setupCoreRouterSsrQueryIntegration<TRouter extends AnyRouter>({
32
36
  router,
33
37
  queryClient,
38
+ dehydrateOptions,
39
+ hydrateOptions,
34
40
  handleRedirects = true,
35
41
  }: RouterSsrQueryOptions<TRouter>) {
36
42
  const ogHydrate = router.options.hydrate
@@ -55,7 +61,10 @@ export function setupCoreRouterSsrQueryIntegration<TRouter extends AnyRouter>({
55
61
  queryStream: queryStream.stream,
56
62
  }
57
63
 
58
- const dehydratedQueryClient = queryDehydrate(queryClient)
64
+ const dehydratedQueryClient = queryDehydrate(
65
+ queryClient,
66
+ dehydrateOptions,
67
+ )
59
68
  if (dehydratedQueryClient.queries.length > 0) {
60
69
  dehydratedQueryClient.queries.forEach((query) => {
61
70
  sentQueries.add(query.queryHash)
@@ -95,19 +104,27 @@ export function setupCoreRouterSsrQueryIntegration<TRouter extends AnyRouter>({
95
104
  )
96
105
  return
97
106
  }
98
- sentQueries.add(event.query.queryHash)
99
- queryStream.enqueue(
100
- queryDehydrate(queryClient, {
101
- shouldDehydrateQuery: (query) => {
102
- if (query.queryHash === event.query.queryHash) {
103
- return (
104
- ogClientOptions.dehydrate?.shouldDehydrateQuery?.(query) ?? true
105
- )
106
- }
107
+ const dehydratedQuery = queryDehydrate(queryClient, {
108
+ ...dehydrateOptions,
109
+ shouldDehydrateQuery: (query) => {
110
+ if (query.queryHash !== event.query.queryHash) {
107
111
  return false
108
- },
109
- }),
110
- )
112
+ }
113
+
114
+ return (
115
+ (ogClientOptions.dehydrate?.shouldDehydrateQuery?.(query) ??
116
+ true) &&
117
+ (dehydrateOptions?.shouldDehydrateQuery?.(query) ?? true)
118
+ )
119
+ },
120
+ })
121
+
122
+ if (dehydratedQuery.queries.length === 0) {
123
+ return
124
+ }
125
+
126
+ sentQueries.add(event.query.queryHash)
127
+ queryStream.enqueue(dehydratedQuery)
111
128
  })
112
129
  // on the client
113
130
  } else {
@@ -115,7 +132,11 @@ export function setupCoreRouterSsrQueryIntegration<TRouter extends AnyRouter>({
115
132
  await ogHydrate?.(dehydrated)
116
133
  // hydrate the query client with the dehydrated data (if it was dehydrated on the server)
117
134
  if (dehydrated.dehydratedQueryClient) {
118
- queryHydrate(queryClient, dehydrated.dehydratedQueryClient)
135
+ queryHydrate(
136
+ queryClient,
137
+ dehydrated.dehydratedQueryClient,
138
+ hydrateOptions,
139
+ )
119
140
  }
120
141
 
121
142
  // read the query stream and hydrate the queries as they come in
@@ -123,7 +144,7 @@ export function setupCoreRouterSsrQueryIntegration<TRouter extends AnyRouter>({
123
144
  reader
124
145
  .read()
125
146
  .then(async function handle({ done, value }) {
126
- queryHydrate(queryClient, value)
147
+ queryHydrate(queryClient, value, hydrateOptions)
127
148
  if (done) {
128
149
  return
129
150
  }
@@ -140,7 +161,7 @@ export function setupCoreRouterSsrQueryIntegration<TRouter extends AnyRouter>({
140
161
  ...ogMutationCacheConfig,
141
162
  onError: (error, ...rest) => {
142
163
  if (isRedirect(error)) {
143
- error.options._fromLocation = router.stores.location.state
164
+ error.options._fromLocation = router.stores.location.get()
144
165
  return router.navigate(router.resolveRedirect(error).options)
145
166
  }
146
167
 
@@ -153,7 +174,7 @@ export function setupCoreRouterSsrQueryIntegration<TRouter extends AnyRouter>({
153
174
  ...ogQueryCacheConfig,
154
175
  onError: (error, ...rest) => {
155
176
  if (isRedirect(error)) {
156
- error.options._fromLocation = router.stores.location.state
177
+ error.options._fromLocation = router.stores.location.get()
157
178
  return router.navigate(router.resolveRedirect(error).options)
158
179
  }
159
180