From 9b244076bb345a3aba968dd0628061c63d950ca8 Mon Sep 17 00:00:00 2001 From: Ahmed Gamal Date: Tue, 13 Oct 2026 20:21:40 +0300 Subject: [PATCH] fix(request): forward duplex to the native request Since undici 8.11 (Node.js 26.11), Request getters use private-field brand checks, so reading `duplex` on the lightweight request falls through to the native getter and throws ERR_INVALID_THIS. This breaks passing the request as RequestInit, e.g. `new Request(url, c.req.raw)` and `app.mount()`. Fixes #408 --- src/request.ts | 1 + test/request.test.ts | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 33 insertions(+) diff --git a/src/request.ts b/src/request.ts index a4b0e11..57c6705 100644 --- a/src/request.ts +++ b/src/request.ts @@ -660,6 +660,7 @@ Object.defineProperty(requestPrototype, 'signal', { 'cache', 'credentials', 'destination', + 'duplex', 'integrity', 'mode', 'redirect', diff --git a/test/request.test.ts b/test/request.test.ts index a15927c..5ce7e95 100644 --- a/test/request.test.ts +++ b/test/request.test.ts @@ -34,6 +34,7 @@ describe('Request', () => { expect(req.url).toBe('http://localhost/') expect(req.headers.get('host')).toBe('localhost') expect(req.keepalive).toBe(false) + expect(req.duplex).toBe('half') }) it('Should not generate GlobalRequest when accessing method, url or headers', async () => { @@ -1170,6 +1171,37 @@ describe('Request', () => { expect(req2).toBeInstanceOf(GlobalRequest) await expect(req2.text()).resolves.toBe('bar') }) + + it('should be success to create instance with a lightweight GET request as init option', () => { + const req = newRequest({ + method: 'GET', + url: '/', + headers: { + host: 'localhost', + }, + rawHeaders: ['host', 'localhost'], + } as IncomingMessage) + const req2 = new Request('http://localhost/subapp', req) + expect(req2).toBeInstanceOf(GlobalRequest) + expect(req2.method).toBe('GET') + expect(req2.url).toBe('http://localhost/subapp') + }) + + it('should be success to create instance with a lightweight POST request as init option', async () => { + const req = newRequest({ + method: 'POST', + url: '/', + headers: { + host: 'localhost', + }, + rawHeaders: ['host', 'localhost'], + rawBody: Buffer.from('foo'), + } as IncomingMessage & { rawBody: Buffer }) + const req2 = new Request('http://localhost/subapp', req) + expect(req2).toBeInstanceOf(GlobalRequest) + expect(req2.method).toBe('POST') + await expect(req2.text()).resolves.toBe('foo') + }) }) })