{"version":3,"file":"router-server.mjs","names":["createRouter","createTanStackRouter"],"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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"}