diff --git a/src/index.ts b/src/index.ts index b2fc616..6de5948 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,2 +1,3 @@ export { serve, createAdaptorServer } from './server' export { getRequestListener } from './listener' +export type { HttpBindings, Http2Bindings } from './types' diff --git a/src/listener.ts b/src/listener.ts index 1e02c5c..d25f512 100644 --- a/src/listener.ts +++ b/src/listener.ts @@ -2,7 +2,7 @@ import type { IncomingMessage, ServerResponse, OutgoingHttpHeaders } from 'node: import type { Http2ServerRequest, Http2ServerResponse } from 'node:http2' import { newRequest } from './request' import { cacheKey } from './response' -import type { FetchCallback } from './types' +import type { FetchCallback, HttpBindings } from './types' import { writeFromReadableStream, buildOutgoingHttpHeaders } from './utils' import './globals' @@ -115,7 +115,7 @@ export const getRequestListener = (fetchCallback: FetchCallback) => { const req = newRequest(incoming) try { - res = fetchCallback(req) as Response | Promise + res = fetchCallback(req, { incoming, outgoing } as HttpBindings) as Response | Promise if (cacheKey in res) { // synchronous, cacheable response return responseViaCache(res as Response, outgoing) diff --git a/src/types.ts b/src/types.ts index 94461b0..7ccef14 100644 --- a/src/types.ts +++ b/src/types.ts @@ -1,8 +1,16 @@ -import type { createServer, Server, ServerOptions as HttpServerOptions } from 'node:http' +import type { + createServer, + IncomingMessage, + Server, + ServerOptions as HttpServerOptions, + ServerResponse as HttpServerResponse, +} from 'node:http' import type { createSecureServer as createSecureHttp2Server, createServer as createHttp2Server, + Http2ServerRequest, Http2Server, + Http2ServerResponse, Http2SecureServer, SecureServerOptions as SecureHttp2ServerOptions, ServerOptions as Http2ServerOptions, @@ -12,7 +20,17 @@ import type { ServerOptions as HttpsServerOptions, } from 'node:https' -export type FetchCallback = (request: Request) => Promise | unknown +export type HttpBindings = { + incoming: IncomingMessage + outgoing: HttpServerResponse +} + +export type Http2Bindings = { + incoming: Http2ServerRequest + outgoing: Http2ServerResponse +} + +export type FetchCallback = (request: Request, env: HttpBindings | Http2Bindings) => Promise | unknown export type NextHandlerOption = { fetch: FetchCallback diff --git a/test/server.test.ts b/test/server.test.ts index a7a111c..6c8920b 100644 --- a/test/server.test.ts +++ b/test/server.test.ts @@ -8,6 +8,7 @@ import { compress } from 'hono/compress' import { poweredBy } from 'hono/powered-by' import request from 'supertest' import { createAdaptorServer } from '../src/server' +import type { HttpBindings } from '../src/types' describe('Basic', () => { const app = new Hono() @@ -462,10 +463,10 @@ describe('SSL', () => { describe('HTTP2', () => { const app = new Hono() app.get('/', (c) => c.text('Hello! Node!')) - app.get('/headers', (c) => { + app.get('/headers', (c) => { // call newRequestFromIncoming c.req.header('Accept') - return c.text('Hello! Node!') + return c.text('Hello! Node!') }) app.get('/url', (c) => c.text(c.req.url)) @@ -541,3 +542,24 @@ describe('set child response to c.res', () => { expect(res.headers['content-type']).toMatch(/application\/json/) }) }) + +describe('forwarding IncomingMessage and ServerResponse in env', () => { + const app = new Hono<{ Bindings: HttpBindings }>() + app.get('/', (c) => c.json({ + incoming: c.env.incoming.constructor.name, + url: c.env.incoming.url, + outgoing: c.env.outgoing.constructor.name, + status: c.env.outgoing.statusCode + })) + + it('Should add `incoming` and `outgoing` to env', async () => { + const server = createAdaptorServer(app) + const res = await request(server).get('/') + + expect(res.status).toBe(200) + expect(res.body.incoming).toBe('IncomingMessage') + expect(res.body.url).toBe('/') + expect(res.body.outgoing).toBe('ServerResponse') + expect(res.body.status).toBe(200) + }) +})