everything-dev
Version:
A consolidated product package for building Module Federation apps with oRPC APIs.
1 lines • 11.1 kB
Source Map (JSON)
{"version":3,"file":"router-server.cjs","names":["defaultQueryClient","createMemoryHistory","createTanStackRouter","createAuthClient","RouterError","dehydrate","QueryClient","createApiClient","collectHeadData","createRequestHandler","resolveLocale","readAcceptLanguage","renderRouterToStream","QueryClientProvider","RouterServer"],"sources":["../../src/ui/router-server.tsx"],"sourcesContent":["/**\n * SSR router factory — creates request-scoped server routers and server-side\n * API/auth clients per request. Mirrors the client router shape for\n * hydration consistency. The app injects its generated route tree and (for\n * a byte-identical child surface) its error component.\n */\n\nimport { dehydrate, hydrate, QueryClient, QueryClientProvider } from \"@tanstack/react-query\";\nimport {\n type AnyRoute,\n type AnyRouter,\n createMemoryHistory,\n createRouter as createTanStackRouter,\n} from \"@tanstack/react-router\";\nimport {\n createRequestHandler,\n RouterServer,\n renderRouterToStream,\n} from \"@tanstack/react-router/ssr/server\";\nimport { createApiClient } from \"./api\";\nimport { createAuthClient } from \"./auth\";\nimport { type LocaleOptions, readAcceptLanguage, resolveLocale } from \"./locale\";\nimport { collectHeadData } from \"./router\";\nimport {\n defaultNotFoundComponent,\n defaultPendingComponent,\n defaultQueryClient,\n} from \"./router-defaults\";\nimport { RouterError } from \"./router-error\";\nimport type {\n AppRouterFactory,\n CreateRouterOptions,\n HeadData,\n RenderOptionsWithApi,\n RenderResult,\n RouterContextWithApi,\n} from \"./types\";\n\nexport interface ServerRouterModuleOptions<TRouteTree extends AnyRoute = AnyRoute> {\n /** The app's generated route tree — the core-only fallback when no composed tree is passed. */\n defaultRouteTree?: TRouteTree;\n /**\n * The app's authored router factory — SSR parity: each request's router is\n * minted through the same factory the client hydrates with, so notFound/\n * pending/error options match. Absent, the framework's own factory runs.\n */\n createRouter?: AppRouterFactory;\n /** The app's query client factory (staleTime, gcTime, …) — SSR parity with the client hydrator. Absent, the framework default. */\n createQueryClient?: () => QueryClient;\n /** Locale negotiation for SSR — resolves the request-scoped locale into router context. */\n locale?: LocaleOptions;\n}\n\ntype ServerRouterOptions<TRouteTree extends AnyRoute> = CreateRouterOptions & {\n context?: Partial<RouterContextWithApi> & { pluginNav?: unknown };\n routeTree?: TRouteTree;\n};\n\nexport function createServerRouterModule<TRouteTree extends AnyRoute = AnyRoute>(\n options: ServerRouterModuleOptions<TRouteTree> = {},\n) {\n const defaultRouteTree = options.defaultRouteTree;\n\n const createRouter = (\n opts?: ServerRouterOptions<TRouteTree>,\n ): { router: AnyRouter; queryClient: QueryClient } => {\n const context = opts?.context;\n const queryClient = context?.queryClient ?? defaultQueryClient();\n\n const history = opts?.history ?? createMemoryHistory();\n\n const cspNonce = context?.cspNonce;\n // RouterCore's `in out` type parameters reject the framework's loose\n // AnyRouter contract when the tree is typed as the wide AnyRoute — the\n // runtime instance genuinely satisfies it, so the boundary casts once.\n const router = createTanStackRouter({\n routeTree: (opts?.routeTree ?? defaultRouteTree) as TRouteTree,\n history,\n basepath: opts?.basepath,\n context: {\n queryClient,\n runtimeConfig: context?.runtimeConfig,\n apiClient: context?.apiClient,\n authClient:\n context?.authClient ??\n createAuthClient({\n runtimeConfig: context?.runtimeConfig,\n cspNonce: context?.cspNonce,\n }),\n session: context?.session,\n cspNonce,\n locale: context?.locale,\n pluginNav: context?.pluginNav,\n },\n ...(cspNonce ? { ssr: { nonce: cspNonce } } : {}),\n defaultPreload: \"intent\",\n scrollRestoration: true,\n defaultStructuralSharing: true,\n defaultPreloadStaleTime: 0,\n defaultErrorComponent: RouterError,\n defaultOnCatch: (error, errorInfo) => {\n console.error(\"[SSR] Router error boundary caught:\", error, {\n componentStack: errorInfo.componentStack,\n });\n },\n defaultNotFoundComponent,\n defaultPendingComponent,\n defaultPendingMinMs: 0,\n dehydrate: () => {\n if (typeof window === \"undefined\") {\n return { queryClientState: dehydrate(queryClient) };\n }\n\n return { queryClientState: {} };\n },\n hydrate: (dehydrated: { queryClientState?: unknown }) => {\n if (typeof window !== \"undefined\" && dehydrated?.queryClientState) {\n hydrate(queryClient, dehydrated.queryClientState);\n }\n },\n });\n\n return { router, queryClient };\n };\n\n // SSR parity seam: the app's authored factory (client and server mint\n // through the same code) or the framework's own.\n const buildRouter = options.createRouter ?? createRouter;\n\n const getRouteHead = async (\n pathname: string,\n context?: Partial<RouterContextWithApi> & { routeTree?: TRouteTree },\n ): Promise<HeadData> => {\n const history = createMemoryHistory({ initialEntries: [pathname] });\n const queryClient = new QueryClient();\n const runtimeConfig = context?.runtimeConfig;\n if (!runtimeConfig?.hostUrl || !runtimeConfig.rpcBase) {\n throw new Error(\"Missing runtime config for route head generation\");\n }\n\n const router = createTanStackRouter({\n routeTree: context?.routeTree ?? defaultRouteTree,\n history,\n context: {\n queryClient,\n runtimeConfig,\n apiClient:\n context?.apiClient ??\n createApiClient({ hostUrl: runtimeConfig.hostUrl, rpcBase: runtimeConfig.rpcBase }),\n authClient:\n context?.authClient ?? createAuthClient({ runtimeConfig, cspNonce: context?.cspNonce }),\n session: context?.session,\n locale: context?.locale,\n },\n });\n\n return collectHeadData(router);\n };\n\n const renderToStream = async (\n request: Request,\n renderOptions: RenderOptionsWithApi,\n ): Promise<RenderResult> => {\n const url = new URL(request.url);\n const history = createMemoryHistory({ initialEntries: [url.pathname + url.search] });\n let queryClientRef: QueryClient | null = null;\n\n const handler = createRequestHandler({\n request,\n createRouter: () => {\n const localQueryClient =\n queryClientRef ?? options.createQueryClient?.() ?? defaultQueryClient();\n const built = buildRouter({\n history,\n routeTree: renderOptions.routeTree as TRouteTree,\n basepath: renderOptions.basepath,\n context: {\n queryClient: localQueryClient,\n runtimeConfig: renderOptions.runtimeConfig,\n apiClient: renderOptions.apiClient,\n authClient: createAuthClient({\n runtimeConfig: renderOptions.runtimeConfig,\n headers: request.headers,\n cspNonce: renderOptions.cspNonce,\n }),\n session: renderOptions.session,\n cspNonce: renderOptions.cspNonce,\n pluginNav: renderOptions.pluginNav,\n locale: options.locale\n ? resolveLocale({\n ...options.locale,\n cookie: request.headers.get(\"cookie\") ?? \"\",\n browserLocales: readAcceptLanguage(request.headers.get(\"accept-language\")),\n })\n : undefined,\n },\n });\n queryClientRef = built.queryClient ?? localQueryClient;\n return built.router;\n },\n });\n\n const response = await handler(({ request, responseHeaders, router }) =>\n renderRouterToStream({\n request,\n responseHeaders,\n router,\n children: (\n <QueryClientProvider client={queryClientRef!}>\n <RouterServer router={router} />\n </QueryClientProvider>\n ),\n }),\n );\n\n if (options.locale) response.headers.append(\"Vary\", \"Cookie, Accept-Language\");\n\n return {\n stream: response.body!,\n statusCode: response.status,\n headers: response.headers,\n } satisfies RenderResult;\n };\n\n return {\n createRouter,\n getRouteHead,\n renderToStream,\n };\n}\n"],"mappings":"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"}