{"version":3,"file":"createRequestHandler.cjs","names":[],"sources":["../../../src/ssr/createRequestHandler.ts"],"sourcesContent":["import { createMemoryHistory } from '@tanstack/history'\nimport { _getRenderedMatches } from '../load-client'\nimport { mergeHeaders } from './headers'\nimport {\n  attachRouterServerSsrUtils,\n  getNormalizedURL,\n  getOrigin,\n} from './ssr-server'\nimport {\n  bindSsrResponseToRequest,\n  disposeSsrResponseDetached,\n} from './handlerCallback'\nimport type { HandlerCallback } from './handlerCallback'\nimport type { AnyHeaders } from './headers'\nimport type { AnyRouter } from '../router'\nimport type { ServerManifest } from '../manifest'\n\nexport type RequestHandler<TRouter extends AnyRouter> = (\n  cb: HandlerCallback<TRouter>,\n) => Promise<Response>\n\ntype RequestWaiter = ((reason: unknown) => void) | undefined\n\nconst requestWaiters = new WeakMap<AbortSignal, Array<RequestWaiter>>()\n\nfunction removeRequestWaiter(\n  waiters: Array<RequestWaiter>,\n  index: number,\n  reject: (reason: unknown) => void,\n) {\n  if (waiters[index] !== reject) {\n    return\n  }\n  if (index !== waiters.length - 1) {\n    waiters[index] = undefined\n    return\n  }\n\n  waiters.pop()\n  while (waiters.length && waiters[waiters.length - 1] === undefined) {\n    waiters.pop()\n  }\n}\n\nexport function waitForRequest<T>(\n  value: T | PromiseLike<T>,\n  signal: AbortSignal,\n  onLate?: (value: T) => void,\n): Promise<T> {\n  const promise = Promise.resolve(value)\n  if (signal.aborted) {\n    void promise.then(onLate, () => {})\n    return Promise.reject(signal.reason)\n  }\n\n  return new Promise<T>((resolve, reject) => {\n    let waiters = requestWaiters.get(signal)\n    let index: number\n    if (waiters) {\n      index = waiters.push(reject) - 1\n    } else {\n      const newWaiters: Array<RequestWaiter> = [reject]\n      waiters = newWaiters\n      index = 0\n      requestWaiters.set(signal, newWaiters)\n      signal.addEventListener(\n        'abort',\n        () => {\n          requestWaiters.delete(signal)\n          for (const rejectWaiter of newWaiters) {\n            rejectWaiter?.(signal.reason)\n          }\n          newWaiters.length = 0\n        },\n        { once: true },\n      )\n    }\n    void promise.then(\n      (result) => {\n        removeRequestWaiter(waiters, index, reject)\n        if (signal.aborted) {\n          onLate?.(result)\n        } else {\n          resolve(result)\n        }\n      },\n      (error) => {\n        removeRequestWaiter(waiters, index, reject)\n        reject(error)\n      },\n    )\n  })\n}\n\nexport function createRequestHandler<TRouter extends AnyRouter>({\n  createRouter,\n  request,\n  getRouterManifest,\n}: {\n  createRouter: () => TRouter\n  request: Request\n  getRouterManifest?: () => ServerManifest | Promise<ServerManifest>\n}): RequestHandler<TRouter> {\n  return async (cb) => {\n    request.signal.throwIfAborted()\n    const router = createRouter()\n    let responseOwnsCleanup = false\n\n    try {\n      attachRouterServerSsrUtils({\n        router,\n        manifest: await waitForRequest(getRouterManifest?.(), request.signal),\n      })\n\n      // normalizing and sanitizing the pathname here for server, so we always deal with the same format during SSR.\n      const { url } = getNormalizedURL(request.url, 'http://localhost')\n      const origin = getOrigin(request)\n      const href = url.href.replace(url.origin, '')\n\n      // Create a history for the router\n      const history = createMemoryHistory({\n        initialEntries: [href],\n      })\n\n      // Update the router with the history and context\n      router.update({\n        history,\n        origin: router.options.origin ?? origin,\n      })\n\n      await router.load({\n        _signal: request.signal,\n      })\n      request.signal.throwIfAborted()\n\n      const result = router._serverResult\n      if (result?.type === 'redirect') {\n        return result.redirect\n      }\n\n      await waitForRequest(router.serverSsr?.dehydrate(), request.signal)\n      request.signal.throwIfAborted()\n\n      const responseHeaders = getRequestHeaders({\n        router,\n      })\n\n      request.signal.throwIfAborted()\n      const response = await waitForRequest(\n        cb({\n          request,\n          router,\n          responseHeaders,\n        }),\n        request.signal,\n        (late) => {\n          disposeSsrResponseDetached(late, request.signal.reason)\n        },\n      )\n      const ssrResponse = bindSsrResponseToRequest(\n        router,\n        response,\n        request.signal,\n      )\n      request.signal.throwIfAborted()\n      responseOwnsCleanup = ssrResponse.serverSsrCleanup === 'stream'\n      return ssrResponse.response\n    } finally {\n      if (!responseOwnsCleanup) {\n        // Clean up router SSR state if the callback won't handle it\n        // (e.g., if an error occurred before the callback was invoked).\n        // Transformed streaming response bodies clean up when consumed/cancelled.\n        router.serverSsr?.cleanup()\n      }\n    }\n  }\n}\n\nfunction getRequestHeaders(opts: { router: AnyRouter }): Headers {\n  const matchHeaders: Array<AnyHeaders> = []\n  for (const match of _getRenderedMatches(opts.router.stores.matches.get())) {\n    matchHeaders.push(match.headers)\n  }\n\n  return mergeHeaders(\n    {\n      'Content-Type': 'text/html; charset=UTF-8',\n    },\n    ...matchHeaders,\n  )\n}\n"],"mappings":"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"}