Packages
@edge-runtime/node-utils

Edge Runtime Node Utils

The @edge-runtime/node-utils package contains utilities to run web compliant code into a Node.js environment.

⚠️

Please note this is an alpha version.

Installation

npm install @edge-runtime/node-utils

This package includes built-in TypeScript support.

Usage

import { once } = from 'node:events'
import { createServer } from 'node:http'
import { buildToNodeHandler } from '@edge-runtime/node-utils'
 
// 1. builds a transformer, using Node.js@18 globals, and a base url for URL constructor.
const transformToNode = buildToNodeHandler(global, {
  defaultOrigin: 'http://example.com',
})
 
const server = await createServer(
  // 2. takes an web compliant request handler, that uses Web globals like Request and Response,
  // and turn it into a Node.js compliant request handler.
  transformToNode(async (req: Request) => new Response(req.body))
)
 
// 3. start the node.js server
server.listen()
await once(server, 'listening')
 
// 4. invoke the request handler
const response = await fetch(
  `http://localhost:${(server.address() as AddressInfo).port}`,
  { method: 'POST', body: 'hello world' }
)
 
console.log(await response.text()) // is 'hello world'
await server.close()

API

buildToNodeHandler(dependencies, options): toNodeHandler(handler: WebHandler): NodeHandler

Builds a transformer function to turn an web compliant request handler ((req: Request) => Promise<Response> | Response | null | undefined) into a Node.js compliant request handler (opens in a new tab) ((req: IncomingMessage, res: ServerResponse) => Promise<void> | void).

Limitation: it does support the web handler second parameter, so waitUntil is not implemented yet.

dependencies: object

List of Web globals used by the transformer function:

When running in Node.js 18+ (or Node.js 16 with --experimental-fetch (opens in a new tab)), you may pass the ones from global scope.

import { buildToNodeHandler } from '@edge-runtime/node-utils'
 
buildToNodeHandler(globals, {
  /* ... options */
})

Otherwise, you can reuse primitives from @edge-runtime/primitives

import { buildToNodeHandler } from '@edge-runtime/node-utils'
import * as primitives from '@edge-runtime/primitives'
 
buildToNodeHandler(primitives, {
  /* ... options */
})

options: object

Options used to build the transformer function, including:

defaultOrigin: string

The incoming host header (opens in a new tab) is used when turning the incoming request relative url into a full Request.url (opens in a new tab) string. In case no host is provided, this default origin will be used instead.

buildToRequest(dependencies, options): toRequest(request: IncomingMessage, options: object): Request

Builds a transformer function to turn a Node.js IncomingMessage (opens in a new tab) into a Web [Request]. It needs globals Web contstructor a dependencies, as well as options to handle incoming url.

buildToFetchEvent(dependencies): toFetchEvent(request: Request): FetchEvent

Builds a transformer function to build a fetch event from a web [Request]. The returned event is linked to provided request, and has a mocked waitUntil() (opens in a new tab) method, which throws on access.

It needs globals Web constructor a dependencies.

toOutgoingHeaders(headers: Headers): OutgoingHttpHeaders

Turns Web Request.headers (opens in a new tab) into Node.js ServerResponse OutgoingHttpHeaders (opens in a new tab).

Includes set-cookie special handling, splitting multiple values when relevant.

buildToHeaders(dependencies): toHeaders(nodeHeaders: IncomingHttpHeaders): Headers

Builds a transformer to turn Node.js IncomingHttpHeaders (opens in a new tab) into Web Request.headers (opens in a new tab).

toToReadable(webStream: ReadableStream, options: object): Readable

Turns Web ReadableStream (opens in a new tab) (typically, the Response.body (opens in a new tab)) into Node.js Readable (opens in a new tab) stream.

buildToReadableStream(dependencies): toReadableStream(stream: Readable): ReadableStream

Builds a transformer to turn Node.js Readable (opens in a new tab) (typically, the IncomingMessage (opens in a new tab)'s payload) into Web ReadableStream (opens in a new tab).