{"version":3,"sources":["../../src/hydration.ts"],"sourcesContent":["import 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\nfunction defaultTransformerFn(data: any): any {\n  return data\n}\n\nexport interface DehydrateOptions {\n  serializeData?: TransformerFn\n  shouldDehydrateMutation?: (mutation: Mutation) => boolean\n  shouldDehydrateQuery?: (query: Query) => boolean\n}\n\nexport interface HydrateOptions {\n  defaultOptions?: {\n    deserializeData?: TransformerFn\n    queries?: QueryOptions\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  promise?: Promise<unknown>\n  meta?: QueryMeta\n}\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\n// Most config is not dehydrated but instead meant to configure again when\n// consuming the de/rehydrated data, typically with useQuery on the client.\n// Sometimes it might make sense to prefetch data on the server and include\n// in the html-payload, but not consume it on the initial render.\nfunction dehydrateQuery(\n  query: Query,\n  serializeData: TransformerFn,\n): DehydratedQuery {\n  return {\n    state: {\n      ...query.state,\n      ...(query.state.data !== undefined && {\n        data: serializeData(query.state.data),\n      }),\n    },\n    queryKey: query.queryKey,\n    queryHash: query.queryHash,\n    ...(query.state.status === 'pending' && {\n      promise: query.promise?.then(serializeData).catch((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    ...(query.meta && { meta: query.meta }),\n  }\n}\n\nexport function defaultShouldDehydrateMutation(mutation: Mutation) {\n  return mutation.state.isPaused\n}\n\nexport function defaultShouldDehydrateQuery(query: Query) {\n  return query.state.status === 'success'\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 serializeData =\n    options.serializeData ??\n    client.getDefaultOptions().dehydrate?.serializeData ??\n    defaultTransformerFn\n\n  const queries = client\n    .getQueryCache()\n    .getAll()\n    .flatMap((query) =>\n      filterQuery(query) ? [dehydrateQuery(query, serializeData)] : [],\n    )\n\n  return { mutations, queries }\n}\n\nexport function hydrate(\n  client: QueryClient,\n  dehydratedState: unknown,\n  options?: HydrateOptions,\n): void {\n  if (typeof dehydratedState !== 'object' || dehydratedState === null) {\n    return\n  }\n\n  const mutationCache = client.getMutationCache()\n  const queryCache = client.getQueryCache()\n  const deserializeData =\n    options?.defaultOptions?.deserializeData ??\n    client.getDefaultOptions().hydrate?.deserializeData ??\n    defaultTransformerFn\n\n  // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition\n  const mutations = (dehydratedState as DehydratedState).mutations || []\n  // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition\n  const queries = (dehydratedState as DehydratedState).queries || []\n\n  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  queries.forEach(({ queryKey, state, queryHash, meta, promise }) => {\n    let query = queryCache.get(queryHash)\n\n    const data =\n      state.data === undefined ? state.data : deserializeData(state.data)\n\n    // Do not hydrate if an existing query exists with newer data\n    if (query) {\n      if (query.state.dataUpdatedAt < state.dataUpdatedAt) {\n        // omit fetchStatus from dehydrated state\n        // so that query stays in its current fetchStatus\n        const { fetchStatus: _ignored, ...serializedState } = state\n        query.setState({\n          ...serializedState,\n          data,\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        },\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        },\n      )\n    }\n\n    if (promise) {\n      // Note: `Promise.resolve` required cause\n      // RSC transformed promises are not thenable\n      const initialPromise = Promise.resolve(promise).then(deserializeData)\n\n      // this doesn't actually fetch - it just creates a retryer\n      // which will re-use the passed `initialPromise`\n      void query.fetch(undefined, { initialPromise })\n    }\n  })\n}\n"],"mappings":"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","names":[]}