@mjackson/node-fetch-server
Advanced tools
@@ -23,3 +23,5 @@ "use strict"; | ||
| __export(node_fetch_server_exports, { | ||
| createRequestListener: () => createRequestListener | ||
| createRequest: () => createRequest, | ||
| createRequestListener: () => createRequestListener, | ||
| sendResponse: () => sendResponse | ||
| }); | ||
@@ -32,7 +34,3 @@ module.exports = __toCommonJS(node_fetch_server_exports); | ||
| return async (req, res) => { | ||
| let controller = new AbortController(); | ||
| res.on("close", () => { | ||
| controller.abort(); | ||
| }); | ||
| let request = createRequest(req, controller.signal, options); | ||
| let request = createRequest(req, options); | ||
| let client = { | ||
@@ -54,13 +52,3 @@ address: req.socket.remoteAddress, | ||
| } | ||
| let rawHeaders = []; | ||
| for (let [key, value] of response.headers) { | ||
| rawHeaders.push(key, value); | ||
| } | ||
| res.writeHead(response.status, rawHeaders); | ||
| if (response.body != null && req.method !== "HEAD") { | ||
| for await (let chunk of response.body) { | ||
| res.write(chunk); | ||
| } | ||
| } | ||
| res.end(); | ||
| await sendResponse(res, response); | ||
| }; | ||
@@ -106,3 +94,7 @@ } | ||
| } | ||
| function createRequest(req, signal, options) { | ||
| function createRequest(req, options) { | ||
| let controller = new AbortController(); | ||
| req.on("close", () => { | ||
| controller.abort(); | ||
| }); | ||
| let method = req.method ?? "GET"; | ||
@@ -113,11 +105,11 @@ let headers = createHeaders(req.rawHeaders); | ||
| let url = new URL(req.url, `${protocol}//${host}`); | ||
| let init = { method, headers, signal }; | ||
| let init = { method, headers, signal: controller.signal }; | ||
| if (method !== "GET" && method !== "HEAD") { | ||
| init.body = new ReadableStream({ | ||
| start(controller) { | ||
| start(controller2) { | ||
| req.on("data", (chunk) => { | ||
| controller.enqueue(new Uint8Array(chunk.buffer, chunk.byteOffset, chunk.byteLength)); | ||
| controller2.enqueue(new Uint8Array(chunk.buffer, chunk.byteOffset, chunk.byteLength)); | ||
| }); | ||
| req.on("end", () => { | ||
| controller.close(); | ||
| controller2.close(); | ||
| }); | ||
@@ -137,1 +129,14 @@ } | ||
| } | ||
| async function sendResponse(res, response) { | ||
| let rawHeaders = []; | ||
| for (let [key, value] of response.headers) { | ||
| rawHeaders.push(key, value); | ||
| } | ||
| res.writeHead(response.status, rawHeaders); | ||
| if (response.body != null && res.req.method !== "HEAD") { | ||
| for await (let chunk of response.body) { | ||
| res.write(chunk); | ||
| } | ||
| } | ||
| res.end(); | ||
| } |
@@ -74,7 +74,7 @@ import * as http from 'node:http'; | ||
| * import * as http from 'node:http'; | ||
| * import { type FetchHandler, createRequestListener } from '@mjackson/node-fetch-server'; | ||
| * import { createRequestListener } from '@mjackson/node-fetch-server'; | ||
| * | ||
| * let handler: FetchHandler = async (request) => { | ||
| * async function handler(request) { | ||
| * return new Response('Hello, world!'); | ||
| * }; | ||
| * } | ||
| * | ||
@@ -87,5 +87,23 @@ * let server = http.createServer( | ||
| * ``` | ||
| * | ||
| * @param handler The fetch handler to use for processing incoming requests. | ||
| * @param options Configuration options. | ||
| * @returns A Node.js `http.RequestListener` that can be used with `http.createServer()` or `https.createServer()`. | ||
| */ | ||
| declare function createRequestListener(handler: FetchHandler, options?: RequestListenerOptions): http.RequestListener; | ||
| type RequestOptions = Omit<RequestListenerOptions, 'onError'>; | ||
| /** | ||
| * Creates a `Request` object from an incoming Node.js request object. | ||
| * @param req The incoming request object. | ||
| * @param options | ||
| * @returns A `Request` object. | ||
| */ | ||
| declare function createRequest(req: http.IncomingMessage, options?: RequestOptions): Request; | ||
| /** | ||
| * Sends a `Response` to the client using the Node.js response object. | ||
| * @param res The server response object. | ||
| * @param response The response to send. | ||
| */ | ||
| declare function sendResponse(res: http.ServerResponse, response: Response): Promise<void>; | ||
| export { type ClientAddress, type ErrorHandler, type FetchHandler, type RequestListenerOptions, createRequestListener }; | ||
| export { type ClientAddress, type ErrorHandler, type FetchHandler, type RequestListenerOptions, type RequestOptions, createRequest, createRequestListener, sendResponse }; |
@@ -74,7 +74,7 @@ import * as http from 'node:http'; | ||
| * import * as http from 'node:http'; | ||
| * import { type FetchHandler, createRequestListener } from '@mjackson/node-fetch-server'; | ||
| * import { createRequestListener } from '@mjackson/node-fetch-server'; | ||
| * | ||
| * let handler: FetchHandler = async (request) => { | ||
| * async function handler(request) { | ||
| * return new Response('Hello, world!'); | ||
| * }; | ||
| * } | ||
| * | ||
@@ -87,5 +87,23 @@ * let server = http.createServer( | ||
| * ``` | ||
| * | ||
| * @param handler The fetch handler to use for processing incoming requests. | ||
| * @param options Configuration options. | ||
| * @returns A Node.js `http.RequestListener` that can be used with `http.createServer()` or `https.createServer()`. | ||
| */ | ||
| declare function createRequestListener(handler: FetchHandler, options?: RequestListenerOptions): http.RequestListener; | ||
| type RequestOptions = Omit<RequestListenerOptions, 'onError'>; | ||
| /** | ||
| * Creates a `Request` object from an incoming Node.js request object. | ||
| * @param req The incoming request object. | ||
| * @param options | ||
| * @returns A `Request` object. | ||
| */ | ||
| declare function createRequest(req: http.IncomingMessage, options?: RequestOptions): Request; | ||
| /** | ||
| * Sends a `Response` to the client using the Node.js response object. | ||
| * @param res The server response object. | ||
| * @param response The response to send. | ||
| */ | ||
| declare function sendResponse(res: http.ServerResponse, response: Response): Promise<void>; | ||
| export { type ClientAddress, type ErrorHandler, type FetchHandler, type RequestListenerOptions, createRequestListener }; | ||
| export { type ClientAddress, type ErrorHandler, type FetchHandler, type RequestListenerOptions, type RequestOptions, createRequest, createRequestListener, sendResponse }; |
@@ -5,7 +5,3 @@ // src/lib/request-listener.ts | ||
| return async (req, res) => { | ||
| let controller = new AbortController(); | ||
| res.on("close", () => { | ||
| controller.abort(); | ||
| }); | ||
| let request = createRequest(req, controller.signal, options); | ||
| let request = createRequest(req, options); | ||
| let client = { | ||
@@ -27,13 +23,3 @@ address: req.socket.remoteAddress, | ||
| } | ||
| let rawHeaders = []; | ||
| for (let [key, value] of response.headers) { | ||
| rawHeaders.push(key, value); | ||
| } | ||
| res.writeHead(response.status, rawHeaders); | ||
| if (response.body != null && req.method !== "HEAD") { | ||
| for await (let chunk of response.body) { | ||
| res.write(chunk); | ||
| } | ||
| } | ||
| res.end(); | ||
| await sendResponse(res, response); | ||
| }; | ||
@@ -79,3 +65,7 @@ } | ||
| } | ||
| function createRequest(req, signal, options) { | ||
| function createRequest(req, options) { | ||
| let controller = new AbortController(); | ||
| req.on("close", () => { | ||
| controller.abort(); | ||
| }); | ||
| let method = req.method ?? "GET"; | ||
@@ -86,11 +76,11 @@ let headers = createHeaders(req.rawHeaders); | ||
| let url = new URL(req.url, `${protocol}//${host}`); | ||
| let init = { method, headers, signal }; | ||
| let init = { method, headers, signal: controller.signal }; | ||
| if (method !== "GET" && method !== "HEAD") { | ||
| init.body = new ReadableStream({ | ||
| start(controller) { | ||
| start(controller2) { | ||
| req.on("data", (chunk) => { | ||
| controller.enqueue(new Uint8Array(chunk.buffer, chunk.byteOffset, chunk.byteLength)); | ||
| controller2.enqueue(new Uint8Array(chunk.buffer, chunk.byteOffset, chunk.byteLength)); | ||
| }); | ||
| req.on("end", () => { | ||
| controller.close(); | ||
| controller2.close(); | ||
| }); | ||
@@ -110,4 +100,19 @@ } | ||
| } | ||
| async function sendResponse(res, response) { | ||
| let rawHeaders = []; | ||
| for (let [key, value] of response.headers) { | ||
| rawHeaders.push(key, value); | ||
| } | ||
| res.writeHead(response.status, rawHeaders); | ||
| if (response.body != null && res.req.method !== "HEAD") { | ||
| for await (let chunk of response.body) { | ||
| res.write(chunk); | ||
| } | ||
| } | ||
| res.end(); | ||
| } | ||
| export { | ||
| createRequestListener | ||
| createRequest, | ||
| createRequestListener, | ||
| sendResponse | ||
| }; |
+1
-1
| { | ||
| "name": "@mjackson/node-fetch-server", | ||
| "version": "0.2.0", | ||
| "version": "0.3.0", | ||
| "description": "Build servers for Node.js using the web fetch API", | ||
@@ -5,0 +5,0 @@ "author": "Michael Jackson <mjijackson@gmail.com>", |
+33
-4
@@ -34,5 +34,5 @@ # node-fetch-server | ||
| let handler = (request: Request) => { | ||
| function handler(request: Request) { | ||
| return new Response('Hello, world!'); | ||
| }; | ||
| } | ||
@@ -51,7 +51,7 @@ let server = http.createServer(createRequestListener(handler)); | ||
| let handler = (request: Request) => { | ||
| function handler(request: Request) { | ||
| // This is now true | ||
| assert.equal(new URL(request.url).host, process.env.HOST); | ||
| return new Response('Hello, world!'); | ||
| }; | ||
| } | ||
@@ -73,2 +73,31 @@ let server = http.createServer(createRequestListener(handler, { host: process.env.HOST })); | ||
| ## Low-level API | ||
| In addition to the high-level `createRequestListener()` API, this package also provides 2 low-level APIs that are useful when building custom `fetch`-based servers in Node.js: | ||
| - `createRequest(req: http.IncomingMessage, options: RequestOptions): Request` | ||
| - `sendResponse(res: http.ServerResponse, response: Response): Promise<void>` | ||
| These two functions serve as an efficient, minimal translation layer between Node.js `req`/`res` objects and fetch `Request`/`Response` objects. You could build your own custom server like this: | ||
| ```ts | ||
| import * as http from 'node:http'; | ||
| import { createRequest, sendResponse } from '@mjackson/node-fetch-server'; | ||
| let server = http.createServer(async (req, res) => { | ||
| let request = createRequest(req, { host: process.env.HOST }); | ||
| try { | ||
| let response = await customAppLogic(request); | ||
| await sendResponse(res, response); | ||
| } catch (error) { | ||
| console.error(error); | ||
| res.writeHead(500, { 'Content-Type': 'text/plain' }); | ||
| res.end('Internal Server Error'); | ||
| } | ||
| }); | ||
| server.listen(3000); | ||
| ``` | ||
| ## Related Packages | ||
@@ -75,0 +104,0 @@ |
Network access
Supply chain riskThis module accesses the network.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Network access
Supply chain riskThis module accesses the network.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 1 instance in 1 package
23420
14.36%351
8.67%156
22.83%7
16.67%