{"version":3,"file":"hydration.cjs","names":["noop"],"sources":["../../src/hydration.ts"],"sourcesContent":["import { noop } from './utils'\nimport type {\n  DefaultError,\n  MutationKey,\n  MutationMeta,\n  MutationOptions,\n  MutationScope,\n  QueryKey,\n  QueryMeta,\n  QueryOptions,\n} from './types'\nimport type { QueryClient } from './queryClient'\nimport type { Query, QueryState } from './query'\nimport type { Mutation, MutationState } from './mutation'\n\n// TYPES\ntype TransformerFn = (data: any) => any\n\nfunction tryResolveSync(promise: PromiseLike<unknown>) {\n  let data: unknown\n\n  const thenResult = promise.then((result) => {\n    data = result\n    return result\n  }, noop) as Promise<unknown> | undefined\n\n  // .catch can be unavailable on certain kinds of thenable's\n  // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition\n  thenResult?.catch?.(noop)\n\n  if (data !== undefined) {\n    return { data }\n  }\n\n  return undefined\n}\n\n/**\n * Options for `dehydrate`, controlling which queries/mutations are included in the resulting `DehydratedState` and\n * how their data/errors are transformed before being serialized (e.g. for embedding in server-rendered markup).\n */\nexport interface DehydrateOptions {\n  /** Transforms a query's `data` before it is dehydrated. Useful for non-JSON-serializable data. */\n  serializeData?: TransformerFn\n  /** Predicate to decide whether a given `Mutation` should be dehydrated. Defaults to `defaultShouldDehydrateMutation`. */\n  shouldDehydrateMutation?: (mutation: Mutation) => boolean\n  /** Predicate to decide whether a given `Query` should be dehydrated. Defaults to `defaultShouldDehydrateQuery`. */\n  shouldDehydrateQuery?: (query: Query) => boolean\n  /**\n   * Predicate to decide whether a query's error should be redacted before dehydration. Errors are redacted\n   * (replaced with a generic `Error('redacted')`) unless this function is provided and returns `false` for the\n   * given error, in which case the original error is kept.\n   */\n  shouldRedactErrors?: (error: unknown) => boolean\n}\n\n/**\n * Options for `hydrate`, controlling the default options applied to queries/mutations restored from a\n * `DehydratedState`, and how to reverse any transformation applied by `DehydrateOptions.serializeData`.\n */\nexport interface HydrateOptions {\n  /** Options applied to the queries and mutations restored from the dehydrated state. */\n  defaultOptions?: {\n    /** Transforms a query's `data` after it is read from the dehydrated state, reversing `serializeData`. */\n    deserializeData?: TransformerFn\n    /** Default options merged into every query restored from the dehydrated state. */\n    queries?: QueryOptions\n    /** Default options merged into every mutation restored from the dehydrated state. */\n    mutations?: MutationOptions<unknown, DefaultError, unknown, unknown>\n  }\n}\n\ninterface DehydratedMutation {\n  mutationKey?: MutationKey\n  state: MutationState\n  meta?: MutationMeta\n  scope?: MutationScope\n}\n\ninterface DehydratedQuery {\n  queryHash: string\n  queryKey: QueryKey\n  state: QueryState\n  dehydratedAt: number\n  promise?: Promise<unknown>\n  meta?: QueryMeta\n  queryType?: 'infinite'\n}\n\n/**\n * A serializable snapshot of a `QueryClient`'s cache, as produced by `dehydrate` and consumed by `hydrate`. Typically\n * transported from server to client (e.g. embedded in server-rendered markup) to seed the client's cache with data\n * that has already been fetched, avoiding a redundant fetch on the client.\n */\nexport interface DehydratedState {\n  mutations: Array<DehydratedMutation>\n  queries: Array<DehydratedQuery>\n}\n\n// FUNCTIONS\n\nfunction dehydrateMutation(mutation: Mutation): DehydratedMutation {\n  return {\n    mutationKey: mutation.options.mutationKey,\n    state: mutation.state,\n    ...(mutation.options.scope && { scope: mutation.options.scope }),\n    ...(mutation.meta && { meta: mutation.meta }),\n  }\n}\n\nfunction dehydratePromise(\n  query: Query,\n  serializeData?: TransformerFn,\n  shouldRedactErrors?: (error: unknown) => boolean,\n): Promise<unknown> | undefined {\n  const promise = query.promise?.then(serializeData).catch((error) => {\n    if (shouldRedactErrors?.(error) === false) {\n      // Reject original error if it should not be redacted\n      return Promise.reject(error)\n    }\n    // If not in production, log original error before rejecting redacted error\n    if (process.env.NODE_ENV !== 'production') {\n      console.error(\n        `A query that was dehydrated as pending ended up rejecting. [${query.queryHash}]: ${error}; The error will be redacted in production builds`,\n      )\n    }\n    return Promise.reject(new Error('redacted'))\n  })\n\n  // Avoid unhandled promise rejections\n  // We need the promise we dehydrate to reject to get the correct result into\n  // the query cache, but we also want to avoid unhandled promise rejections\n  // in whatever environment the prefetches are happening in.\n  promise?.catch(noop)\n\n  return promise\n}\n\n/**\n * Dehydrates a single `Query` into a serializable `DehydratedQuery` snapshot. Note that most query config (e.g.\n * `queryFn`, `staleTime`) is not dehydrated but instead meant to be configured again when consuming the\n * de/rehydrated data, typically with `useQuery` on the client. If the query is still `pending`, its in-flight\n * promise is dehydrated too so it can be resumed on the other side instead of re-fetched.\n * @param query - The query to dehydrate.\n * @param serializeData - Optional transform applied to `query.state.data` before it is included in the snapshot.\n * @param shouldRedactErrors - Optional predicate; if it returns `false` for the promise's rejection error, that\n * error is kept as-is instead of being redacted.\n */\nexport function dehydrateQuery(\n  query: Query,\n  serializeData?: TransformerFn,\n  shouldRedactErrors?: (error: unknown) => boolean,\n): DehydratedQuery {\n  return {\n    dehydratedAt: Date.now(),\n    state: {\n      ...query.state,\n      ...(query.state.data !== undefined && {\n        data: serializeData\n          ? serializeData(query.state.data)\n          : query.state.data,\n      }),\n    },\n    queryKey: query.queryKey,\n    queryHash: query.queryHash,\n    ...(query.state.status === 'pending' && {\n      promise: dehydratePromise(query, serializeData, shouldRedactErrors),\n    }),\n    ...(query.meta && { meta: query.meta }),\n    ...(query.queryType && { queryType: query.queryType }),\n  }\n}\n\n/**\n * The default `shouldDehydrateMutation` predicate used by `dehydrate`. Only dehydrates mutations that are\n * currently paused (e.g. paused by `networkMode` while offline).\n */\nexport function defaultShouldDehydrateMutation(mutation: Mutation) {\n  return mutation.state.isPaused\n}\n\n/**\n * The default `shouldDehydrateQuery` predicate used by `dehydrate`. Only dehydrates queries whose status is\n * `'success'`.\n */\nexport function defaultShouldDehydrateQuery(query: Query) {\n  return query.state.status === 'success'\n}\n\n/**\n * Dehydrates a `QueryClient`'s cache (queries and mutations) into a plain, serializable `DehydratedState`,\n * typically to embed in server-rendered markup and later restore into a client-side `QueryClient` via `hydrate`.\n * Which queries/mutations are included, and how their data/errors are transformed, is controlled by `options`,\n * falling back to the client's `dehydrate` default options, and finally to `defaultShouldDehydrateQuery` /\n * `defaultShouldDehydrateMutation`.\n * @example\n * ```ts\n * const queryClient = new QueryClient()\n *\n * await queryClient.prefetchQuery({\n *   queryKey: ['posts'],\n *   queryFn: getPosts,\n * })\n *\n * const dehydratedState = dehydrate(queryClient)\n * ```\n */\nexport function dehydrate(\n  client: QueryClient,\n  options: DehydrateOptions = {},\n): DehydratedState {\n  const filterMutation =\n    options.shouldDehydrateMutation ??\n    client.getDefaultOptions().dehydrate?.shouldDehydrateMutation ??\n    defaultShouldDehydrateMutation\n\n  const mutations = client\n    .getMutationCache()\n    .getAll()\n    .flatMap((mutation) =>\n      filterMutation(mutation) ? [dehydrateMutation(mutation)] : [],\n    )\n\n  const filterQuery =\n    options.shouldDehydrateQuery ??\n    client.getDefaultOptions().dehydrate?.shouldDehydrateQuery ??\n    defaultShouldDehydrateQuery\n\n  const shouldRedactErrors =\n    options.shouldRedactErrors ??\n    client.getDefaultOptions().dehydrate?.shouldRedactErrors\n\n  const serializeData =\n    options.serializeData ?? client.getDefaultOptions().dehydrate?.serializeData\n\n  const queries = client\n    .getQueryCache()\n    .getAll()\n    .flatMap((query) =>\n      filterQuery(query)\n        ? [dehydrateQuery(query, serializeData, shouldRedactErrors)]\n        : [],\n    )\n\n  return { mutations, queries }\n}\n\n/**\n * Restores a `DehydratedState` (as produced by `dehydrate`) into a `QueryClient`'s cache, typically to seed the\n * client with data already fetched on the server. `mutations` and `queries` are each optional on `dehydratedState`.\n * Queries not yet in the cache are built from the dehydrated snapshot; queries that already exist are only updated\n * when the dehydrated data is newer than what's already cached. Newly built queries have their `fetchStatus` reset\n * to `'idle'` so they don't hydrate stuck in a fetching state. If a dehydrated query still had an in-flight\n * promise, it is resumed via `query.fetch()` (reusing that promise as `initialPromise`) rather than re-invoking\n * `queryFn`.\n * @example\n * ```ts\n * // dehydratedState was produced by `dehydrate` on the server\n * // and sent to the client, e.g. embedded in server-rendered markup.\n * const queryClient = new QueryClient()\n *\n * hydrate(queryClient, dehydratedState)\n * ```\n */\nexport function hydrate(\n  client: QueryClient,\n  dehydratedState: Partial<DehydratedState>,\n  options?: HydrateOptions,\n): void {\n  const mutationCache = client.getMutationCache()\n  const queryCache = client.getQueryCache()\n  const deserializeData =\n    options?.defaultOptions?.deserializeData ??\n    client.getDefaultOptions().hydrate?.deserializeData\n\n  dehydratedState.mutations?.forEach(({ state, ...mutationOptions }) => {\n    mutationCache.build(\n      client,\n      {\n        ...client.getDefaultOptions().hydrate?.mutations,\n        ...options?.defaultOptions?.mutations,\n        ...mutationOptions,\n      },\n      state,\n    )\n  })\n\n  dehydratedState.queries?.forEach(\n    ({\n      queryKey,\n      state,\n      queryHash,\n      meta,\n      promise,\n      dehydratedAt,\n      queryType,\n    }) => {\n      const syncData = promise ? tryResolveSync(promise) : undefined\n      const rawData = state.data === undefined ? syncData?.data : state.data\n      const data =\n        rawData === undefined\n          ? rawData\n          : deserializeData\n            ? deserializeData(rawData)\n            : rawData\n\n      let query = queryCache.get(queryHash)\n      const existingQueryIsPending = query?.state.status === 'pending'\n      const existingQueryIsFetching = query?.state.fetchStatus === 'fetching'\n\n      // Do not hydrate if an existing query exists with newer data\n      if (query) {\n        const hasNewerSyncData =\n          syncData && dehydratedAt > query.state.dataUpdatedAt\n        if (\n          state.dataUpdatedAt > query.state.dataUpdatedAt ||\n          hasNewerSyncData\n        ) {\n          // Omit fetchStatus from dehydrated state so that query stays in its current fetchStatus\n          const { fetchStatus: _ignored, ...serializedState } = state\n          query.setState({\n            ...serializedState,\n            data,\n            // If the query was pending at the moment of dehydration, but resolved to have data\n            // before hydration, we can assume the query should be hydrated as successful.\n            //\n            // Since you can opt into dehydrating failed queries, and those can have data from\n            // previous successful fetches, we make sure we only do this for pending queries.\n            ...(state.status === 'pending' &&\n              data !== undefined && {\n                status: 'success' as const,\n                dataUpdatedAt: dehydratedAt,\n                // Preserve existing fetchStatus if the existing query is actively fetching.\n                ...(!existingQueryIsFetching && {\n                  fetchStatus: 'idle' as const,\n                }),\n              }),\n          })\n        }\n      } else {\n        // Restore query\n        query = queryCache.build(\n          client,\n          {\n            ...client.getDefaultOptions().hydrate?.queries,\n            ...options?.defaultOptions?.queries,\n            queryKey,\n            queryHash,\n            meta,\n            _type: queryType,\n          },\n          // Reset fetch status to idle to avoid\n          // query being stuck in fetching state upon hydration\n          {\n            ...state,\n            data,\n            fetchStatus: 'idle',\n            // Like above, if the query was pending at the moment of dehydration but has data,\n            // we can assume it should be hydrated as successful.\n            status:\n              state.status === 'pending' && data !== undefined\n                ? 'success'\n                : state.status,\n            ...(state.status === 'pending' &&\n              data !== undefined && {\n                dataUpdatedAt: dehydratedAt,\n              }),\n          },\n        )\n      }\n\n      if (\n        promise &&\n        // If the data was synchronously available, there is no need to set up\n        // a retryer and thus no reason to call fetch\n        !syncData &&\n        !existingQueryIsPending &&\n        !existingQueryIsFetching &&\n        // Only hydrate if dehydration is newer than any existing data,\n        // this is always true for new queries\n        dehydratedAt > query.state.dataUpdatedAt\n      ) {\n        // This doesn't actually fetch - it just creates a retryer\n        // which will re-use the passed `initialPromise`\n        query\n          .fetch(undefined, {\n            // RSC transformed promises are not thenable\n            initialPromise: Promise.resolve(promise).then(deserializeData),\n          })\n          // Avoid unhandled promise rejections\n          .catch(noop)\n      }\n    },\n  )\n}\n"],"mappings":"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"}