diff --git a/src/__tests__/__snapshots__/exports.ts.snap b/src/__tests__/__snapshots__/exports.ts.snap index c7343506bff..41bb3792449 100644 --- a/src/__tests__/__snapshots__/exports.ts.snap +++ b/src/__tests__/__snapshots__/exports.ts.snap @@ -467,6 +467,7 @@ Array [ "removeMaskedFragmentSpreads", "resultKeyNameFromField", "shouldInclude", + "skipToken", "storeKeyNameFromField", "stringifyForDisplay", "toQueryResult", diff --git a/src/core/ObservableQuery.ts b/src/core/ObservableQuery.ts index 5b81a7a9ec1..dd29d05d735 100644 --- a/src/core/ObservableQuery.ts +++ b/src/core/ObservableQuery.ts @@ -24,6 +24,7 @@ import { getOperationName, getQueryDefinition, preventUnhandledRejection, + skipToken, toQueryResult, } from "@apollo/client/utilities/internal"; import { invariant } from "@apollo/client/utilities/invariant"; @@ -1068,6 +1069,13 @@ Did you mean to call refetch(variables) instead of refetch({ variables })?`, newOptions: Partial> ): void { const mergedOptions = compact(this.options, newOptions || {}); + if (skipToken in (newOptions.variables || {})) { + Object.assign( + mergedOptions.variables, + this.options.variables, + newOptions.variables + ); + } assign(this.options, mergedOptions); this.updatePolling(); } diff --git a/src/core/QueryManager.ts b/src/core/QueryManager.ts index d9fef505af9..a48a9209d1e 100644 --- a/src/core/QueryManager.ts +++ b/src/core/QueryManager.ts @@ -61,6 +61,7 @@ import { isNonNullObject, makeUniqueId, removeDirectivesFromDocument, + skipToken, toQueryResult, } from "@apollo/client/utilities/internal"; import { @@ -1295,7 +1296,10 @@ export class QueryManager { if (include) { this.getObservableQueries(include).forEach((oq) => { - if (oq.options.fetchPolicy === "cache-only") { + if ( + oq.options.fetchPolicy === "cache-only" || + skipToken in oq.options.variables + ) { return; } diff --git a/src/react/hooks/__tests__/useQuery.test.tsx b/src/react/hooks/__tests__/useQuery.test.tsx index 2d544bb11ac..99db9d61a0a 100644 --- a/src/react/hooks/__tests__/useQuery.test.tsx +++ b/src/react/hooks/__tests__/useQuery.test.tsx @@ -1749,7 +1749,7 @@ describe("useQuery Hook", () => { }); await rerender(skipToken); - + // !!! rerenders with `undefined` variables await expect(renderStream).toRerenderWithSimilarSnapshot(); client.writeQuery({ @@ -1889,7 +1889,7 @@ describe("useQuery Hook", () => { }); await rerender(skipToken); - + // !!! rerenders with `undefined` variables await expect(renderStream).toRerenderWithSimilarSnapshot(); client.writeQuery({ @@ -8702,6 +8702,7 @@ describe("useQuery Hook", () => { const { fetchPolicy, initialFetchPolicy } = observable.options; expect(fetchPolicy).toBe(expectedFetchPolicy); + // last failing test, should be "cache-and-network", but is "cache-first" expect(initialFetchPolicy).toBe(expectedInitialFetchPolicy); } diff --git a/src/react/hooks/__tests__/useSuspenseQuery.test.tsx b/src/react/hooks/__tests__/useSuspenseQuery.test.tsx index 7122e12171a..20d913b08d7 100644 --- a/src/react/hooks/__tests__/useSuspenseQuery.test.tsx +++ b/src/react/hooks/__tests__/useSuspenseQuery.test.tsx @@ -168,19 +168,24 @@ async function renderSuspenseHook( } function useSimpleQueryCase() { - const query: TypedDocumentNode> = gql` - query UserQuery { + const query: TypedDocumentNode< + SimpleQueryData, + { optionalVariable?: string } + > = gql` + query UserQuery($optionalVariable: String) { greeting } `; const mocks = [ { - request: { query }, + request: { query, variables: () => true }, result: { data: { greeting: "Hello" } }, delay: 20, }, - ]; + ] satisfies Array< + MockLink.MockedResponse + >; return { query, mocks }; } @@ -1110,7 +1115,7 @@ describe("useSuspenseQuery", () => { }); }); - expect(renders.count).toBe(4 + (IS_REACT_19 ? renders.suspenseCount : 0)); + expect(renders.count).toBe(5 + (IS_REACT_19 ? renders.suspenseCount : 0)); expect(renders.suspenseCount).toBe(2); expect(renders.frames).toStrictEqualTyped([ { @@ -1125,6 +1130,12 @@ describe("useSuspenseQuery", () => { networkStatus: NetworkStatus.ready, error: undefined, }, + { + ...mocks[1].result, + dataState: "complete", + networkStatus: NetworkStatus.ready, + error: undefined, + }, ]); }); @@ -1607,7 +1618,7 @@ describe("useSuspenseQuery", () => { }); expect(renders.suspenseCount).toBe(2); - expect(renders.count).toBe(5 + (IS_REACT_19 ? renders.suspenseCount : 0)); + expect(renders.count).toBe(6 + (IS_REACT_19 ? renders.suspenseCount : 0)); expect(renders.frames).toStrictEqualTyped([ { ...mocks[0].result, @@ -1621,6 +1632,12 @@ describe("useSuspenseQuery", () => { networkStatus: NetworkStatus.ready, error: undefined, }, + { + ...mocks[1].result, + dataState: "complete", + networkStatus: NetworkStatus.ready, + error: undefined, + }, { data: { character: { id: "2", name: "Cached hero" } }, dataState: "complete", @@ -1671,7 +1688,7 @@ describe("useSuspenseQuery", () => { error: undefined, }); - expect(renders.count).toBe(5 + (IS_REACT_19 ? renders.suspenseCount : 0)); + expect(renders.count).toBe(7 + (IS_REACT_19 ? renders.suspenseCount : 0)); expect(renders.suspenseCount).toBe(2); expect(renders.frames).toStrictEqualTyped([ { @@ -1686,6 +1703,18 @@ describe("useSuspenseQuery", () => { networkStatus: NetworkStatus.ready, error: undefined, }, + { + ...mocks[1].result, + dataState: "complete", + networkStatus: NetworkStatus.ready, + error: undefined, + }, + { + ...mocks[0].result, + dataState: "complete", + networkStatus: NetworkStatus.ready, + error: undefined, + }, { ...mocks[0].result, dataState: "complete", @@ -1791,7 +1820,7 @@ describe("useSuspenseQuery", () => { }); }); - expect(renders.count).toBe(6 + (IS_REACT_19 ? renders.suspenseCount : 0)); + expect(renders.count).toBe(8 + (IS_REACT_19 ? renders.suspenseCount : 0)); expect(renders.suspenseCount).toBe(2); expect(renders.frames).toStrictEqualTyped([ { @@ -1806,6 +1835,18 @@ describe("useSuspenseQuery", () => { networkStatus: NetworkStatus.ready, error: undefined, }, + { + ...mocks[1].result, + dataState: "complete", + networkStatus: NetworkStatus.ready, + error: undefined, + }, + { + ...mocks[0].result, + dataState: "complete", + networkStatus: NetworkStatus.loading, + error: undefined, + }, { ...mocks[0].result, dataState: "complete", @@ -1910,7 +1951,7 @@ describe("useSuspenseQuery", () => { }); }); - expect(renders.count).toBe(6 + (IS_REACT_19 ? renders.suspenseCount : 0)); + expect(renders.count).toBe(8 + (IS_REACT_19 ? renders.suspenseCount : 0)); expect(renders.suspenseCount).toBe(3); expect(renders.frames).toStrictEqualTyped([ { @@ -1925,6 +1966,18 @@ describe("useSuspenseQuery", () => { networkStatus: NetworkStatus.ready, error: undefined, }, + { + ...mocks[1].result, + dataState: "complete", + networkStatus: NetworkStatus.ready, + error: undefined, + }, + { + ...mocks[2].result, + dataState: "complete", + networkStatus: NetworkStatus.ready, + error: undefined, + }, { ...mocks[2].result, dataState: "complete", @@ -2023,7 +2076,7 @@ describe("useSuspenseQuery", () => { }); }); - expect(renders.count).toBe(6 + (IS_REACT_19 ? renders.suspenseCount : 0)); + expect(renders.count).toBe(8 + (IS_REACT_19 ? renders.suspenseCount : 0)); expect(renders.suspenseCount).toBe(3); expect(renders.frames).toStrictEqualTyped([ { @@ -2038,6 +2091,18 @@ describe("useSuspenseQuery", () => { networkStatus: NetworkStatus.ready, error: undefined, }, + { + ...mocks[1].result, + dataState: "complete", + networkStatus: NetworkStatus.ready, + error: undefined, + }, + { + ...mocks[2].result, + dataState: "complete", + networkStatus: NetworkStatus.ready, + error: undefined, + }, { ...mocks[2].result, dataState: "complete", @@ -2109,7 +2174,7 @@ describe("useSuspenseQuery", () => { }); expect(renders.suspenseCount).toBe(2); - expect(renders.count).toBe(6 + (IS_REACT_19 ? renders.suspenseCount : 0)); + expect(renders.count).toBe(8 + (IS_REACT_19 ? renders.suspenseCount : 0)); expect(renders.frames).toStrictEqualTyped([ { ...mocks[0].result, @@ -2123,6 +2188,18 @@ describe("useSuspenseQuery", () => { networkStatus: NetworkStatus.ready, error: undefined, }, + { + ...mocks[1].result, + dataState: "complete", + networkStatus: NetworkStatus.ready, + error: undefined, + }, + { + ...mocks[0].result, + dataState: "complete", + networkStatus: NetworkStatus.ready, + error: undefined, + }, { ...mocks[0].result, dataState: "complete", @@ -2395,7 +2472,7 @@ describe("useSuspenseQuery", () => { }); }); - expect(renders.count).toBe(4 + (IS_REACT_19 ? renders.suspenseCount : 0)); + expect(renders.count).toBe(5 + (IS_REACT_19 ? renders.suspenseCount : 0)); expect(renders.suspenseCount).toBe(1); expect(renders.frames).toStrictEqualTyped([ { @@ -2416,6 +2493,12 @@ describe("useSuspenseQuery", () => { networkStatus: NetworkStatus.ready, error: undefined, }, + { + ...mocks[1].result, + dataState: "complete", + networkStatus: NetworkStatus.ready, + error: undefined, + }, ]); }); @@ -2885,7 +2968,7 @@ describe("useSuspenseQuery", () => { }); }); - expect(renders.count).toBe(4 + (IS_REACT_19 ? renders.suspenseCount : 0)); + expect(renders.count).toBe(5 + (IS_REACT_19 ? renders.suspenseCount : 0)); expect(renders.suspenseCount).toBe(1); expect(renders.frames).toStrictEqualTyped([ { @@ -2906,6 +2989,12 @@ describe("useSuspenseQuery", () => { networkStatus: NetworkStatus.ready, error: undefined, }, + { + ...mocks[1].result, + dataState: "complete", + networkStatus: NetworkStatus.ready, + error: undefined, + }, ]); }); @@ -3096,7 +3185,7 @@ describe("useSuspenseQuery", () => { // 2. Unsuspend and return results from initial fetch // 3. Change variables and suspend // 5. Unsuspend and return results from refetch - expect(renders.count).toBe(4 + (IS_REACT_19 ? renders.suspenseCount : 0)); + expect(renders.count).toBe(5 + (IS_REACT_19 ? renders.suspenseCount : 0)); expect(renders.suspenseCount).toBe(2); expect(renders.frames).toStrictEqualTyped([ { @@ -3111,6 +3200,12 @@ describe("useSuspenseQuery", () => { networkStatus: NetworkStatus.ready, error: undefined, }, + { + ...mocks[1].result, + dataState: "complete", + networkStatus: NetworkStatus.ready, + error: undefined, + }, ]); } ); @@ -3575,6 +3670,14 @@ describe("useSuspenseQuery", () => { networkStatus: NetworkStatus.ready, error: undefined, }, + { + data: { + vars: { source: "rerender", globalOnlyVar: true, localOnlyVar: true }, + }, + dataState: "complete", + networkStatus: NetworkStatus.ready, + error: undefined, + }, ]); }); @@ -4396,7 +4499,7 @@ describe("useSuspenseQuery", () => { }); }); - expect(renders.count).toBe(4 + (IS_REACT_19 ? renders.suspenseCount : 0)); + expect(renders.count).toBe(5 + (IS_REACT_19 ? renders.suspenseCount : 0)); expect(renders.errorCount).toBe(0); expect(renders.errors).toEqual([]); expect(renders.suspenseCount).toBe(2); @@ -4413,6 +4516,12 @@ describe("useSuspenseQuery", () => { networkStatus: NetworkStatus.ready, error: undefined, }, + { + data: mocks[1].result.data, + dataState: "complete", + networkStatus: NetworkStatus.ready, + error: undefined, + }, ]); }); @@ -5710,7 +5819,7 @@ describe("useSuspenseQuery", () => { }); }); - expect(renders.count).toBe(3 + (IS_REACT_19 ? renders.suspenseCount : 0)); + expect(renders.count).toBe(4 + (IS_REACT_19 ? renders.suspenseCount : 0)); expect(renders.suspenseCount).toBe(1); expect(renders.frames).toStrictEqualTyped([ { @@ -5725,6 +5834,12 @@ describe("useSuspenseQuery", () => { networkStatus: NetworkStatus.ready, error: undefined, }, + { + ...mocks[0].result, + dataState: "complete", + networkStatus: NetworkStatus.ready, + error: undefined, + }, ]); }); @@ -5778,55 +5893,60 @@ describe("useSuspenseQuery", () => { ]); }); - it("renders skip result, does not suspend, and maintains `data` when skipping a query with `skipToken` as options after it was enabled", async () => { - const { query, mocks } = useSimpleQueryCase(); - - const cache = new InMemoryCache(); + it.each([ + ["with options", { variables: { optionalVariable: "foo" } }], + ["no options", undefined], + ] as const)( + "renders skip result, does not suspend, and maintains `data` when skipping a query with `skipToken` as options after it was enabled (%s)", + async (_, options) => { + const { query, mocks } = useSimpleQueryCase(); + const cache = new InMemoryCache(); - const { result, renders, rerenderAsync } = await renderSuspenseHook( - ({ skip }) => useSuspenseQuery(query, skip ? skipToken : void 0), - { cache, mocks, initialProps: { skip: false } } - ); + const { result, renders, rerenderAsync } = await renderSuspenseHook( + ({ skip }) => useSuspenseQuery(query, skip ? skipToken : options), + { cache, mocks, initialProps: { skip: false } } + ); - expect(renders.suspenseCount).toBe(1); + expect(renders.suspenseCount).toBe(1); - await waitFor(() => { - expect(result.current).toStrictEqualTyped({ - ...mocks[0].result, - dataState: "complete", - networkStatus: NetworkStatus.ready, - error: undefined, + await waitFor(() => { + expect(result.current).toStrictEqualTyped({ + ...mocks[0].result, + dataState: "complete", + networkStatus: NetworkStatus.ready, + error: undefined, + }); }); - }); - await rerenderAsync({ skip: true }); + await rerenderAsync({ skip: true }); - expect(renders.suspenseCount).toBe(1); - - expect(result.current).toStrictEqualTyped({ - ...mocks[0].result, - dataState: "complete", - networkStatus: NetworkStatus.ready, - error: undefined, - }); + expect(renders.suspenseCount).toBe(1); - expect(renders.count).toBe(3 + (IS_REACT_19 ? renders.suspenseCount : 0)); - expect(renders.suspenseCount).toBe(1); - expect(renders.frames).toStrictEqualTyped([ - { - ...mocks[0].result, - dataState: "complete", - networkStatus: NetworkStatus.ready, - error: undefined, - }, - { + expect(result.current).toStrictEqualTyped({ ...mocks[0].result, dataState: "complete", networkStatus: NetworkStatus.ready, error: undefined, - }, - ]); - }); + }); + + expect(renders.count).toBe(3 + (IS_REACT_19 ? renders.suspenseCount : 0)); + expect(renders.suspenseCount).toBe(1); + expect(renders.frames).toStrictEqualTyped([ + { + ...mocks[0].result, + dataState: "complete", + networkStatus: NetworkStatus.ready, + error: undefined, + }, + { + ...mocks[0].result, + dataState: "complete", + networkStatus: NetworkStatus.ready, + error: undefined, + }, + ]); + } + ); it("does not make network requests when `skip` is `true`", async () => { const { query, mocks } = useVariablesQueryCase(); diff --git a/src/react/hooks/useBackgroundQuery.ts b/src/react/hooks/useBackgroundQuery.ts index 6634b99adc4..137293c5eb2 100644 --- a/src/react/hooks/useBackgroundQuery.ts +++ b/src/react/hooks/useBackgroundQuery.ts @@ -28,10 +28,10 @@ import { import type { DocumentationTypes as UtilityDocumentationTypes, NoInfer, + SkipToken, VariablesOption, } from "@apollo/client/utilities/internal"; -import type { SkipToken } from "./constants.js"; import { wrapHook } from "./internal/index.js"; import { useApolloClient } from "./useApolloClient.js"; import { useWatchQueryOptions } from "./useSuspenseQuery.js"; diff --git a/src/react/hooks/useLoadableQuery.ts b/src/react/hooks/useLoadableQuery.ts index 62f838ae445..09c0f7e7287 100644 --- a/src/react/hooks/useLoadableQuery.ts +++ b/src/react/hooks/useLoadableQuery.ts @@ -282,7 +282,7 @@ export function useLoadableQuery< "useLoadableQuery: 'loadQuery' should not be called during render. To start a query during render, use the 'useBackgroundQuery' hook." ); - const [variables] = args; + const [variables = {}] = args; const cacheKey: CacheKey = [ query, diff --git a/src/react/hooks/useQuery.ts b/src/react/hooks/useQuery.ts index 20bb81a6842..5bf53acc746 100644 --- a/src/react/hooks/useQuery.ts +++ b/src/react/hooks/useQuery.ts @@ -37,15 +37,15 @@ import type { MaybeMasked } from "@apollo/client/masking"; import type { DocumentationTypes as UtilityDocumentationTypes, NoInfer, + SkipToken, VariablesOption, } from "@apollo/client/utilities/internal"; import { maybeDeepFreeze, mergeOptions, + skipToken, } from "@apollo/client/utilities/internal"; -import type { SkipToken } from "./constants.js"; -import { skipToken } from "./constants.js"; import { useDeepMemo, wrapHook } from "./internal/index.js"; import { useApolloClient } from "./useApolloClient.js"; import { useSyncExternalStore } from "./useSyncExternalStore.js"; @@ -212,7 +212,7 @@ const lastWatchOptions = Symbol(); interface ObsQueryWithMeta extends ObservableQuery { [lastWatchOptions]?: Readonly< - ApolloClient.WatchQueryOptions + ApolloClient.WatchQueryOptions >; } @@ -439,6 +439,14 @@ function useQuery_( let [state, setState] = React.useState(createState); + // TODO: needs to move into non-memoized hook + if (options === skipToken && state.observable[lastWatchOptions]?.variables) { + watchQueryOptions.variables = { + ...state.observable[lastWatchOptions].variables, + [skipToken]: true, + }; + } + if (client !== state.client || query !== state.query) { // If the client or query have changed, we need to create a new InternalState. // This will trigger a re-render with the new state, but it will also continue @@ -491,8 +499,6 @@ function useQuery_( }, [result, client, observable, previousData, obsQueryFields]); } -const fromSkipToken = Symbol(); - function useOptions( query: DocumentNode | TypedDocumentNode, options: SkipToken | useQuery.Options, NoInfer>, @@ -504,10 +510,9 @@ function useOptions( mergeOptions(defaultOptions as any, { query, fetchPolicy: "standby", + variables: { [skipToken]: true }, }); - (opts as any)[fromSkipToken] = true; - return opts; } @@ -605,18 +610,16 @@ function useResubscribeIfNecessary< resultData: InternalResult, /** this hook will mutate properties on `observable` */ observable: ObsQueryWithMeta, - watchQueryOptions: Readonly> + watchQueryOptions: ApolloClient.WatchQueryOptions ) { "use no memo"; - if ( - observable[lastWatchOptions] && - !equal(observable[lastWatchOptions], watchQueryOptions) - ) { + const lastOptions = observable[lastWatchOptions]; + if (lastOptions && !equal(lastOptions, watchQueryOptions)) { // If skipToken was used to generate options, we won't know the correct // initialFetchPolicy until the hook is rerendered with real options, so we // set it the next time we get real options if ( - (observable[lastWatchOptions] as any)[fromSkipToken] && + lastOptions.variables?.[skipToken] && !watchQueryOptions.initialFetchPolicy ) { (watchQueryOptions.initialFetchPolicy as any) = @@ -630,7 +633,7 @@ function useResubscribeIfNecessary< // subscriptions, though it does feel less than ideal that reobserve // (potentially) kicks off a network request (for example, when the // variables have changed), which is technically a side-effect. - if (shouldReobserve(observable[lastWatchOptions], watchQueryOptions)) { + if (shouldReobserve(lastOptions, watchQueryOptions)) { observable.reobserve(watchQueryOptions); } else { observable.applyOptions(watchQueryOptions); diff --git a/src/react/hooks/useSuspenseQuery.ts b/src/react/hooks/useSuspenseQuery.ts index b8ff4434a72..70ca12247b5 100644 --- a/src/react/hooks/useSuspenseQuery.ts +++ b/src/react/hooks/useSuspenseQuery.ts @@ -1,3 +1,4 @@ +import { equal } from "@wry/equality"; import * as React from "react"; import type { @@ -31,9 +32,9 @@ import type { NoInfer, VariablesOption, } from "@apollo/client/utilities/internal"; +import type { SkipToken } from "@apollo/client/utilities/internal"; +import { skipToken } from "@apollo/client/utilities/internal"; -import type { SkipToken } from "./constants.js"; -import { skipToken } from "./constants.js"; import { __use, useDeepMemo, wrapHook } from "./internal/index.js"; import { validateSuspenseHookOptions } from "./internal/validateSuspenseHookOptions.js"; import { useApolloClient } from "./useApolloClient.js"; @@ -383,7 +384,6 @@ function useSuspenseQuery_< canonicalStringify(variables), ...([] as any[]).concat(queryKey), ]; - const queryRef = suspenseCache.getQueryRef(cacheKey, () => client.watchQuery(watchQueryOptions) ); @@ -500,11 +500,19 @@ export function useWatchQueryOptions< TData, TVariables >): ApolloClient.WatchQueryOptions { + const incomingVariables = + options === skipToken ? undefined : options.variables || ({} as TVariables); + let [variables, setLastVariables] = React.useState(incomingVariables); + if (options !== skipToken && !equal(incomingVariables, variables)) { + setLastVariables((variables = incomingVariables)); + } + return useDeepMemo>(() => { if (options === skipToken) { return { query, fetchPolicy: "standby", + variables: { [skipToken]: true, ...variables } as any, } as ApolloClient.WatchQueryOptions; } @@ -516,11 +524,12 @@ export function useWatchQueryOptions< const watchQueryOptions: ApolloClient.WatchQueryOptions = { ...options, + variables, fetchPolicy, query, notifyOnNetworkStatusChange: false, nextFetchPolicy: void 0, - }; + } satisfies ApolloClient.WatchQueryOptions as any; if (__DEV__) { validateSuspenseHookOptions(watchQueryOptions); diff --git a/src/react/index.ts b/src/react/index.ts index fbfcb2d00b2..064803d8898 100644 --- a/src/react/index.ts +++ b/src/react/index.ts @@ -15,8 +15,8 @@ export { useSuspenseFragment } from "./hooks/useSuspenseFragment.js"; export { useLoadableQuery } from "./hooks/useLoadableQuery.js"; export { useQueryRefHandlers } from "./hooks/useQueryRefHandlers.js"; export { useReadQuery } from "./hooks/useReadQuery.js"; -export { skipToken } from "./hooks/constants.js"; -export type { SkipToken } from "./hooks/constants.js"; +export { skipToken } from "@apollo/client/utilities/internal"; +export type { SkipToken } from "@apollo/client/utilities/internal"; export type { PreloadQueryFetchPolicy, diff --git a/src/testing/matchers/toHaveSuspenseCacheEntryUsing.ts b/src/testing/matchers/toHaveSuspenseCacheEntryUsing.ts index 4e7b85dc7f6..587db51d2be 100644 --- a/src/testing/matchers/toHaveSuspenseCacheEntryUsing.ts +++ b/src/testing/matchers/toHaveSuspenseCacheEntryUsing.ts @@ -15,7 +15,7 @@ export const toHaveSuspenseCacheEntryUsing: MatcherFunction< queryKey?: string | number | any[]; }, ] -> = function (client, query, { variables, queryKey = [] } = {}) { +> = function (client, query, { variables = {}, queryKey = [] } = {}) { if (!(client instanceof ApolloClient)) { throw new Error("Actual must be an instance of `ApolloClient`"); } diff --git a/src/utilities/internal/index.ts b/src/utilities/internal/index.ts index 47add2520ec..bf4953d1ef6 100644 --- a/src/utilities/internal/index.ts +++ b/src/utilities/internal/index.ts @@ -62,6 +62,8 @@ export { toQueryResult } from "./toQueryResult.js"; export { filterMap } from "./filterMap.js"; export { equalByQuery } from "./equalByQuery.js"; export { canonicalStringify } from "./canonicalStringify.js"; +export { skipToken } from "./skipToken.js"; +export type { SkipToken } from "./skipToken.js"; export { getApolloCacheMemoryInternals, diff --git a/src/react/hooks/constants.ts b/src/utilities/internal/skipToken.ts similarity index 100% rename from src/react/hooks/constants.ts rename to src/utilities/internal/skipToken.ts