{"version":3,"sources":["../../src/server/body-streams.ts"],"sourcesContent":["import type { IncomingMessage } from 'http'\nimport type { Readable } from 'stream'\nimport { PassThrough } from 'stream'\nimport bytes from 'next/dist/compiled/bytes'\n\nconst DEFAULT_BODY_CLONE_SIZE_LIMIT = 10 * 1024 * 1024 // 10MB\n\nexport function requestToBodyStream(\n context: { ReadableStream: typeof ReadableStream },\n KUint8Array: typeof Uint8Array,\n stream: Readable\n) {\n return new context.ReadableStream({\n start: async (controller) => {\n for await (const chunk of stream) {\n controller.enqueue(new KUint8Array(chunk))\n }\n controller.close()\n },\n })\n}\n\nfunction replaceRequestBody(\n base: T,\n stream: Readable\n): T {\n for (const key in stream) {\n let v = stream[key as keyof Readable] as any\n if (typeof v === 'function') {\n v = v.bind(base)\n }\n base[key as keyof T] = v\n }\n\n return base\n}\n\nexport interface CloneableBody {\n finalize(): Promise\n cloneBodyStream(): Readable\n}\n\nexport function getCloneableBody(\n readable: T,\n sizeLimit?: number\n): CloneableBody {\n let buffered: Readable | null = null\n\n const endPromise = new Promise(\n (resolve, reject) => {\n readable.on('end', resolve)\n readable.on('error', reject)\n }\n ).catch((error) => {\n return { error }\n })\n\n return {\n /**\n * Replaces the original request body if necessary.\n * This is done because once we read the body from the original request,\n * we can't read it again.\n */\n async finalize(): Promise {\n if (buffered) {\n const res = await endPromise\n\n if (res && typeof res === 'object' && res.error) {\n throw res.error\n }\n replaceRequestBody(readable, buffered)\n buffered = readable\n }\n },\n /**\n * Clones the body stream\n * to pass into a middleware\n */\n cloneBodyStream() {\n const input = buffered ?? readable\n const p1 = new PassThrough()\n const p2 = new PassThrough()\n\n let bytesRead = 0\n const bodySizeLimit = sizeLimit ?? DEFAULT_BODY_CLONE_SIZE_LIMIT\n let limitExceeded = false\n\n input.on('data', (chunk) => {\n if (limitExceeded) return\n\n bytesRead += chunk.length\n\n if (bytesRead > bodySizeLimit) {\n limitExceeded = true\n const urlInfo = readable.url ? ` for ${readable.url}` : ''\n console.warn(\n // TODO(jiwon): Update this document link\n `Request body exceeded ${bytes.format(bodySizeLimit)}${urlInfo}. Only the first ${bytes.format(bodySizeLimit)} will be available unless configured. See https://nextjs.org/docs/app/api-reference/config/next-config-js/middlewareClientMaxBodySize for more details.`\n )\n p1.push(null)\n p2.push(null)\n return\n }\n\n p1.push(chunk)\n p2.push(chunk)\n })\n input.on('end', () => {\n if (!limitExceeded) {\n p1.push(null)\n p2.push(null)\n }\n })\n buffered = p2\n return p1\n },\n }\n}\n"],"names":["PassThrough","bytes","DEFAULT_BODY_CLONE_SIZE_LIMIT","requestToBodyStream","context","KUint8Array","stream","ReadableStream","start","controller","chunk","enqueue","close","replaceRequestBody","base","key","v","bind","getCloneableBody","readable","sizeLimit","buffered","endPromise","Promise","resolve","reject","on","catch","error","finalize","res","cloneBodyStream","input","p1","p2","bytesRead","bodySizeLimit","limitExceeded","length","urlInfo","url","console","warn","format","push"],"mappings":"AAEA,SAASA,WAAW,QAAQ,SAAQ;AACpC,OAAOC,WAAW,2BAA0B;AAE5C,MAAMC,gCAAgC,KAAK,OAAO,KAAK,OAAO;;AAE9D,OAAO,SAASC,oBACdC,OAAkD,EAClDC,WAA8B,EAC9BC,MAAgB;IAEhB,OAAO,IAAIF,QAAQG,cAAc,CAAC;QAChCC,OAAO,OAAOC;YACZ,WAAW,MAAMC,SAASJ,OAAQ;gBAChCG,WAAWE,OAAO,CAAC,IAAIN,YAAYK;YACrC;YACAD,WAAWG,KAAK;QAClB;IACF;AACF;AAEA,SAASC,mBACPC,IAAO,EACPR,MAAgB;IAEhB,IAAK,MAAMS,OAAOT,OAAQ;QACxB,IAAIU,IAAIV,MAAM,CAACS,IAAsB;QACrC,IAAI,OAAOC,MAAM,YAAY;YAC3BA,IAAIA,EAAEC,IAAI,CAACH;QACb;QACAA,IAAI,CAACC,IAAe,GAAGC;IACzB;IAEA,OAAOF;AACT;AAOA,OAAO,SAASI,iBACdC,QAAW,EACXC,SAAkB;IAElB,IAAIC,WAA4B;IAEhC,MAAMC,aAAa,IAAIC,QACrB,CAACC,SAASC;QACRN,SAASO,EAAE,CAAC,OAAOF;QACnBL,SAASO,EAAE,CAAC,SAASD;IACvB,GACAE,KAAK,CAAC,CAACC;QACP,OAAO;YAAEA;QAAM;IACjB;IAEA,OAAO;QACL;;;;KAIC,GACD,MAAMC;YACJ,IAAIR,UAAU;gBACZ,MAAMS,MAAM,MAAMR;gBAElB,IAAIQ,OAAO,OAAOA,QAAQ,YAAYA,IAAIF,KAAK,EAAE;oBAC/C,MAAME,IAAIF,KAAK;gBACjB;gBACAf,mBAAmBM,UAAUE;gBAC7BA,WAAWF;YACb;QACF;QACA;;;KAGC,GACDY;YACE,MAAMC,QAAQX,YAAYF;YAC1B,MAAMc,KAAK,IAAIjC;YACf,MAAMkC,KAAK,IAAIlC;YAEf,IAAImC,YAAY;YAChB,MAAMC,gBAAgBhB,aAAalB;YACnC,IAAImC,gBAAgB;YAEpBL,MAAMN,EAAE,CAAC,QAAQ,CAAChB;gBAChB,IAAI2B,eAAe;gBAEnBF,aAAazB,MAAM4B,MAAM;gBAEzB,IAAIH,YAAYC,eAAe;oBAC7BC,gBAAgB;oBAChB,MAAME,UAAUpB,SAASqB,GAAG,GAAG,CAAC,KAAK,EAAErB,SAASqB,GAAG,EAAE,GAAG;oBACxDC,QAAQC,IAAI,CACV,yCAAyC;oBACzC,CAAC,sBAAsB,EAAEzC,MAAM0C,MAAM,CAACP,iBAAiBG,QAAQ,iBAAiB,EAAEtC,MAAM0C,MAAM,CAACP,eAAe,uJAAuJ,CAAC;oBAExQH,GAAGW,IAAI,CAAC;oBACRV,GAAGU,IAAI,CAAC;oBACR;gBACF;gBAEAX,GAAGW,IAAI,CAAClC;gBACRwB,GAAGU,IAAI,CAAClC;YACV;YACAsB,MAAMN,EAAE,CAAC,OAAO;gBACd,IAAI,CAACW,eAAe;oBAClBJ,GAAGW,IAAI,CAAC;oBACRV,GAAGU,IAAI,CAAC;gBACV;YACF;YACAvB,WAAWa;YACX,OAAOD;QACT;IACF;AACF","ignoreList":[0]}