Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
77 commits
Select commit Hold shift + click to select a range
ca4594b
Begin work on undici migration
404Wolf Aug 11, 2025
80291b1
More work
404Wolf Aug 11, 2025
048bc7d
Tests passing
404Wolf Aug 12, 2025
1807519
Use custom request types
404Wolf Aug 13, 2025
b67a140
Remove console log
404Wolf Aug 13, 2025
4e0d8d9
Merge branch 'main' into undinci-pool
404Wolf Aug 13, 2025
172e5e6
Update package version
404Wolf Aug 13, 2025
794dd79
Remove utils
404Wolf Aug 13, 2025
568b14f
Relock
404Wolf Aug 13, 2025
535aaf8
Add back fix
404Wolf Aug 13, 2025
4cbaffb
Unskip test
404Wolf Aug 13, 2025
c882e3e
Bring back one other change
404Wolf Aug 13, 2025
bc935d2
Rename agent to pool
404Wolf Aug 13, 2025
8a7a655
Make sure header is cleared
404Wolf Aug 13, 2025
7cf9a55
Clear headers
404Wolf Aug 13, 2025
a96e297
Update small test
404Wolf Aug 13, 2025
9ef4ea9
Force deno origin
404Wolf Aug 13, 2025
52707f2
Revert to taking an input url
404Wolf Aug 13, 2025
c32bf5e
Fix failing test
404Wolf Aug 13, 2025
81a14c7
PR feedback
404Wolf Aug 13, 2025
6af752e
Bring back a test
404Wolf Aug 13, 2025
c8dc462
Await promises
404Wolf Aug 14, 2025
c21beed
Remove test focus
404Wolf Aug 14, 2025
ec18f20
Fix tests
404Wolf Aug 14, 2025
00f0831
Add to stack trace
404Wolf Aug 14, 2025
7489182
Make terminate async
404Wolf Aug 14, 2025
248c1aa
Add back package.json
404Wolf Aug 14, 2025
e04a2c2
Await warm request
404Wolf Aug 15, 2025
dcb9cc3
Update readme
404Wolf Aug 15, 2025
c8e885e
Merge pull request #43 from val-town/undinci-pool
404Wolf Aug 15, 2025
7f3f17d
Export types
404Wolf Aug 15, 2025
0b9f5cf
Merge pull request #48 from val-town/expose-types
404Wolf Aug 15, 2025
8919b76
Update dependency undici to v7.14.0 (#50)
renovate[bot] Aug 18, 2025
68c9f38
Keep connection open
404Wolf Aug 19, 2025
695b13a
Bump version
404Wolf Aug 19, 2025
58378b5
Revert to oldish logic
404Wolf Aug 19, 2025
babdb83
Merge pull request #52 from val-town/keep-connection-open
404Wolf Aug 19, 2025
55ece86
Don't ignore unhandled rejections (#55)
404Wolf Aug 20, 2025
f1aba66
Update test
404Wolf Aug 20, 2025
3b3f405
Merge pull request #56 from val-town/add-unhandled-rejection-test
404Wolf Aug 20, 2025
7eb0788
Add support for Websockets (#53)
404Wolf Aug 21, 2025
d29a785
docs: Update README.md
tmcw Aug 21, 2025
0c45201
Fix readme image (#57)
maxmcd Aug 21, 2025
0ea86ff
chore(deps): update actions/setup-node action to v5 (#60)
renovate[bot] Sep 8, 2025
3a94be2
chore(deps): update dependency @types/node to v24.3.1 (#46)
renovate[bot] Sep 8, 2025
bfca7b1
fix(deps): update dependency undici to v7.15.0 (#59)
renovate[bot] Sep 8, 2025
00bcd95
chore(deps): update dependency deno to v2.5.0 (#63)
renovate[bot] Sep 10, 2025
01ba605
chore(deps): update dependency deno to v2.5.2 (#65)
renovate[bot] Sep 25, 2025
0b5fe17
chore(deps): update dependency deno to v2.5.3 (#67)
renovate[bot] Oct 6, 2025
94efbf1
Add changesets (#69)
tmcw Oct 7, 2025
799f6c1
Install Deno in the release flow
tmcw Oct 7, 2025
c48cbdd
Create changeset config and first changeset
tmcw Oct 7, 2025
b9aa2bd
Add changesets/cli as devDep
tmcw Oct 7, 2025
4baa100
chore(deps): update dependency typescript to v5.9.3 (#66)
renovate[bot] Oct 7, 2025
8cb970d
chore(deps): update dependency @types/node to v24.7.0 (#64)
renovate[bot] Oct 7, 2025
242c34f
chore(deps): update dependency undici to v7.16.0 (#61)
renovate[bot] Oct 7, 2025
6463ab7
Version Packages (#70)
github-actions[bot] Oct 7, 2025
d74caf6
Attempt publishing with OIDC
tmcw Oct 7, 2025
f009504
Update Deno version in test, adopt OIDC
tmcw Oct 7, 2025
b5d17a5
Add permissions
tmcw Oct 7, 2025
20320a5
Version Packages (#71)
github-actions[bot] Oct 7, 2025
d2d6cd2
Use modern npm
tmcw Oct 7, 2025
c9b56ac
Close pools (#72)
tmcw Oct 8, 2025
1ad123c
Don't include tests in dist (#49)
404Wolf Oct 8, 2025
b780b19
Version Packages (#73)
github-actions[bot] Oct 8, 2025
6764cf6
Dont close pool (#74)
tmcw Oct 8, 2025
00ac501
Version Packages (#75)
github-actions[bot] Oct 8, 2025
7fef5bf
Remove configurable spawn (#77)
tmcw Oct 8, 2025
3bca30f
Move sync code, use once (#84)
tmcw Oct 10, 2025
c834beb
Improve failure tests (#85)
tmcw Oct 10, 2025
cee6ef5
chore(deps): update actions/setup-node action to v6 (#86)
renovate[bot] Oct 14, 2025
c76ade8
chore(deps): update dependency vitest to v4 (#87)
renovate[bot] Oct 27, 2025
31a28c8
chore(deps): update dependency vitest to v4.0.5 (#89)
renovate[bot] Oct 29, 2025
a5e8c1d
chore(deps): update dependency node to v24 (#88)
renovate[bot] Oct 29, 2025
2de73ae
chore(deps): update dependency @types/node to v24.9.2 (#82)
renovate[bot] Oct 29, 2025
74fd777
chore(deps): update dependency deno to v2.5.5 (#81)
renovate[bot] Oct 29, 2025
506ad15
Version Packages
github-actions[bot] Oct 29, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions .changeset/config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"$schema": "https://unpkg.com/@changesets/config@3.1.1/schema.json",
"changelog": "@changesets/cli/changelog",
"commit": false,
"fixed": [],
"linked": [],
"access": "public",
"baseBranch": "main",
"updateInternalDependencies": "patch",
"ignore": []
}
16 changes: 5 additions & 11 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
name: ci
name: Tests

on: [push]

Expand All @@ -9,12 +9,14 @@ jobs:
matrix:
os: [ubuntu-latest]
node-version: [22.x, 24.x]
deno-version: [1.40.x]
deno-version: [2.5.x]
runs-on: ${{ matrix.os }}
env:
CI: true
steps:
- uses: actions/checkout@v5
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v4
uses: actions/setup-node@v6
with:
node-version: ${{ matrix.node-version }}
- name: Use Deno Version ${{ matrix.deno-version }}
Expand All @@ -23,13 +25,5 @@ jobs:
deno-version: ${{ matrix.deno-version }}
- name: npm install
run: npm ci
env:
CI: true
- name: prepare
run: npm run prepare
env:
CI: true
- name: vitest
run: npm run test
env:
CI: true
46 changes: 46 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
name: Release

on:
push:
branches:
- main

concurrency: ${{ github.workflow }}-${{ github.ref }}

permissions:
contents: write
pull-requests: write
id-token: write

jobs:
release:
name: Release
runs-on: ubuntu-latest
steps:
- name: Checkout Repo
uses: actions/checkout@v5

- name: Setup Node.js 22
uses: actions/setup-node@v6
with:
node-version: 24

- name: Use Deno Version 2.5.3
uses: denolib/setup-deno@master
with:
deno-version: 2.5.3

- name: update npm
run: npm update -g npm

- name: Install Dependencies
run: npm install

- name: Create Release Pull Request or Publish to npm
id: changesets
uses: changesets/action@v1
with:
publish: npm publish
env:
NPM_CONFIG_PROVENANCE: true
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
node_modules
.DS_Store
dist
tsconfig.tsbuildinfo
*.tsbuildinfo
3 changes: 3 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"deno.enablePaths": ["deno-bootstrap", "src/test"]
}
41 changes: 41 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# @valtown/deno-http-worker

## 2.0.0

### Major Changes

- 7fef5bf: Remove configurable spawn function option

Previously, we supported a `spawnFunc` option which let you use spawn methods
other than child_process.spawn. Given the lack of useful alternatives to child_process.spawn
and our efforts to really optimize this module, we're removing this option.

### Patch Changes

- c834beb: Improve error testing
- 3bca30f: Internal refactor: use once() and move sync code out of promise callback

## 1.1.4

### Patch Changes

- 6764cf6: Don't close the pool (bugfix)

## 1.1.3

### Patch Changes

- 1ad123c: Don't include tests in NPM dist
- c9b56ac: Close request pools when terminating workers

## 1.1.2

### Patch Changes

- f009504: Adopt deno 2.5.x and OIDC

## 1.1.1

### Patch Changes

- c48cbdd: Adopt changesets
52 changes: 31 additions & 21 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,43 +1,53 @@
# deno-http-worker

[![NPM version](https://img.shields.io/npm/v/deno-http-worker.svg?style=flat)](https://npmjs.org/package/deno-http-worker)
[![NPM version](https://img.shields.io/npm/v/@valtown/deno-http-worker.svg?style=flat)](https://npmjs.org/package/@valtown/deno-http-worker)

Similarly to [deno-vm](https://github.com/casual-simulation/node-deno-vm), deno-http-worker lets you securely spawn Deno http servers.
Similarly to [deno-vm](https://github.com/casual-simulation/node-deno-vm),
deno-http-worker lets you securely spawn Deno http servers.

## Usage

```ts
import { newDenoHTTPWorker } from 'deno-http-worker';
import { newDenoHTTPWorker } from "@valtown/deno-http-worker";

let worker = await newDenoHTTPWorker(
`export default {
async fetch(req: Request): Promise<Response> {
return Response.json({ ok: req.url });
},
}`,
{ printOutput: true, runFlags: ["--allow-net"] }
{ printOutput: true, runFlags: ["--allow-net"] },
);

const body = await new Promise((resolve, reject) => {
const req = worker.request("https://hello/world?query=param", {}, (resp) => {
const body = [];
resp.on("error", reject);
resp.on("data", (chunk) => {
body.push(chunk);
});
resp.on("end", () => {
resolve(Buffer.concat(body).toString());
});
})
req.end();
})
console.log(body) // => {"ok":"https://hello/world?query=param"}
const req = await worker.request({
url: "https://hello/world?query=param",
method: "GET",
});
const body = await req.body.json();

console.log(body); // => {"ok":"https://hello/world?query=param"}

worker.terminate();
```

## Internals

Deno-http-worker connects to the Deno process over a Unix socket to make requests. As a result, the worker does not provide an address or url, but instead returns `request` function that calls `http.request` under the hood, but modifies the request attributes to work over the socket.

If you need more advanced usage here, or run into bugs, please open an issue.
> [!TIP]
> This package [globally patches](/deno-bootstrap/index.ts#L28)
> Deno.upgradeWebSocket to enable websocket proxying. You can provide your own
> bootstrap script if different behavior is desired.

Deno-http-worker connects to the Deno process over a Unix socket via undici to
make requests. As a result, the worker does not provide an address or url, but
instead returns `undici.ResponseData` that uses `undici.Pool.request` under the
hood, but modifies the request attributes to work over the socket, and we expose
parts of [request and response interface](./src/types.ts).

You can also connect to the Deno process over a WebSocket connection, which uses
the same `undici.Pool`. We modify the inbound Request objects to preserve
various headers. Unfortunately Deno doesn't let you copy a request and then
modify properties, so we patch `Deno.upgradeWebSocket` when you use the
WebSockets functionality to use the original request for the upgrade, which may
be slightly different.

If you need more advanced usage here, or run into bugs, please open an issue.
3 changes: 2 additions & 1 deletion biome.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,11 @@
"indentStyle": "space"
},
"files": {
"includes": ["**", "!**/dist"]
"includes": ["**", "!**/dist", "!**/deno-bootstrap", "!**/src/test"]
},
"assist": { "actions": { "source": { "organizeImports": "off" } } },
"linter": {
"includes": ["**", "!**/dist", "!**/deno-bootstrap", "!**/src/test"],
"enabled": true,
"rules": {
"recommended": true,
Expand Down
39 changes: 27 additions & 12 deletions deno-bootstrap/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,23 +21,43 @@ const onError = mod.default.onError ??
});
const onListen = mod.default.onListen ?? ((_localAddr: Deno.NetAddr) => {});

// Use an empty onListen callback to prevent Deno from logging
const originalRequestProp = Symbol("originalRequest");

// We need to override Deno.upgradeWebSocket to use the original request object
// since Deno doesn't let us use copied request objects.
const originalUpgrade = Deno.upgradeWebSocket;
Object.defineProperty(Deno, "upgradeWebSocket", {
value: (req: Request) => {
return originalUpgrade(
(req as unknown as { [originalRequestProp]: Request })[
originalRequestProp
],
);
},
});

const server = Deno.serve(
{
path: socketFile,
// Use an empty onListen callback to prevent Deno from logging
onListen: onListen,
onError: onError,
},
(req: Request) => {
const headerUrl = req.headers.get("X-Deno-Worker-URL");
(originalReq: Request) => {
const headerUrl = originalReq.headers.get("X-Deno-Worker-URL");
if (!headerUrl) {
// This is just for the warming request, shouldn't be seen by clients.
return Response.json({ warming: true }, { status: 200 });
}
const url = new URL(headerUrl);

// Deno Request headers are immutable so we must make a new Request in order
// to delete our headers.
req = new Request(url.toString(), req);
const req = new Request(headerUrl, originalReq);

// Add the original request so that we can use it during Deno.upgradeWebSocket
(req as unknown as { [originalRequestProp]: Request })[
originalRequestProp
] = originalReq;

// Restore host and connection headers.
req.headers.delete("host");
Expand All @@ -51,24 +71,19 @@ const server = Deno.serve(
req.headers.get("X-Deno-Worker-Connection")!,
);
}

req.headers.delete("X-Deno-Worker-URL");
req.headers.delete("X-Deno-Worker-Host");
req.headers.delete("X-Deno-Worker-Connection");

return mod.default.fetch(req);
},
);

addEventListener("error", (e) => {
globalThis.addEventListener("error", (e) => {
console.error(e.error);
e.preventDefault();
});

addEventListener("unhandledrejection", (e) => {
console.error(e.reason);
e.preventDefault();
});

Deno.addSignalListener("SIGINT", async () => {
// On interrupt we only shut down the server. Deno will wait for all
// unresolved promises to complete before exiting.
Expand Down
1 change: 1 addition & 0 deletions mise.toml
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
[tools]
node = "24"
deno = "2.5.5"
Loading