{"version":3,"file":"transformStreamWithRouter.cjs","names":[],"sources":["../../../src/ssr/transformStreamWithRouter.ts"],"sourcesContent":["import { ReadableStream } from 'node:stream/web'\nimport { Readable } from 'node:stream'\nimport { TSR_SCRIPT_BARRIER_ID } from './constants'\nimport type { AnyRouter } from '../router'\n\nexport type TransformStreamWithRouterOptions = {\n  /** Timeout for serialization to complete after app render finishes (default: 60000ms) */\n  timeoutMs?: number\n  /** Maximum lifetime of the stream transform (default: 120000ms). Safety net for cleanup. */\n  lifetimeMs?: number\n  /**\n   * Called exactly once when the stream is torn down due to abort/error/\n   * cancel/timeout — NOT on natural successful completion. Use this to\n   * abort a hidden producer upstream of any PassThrough you passed in\n   * (e.g. React `renderToPipeableStream`'s `abort()`).\n   * Errors thrown from this callback are swallowed.\n   */\n  onAbort?: (reason?: unknown) => void\n}\n\nexport function transformReadableStreamWithRouter(\n  router: AnyRouter,\n  routerStream: ReadableStream,\n  opts?: TransformStreamWithRouterOptions,\n) {\n  return transformStreamWithRouter(router, routerStream, opts)\n}\n\nexport function transformPipeableStreamWithRouter(\n  router: AnyRouter,\n  routerStream: Readable,\n  opts?: TransformStreamWithRouterOptions,\n) {\n  return Readable.fromWeb(\n    transformStreamWithRouter(router, Readable.toWeb(routerStream), opts),\n  )\n}\n\n// Minimum length of a valid closing tag: </a> = 4 characters\nconst MIN_CLOSING_TAG_LENGTH = 4\n\n// Default timeout values (in milliseconds)\nconst DEFAULT_SERIALIZATION_TIMEOUT_MS = 60000\nconst DEFAULT_LIFETIME_TIMEOUT_MS = DEFAULT_SERIALIZATION_TIMEOUT_MS * 2\nconst MAX_LEFTOVER_CHARS = 2048\nconst MAX_TAIL_CHARS = 64 * 1024\nconst MAX_ROUTER_HTML_CHARS = 16 * 1024 * 1024\nconst MAX_PENDING_WRITE_CHARS = 16 * 1024 * 1024\n\n// Merge lifecycle: body bytes can stream, router HTML must precede tail,\n// terminal states own close/error/cleanup exactly once.\nconst MergeState = {\n  ReadingBody: 0,\n  HoldingTail: 1,\n  AppDone: 2,\n  Draining: 3,\n  Done: 4,\n} as const\n\ntype MergeState = (typeof MergeState)[keyof typeof MergeState]\n\n// Module-level encoder (stateless, safe to reuse)\nconst textEncoder = new TextEncoder()\n\nconst noop = () => {}\nconst resolvedPromise = Promise.resolve()\n\n// Returns -bodyEndIndex - 2 when </body> is found; otherwise returns\n// the position after the last valid closing tag, or -1 when none exists.\nfunction findHtmlBoundary(str: string): number {\n  let lastClosingTagEnd = -1\n  let searchFrom = str.length - MIN_CLOSING_TAG_LENGTH\n\n  while (searchFrom >= 0) {\n    const openSlash = str.lastIndexOf('</', searchFrom)\n    if (openSlash === -1) break\n\n    // Fast case-insensitive match for </body>. Negative return encodes the\n    // body start index without allocating a result object.\n    if (\n      (str.charCodeAt(openSlash + 2) | 32) === 98 &&\n      (str.charCodeAt(openSlash + 3) | 32) === 111 &&\n      (str.charCodeAt(openSlash + 4) | 32) === 100 &&\n      (str.charCodeAt(openSlash + 5) | 32) === 121 &&\n      str.charCodeAt(openSlash + 6) === 62\n    ) {\n      return -openSlash - 2\n    }\n\n    if (lastClosingTagEnd === -1) {\n      let i = openSlash + 2\n      const startCode = str.charCodeAt(i)\n      if (\n        (startCode >= 97 && startCode <= 122) ||\n        (startCode >= 65 && startCode <= 90)\n      ) {\n        i++\n        while (i < str.length) {\n          const code = str.charCodeAt(i)\n          if (\n            (code >= 97 && code <= 122) || // a-z\n            (code >= 65 && code <= 90) || // A-Z\n            (code >= 48 && code <= 57) || // 0-9\n            code === 95 || // _\n            code === 58 || // :\n            code === 46 || // .\n            code === 45 // -\n          ) {\n            i++\n          } else {\n            break\n          }\n        }\n\n        if (str.charCodeAt(i) === 62) {\n          lastClosingTagEnd = i + 1\n        }\n      }\n    }\n\n    searchFrom = openSlash - 1\n  }\n\n  return lastClosingTagEnd\n}\n\n/**\n * Releasing the lock can throw if a pending read is still settling or if the\n * lock was already released.\n */\ntype ReaderOps = {\n  cancel: (reason?: unknown) => Promise<unknown>\n  releaseLock: () => void\n}\n\nfunction safeReleaseReader(reader: ReaderOps) {\n  try {\n    reader.releaseLock()\n    return true\n  } catch {\n    return false\n  }\n}\n\n/**\n * Cancel a reader without producing an unhandled rejection. `reader.cancel()`\n * can reject (e.g. when the underlying source's cancel() throws), and\n * downstream cancel() should still wait for upstream teardown when possible.\n */\nfunction safeCancelReader(reader: ReaderOps, reason?: unknown): Promise<void> {\n  let cancelPromise: Promise<unknown> | undefined\n  try {\n    cancelPromise = reader.cancel(reason)\n  } catch {\n    // ignore\n  }\n\n  if (!safeReleaseReader(reader) && cancelPromise) {\n    return cancelPromise.then(noop, noop).then(() => {\n      safeReleaseReader(reader)\n    })\n  }\n\n  return cancelPromise ? cancelPromise.then(noop, noop) : resolvedPromise\n}\n\nfunction createReaderState<T>(appStream: ReadableStream<T>) {\n  const reader = appStream.getReader()\n  let released = false\n\n  return {\n    reader,\n    cancel: (reason?: unknown) => {\n      if (released) return resolvedPromise\n      released = true\n      return safeCancelReader(reader, reason)\n    },\n    release: () => {\n      if (released) return\n      released = true\n      safeReleaseReader(reader)\n    },\n  }\n}\n\nfunction createAbortNotifier(opts?: TransformStreamWithRouterOptions) {\n  let abortNotified = false\n  return (reason?: unknown) => {\n    if (abortNotified) return\n    abortNotified = true\n    try {\n      opts?.onAbort?.(reason)\n    } catch {\n      // swallow user errors\n    }\n  }\n}\n\nexport function transformStreamWithRouter(\n  router: AnyRouter,\n  appStream: ReadableStream,\n  opts?: TransformStreamWithRouterOptions,\n) {\n  const serverSsr = router.serverSsr\n  if (!serverSsr) {\n    throw new Error('Invariant failed: router.serverSsr is required')\n  }\n  if (serverSsr.reserveStreamFastPath()) {\n    return makeFastPathStream(appStream, opts, serverSsr)\n  }\n\n  return makeMainStream(serverSsr, appStream, opts)\n}\n\n// =====================================================================\n// Fast path: passthrough with cleanup + backpressure on app reads.\n// =====================================================================\nfunction makeFastPathStream(\n  appStream: ReadableStream<Uint8Array>,\n  opts?: TransformStreamWithRouterOptions,\n  serverSsr?: NonNullable<AnyRouter['serverSsr']>,\n) {\n  let cleanedUp = false\n  let controller: ReadableStreamDefaultController<Uint8Array> | undefined\n  let state: MergeState = MergeState.ReadingBody\n  let lifetimeTimeoutHandle: ReturnType<typeof setTimeout> | undefined\n  let stopListeningToInjectedHtml: (() => void) | undefined\n  const readerState = createReaderState(appStream)\n  const notifyAbort = createAbortNotifier(opts)\n  const isDone = () => state === MergeState.Done\n  let renderFinished = false\n\n  const finishSsrRendering = () => {\n    if (!serverSsr || renderFinished) return true\n    renderFinished = true\n    try {\n      serverSsr.setRenderFinished()\n      return true\n    } catch (error) {\n      safeError(error)\n      cleanup(error)\n      return false\n    }\n  }\n\n  const cleanup = (reason?: unknown, cancelReader = true) => {\n    if (cleanedUp) return resolvedPromise\n    cleanedUp = true\n\n    if (lifetimeTimeoutHandle !== undefined) {\n      clearTimeout(lifetimeTimeoutHandle)\n      lifetimeTimeoutHandle = undefined\n    }\n    try {\n      stopListeningToInjectedHtml?.()\n    } catch {\n      // ignore\n    }\n    stopListeningToInjectedHtml = undefined\n\n    if (cancelReader) {\n      // Notify the producer immediately. Reader cancellation may take time to\n      // settle, and upstream renderers must tolerate abort + cancel overlap.\n      notifyAbort(reason)\n    }\n    const readerDone = cancelReader\n      ? readerState.cancel(reason)\n      : (readerState.release(), resolvedPromise)\n    if (serverSsr) {\n      try {\n        serverSsr.cleanup()\n      } catch (error) {\n        console.error('Error in SSR cleanup:', error)\n      }\n    }\n    return readerDone\n  }\n\n  const safeClose = () => {\n    if (isDone()) return\n    state = MergeState.Done\n    try {\n      controller?.close()\n    } catch {\n      // ignore\n    }\n  }\n\n  const safeError = (error: unknown) => {\n    if (isDone()) return\n    state = MergeState.Done\n    try {\n      controller?.error(error)\n    } catch {\n      // ignore\n    }\n  }\n\n  if (serverSsr) {\n    stopListeningToInjectedHtml = serverSsr.onInjectedHtml(() => {\n      const err = new Error('SSR router HTML injected during fast path')\n      safeError(err)\n      cleanup(err)\n    })\n  }\n\n  const lifetimeMs = opts?.lifetimeMs ?? DEFAULT_LIFETIME_TIMEOUT_MS\n  lifetimeTimeoutHandle = setTimeout(() => {\n    if (!cleanedUp && !isDone()) {\n      const err = new Error('Stream lifetime exceeded')\n      console.warn(\n        `SSR stream transform exceeded maximum lifetime (${lifetimeMs}ms), forcing cleanup`,\n      )\n      safeError(err)\n      cleanup(err)\n    }\n  }, lifetimeMs)\n\n  const stream = new ReadableStream<Uint8Array>({\n    start(c) {\n      controller = c\n    },\n    async pull(c) {\n      if (cleanedUp || isDone()) return\n      try {\n        const { done, value } = await readerState.reader.read()\n        if (!done) {\n          if (!cleanedUp && !isDone()) {\n            c.enqueue(value)\n          }\n          return\n        }\n\n        if (cleanedUp || isDone()) return\n\n        if (!finishSsrRendering()) return\n        safeClose()\n        return cleanup(undefined, false)\n      } catch (error) {\n        if (cleanedUp) return\n        console.error('Error reading appStream:', error)\n        if (state < MergeState.AppDone) {\n          try {\n            serverSsr?.setRenderFinished()\n          } catch {\n            // ignore\n          }\n        }\n        safeError(error)\n        return cleanup(error)\n      } finally {\n        if (cleanedUp || isDone()) {\n          readerState.release()\n        }\n      }\n    },\n    cancel(reason) {\n      state = MergeState.Done\n      return cleanup(reason)\n    },\n  })\n\n  return stream\n}\n\n// =====================================================================\n// Main path: scan + inject router HTML/scripts with full backpressure.\n//\n// ALL output (app chunks AND router-injected HTML/scripts) flows through a\n// single pendingWrites queue and is only enqueued onto the downstream\n// controller when desiredSize > 0. This prevents native-memory growth of\n// queued Uint8Arrays under slow HTTP consumers.\n// =====================================================================\nfunction makeMainStream(\n  serverSsr: NonNullable<AnyRouter['serverSsr']>,\n  appStream: ReadableStream,\n  opts?: TransformStreamWithRouterOptions,\n) {\n  let stopListeningToInjectedHtml: (() => void) | undefined\n  let stopListeningToSerializationFinished: (() => void) | undefined\n  let serializationTimeoutHandle: ReturnType<typeof setTimeout> | undefined\n  let lifetimeTimeoutHandle: ReturnType<typeof setTimeout> | undefined\n  let cleanedUp = false\n\n  let controller: ReadableStreamDefaultController<Uint8Array> | undefined\n  let closeWhenDrained = false\n  let state: MergeState = MergeState.ReadingBody\n\n  const readerState = createReaderState(appStream)\n  const notifyAbort = createAbortNotifier(opts)\n\n  // Single output queue: app chunks + router-injected HTML/scripts.\n  // Stored as STRINGS to avoid holding native-backed Uint8Arrays in our queue\n  // while waiting for downstream capacity. Encoding happens at enqueue time\n  // (drainPending) so the bytes live only inside the controller's internal\n  // queue, not in two places.\n  //\n  // Uses an index pointer instead of Array.prototype.shift() (which is O(n))\n  // so many small router-injected script chunks stay O(1) per chunk.\n  const pendingWrites: Array<string> = []\n  let pendingWriteHead = 0\n  let pendingWriteChars = 0\n\n  function clearPending() {\n    pendingWrites.length = 0\n    pendingWriteHead = 0\n    pendingWriteChars = 0\n  }\n\n  // Backpressure: pull() resolves drainResolve to let the read loop advance.\n  let drainResolve: (() => void) | null = null\n  const waitForDrain = () =>\n    new Promise<void>((r) => {\n      drainResolve = r\n    })\n  const signalDrain = () => {\n    if (drainResolve) {\n      const r = drainResolve\n      drainResolve = null\n      r()\n    }\n  }\n\n  const isDone = () => state === MergeState.Done\n\n  function drainPending() {\n    if (!controller || isDone()) return\n    while (pendingWriteHead < pendingWrites.length) {\n      const ds = controller.desiredSize\n      if (ds !== null && ds <= 0) return\n      const next = pendingWrites[pendingWriteHead]!\n      // Release reference for GC; compact when fully drained.\n      pendingWrites[pendingWriteHead] = ''\n      pendingWriteHead++\n      pendingWriteChars -= next.length\n      try {\n        controller.enqueue(textEncoder.encode(next))\n      } catch (error) {\n        safeError(error)\n        cleanup(error)\n        return\n      }\n    }\n    // Fully drained: reset array so it doesn't grow unbounded across SSR.\n    if (pendingWriteHead >= pendingWrites.length) {\n      pendingWrites.length = 0\n      pendingWriteHead = 0\n    }\n    // If we've flushed everything and tryFinish requested close, close now.\n    if (closeWhenDrained && pendingWriteHead >= pendingWrites.length) {\n      closeWhenDrained = false\n      safeClose()\n      cleanup(undefined, false)\n    }\n  }\n\n  /**\n   * Enqueue a string chunk through the backpressure queue. Stored as a\n   * string and encoded only when the downstream actually accepts the chunk\n   * — keeps native-memory pressure inside the controller's queue (which\n   * honors desiredSize) rather than ours.\n   */\n  function writeChunk(chunk: string) {\n    if (cleanedUp || isDone()) return\n    if (!chunk.length) return\n    if (pendingWriteChars + chunk.length > MAX_PENDING_WRITE_CHARS) {\n      const err = new Error('SSR stream pending output exceeded maximum buffer')\n      safeError(err)\n      cleanup(err)\n      return\n    }\n    pendingWrites.push(chunk)\n    pendingWriteChars += chunk.length\n    drainPending()\n  }\n\n  function safeClose() {\n    if (isDone()) return\n    state = MergeState.Done\n    try {\n      controller?.close()\n    } catch {\n      // ignore\n    }\n  }\n\n  function safeError(error: unknown) {\n    if (isDone()) return\n    state = MergeState.Done\n    try {\n      controller?.error(error)\n    } catch {\n      // ignore\n    }\n  }\n\n  /**\n   * Cleanup with guards; must be idempotent.\n   */\n  function cleanup(reason?: unknown, cancelReader = true) {\n    if (cleanedUp) return resolvedPromise\n    cleanedUp = true\n\n    try {\n      stopListeningToInjectedHtml?.()\n      stopListeningToSerializationFinished?.()\n    } catch {\n      // ignore\n    }\n    stopListeningToInjectedHtml = undefined\n    stopListeningToSerializationFinished = undefined\n\n    if (serializationTimeoutHandle !== undefined) {\n      clearTimeout(serializationTimeoutHandle)\n      serializationTimeoutHandle = undefined\n    }\n    if (lifetimeTimeoutHandle !== undefined) {\n      clearTimeout(lifetimeTimeoutHandle)\n      lifetimeTimeoutHandle = undefined\n    }\n\n    clearPendingRouterHtml()\n    leftover = ''\n    pendingTail = ''\n    clearPending()\n\n    if (cancelReader) {\n      // Notify the producer immediately. Reader cancellation may take time to\n      // settle, and upstream renderers must tolerate abort + cancel overlap.\n      notifyAbort(reason)\n    }\n    const readerDone = cancelReader\n      ? readerState.cancel(reason)\n      : (readerState.release(), resolvedPromise)\n    signalDrain()\n    try {\n      serverSsr.cleanup()\n    } catch (error) {\n      console.error('Error in SSR cleanup:', error)\n    }\n    return readerDone\n  }\n\n  const textDecoder = new TextDecoder()\n\n  // Router-injected scripts/HTML waiting for the next safe body boundary.\n  // Keep chunks separate so flushing does not flatten a large rope string.\n  const pendingRouterHtml: Array<string> = []\n  let pendingRouterHtmlChars = 0\n\n  // between-chunk text buffer; keep bounded to avoid unbounded memory\n  let leftover = ''\n\n  // captured bytes from </body> onward; must stay behind router scripts.\n  let pendingTail = ''\n\n  let streamBarrierLifted = false\n  let streamBarrierMarkerSeen = false\n  let serializationFinished = false\n\n  function noteBarrierMarker(chunk: string) {\n    if (streamBarrierMarkerSeen) return\n    if (chunk.includes(TSR_SCRIPT_BARRIER_ID)) {\n      streamBarrierMarkerSeen = true\n    }\n  }\n\n  function liftBarrierAfterBoundary() {\n    if (streamBarrierLifted) return\n    if (!streamBarrierMarkerSeen) return\n    streamBarrierLifted = true\n    serverSsr.liftScriptBarrier()\n  }\n\n  const stream = new ReadableStream<Uint8Array>({\n    start(c) {\n      controller = c\n      // If anything queued before start (shouldn't happen but be safe), drain.\n      drainPending()\n    },\n    pull() {\n      // Consumer has capacity; flush queue then unblock read loop.\n      drainPending()\n      signalDrain()\n    },\n    cancel(reason) {\n      state = MergeState.Done\n      return cleanup(reason)\n    },\n  })\n\n  function drainRouterHtml() {\n    if (cleanedUp || isDone()) return\n    let html: string | undefined\n    try {\n      html = serverSsr.takeBufferedHtml()\n    } catch (error) {\n      safeError(error)\n      cleanup(error)\n      return\n    }\n    if (!html) return\n    if (state >= MergeState.Draining) {\n      // At this point final tail/close has already been queued. Emitting late\n      // router HTML would put scripts after </body> or drop them silently.\n      const err = new Error(\n        'SSR router HTML injected after stream finalization',\n      )\n      safeError(err)\n      cleanup(err)\n      return\n    }\n    if (state === MergeState.HoldingTail) {\n      flushPendingRouterHtml()\n      writeChunk(html)\n    } else {\n      if (pendingRouterHtmlChars + html.length > MAX_ROUTER_HTML_CHARS) {\n        const err = new Error('SSR router HTML exceeded maximum buffer')\n        safeError(err)\n        cleanup(err)\n        return\n      }\n      pendingRouterHtml.push(html)\n      pendingRouterHtmlChars += html.length\n    }\n  }\n\n  function flushPendingRouterHtml() {\n    if (!pendingRouterHtml.length) return\n    for (const html of pendingRouterHtml) {\n      writeChunk(html)\n    }\n    clearPendingRouterHtml()\n  }\n\n  function clearPendingRouterHtml() {\n    pendingRouterHtml.length = 0\n    pendingRouterHtmlChars = 0\n  }\n\n  function appendTail(chunk: string) {\n    pendingTail += chunk\n    if (pendingTail.length > MAX_TAIL_CHARS) {\n      throw new Error('SSR stream tail exceeded maximum buffer')\n    }\n  }\n\n  function waitForBackpressure() {\n    return !!(\n      controller &&\n      controller.desiredSize !== null &&\n      controller.desiredSize <= 0\n    )\n  }\n\n  function startSerializationTimeout() {\n    if (cleanedUp || isDone()) return\n    if (serializationTimeoutHandle !== undefined) return\n    const timeoutMs = opts?.timeoutMs ?? DEFAULT_SERIALIZATION_TIMEOUT_MS\n    serializationTimeoutHandle = setTimeout(() => {\n      if (!cleanedUp && !isDone()) {\n        const err = new Error('Serialization timeout after app render finished')\n        console.error('Serialization timeout after app render finished')\n        safeError(err)\n        cleanup(err)\n      }\n    }, timeoutMs)\n  }\n\n  /**\n   * Finish only when app done and serialization complete. Queues final\n   * output and requests close-when-drained so we don't close ahead of\n   * pending writes still waiting on downstream capacity.\n   */\n  function tryFinish() {\n    if (state !== MergeState.AppDone || !serializationFinished) return\n    if (cleanedUp || isDone()) return\n\n    if (serializationTimeoutHandle !== undefined) {\n      clearTimeout(serializationTimeoutHandle)\n      serializationTimeoutHandle = undefined\n    }\n\n    drainRouterHtml()\n    if (cleanedUp || isDone()) return\n\n    // Flush any remaining bytes in the TextDecoder\n    const decoderRemainder = textDecoder.decode()\n\n    if (leftover) writeChunk(leftover)\n    if (cleanedUp || isDone()) return\n    if (decoderRemainder) writeChunk(decoderRemainder)\n    if (cleanedUp || isDone()) return\n    flushPendingRouterHtml()\n    if (cleanedUp || isDone()) return\n    if (pendingTail) writeChunk(pendingTail)\n    if (cleanedUp || isDone()) return\n\n    leftover = ''\n    pendingTail = ''\n\n    state = MergeState.Draining\n    closeWhenDrained = true\n    // Try immediately; if queue not drained yet, pull() will retry.\n    drainPending()\n  }\n\n  function finishAppRendering() {\n    if (state >= MergeState.AppDone) return\n    state = MergeState.AppDone\n    try {\n      serverSsr.setRenderFinished()\n    } catch (error) {\n      safeError(error)\n      cleanup(error)\n      return\n    }\n    drainRouterHtml()\n    if (cleanedUp || isDone()) return\n    serializationFinished =\n      serializationFinished || serverSsr.isSerializationFinished()\n    if (serializationFinished) {\n      tryFinish()\n    } else {\n      startSerializationTimeout()\n    }\n  }\n\n  // Safety net: cleanup even if consumer never reads\n  const timeoutMs = opts?.timeoutMs ?? DEFAULT_SERIALIZATION_TIMEOUT_MS\n  const lifetimeMs = opts?.lifetimeMs ?? timeoutMs * 2\n  lifetimeTimeoutHandle = setTimeout(() => {\n    if (!cleanedUp && !isDone()) {\n      const err = new Error('Stream lifetime exceeded')\n      console.warn(\n        `SSR stream transform exceeded maximum lifetime (${lifetimeMs}ms), forcing cleanup`,\n      )\n      safeError(err)\n      cleanup(err)\n    }\n  }, lifetimeMs)\n\n  stopListeningToInjectedHtml = serverSsr.onInjectedHtml(() => {\n    drainRouterHtml()\n  })\n\n  stopListeningToSerializationFinished = serverSsr.onSerializationFinished(\n    () => {\n      serializationFinished = true\n      drainRouterHtml()\n      tryFinish()\n    },\n  )\n\n  // Subscriptions are installed before snapshots, so missed events are\n  // recovered by these synchronous drains/rechecks.\n  drainRouterHtml()\n  if (cleanedUp || isDone()) return stream\n  serializationFinished =\n    serializationFinished || serverSsr.isSerializationFinished()\n  if (serializationFinished) {\n    drainRouterHtml()\n    if (cleanedUp || isDone()) return stream\n  }\n\n  // Transform the appStream\n  ;(async () => {\n    try {\n      while (true) {\n        // Backpressure: pause upstream reads while downstream is full.\n        if (waitForBackpressure()) {\n          await waitForDrain()\n          if (cleanedUp || isDone()) return\n        }\n\n        const { done, value } = await readerState.reader.read()\n        if (done) break\n\n        if (cleanedUp || isDone()) return\n\n        const text =\n          typeof value === 'string'\n            ? value\n            : textDecoder.decode(value as ArrayBufferView, { stream: true })\n\n        const chunkString = leftover ? leftover + text : text\n\n        // If we already saw </body>, everything else is tail. Keep it bounded\n        // and held until router scripts are ready so injection remains before </body>.\n        if (state >= MergeState.HoldingTail) {\n          appendTail(chunkString)\n          leftover = ''\n          continue\n        }\n\n        const boundary = findHtmlBoundary(chunkString)\n        if (boundary < -1) {\n          const bodyEndIndex = -boundary - 2\n          state = MergeState.HoldingTail\n          appendTail(chunkString.slice(bodyEndIndex))\n          const bodyChunk = chunkString.slice(0, bodyEndIndex)\n          writeChunk(bodyChunk)\n          if (cleanedUp || isDone()) return\n          noteBarrierMarker(bodyChunk)\n          liftBarrierAfterBoundary()\n          if (cleanedUp || isDone()) return\n          flushPendingRouterHtml()\n          leftover = ''\n          continue\n        }\n\n        const lastClosingTagEnd = boundary\n\n        if (lastClosingTagEnd > 0) {\n          const safeChunk = chunkString.slice(0, lastClosingTagEnd)\n          writeChunk(safeChunk)\n          if (cleanedUp || isDone()) return\n          noteBarrierMarker(safeChunk)\n          liftBarrierAfterBoundary()\n          if (cleanedUp || isDone()) return\n          flushPendingRouterHtml()\n\n          leftover = chunkString.slice(lastClosingTagEnd)\n          if (leftover.length > MAX_LEFTOVER_CHARS) {\n            // Ensure bounded memory even if a consumer streams long text sequences\n            // without any closing tags. This may reduce injection granularity but is correct.\n            noteBarrierMarker(leftover)\n            const flushed = leftover.slice(\n              0,\n              leftover.length - MAX_LEFTOVER_CHARS,\n            )\n            writeChunk(flushed)\n            leftover = leftover.slice(-MAX_LEFTOVER_CHARS)\n          }\n        } else {\n          // No closing tag found; keep small tail to handle split closing tags,\n          // but stream older bytes to prevent unbounded buffering.\n          const combined = chunkString\n          if (combined.length > MAX_LEFTOVER_CHARS) {\n            noteBarrierMarker(combined)\n            const flushUpto = combined.length - MAX_LEFTOVER_CHARS\n            const flushed = combined.slice(0, flushUpto)\n            writeChunk(flushed)\n            leftover = combined.slice(flushUpto)\n          } else {\n            leftover = combined\n          }\n        }\n      }\n\n      if (cleanedUp || isDone()) return\n\n      finishAppRendering()\n    } catch (error) {\n      if (cleanedUp) return\n      console.error('Error reading appStream:', error)\n      if (state < MergeState.AppDone) {\n        try {\n          serverSsr.setRenderFinished()\n        } catch {\n          // ignore\n        }\n      }\n      safeError(error)\n      cleanup(error)\n    } finally {\n      readerState.release()\n    }\n  })().catch((error) => {\n    if (cleanedUp) return\n    console.error('Error in stream transform:', error)\n    safeError(error)\n    cleanup(error)\n  })\n\n  return stream\n}\n"],"mappings":"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"}