{"version":3,"sources":["../../../../src/server/dev/debug-channel.ts"],"sourcesContent":["import type { Readable } from 'node:stream'\nimport { createBufferedTransformStream } from '../stream-utils/node-web-streams-helper'\nimport { createNodeBufferedTransformStream } from '../stream-utils/node-buffered-transform-stream'\nimport {\n  HMR_MESSAGE_SENT_TO_BROWSER,\n  type HmrMessageSentToBrowser,\n} from './hot-reloader-types'\nimport type { AnyStream } from '../app-render/stream-ops'\n\n// Chunks are sent to the browser in batches to reduce overhead, flushing\n// synchronously once this many bytes have accumulated.\nconst MAX_DEBUG_CHANNEL_BATCH_BYTES = 128 * 1024\n\nexport interface ReactDebugChannelForBrowser {\n  readonly readable: AnyStream\n}\n\nconst reactDebugChannelsByHtmlRequestId = new Map<\n  string,\n  ReactDebugChannelForBrowser\n>()\n\n/**\n * Reads the React debug channel and forwards its chunks to the browser through\n * the websocket. Branches on the stream type so that Node streams stay\n * node-native — batched with a Node `Transform` and consumed via events.\n */\nexport function connectReactDebugChannel(\n  requestId: string,\n  debugChannel: ReactDebugChannelForBrowser,\n  sendToClient: (message: HmrMessageSentToBrowser) => void\n) {\n  let finished = false\n\n  const stop = () => {\n    if (finished) {\n      return\n    }\n    finished = true\n    sendToClient({\n      type: HMR_MESSAGE_SENT_TO_BROWSER.REACT_DEBUG_CHUNK,\n      requestId,\n      chunk: null,\n    })\n  }\n\n  const onError = (err: unknown) => {\n    if (!finished) {\n      console.error(\n        new Error('React debug channel stream error', { cause: err })\n      )\n    }\n    stop()\n  }\n\n  const sendChunk = (chunk: Uint8Array) => {\n    sendToClient({\n      type: HMR_MESSAGE_SENT_TO_BROWSER.REACT_DEBUG_CHUNK,\n      requestId,\n      chunk,\n    })\n  }\n\n  const { readable } = debugChannel\n\n  if (readable instanceof ReadableStream) {\n    const reader = readable\n      .pipeThrough(\n        createBufferedTransformStream({\n          maxBufferByteLength: MAX_DEBUG_CHANNEL_BATCH_BYTES,\n        })\n      )\n      .getReader()\n\n    const progress = (entry: ReadableStreamReadResult<Uint8Array>) => {\n      if (entry.done) {\n        stop()\n      } else {\n        sendChunk(entry.value)\n        reader.read().then(progress, onError)\n      }\n    }\n\n    reader.read().then(progress, onError)\n  } else {\n    const source = readable as Readable\n    // `pipe` does not forward source errors to the destination, so handle them\n    // on the source directly.\n    source.on('error', onError)\n    const batched = source.pipe(\n      createNodeBufferedTransformStream(MAX_DEBUG_CHANNEL_BATCH_BYTES)\n    )\n    batched.on('data', sendChunk)\n    batched.on('end', stop)\n    batched.on('error', onError)\n  }\n}\n\nexport function connectReactDebugChannelForHtmlRequest(\n  htmlRequestId: string,\n  sendToClient: (message: HmrMessageSentToBrowser) => void\n) {\n  const debugChannel = reactDebugChannelsByHtmlRequestId.get(htmlRequestId)\n\n  if (!debugChannel) {\n    return\n  }\n\n  reactDebugChannelsByHtmlRequestId.delete(htmlRequestId)\n\n  connectReactDebugChannel(htmlRequestId, debugChannel, sendToClient)\n}\n\nexport function setReactDebugChannelForHtmlRequest(\n  htmlRequestId: string,\n  debugChannel: ReactDebugChannelForBrowser\n) {\n  // TODO: Clean up after a timeout, in case the client never connects, e.g.\n  // when CURL'ing the page, or loading the page with JavaScript disabled etc.\n  reactDebugChannelsByHtmlRequestId.set(htmlRequestId, debugChannel)\n}\n\nexport function deleteReactDebugChannelForHtmlRequest(htmlRequestId: string) {\n  reactDebugChannelsByHtmlRequestId.delete(htmlRequestId)\n}\n"],"names":["createBufferedTransformStream","createNodeBufferedTransformStream","HMR_MESSAGE_SENT_TO_BROWSER","MAX_DEBUG_CHANNEL_BATCH_BYTES","reactDebugChannelsByHtmlRequestId","Map","connectReactDebugChannel","requestId","debugChannel","sendToClient","finished","stop","type","REACT_DEBUG_CHUNK","chunk","onError","err","console","error","Error","cause","sendChunk","readable","ReadableStream","reader","pipeThrough","maxBufferByteLength","getReader","progress","entry","done","value","read","then","source","on","batched","pipe","connectReactDebugChannelForHtmlRequest","htmlRequestId","get","delete","setReactDebugChannelForHtmlRequest","set","deleteReactDebugChannelForHtmlRequest"],"mappings":"AACA,SAASA,6BAA6B,QAAQ,0CAAyC;AACvF,SAASC,iCAAiC,QAAQ,iDAAgD;AAClG,SACEC,2BAA2B,QAEtB,uBAAsB;AAG7B,yEAAyE;AACzE,uDAAuD;AACvD,MAAMC,gCAAgC,MAAM;AAM5C,MAAMC,oCAAoC,IAAIC;AAK9C;;;;CAIC,GACD,OAAO,SAASC,yBACdC,SAAiB,EACjBC,YAAyC,EACzCC,YAAwD;IAExD,IAAIC,WAAW;IAEf,MAAMC,OAAO;QACX,IAAID,UAAU;YACZ;QACF;QACAA,WAAW;QACXD,aAAa;YACXG,MAAMV,4BAA4BW,iBAAiB;YACnDN;YACAO,OAAO;QACT;IACF;IAEA,MAAMC,UAAU,CAACC;QACf,IAAI,CAACN,UAAU;YACbO,QAAQC,KAAK,CACX,qBAA6D,CAA7D,IAAIC,MAAM,oCAAoC;gBAAEC,OAAOJ;YAAI,IAA3D,qBAAA;uBAAA;4BAAA;8BAAA;YAA4D;QAEhE;QACAL;IACF;IAEA,MAAMU,YAAY,CAACP;QACjBL,aAAa;YACXG,MAAMV,4BAA4BW,iBAAiB;YACnDN;YACAO;QACF;IACF;IAEA,MAAM,EAAEQ,QAAQ,EAAE,GAAGd;IAErB,IAAIc,oBAAoBC,gBAAgB;QACtC,MAAMC,SAASF,SACZG,WAAW,CACVzB,8BAA8B;YAC5B0B,qBAAqBvB;QACvB,IAEDwB,SAAS;QAEZ,MAAMC,WAAW,CAACC;YAChB,IAAIA,MAAMC,IAAI,EAAE;gBACdnB;YACF,OAAO;gBACLU,UAAUQ,MAAME,KAAK;gBACrBP,OAAOQ,IAAI,GAAGC,IAAI,CAACL,UAAUb;YAC/B;QACF;QAEAS,OAAOQ,IAAI,GAAGC,IAAI,CAACL,UAAUb;IAC/B,OAAO;QACL,MAAMmB,SAASZ;QACf,2EAA2E;QAC3E,0BAA0B;QAC1BY,OAAOC,EAAE,CAAC,SAASpB;QACnB,MAAMqB,UAAUF,OAAOG,IAAI,CACzBpC,kCAAkCE;QAEpCiC,QAAQD,EAAE,CAAC,QAAQd;QACnBe,QAAQD,EAAE,CAAC,OAAOxB;QAClByB,QAAQD,EAAE,CAAC,SAASpB;IACtB;AACF;AAEA,OAAO,SAASuB,uCACdC,aAAqB,EACrB9B,YAAwD;IAExD,MAAMD,eAAeJ,kCAAkCoC,GAAG,CAACD;IAE3D,IAAI,CAAC/B,cAAc;QACjB;IACF;IAEAJ,kCAAkCqC,MAAM,CAACF;IAEzCjC,yBAAyBiC,eAAe/B,cAAcC;AACxD;AAEA,OAAO,SAASiC,mCACdH,aAAqB,EACrB/B,YAAyC;IAEzC,0EAA0E;IAC1E,4EAA4E;IAC5EJ,kCAAkCuC,GAAG,CAACJ,eAAe/B;AACvD;AAEA,OAAO,SAASoC,sCAAsCL,aAAqB;IACzEnC,kCAAkCqC,MAAM,CAACF;AAC3C","ignoreList":[0]}