{"version":3,"file":"ssrPrepass.mjs","names":["result: TState","newError: TRPCClientErrorLike","ssrPrepass: TRPCPrepassHelper","appOrPageCtx: AppContextType","ctx: NextPageContext","pageProps: Dict","props: Record","trpcProp: $PrepassProps"],"sources":["../src/ssrPrepass.ts"],"sourcesContent":["/**\n * Heavily based on urql's ssr\n * https://github.com/FormidableLabs/urql/blob/main/packages/next-urql/src/with-urql-client.ts\n */\nimport type { DehydratedState } from '@tanstack/react-query';\nimport { dehydrate } from '@tanstack/react-query';\nimport { createTRPCUntypedClient } from '@trpc/client';\nimport type { TRPCClientError, TRPCClientErrorLike } from '@trpc/client';\nimport type { CoercedTransformerParameters } from '@trpc/client/unstable-internals';\nimport { getTransformer } from '@trpc/client/unstable-internals';\nimport { getQueryClient } from '@trpc/react-query/shared';\nimport type {\n AnyRouter,\n Dict,\n Maybe,\n} from '@trpc/server/unstable-core-do-not-import';\nimport type {\n AppContextType,\n NextPageContext,\n} from 'next/dist/shared/lib/utils';\nimport { createElement } from 'react';\nimport type { TRPCPrepassHelper, TRPCPrepassProps } from './withTRPC';\n\nfunction transformQueryOrMutationCacheErrors<\n TState extends\n | DehydratedState['mutations'][0]\n | DehydratedState['queries'][0],\n>(result: TState): TState {\n const error = result.state.error as Maybe>;\n if (error instanceof Error && error.name === 'TRPCClientError') {\n const newError: TRPCClientErrorLike = {\n message: error.message,\n data: error.data,\n shape: error.shape,\n };\n return {\n ...result,\n state: {\n ...result.state,\n error: newError,\n },\n };\n }\n return result;\n}\n\nexport const ssrPrepass: TRPCPrepassHelper = (opts) => {\n const { parent, WithTRPC, AppOrPage } = opts;\n type $PrepassProps = TRPCPrepassProps;\n\n const transformer = getTransformer(\n (parent as CoercedTransformerParameters).transformer,\n );\n WithTRPC.getInitialProps = async (appOrPageCtx: AppContextType) => {\n const shouldSsr = async () => {\n if (typeof window !== 'undefined') {\n return false;\n }\n if (typeof parent.ssr === 'function') {\n try {\n return await parent.ssr({ ctx: appOrPageCtx.ctx });\n } catch {\n return false;\n }\n }\n return parent.ssr;\n };\n const ssrEnabled = await shouldSsr();\n const AppTree = appOrPageCtx.AppTree;\n\n // Determine if we are wrapping an App component or a Page component.\n const isApp = !!appOrPageCtx.Component;\n const ctx: NextPageContext = isApp\n ? appOrPageCtx.ctx\n : (appOrPageCtx as any as NextPageContext);\n\n // Run the wrapped component's getInitialProps function.\n let pageProps: Dict = {};\n if (AppOrPage.getInitialProps) {\n const originalProps = await AppOrPage.getInitialProps(\n appOrPageCtx as any,\n );\n const originalPageProps = isApp\n ? (originalProps.pageProps ?? {})\n : originalProps;\n\n pageProps = {\n ...originalPageProps,\n ...pageProps,\n };\n }\n const getAppTreeProps = (props: Record) =>\n isApp ? { pageProps: props } : props;\n\n if (typeof window !== 'undefined' || !ssrEnabled) {\n return getAppTreeProps(pageProps);\n }\n\n const config = parent.config({ ctx });\n const trpcClient = createTRPCUntypedClient(config);\n const queryClient = getQueryClient(config);\n\n const trpcProp: $PrepassProps = {\n config,\n trpcClient,\n queryClient,\n ssrState: 'prepass',\n ssrContext: ctx,\n };\n const prepassProps = {\n pageProps,\n trpc: trpcProp,\n };\n\n const reactDomServer = await import('react-dom/server');\n\n // Run the prepass step on AppTree. This will run all trpc queries on the server.\n // multiple prepass ensures that we can do batching on the server\n while (true) {\n // render full tree\n reactDomServer.renderToString(createElement(AppTree, prepassProps));\n if (!queryClient.isFetching()) {\n // the render didn't cause the queryClient to fetch anything\n break;\n }\n\n // wait until the query cache has settled it's promises\n await new Promise((resolve) => {\n const unsub = queryClient.getQueryCache().subscribe((event) => {\n if (event?.query.getObserversCount() === 0) {\n resolve();\n unsub();\n }\n });\n });\n }\n const dehydratedCache = dehydrate(queryClient, {\n shouldDehydrateQuery(query) {\n // filter out queries that are marked as trpc: { ssr: false } or are not enabled, but make sure errors are dehydrated\n const isExcludedFromSSr =\n query.state.fetchStatus === 'idle' &&\n query.state.status === 'pending';\n return !isExcludedFromSSr;\n },\n });\n // since error instances can't be serialized, let's make them into `TRPCClientErrorLike`-objects\n const dehydratedCacheWithErrors = {\n ...dehydratedCache,\n queries: dehydratedCache.queries.map(transformQueryOrMutationCacheErrors),\n mutations: dehydratedCache.mutations.map(\n transformQueryOrMutationCacheErrors,\n ),\n };\n\n // dehydrate query client's state and add it to the props\n pageProps['trpcState'] = transformer.input.serialize(\n dehydratedCacheWithErrors,\n );\n\n const appTreeProps = getAppTreeProps(pageProps);\n\n const meta =\n parent.responseMeta?.({\n ctx,\n clientErrors: [...dehydratedCache.queries, ...dehydratedCache.mutations]\n .map((v) => v.state.error)\n .flatMap((err) =>\n err instanceof Error && err.name === 'TRPCClientError'\n ? [err as TRPCClientError]\n : [],\n ),\n }) ?? {};\n\n for (const [key, value] of Object.entries(meta.headers ?? {})) {\n if (typeof value === 'string') {\n ctx.res?.setHeader(key, value);\n }\n }\n if (meta.status && ctx.res) {\n ctx.res.statusCode = meta.status;\n }\n\n return appTreeProps;\n };\n};\n"],"mappings":"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"}