diff --git a/src/listener.ts b/src/listener.ts index 0957347..82655d2 100644 --- a/src/listener.ts +++ b/src/listener.ts @@ -1,7 +1,7 @@ import type { IncomingMessage, ServerResponse, OutgoingHttpHeaders } from 'node:http' import type { Http2ServerRequest, Http2ServerResponse } from 'node:http2' -import { getAbortController, newRequest } from './request' -import { cacheKey, getInternalBody } from './response' +import { getAbortController, newRequest, Request as LightweightRequest } from './request' +import { cacheKey, getInternalBody, Response as LightweightResponse } from './response' import type { CustomErrorHandler, FetchCallback, HttpBindings } from './types' import { writeFromReadableStream, buildOutgoingHttpHeaders } from './utils' import { X_ALREADY_SENT } from './utils/response/constants' @@ -139,8 +139,20 @@ const responseViaResponseObject = async ( export const getRequestListener = ( fetchCallback: FetchCallback, - options: { errorHandler?: CustomErrorHandler } = {} + options: { + errorHandler?: CustomErrorHandler + overrideGlobalObjects?: boolean + } = {} ) => { + if (options.overrideGlobalObjects !== false && global.Request !== LightweightRequest) { + Object.defineProperty(global, 'Request', { + value: LightweightRequest, + }) + Object.defineProperty(global, 'Response', { + value: LightweightResponse, + }) + } + return async ( incoming: IncomingMessage | Http2ServerRequest, outgoing: ServerResponse | Http2ServerResponse diff --git a/src/request.ts b/src/request.ts index 9bffea8..49613d8 100644 --- a/src/request.ts +++ b/src/request.ts @@ -20,9 +20,6 @@ export class Request extends GlobalRequest { super(input, options) } } -Object.defineProperty(global, 'Request', { - value: Request, -}) const newRequestFromIncoming = ( method: string, diff --git a/src/response.ts b/src/response.ts index a031464..0750dce 100644 --- a/src/response.ts +++ b/src/response.ts @@ -80,9 +80,6 @@ export class Response { }) Object.setPrototypeOf(Response, GlobalResponse) Object.setPrototypeOf(Response.prototype, GlobalResponse.prototype) -Object.defineProperty(global, 'Response', { - value: Response, -}) const stateKey = Reflect.ownKeys(new GlobalResponse()).find( (k) => typeof k === 'symbol' && k.toString() === 'Symbol(state)' diff --git a/src/server.ts b/src/server.ts index 3ee0d02..d1b3146 100644 --- a/src/server.ts +++ b/src/server.ts @@ -5,7 +5,9 @@ import type { Options, ServerType } from './types' export const createAdaptorServer = (options: Options): ServerType => { const fetchCallback = options.fetch - const requestListener = getRequestListener(fetchCallback) + const requestListener = getRequestListener(fetchCallback, { + overrideGlobalObjects: options.overrideGlobalObjects, + }) // ts will complain about createServerHTTP and createServerHTTP2 not being callable, which works just fine // eslint-disable-next-line @typescript-eslint/no-explicit-any const createServer: any = options.createServer || createServerHTTP diff --git a/src/types.ts b/src/types.ts index 3dfb2f4..90ed29b 100644 --- a/src/types.ts +++ b/src/types.ts @@ -69,6 +69,7 @@ type ServerOptions = export type Options = { fetch: FetchCallback + overrideGlobalObjects?: boolean port?: number hostname?: string } & ServerOptions diff --git a/test/listener.test.ts b/test/listener.test.ts index 77e6c01..58973a2 100644 --- a/test/listener.test.ts +++ b/test/listener.test.ts @@ -1,6 +1,8 @@ import { createServer } from 'node:http' import request from 'supertest' import { getRequestListener } from '../src/listener' +import { GlobalRequest, Request as LightweightRequest } from '../src/request' +import { GlobalResponse, Response as LightweightResponse } from '../src/response' describe('Error handling - sync fetchCallback', () => { const fetchCallback = jest.fn(() => { @@ -205,3 +207,46 @@ describe('Abort request', () => { } }) }) + +describe('overrideGlobalObjects', () => { + const fetchCallback = jest.fn() + + beforeEach(() => { + Object.defineProperty(global, 'Request', { + value: GlobalRequest, + writable: true, + }) + Object.defineProperty(global, 'Response', { + value: GlobalResponse, + writable: true, + }) + }) + + describe('default', () => { + it('Should be overridden', () => { + getRequestListener(fetchCallback) + expect(global.Request).toBe(LightweightRequest) + expect(global.Response).toBe(LightweightResponse) + }) + }) + + describe('overrideGlobalObjects: true', () => { + it('Should be overridden', () => { + getRequestListener(fetchCallback, { + overrideGlobalObjects: true, + }) + expect(global.Request).toBe(LightweightRequest) + expect(global.Response).toBe(LightweightResponse) + }) + }) + + describe('overrideGlobalObjects: false', () => { + it('Should not be overridden', () => { + getRequestListener(fetchCallback, { + overrideGlobalObjects: false, + }) + expect(global.Request).toBe(GlobalRequest) + expect(global.Response).toBe(GlobalResponse) + }) + }) +}) diff --git a/test/request.test.ts b/test/request.test.ts index 340851a..f86bc65 100644 --- a/test/request.test.ts +++ b/test/request.test.ts @@ -1,5 +1,14 @@ import type { IncomingMessage } from 'node:http' -import { newRequest, Request, GlobalRequest, getAbortController } from '../src/request' +import { + newRequest, + Request as LightweightRequest, + GlobalRequest, + getAbortController, +} from '../src/request' + +Object.defineProperty(global, 'Request', { + value: LightweightRequest, +}) describe('Request', () => { describe('newRequest', () => { diff --git a/test/response.test.ts b/test/response.test.ts index 175a340..41e4a9a 100644 --- a/test/response.test.ts +++ b/test/response.test.ts @@ -1,8 +1,12 @@ import { createServer, type Server } from 'node:http' import type { AddressInfo } from 'node:net' -import { GlobalResponse } from '../src/response' +import { GlobalResponse, Response as LightweightResponse } from '../src/response' -class NextResponse extends Response {} +Object.defineProperty(global, 'Response', { + value: LightweightResponse, +}) + +class NextResponse extends LightweightResponse {} class UpperCaseStream extends TransformStream { constructor() { diff --git a/test/server.test.ts b/test/server.test.ts index 3bd61f2..9780fff 100644 --- a/test/server.test.ts +++ b/test/server.test.ts @@ -8,6 +8,8 @@ import { compress } from 'hono/compress' import { poweredBy } from 'hono/powered-by' import { stream } from 'hono/streaming' import request from 'supertest' +import { GlobalRequest, Request as LightweightRequest } from '../src/request' +import { GlobalResponse, Response as LightweightResponse } from '../src/response' import { createAdaptorServer } from '../src/server' import type { HttpBindings } from '../src/types' @@ -755,3 +757,42 @@ describe('forwarding IncomingMessage and ServerResponse in env', () => { expect(res.body.status).toBe(200) }) }) + +describe('overrideGlobalObjects', () => { + const app = new Hono() + + beforeEach(() => { + Object.defineProperty(global, 'Request', { + value: GlobalRequest, + writable: true, + }) + Object.defineProperty(global, 'Response', { + value: GlobalResponse, + writable: true, + }) + }) + + describe('default', () => { + it('Should be overridden', () => { + createAdaptorServer(app) + expect(global.Request).toBe(LightweightRequest) + expect(global.Response).toBe(LightweightResponse) + }) + }) + + describe('overrideGlobalObjects: true', () => { + it('Should be overridden', () => { + createAdaptorServer({ overrideGlobalObjects: true, fetch: app.fetch }) + expect(global.Request).toBe(LightweightRequest) + expect(global.Response).toBe(LightweightResponse) + }) + }) + + describe('overrideGlobalObjects: false', () => { + it('Should not be overridden', () => { + createAdaptorServer({ overrideGlobalObjects: false, fetch: app.fetch }) + expect(global.Request).toBe(GlobalRequest) + expect(global.Response).toBe(GlobalResponse) + }) + }) +}) diff --git a/test/setup.ts b/test/setup.ts index da76d94..c89e1b7 100644 --- a/test/setup.ts +++ b/test/setup.ts @@ -1,3 +1,7 @@ +Object.defineProperty(global, 'fetch', { + value: global.fetch, + writable: true, +}) Object.defineProperty(global, 'Response', { value: global.Response, writable: true,