diff --git a/README.md b/README.md new file mode 100644 index 0000000..1485ccf --- /dev/null +++ b/README.md @@ -0,0 +1,105 @@ +# hono-node-workers-server + +Node.js Worker Threads runtime adapter for Hono. + +This adapter keeps Hono routing and middleware in the main thread, then runs selected route logic in a new Node.js `Worker` for each request. Worker route modules use Web-standard `Request` and `Response` objects so the route logic stays easy to port to other Hono runtimes. + +## Requirements + +- Node.js 22+ +- Hono 4+ + +## Server + +```ts +import { Hono } from 'hono' +import { serve, workerRoute } from 'hono-node-workers-server' + +const app = new Hono() + +app.get( + '/hello/:name', + workerRoute(new URL('./routes/hello.mjs', import.meta.url), { + env: () => ({ greeting: 'Hello' }), + }) +) + +serve({ fetch: app.fetch, port: 3000 }) +``` + +## Worker Route + +```ts +import { defineWorkerRoute } from 'hono-node-workers-server/worker' + +export default defineWorkerRoute(async (request, context) => { + const url = new URL(request.url) + + return Response.json({ + greeting: context.env.greeting, + name: context.params.name, + excited: url.searchParams.get('excited') === 'true', + }) +}) +``` + +The worker route file must be importable by a plain Node.js worker. In practice, point `workerRoute()` at compiled JavaScript, an `.mjs` file, or another module Node can import directly. + +## Portability + +Worker route modules are just fetch-style handlers. To run the same logic in a normal Hono route, call it from a Hono handler: + +```ts +import hello from './routes/hello.mjs' + +app.get('/hello/:name', (c) => { + return hello(c.req.raw, { + params: c.req.param(), + env: { greeting: 'Hello' }, + }) +}) +``` + +## API + +### `serve(options, listeningListener?)` + +Starts a Node HTTP server. + +```ts +serve({ fetch: app.fetch, port: 3000 }) +``` + +### `createAdaptorServer(options)` + +Creates a Node HTTP server without calling `.listen()`. + +```ts +const server = createAdaptorServer({ fetch: app.fetch }) +``` + +### `workerRoute(moduleSpecifier, options?)` + +Creates a Hono middleware handler that runs the route module in a fresh Worker Thread. + +```ts +workerRoute(new URL('./routes/echo.mjs', import.meta.url), { + exportName: 'default', + env: (c) => ({ requestId: c.req.header('x-request-id') }), + timeoutMs: 1000, +}) +``` + +Options: + +- `exportName`: export to call from the worker module. Defaults to `default`. +- `env`: selects cloneable data to pass as `context.env`. If omitted, `context.env` is `undefined`. +- `timeoutMs`: aborts the worker if it does not produce a response in time. + +## Current Limitations + +- A new Worker Thread is created for each request. There is no worker pool yet. +- Only HTTP/1 is implemented. +- WebSockets are not implemented. +- `context.env` must be structured-cloneable. Use `options.env` to select only the data a worker route needs. +- `Request` and `Response` objects are serialized across the worker boundary; Node cannot clone them directly.