{"version":3,"file":"ssr-server.cjs","names":[],"sources":["../../../src/ssr/ssr-server.ts"],"sourcesContent":["import { crossSerializeStream, getCrossReferenceHeader } from 'seroval'\nimport { invariant } from '../invariant'\nimport {\n  createInlineCssPlaceholderAsset,\n  createInlineCssStyleAsset,\n  getStylesheetHref,\n} from '../manifest'\nimport { decodePath } from '../utils'\nimport { createLRUCache } from '../lru-cache'\nimport { rootRouteId } from '../root'\nimport minifiedTsrBootStrapScript from './tsrScript?script-string'\nimport { GLOBAL_TSR, TSR_SCRIPT_BARRIER_ID } from './constants'\nimport { dehydrateSsrMatchId } from './ssr-match-id'\nimport { defaultSerovalPlugins } from './serializer/seroval-plugins'\nimport { makeSsrSerovalPlugin } from './serializer/transformer'\nimport type { LRUCache } from '../lru-cache'\nimport type { DehydratedMatch, DehydratedRouter } from './types'\nimport type { AnySerializationAdapter } from './serializer/transformer'\nimport type { AnyRouter, ServerSsr } from '../router'\nimport type { AnyRouteMatch } from '../Matches'\nimport type {\n  Manifest,\n  ManifestRoute,\n  ManifestRouteAssets,\n  RouterManagedTag,\n  ServerManifest,\n} from '../manifest'\n\nconst SCOPE_ID = 'tsr'\n\nconst TSR_PREFIX = GLOBAL_TSR + '.router='\nconst P_PREFIX = GLOBAL_TSR + '.p(()=>'\nconst P_SUFFIX = ')'\n\nexport function dehydrateMatch(match: AnyRouteMatch): DehydratedMatch {\n  const dehydratedMatch: DehydratedMatch = {\n    i: dehydrateSsrMatchId(match.id),\n    u: match.updatedAt,\n    s: match.status,\n  }\n\n  const properties = [\n    ['__beforeLoadContext', 'b'],\n    ['loaderData', 'l'],\n    ['error', 'e'],\n    ['ssr', 'ssr'],\n  ] as const\n\n  for (const [key, shorthand] of properties) {\n    if (match[key] !== undefined) {\n      dehydratedMatch[shorthand] = match[key]\n    }\n  }\n  if (match.globalNotFound) {\n    dehydratedMatch.g = true\n  }\n  return dehydratedMatch\n}\n\nconst INITIAL_SCRIPTS = [\n  getCrossReferenceHeader(SCOPE_ID),\n  minifiedTsrBootStrapScript,\n]\n\nclass ScriptBuffer {\n  private injectScript: ((script: string) => void) | undefined\n  private _queue: Array<string>\n  private _scriptBarrierLifted = false\n  private _cleanedUp = false\n  private _microtaskVersion = 0\n  private _pendingMicrotaskVersion = 0\n\n  constructor(injectScript: (script: string) => void) {\n    this.injectScript = injectScript\n    // Copy INITIAL_SCRIPTS to avoid mutating the shared array\n    this._queue = INITIAL_SCRIPTS.slice()\n  }\n\n  enqueue(script: string) {\n    if (this._cleanedUp) return\n    this._queue.push(script)\n    if (this._scriptBarrierLifted) {\n      this.scheduleInjectBufferedScripts()\n    }\n  }\n\n  liftBarrier() {\n    if (this._scriptBarrierLifted || this._cleanedUp) return\n    this._scriptBarrierLifted = true\n    if (this._queue.length > 0) {\n      this.scheduleInjectBufferedScripts()\n    }\n  }\n\n  scheduleInjectBufferedScripts() {\n    if (this._pendingMicrotaskVersion !== 0) return\n    const pendingVersion = ++this._microtaskVersion\n    this._pendingMicrotaskVersion = pendingVersion\n    queueMicrotask(() => {\n      if (this._pendingMicrotaskVersion !== pendingVersion) return\n      this._pendingMicrotaskVersion = 0\n      this.injectBufferedScripts()\n    })\n  }\n\n  clearPendingMicrotask() {\n    if (this._pendingMicrotaskVersion === 0) return\n    this._pendingMicrotaskVersion = 0\n    this._microtaskVersion++\n  }\n\n  /**\n   * Flushes any pending scripts synchronously.\n   * Call this before signaling serialization finished to ensure all scripts are injected.\n   *\n   * IMPORTANT: Only injects if the barrier has been lifted. Before the barrier is lifted,\n   * scripts should remain in the queue so takeBufferedScripts() can retrieve them\n   */\n  flush() {\n    if (!this._scriptBarrierLifted) return\n    if (this._cleanedUp) return\n    this.clearPendingMicrotask()\n    this.injectBufferedScripts()\n  }\n\n  takeAll() {\n    return this.takeScripts(this._queue.length)\n  }\n\n  takeScripts(count: number) {\n    if (count <= 0) return undefined\n    const bufferedScripts = this._queue.splice(0, count)\n    if (bufferedScripts.length === 0) {\n      return undefined\n    }\n    // Optimization: if only one script, avoid join\n    if (bufferedScripts.length === 1) {\n      return bufferedScripts[0] + ';document.currentScript.remove()'\n    }\n    // Append cleanup script and join - avoid push() to not mutate then iterate\n    return bufferedScripts.join(';') + ';document.currentScript.remove()'\n  }\n\n  hasPending() {\n    return this._queue.length > 0\n  }\n\n  injectBufferedScripts() {\n    if (this._cleanedUp) return\n    // Early return if queue is empty (avoids unnecessary takeAll() call)\n    if (this._queue.length === 0) return\n    const scriptsToInject = this.takeAll()\n    if (scriptsToInject) {\n      this.injectScript?.(scriptsToInject)\n    }\n  }\n\n  cleanup() {\n    this._cleanedUp = true\n    this.clearPendingMicrotask()\n    this._queue = []\n    this.injectScript = undefined\n  }\n}\n\nconst isProd = process.env.NODE_ENV === 'production'\n\ntype FilteredRoutes = Manifest['routes']\n\ntype PreparedMatchedManifestRoutes = {\n  routes: FilteredRoutes\n  hasStrippedRoutes: boolean\n  inlineCssHrefs?: Array<string>\n  inlineCss?: string\n}\n\ntype ManifestLRU = LRUCache<string, PreparedMatchedManifestRoutes>\n\nconst MANIFEST_CACHE_SIZE = 100\nconst manifestCaches = new WeakMap<ServerManifest, ManifestLRU>()\n\nfunction getManifestCache(manifest: ServerManifest): ManifestLRU {\n  const cache = manifestCaches.get(manifest)\n  if (cache) return cache\n  const newCache = createLRUCache<string, PreparedMatchedManifestRoutes>(\n    MANIFEST_CACHE_SIZE,\n  )\n  manifestCaches.set(manifest, newCache)\n  return newCache\n}\n\nfunction getInlineCssForPreparedRoutes(\n  manifest: ServerManifest,\n  preparedRoutes: PreparedMatchedManifestRoutes,\n) {\n  if (preparedRoutes.inlineCss !== undefined) return preparedRoutes.inlineCss\n\n  const styles = manifest.inlineCss?.styles\n  const hrefs = preparedRoutes.inlineCssHrefs\n  if (!styles || !hrefs?.length) return undefined\n\n  let css = ''\n  for (const href of hrefs) {\n    css += styles[href]!\n  }\n\n  preparedRoutes.inlineCss = css\n  return css\n}\n\nfunction getInlineCssAssetForPreparedRoutes(\n  manifest: ServerManifest,\n  preparedRoutes: PreparedMatchedManifestRoutes,\n) {\n  const css = getInlineCssForPreparedRoutes(manifest, preparedRoutes)\n\n  return css === undefined ? undefined : createInlineCssStyleAsset(css)\n}\n\nfunction getMatchedRoutesCacheKey(matches: Array<AnyRouteMatch>) {\n  let cacheKey = ''\n  for (let i = 0; i < matches.length; i++) {\n    cacheKey += (i === 0 ? '' : '\\0') + matches[i]!.routeId\n  }\n  return cacheKey\n}\n\nfunction getPreparedMatchedManifestRoutes(\n  manifest: ServerManifest,\n  matches: Array<AnyRouteMatch>,\n  cacheKey: string,\n) {\n  if (isProd) {\n    const cached = getManifestCache(manifest).get(cacheKey)\n    if (cached) {\n      return cached\n    }\n  }\n\n  const preparedRoutes = prepareMatchedManifestRoutes(manifest, matches)\n\n  if (isProd) {\n    getManifestCache(manifest).set(cacheKey, preparedRoutes)\n  }\n\n  return preparedRoutes\n}\n\nfunction prepareMatchedManifestRoutes(\n  manifest: ServerManifest,\n  matches: Array<AnyRouteMatch>,\n): PreparedMatchedManifestRoutes {\n  const inlineStyles = manifest.inlineCss?.styles\n  const routes: FilteredRoutes = {}\n\n  if (!inlineStyles) {\n    for (const match of matches) {\n      const route = manifest.routes[match.routeId]\n      if (route) {\n        routes[match.routeId] = route\n      }\n    }\n    return { routes, hasStrippedRoutes: false }\n  }\n\n  const inlineCssHrefs: Array<string> = []\n  const seenInlineCssHrefs = new Set<string>()\n  let hasStrippedRoutes = false\n\n  for (const match of matches) {\n    const routeId = match.routeId\n    const route = manifest.routes[routeId]\n    if (!route) {\n      continue\n    }\n\n    const nextRoute = stripInlinedStylesheetAssetsFromRoute(\n      inlineStyles,\n      route,\n      inlineCssHrefs,\n      seenInlineCssHrefs,\n    )\n\n    if (nextRoute !== route) {\n      hasStrippedRoutes = true\n    }\n    routes[routeId] = nextRoute\n  }\n\n  return {\n    routes,\n    hasStrippedRoutes,\n    ...(inlineCssHrefs.length ? { inlineCssHrefs } : {}),\n  }\n}\n\nfunction stripInlinedStylesheetAssetsFromRoute(\n  inlineStyles: Record<string, string>,\n  route: ManifestRoute,\n  inlineCssHrefs: Array<string>,\n  seenInlineCssHrefs: Set<string>,\n): ManifestRoute {\n  const css = route.css\n  if (!css) {\n    return route\n  }\n\n  if (css.length === 0) {\n    const nextRoute = { ...route }\n    delete nextRoute.css\n    return nextRoute\n  }\n\n  let cssLinks: typeof css | undefined\n  for (let i = 0; i < css.length; i++) {\n    const link = css[i]!\n    const href = getStylesheetHref(link)\n    if (inlineStyles[href] === undefined) {\n      if (cssLinks) {\n        cssLinks.push(link)\n      }\n      continue\n    }\n\n    if (!seenInlineCssHrefs.has(href)) {\n      seenInlineCssHrefs.add(href)\n      inlineCssHrefs.push(href)\n    }\n\n    if (!cssLinks) {\n      cssLinks = css.slice(0, i)\n    }\n  }\n\n  if (!cssLinks) {\n    return route\n  }\n\n  if (cssLinks.length > 0) {\n    return { ...route, css: cssLinks }\n  }\n\n  const nextRoute = { ...route }\n  delete nextRoute.css\n  return nextRoute\n}\n\nfunction hasRouteAssets(route: ManifestRoute) {\n  return !!route.scripts?.length || !!route.css?.length\n}\n\nfunction hasRequestAssets(assets: ManifestRouteAssets | undefined) {\n  return !!assets && (!!assets.preloads?.length || hasRouteAssets(assets))\n}\n\nfunction mergeRequestAssetsIntoRootRoute(\n  rootRoute: ManifestRoute | undefined,\n  requestAssets: ManifestRouteAssets | undefined,\n): ManifestRoute {\n  const preloads = requestAssets?.preloads?.length\n    ? [...requestAssets.preloads, ...(rootRoute?.preloads ?? [])]\n    : rootRoute?.preloads\n  const scripts = requestAssets?.scripts?.length\n    ? [...requestAssets.scripts, ...(rootRoute?.scripts ?? [])]\n    : rootRoute?.scripts\n  const cssLinks = requestAssets?.css?.length\n    ? [...requestAssets.css, ...(rootRoute?.css ?? [])]\n    : rootRoute?.css\n\n  return {\n    ...(rootRoute ?? {}),\n    ...(preloads?.length ? { preloads } : {}),\n    ...(scripts?.length ? { scripts } : {}),\n    ...(cssLinks?.length ? { css: cssLinks } : {}),\n  }\n}\n\nexport function attachRouterServerSsrUtils({\n  router,\n  manifest,\n  getRequestAssets,\n}: {\n  router: AnyRouter\n  manifest: ServerManifest | undefined\n  getRequestAssets?: () => ManifestRouteAssets | undefined\n}) {\n  router.ssr = {\n    get manifest() {\n      if (!manifest) return manifest\n\n      const requestAssets = getRequestAssets?.()\n      const matches = router.stores.matches.get()\n      const hasAssets = hasRequestAssets(requestAssets)\n\n      if (!hasAssets && !manifest.inlineCss) {\n        return manifest\n      }\n\n      let inlineCssAsset: Manifest['inlineStyle'] | undefined\n      let routes = manifest.routes\n      if (manifest.inlineCss) {\n        const cacheKey = getMatchedRoutesCacheKey(matches)\n        const preparedManifest = getPreparedMatchedManifestRoutes(\n          manifest,\n          matches,\n          cacheKey,\n        )\n        inlineCssAsset = getInlineCssAssetForPreparedRoutes(\n          manifest,\n          preparedManifest,\n        )\n        if (preparedManifest.hasStrippedRoutes) {\n          routes = { ...manifest.routes, ...preparedManifest.routes }\n        }\n      }\n\n      if (!hasAssets) {\n        return {\n          ...(manifest.scriptFormat\n            ? { scriptFormat: manifest.scriptFormat }\n            : {}),\n          ...(inlineCssAsset ? { inlineStyle: inlineCssAsset } : {}),\n          routes,\n        }\n      }\n\n      const rootRoute = routes[rootRouteId]\n\n      // Merge request-scoped assets into root route without mutating cached manifest\n      return {\n        ...(manifest.scriptFormat\n          ? { scriptFormat: manifest.scriptFormat }\n          : {}),\n        ...(inlineCssAsset ? { inlineStyle: inlineCssAsset } : {}),\n        routes: {\n          ...routes,\n          [rootRouteId]: mergeRequestAssetsIntoRootRoute(\n            rootRoute,\n            requestAssets,\n          ),\n        },\n      }\n    },\n  }\n  let _dehydrated = false\n  let _serializationFinished = false\n  let streamFastPathReserved = false\n  const renderFinishedListeners: Array<() => void> = []\n  const injectedHtmlListeners: Array<() => void> = []\n  const serializationFinishedListeners: Array<() => void> = []\n  const cleanupListeners: Array<() => void> = []\n  let cleanupStarted = false\n  let injectedHtmlBuffer = ''\n\n  const callListeners = (listeners: Array<() => void>, errorPrefix: string) => {\n    const snapshot = listeners.slice()\n    for (const l of snapshot) {\n      try {\n        l()\n      } catch (err) {\n        console.error(`${errorPrefix}:`, err)\n      }\n    }\n  }\n\n  const removeListener = (\n    listeners: Array<() => void>,\n    listener: () => void,\n  ) => {\n    const index = listeners.indexOf(listener)\n    if (index >= 0) listeners.splice(index, 1)\n  }\n\n  const scriptBuffer = new ScriptBuffer((script) => {\n    serverSsr.injectScript(script)\n  })\n\n  const serverSsr: ServerSsr = {\n    injectHtml: (html: string) => {\n      if (!html || cleanupStarted) return\n      // Buffer the HTML so it can be retrieved via takeBufferedHtml()\n      injectedHtmlBuffer += html\n      callListeners(injectedHtmlListeners, 'SSR injected HTML listener error')\n    },\n    injectScript: (script: string) => {\n      if (!script || cleanupStarted) return\n      const html = `<script${router.options.ssr?.nonce ? ` nonce='${router.options.ssr.nonce}'` : ''}>${script}</script>`\n      serverSsr.injectHtml(html)\n    },\n    dehydrate: async (opts?: { requestAssets?: ManifestRouteAssets }) => {\n      if (_dehydrated) {\n        if (process.env.NODE_ENV !== 'production') {\n          throw new Error('Invariant failed: router is already dehydrated!')\n        }\n\n        invariant()\n      }\n      let matchesToDehydrate = router.stores.matches.get()\n      if (router.isShell()) {\n        // In SPA mode we only want to dehydrate the root match\n        matchesToDehydrate = matchesToDehydrate.slice(0, 1)\n      }\n      const matches = matchesToDehydrate.map(dehydrateMatch)\n\n      let manifestToDehydrate: Manifest | undefined = undefined\n      // Only currently matched routes are dehydrated. Other route assets are\n      // loaded through dynamic imports when those routes become active.\n      if (manifest) {\n        const cacheKey = getMatchedRoutesCacheKey(matchesToDehydrate)\n        const preparedManifest = getPreparedMatchedManifestRoutes(\n          manifest,\n          matchesToDehydrate,\n          cacheKey,\n        )\n\n        manifestToDehydrate = {\n          ...(manifest.scriptFormat\n            ? { scriptFormat: manifest.scriptFormat }\n            : {}),\n          ...(preparedManifest.inlineCssHrefs\n            ? { inlineStyle: createInlineCssPlaceholderAsset() }\n            : {}),\n          routes: preparedManifest.routes,\n        }\n\n        // Merge request-scoped assets into root route (without mutating cached manifest)\n        const requestAssets = opts?.requestAssets\n        if (hasRequestAssets(requestAssets)) {\n          const existingRoot = manifestToDehydrate.routes[rootRouteId]\n          manifestToDehydrate.routes = {\n            ...manifestToDehydrate.routes,\n            [rootRouteId]: mergeRequestAssetsIntoRootRoute(\n              existingRoot,\n              requestAssets,\n            ),\n          }\n        }\n      }\n      const dehydratedRouter: DehydratedRouter = {\n        manifest: manifestToDehydrate,\n        matches,\n      }\n      const lastMatchId = matchesToDehydrate[matchesToDehydrate.length - 1]?.id\n      if (lastMatchId) {\n        dehydratedRouter.lastMatchId = dehydrateSsrMatchId(lastMatchId)\n      }\n      const dehydratedData = await router.options.dehydrate?.()\n      if (dehydratedData) {\n        dehydratedRouter.dehydratedData = dehydratedData\n      }\n      _dehydrated = true\n\n      const trackPlugins = { didRun: false }\n      const serializationAdapters = router.options.serializationAdapters as\n        | Array<AnySerializationAdapter>\n        | undefined\n      const plugins = serializationAdapters\n        ? serializationAdapters\n            .map((t) => makeSsrSerovalPlugin(t, trackPlugins))\n            .concat(defaultSerovalPlugins)\n        : defaultSerovalPlugins\n\n      let serializationCompleteSignaled = false\n      const signalSerializationComplete = () => {\n        if (serializationCompleteSignaled || cleanupStarted) return\n        serializationCompleteSignaled = true\n        _serializationFinished = true\n\n        const listeners = serializationFinishedListeners.slice()\n        serializationFinishedListeners.length = 0\n\n        for (const l of listeners) {\n          try {\n            l()\n          } catch (err) {\n            console.error('Serialization listener error:', err)\n          }\n        }\n      }\n\n      const finishScriptSerialization = () => {\n        if (serializationCompleteSignaled || cleanupStarted) return\n        scriptBuffer.enqueue(GLOBAL_TSR + '.e()')\n        // Must synchronously notify injected HTML listeners before signaling\n        // completion; otherwise the held </body> tail could flush ahead of the\n        // end script.\n        scriptBuffer.flush()\n        signalSerializationComplete()\n      }\n\n      crossSerializeStream(dehydratedRouter, {\n        refs: new Map(),\n        plugins,\n        onSerialize: (data, initial) => {\n          let serialized = initial ? TSR_PREFIX + data : data\n          if (trackPlugins.didRun) {\n            serialized = P_PREFIX + serialized + P_SUFFIX\n          }\n          scriptBuffer.enqueue(serialized)\n        },\n        onError: (err: unknown) => {\n          console.error('Serialization error:', err)\n          if (err && (err as any).stack) {\n            console.error((err as any).stack)\n          }\n          finishScriptSerialization()\n        },\n        scopeId: SCOPE_ID,\n        onDone: () => {\n          finishScriptSerialization()\n        },\n      })\n    },\n    isDehydrated() {\n      return _dehydrated\n    },\n    isSerializationFinished() {\n      return _serializationFinished\n    },\n    reserveStreamFastPath() {\n      if (\n        !cleanupStarted &&\n        _serializationFinished &&\n        !streamFastPathReserved &&\n        renderFinishedListeners.length === 0 &&\n        !injectedHtmlBuffer &&\n        !scriptBuffer.hasPending()\n      ) {\n        streamFastPathReserved = true\n        return true\n      }\n      return false\n    },\n    onInjectedHtml: (listener) => {\n      if (cleanupStarted) return () => {}\n      injectedHtmlListeners.push(listener)\n      return () => removeListener(injectedHtmlListeners, listener)\n    },\n    onRenderFinished: (listener) => {\n      if (cleanupStarted || streamFastPathReserved) return\n      renderFinishedListeners.push(listener)\n    },\n    onSerializationFinished: (listener) => {\n      if (cleanupStarted) return () => {}\n      if (_serializationFinished && !cleanupStarted) {\n        try {\n          listener()\n        } catch (err) {\n          console.error('Serialization listener error:', err)\n        }\n        return () => {}\n      }\n      serializationFinishedListeners.push(listener)\n      return () => removeListener(serializationFinishedListeners, listener)\n    },\n    onCleanup: (listener) => {\n      if (cleanupStarted) return\n      cleanupListeners.push(listener)\n    },\n    setRenderFinished: () => {\n      if (cleanupStarted) return\n      scriptBuffer.liftBarrier()\n      const listeners = renderFinishedListeners.slice()\n      renderFinishedListeners.length = 0\n      for (const l of listeners) {\n        try {\n          l()\n        } catch (err) {\n          console.error('Error in render finished listener:', err)\n        }\n      }\n      if (_serializationFinished) {\n        scriptBuffer.flush()\n      }\n    },\n    takeBufferedScripts() {\n      const scripts = scriptBuffer.takeAll()\n      if (!scripts) return undefined\n      const serverBufferedScript: RouterManagedTag = {\n        tag: 'script',\n        attrs: {\n          nonce: router.options.ssr?.nonce,\n          className: '$tsr',\n          id: TSR_SCRIPT_BARRIER_ID,\n        },\n        children: scripts,\n      }\n      return serverBufferedScript\n    },\n    liftScriptBarrier() {\n      scriptBuffer.liftBarrier()\n    },\n    takeBufferedHtml() {\n      if (!injectedHtmlBuffer) {\n        return undefined\n      }\n      const buffered = injectedHtmlBuffer\n      injectedHtmlBuffer = ''\n      return buffered\n    },\n    cleanup() {\n      // Guard against multiple/reentrant cleanup calls. A listener could call\n      // cleanup() again indirectly; snapshot + clear before invoking so each\n      // listener runs exactly once and reentry is a no-op.\n      if (cleanupStarted) return\n      cleanupStarted = true\n      const listeners = cleanupListeners.slice()\n      cleanupListeners.length = 0\n      for (const l of listeners) {\n        try {\n          l()\n        } catch (err) {\n          console.error('Error in SSR cleanup listener:', err)\n        }\n      }\n      renderFinishedListeners.length = 0\n      injectedHtmlListeners.length = 0\n      serializationFinishedListeners.length = 0\n      injectedHtmlBuffer = ''\n      scriptBuffer.cleanup()\n      router.serverSsr = undefined\n    },\n  }\n\n  router.serverSsr = serverSsr\n  for (const listener of router.serverSsrLifecycle?.onServerSsrAttach ?? []) {\n    try {\n      listener(serverSsr)\n    } catch (err) {\n      console.error('SSR attach listener error:', err)\n    }\n  }\n}\n\n/**\n * Get the origin for the request.\n *\n * SECURITY: We intentionally do NOT trust the Origin header for determining\n * the router's origin. The Origin header can be spoofed by attackers, which\n * could lead to SSRF-like vulnerabilities where redirects are constructed\n * using a malicious origin (CVE-2024-34351).\n *\n * Instead, we derive the origin from request.url, which is typically set by\n * the server infrastructure (not client-controlled headers).\n *\n * For applications behind proxies that need to trust forwarded headers,\n * use the router's `origin` option to explicitly configure a trusted origin.\n */\nexport function getOrigin(request: Request) {\n  try {\n    return new URL(request.url).origin\n  } catch {}\n  return 'http://localhost'\n}\n\n// server and browser can decode/encode characters differently in paths and search params.\n// Server generally strictly follows the WHATWG URL Standard, while browsers may differ for legacy reasons.\n// for example, in paths \"|\" is not encoded on the server but is encoded on chromium (and not on firefox) while \"대\" is encoded on both sides.\n// Another anomaly is that in Node new URLSearchParams and new URL also decode/encode characters differently.\n// new URLSearchParams() encodes \"|\" while new URL() does not, and in this instance\n// chromium treats search params differently than paths, i.e. \"|\" is not encoded in search params.\nexport function getNormalizedURL(url: string | URL, base?: string | URL) {\n  // ensure backslashes are encoded correctly in the URL\n  if (typeof url === 'string') url = url.replace('\\\\', '%5C')\n\n  const rawUrl = new URL(url, base)\n  const { path: decodedPathname, handledProtocolRelativeURL } = decodePath(\n    rawUrl.pathname,\n  )\n  const searchParams = new URLSearchParams(rawUrl.search)\n  const normalizedHref =\n    decodedPathname +\n    (searchParams.size > 0 ? '?' : '') +\n    searchParams.toString() +\n    rawUrl.hash\n\n  return {\n    url: new URL(normalizedHref, rawUrl.origin),\n    handledProtocolRelativeURL,\n  }\n}\n"],"mappings":"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"}