UNPKG

@tanstack/router-core

Version:

Modern and scalable routing for React applications

99 lines (86 loc) 2.38 kB
import type { AnyRouter } from '../router' export type SsrResponse = | { response: Response serverSsrCleanup: 'none' } | { response: Response serverSsrCleanup: 'stream' dispose: (reason?: unknown) => Promise<void> } export type HandlerCallbackResult = Response | SsrResponse export function isSsrResponse(value: unknown): value is SsrResponse { return ( typeof value === 'object' && value !== null && 'response' in value && 'serverSsrCleanup' in value ) } export function normalizeSsrResponse( result: HandlerCallbackResult, ): SsrResponse { return isSsrResponse(result) ? result : { response: result, serverSsrCleanup: 'none' } } export function createSsrStreamResponse<TRouter extends AnyRouter>( router: TRouter, response: Response, ): SsrResponse { if (!response.body) { throw new Error('Invariant failed: SSR stream response requires a body') } let disposed = false return { response, serverSsrCleanup: 'stream', async dispose(reason?: unknown) { if (disposed) return disposed = true try { await response.body!.cancel(reason) } catch { // ignore; fallback cleanup below still releases router SSR state } router.serverSsr?.cleanup() }, } } export async function replaceSsrResponse( result: HandlerCallbackResult, response: Response, reason?: unknown, ): Promise<SsrResponse> { const ssrResponse = normalizeSsrResponse(result) if (ssrResponse.serverSsrCleanup === 'stream') { await ssrResponse.dispose(reason) } return { response, serverSsrCleanup: 'none' } } export async function stripSsrResponseBody( result: HandlerCallbackResult, reason?: unknown, ): Promise<SsrResponse> { const ssrResponse = normalizeSsrResponse(result) if (ssrResponse.serverSsrCleanup === 'stream') { await ssrResponse.dispose(reason) } return { response: new Response(null, ssrResponse.response), serverSsrCleanup: 'none', } } export interface HandlerCallback<TRouter extends AnyRouter> { (ctx: { request: Request router: TRouter responseHeaders: Headers }): HandlerCallbackResult | Promise<HandlerCallbackResult> } export function defineHandlerCallback<TRouter extends AnyRouter>( handler: HandlerCallback<TRouter>, ): HandlerCallback<TRouter> { return handler }