Skip to content

Commit 7659aba

Browse files
authored
docs: Cloudflare Workers compatibility matrix (#6)
* docs: add Cloudflare Workers compatibility comparison matrix and API coverage gaps * fix(playground): use workspace dependency for secure-exec instead of relative dist path * fix(typescript): increase timeout for node types typecheck test
1 parent 3e4dfec commit 7659aba

File tree

7 files changed

+174
-3
lines changed

7 files changed

+174
-3
lines changed

docs-internal/todo.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,24 @@
102102
- [ ] Fix HTTP server lifecycle leaks when executions time out or are disposed.
103103
- `packages/secure-exec/src/execution.ts`, `packages/secure-exec/src/index.ts`, `packages/secure-exec/src/node/driver.ts`
104104

105+
## API Coverage Gaps
106+
107+
- [ ] Add missing `fs` APIs: `cp`, `cpSync`, `glob`, `globSync`, `opendir`, `mkdtemp`, `mkdtempSync`, `statfs`, `statfsSync`, `readv`, `readvSync`, `fdatasync`, `fdatasyncSync`, `fsync`, `fsyncSync`.
108+
- `packages/secure-exec/src/bridge/fs.ts`
109+
- Goal: full `node:fs` coverage for core file operations.
110+
111+
- [ ] Implement deferred `fs` APIs: `chmod`, `chown`, `link`, `symlink`, `readlink`, `truncate`, `utimes`, `watch`, `watchFile`.
112+
- `packages/secure-exec/src/bridge/fs.ts`
113+
- Currently throw deterministic unsupported errors.
114+
115+
- [ ] Add missing `http`/`https` APIs: connection pooling (`Agent`), keep-alive tuning, WebSocket upgrade, trailer headers, socket-level events.
116+
- `packages/secure-exec/src/bridge/network.ts`
117+
- Current implementation is fetch-based and fully buffered with no socket-level control.
118+
119+
- [ ] Fix `v8.serialize`/`v8.deserialize` to use V8 structured serialization instead of `JSON.stringify`/`JSON.parse`.
120+
- `packages/secure-exec/isolate-runtime/src/inject/bridge-initial-globals.ts` (~line 51)
121+
- Bug: current implementation silently produces JSON instead of V8 binary format. Code depending on structured clone semantics (`Map`, `Set`, `RegExp`, circular refs) will get wrong results.
122+
105123
## Performance & Correctness
106124

107125
- [ ] Add `stat` and `exists` methods to `VirtualFileSystem` interface.
Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
---
2+
title: Cloudflare Workers Comparison
3+
description: Node.js API compatibility comparison between secure-exec and Cloudflare Workers (standard, Workers for Platforms, dynamic dispatch).
4+
---
5+
6+
*Last updated: 2026-03-10*
7+
8+
## Overview
9+
10+
This document compares Node.js API support across **secure-exec** and three Cloudflare Workers deployment models:
11+
12+
| Platform | Description |
13+
| --- | --- |
14+
| **CF Workers** | Standard Cloudflare Workers with `nodejs_compat` flag and compatibility date ≥ 2024-09-23. |
15+
| **CF Workers for Platforms** | Multi-tenant variant where platform operators deploy user Workers into dispatch namespaces. Same V8 runtime as standard Workers; additional isolation constraints. |
16+
| **CF Dynamic Dispatch** | The routing Worker that invokes user Workers in a Workers for Platforms namespace. Runs as a standard Worker with dispatch namespace bindings. |
17+
18+
All three CF deployment models share the same `nodejs_compat` API surface. WfP adds operational restrictions (no `caches.default`, no `request.cf` without trusted mode, no gradual deployments, operator-enforced CPU/subrequest limits, outbound Worker interception) but no Node.js API differences.
19+
20+
---
21+
22+
## Support Tier Legend
23+
24+
| Icon | Meaning |
25+
| --- | --- |
26+
| 🟢 | Supported — native or full implementation. |
27+
| 🔵 | Planned — not yet implemented; on the roadmap. |
28+
| 🟡 | Partial — functional with behavioral gaps or wrapper limitations. |
29+
|| TBD — under consideration; not yet committed. |
30+
| 🔴 | Stub — requireable but most APIs throw on call. |
31+
|| Unsupported — not available; `require()` throws immediately. |
32+
33+
---
34+
35+
## Module Compatibility Matrix
36+
37+
### Core I/O and Networking
38+
39+
| Module | secure-exec | CF Workers (`nodejs_compat`) | Notes |
40+
| --- | --- | --- | --- |
41+
| **`fs`** | 🟡 Core I/O: `readFile`, `writeFile`, `appendFile`, `open`, `read`, `write`, `close`, `readdir`, `mkdir`, `rmdir`, `rm`, `unlink`, `stat`, `lstat`, `rename`, `copyFile`, `exists`, `createReadStream`, `createWriteStream`, `writev`, `access`, `realpath`. Missing: `cp`, `glob`, `opendir`, `mkdtemp`, `statfs`, `readv`, `fdatasync`, `fsync`. Deferred: `watch`, `watchFile`, `chmod`, `chown`, `link`, `symlink`, `readlink`, `truncate`, `utimes`. Full coverage planned. | 🟡 In-memory VFS only. `/bundle` (read-only), `/tmp` (writable, ephemeral per-request), `/dev` devices. Missing: `watch`, `watchFile`, `globSync`, file permissions/ownership. All operations synchronous regardless of API style. Timestamps frozen to Unix epoch. 128 MB max file size. | **secure-exec**: Permission-gated; filesystem behavior determined by system driver (host FS or VFS). Read-only `/app/node_modules` overlay. **CF**: No persistent storage; `/tmp` contents isolated per request and lost after response; no real permissions or ownership. |
42+
| **`http`** | 🟡 `request`, `get`, `createServer` with bridged request/response classes. Fetch-based, fully buffered. No connection pooling, no keep-alive tuning, no WebSocket upgrade, no trailer headers. `Agent` is stub-only. | 🟡 `request`, `get`, `createServer` via fetch API wrapper. Requires extra compat flags. No `Connection` headers, no `Expect: 100-continue`, no socket-level events (`socket`, `upgrade`), no 1xx responses, no trailer headers. `Agent` is stub-only. | |
43+
| **`https`** | 🟡 Same contract and limitations as `http`. | 🟡 Same wrapper model and limitations as `http`. | |
44+
| **`http2`** | 🔴 Compatibility classes only; `createServer`/`createSecureServer` throw. | 🔴 Non-functional stub. | Neither platform supports HTTP/2 server creation. |
45+
| **`net`** | 🔵 Planned. | 🟡 `net.connect()` / `net.Socket` for outbound TCP via Cloudflare Sockets API. No `net.createServer()`. | **CF**: Outbound TCP connections supported. **secure-exec**: On roadmap. |
46+
| **`tls`** | 🔵 Planned. | 🟡 `tls.connect()` for outbound TLS via Sockets API. No `tls.createServer()`. | **CF**: Outbound TLS supported. **secure-exec**: On roadmap. |
47+
| **`dns`** | 🟢 `lookup`, `resolve`, `resolve4`, `resolve6`, plus `dns.promises`. | 🟡 DNS over HTTPS via Cloudflare 1.1.1.1. `lookup`, `lookupService`, `resolve` (generic) throw "Not implemented". | **secure-exec**: Permission-gated real DNS. **CF**: DoH only; core methods missing. |
48+
| **`dgram`** |`require()` throws. | 🔴 Non-functional stub. | Neither platform supports UDP sockets. |
49+
50+
### Process and Runtime
51+
52+
| Module | secure-exec | CF Workers (`nodejs_compat`) | Notes |
53+
| --- | --- | --- | --- |
54+
| **`process`** | 🟢 `env` (permission-gated), `cwd`/`chdir`, `exit`, timers, stdio event emitters, `hrtime`, `platform`, `arch`, `version`, `argv`, `pid`, `ppid`, `uid`, `gid`. | 🟡 `env`, `cwd`/`chdir`, `exit`, `nextTick`, `stdin`/`stdout`/`stderr`, `platform`, `arch`, `version`. No real process IDs or OS-level user/group IDs. Requires extra `enable_nodejs_process_v2` flag for full surface. | **secure-exec**: Configurable timing mitigation (`freeze` mode); real `pid`/`uid`/`gid` metadata. **CF**: Synthetic process metadata. |
55+
| **`child_process`** | 🟢 `spawn`, `spawnSync`, `exec`, `execSync`, `execFile`, `execFileSync`. `fork` unsupported. | 🔴 Non-functional stub; all methods throw. | **secure-exec**: Bound to the system driver; subprocess behavior determined by driver implementation. CF has no subprocess support. |
56+
| **`os`** | 🟢 `platform`, `arch`, `type`, `release`, `version`, `homedir`, `tmpdir`, `hostname`, `userInfo`, `os.constants`. | 🟡 Basic platform/arch metadata. | **secure-exec**: Richer OS metadata surface. |
57+
| **`worker_threads`** | ⛔ Stubs that throw on API call. | 🔴 Non-functional stub. | Neither platform supports worker threads. |
58+
| **`cluster`** |`require()` throws. | 🔴 Non-functional stub. | Neither platform supports clustering. |
59+
| **`timers`** | 🟢 `setTimeout`, `clearTimeout`, `setInterval`, `clearInterval`, `setImmediate`, `clearImmediate`. | 🟢 Same surface; returns `Timeout` objects. | Equivalent support. |
60+
| **`vm`** | 🔴 Browser polyfill via `Function()`/`eval()`. No real context isolation; shares global scope. | 🔴 Non-functional stub. | Neither offers real `vm` sandboxing. secure-exec polyfill silently runs code in shared scope — not safe for isolation. |
61+
| **`v8`** | 🔴 Mock heap stats; `serialize`/`deserialize` use JSON instead of V8 binary format (bug). | 🔴 Non-functional stub. | Neither exposes real V8 internals. secure-exec `v8.serialize` silently produces JSON — needs fix to use V8 structured serialization. |
62+
63+
### Crypto and Security
64+
65+
| Module | secure-exec | CF Workers (`nodejs_compat`) | Notes |
66+
| --- | --- | --- | --- |
67+
| **`crypto`** | 🔵 Planned. Currently: `getRandomValues()` and `randomUUID()` use host `node:crypto` secure randomness. `subtle.*` throws unsupported errors. | 🟢 Full `node:crypto` surface (hash, HMAC, cipher, sign, verify, key generation). No DSA/DH key pairs, no `ed448`/`x448`, no FIPS mode. | **CF**: Comprehensive crypto support. **secure-exec**: Secure randomness today; full crypto planned. |
68+
| **Web Crypto** | 🔵 Planned. | 🟢 Available without `nodejs_compat`. | CF has native Web Crypto. |
69+
| **Fetch globals** | 🟢 `fetch`, `Headers`, `Request`, `Response`. | 🟢 Supported. | |
70+
71+
### Data and Encoding
72+
73+
| Module | secure-exec | CF Workers (`nodejs_compat`) | Notes |
74+
| --- | --- | --- | --- |
75+
| **`buffer`** | 🟢 Supported. | 🟢 Supported. | |
76+
| **`stream`** | 🟢 Supported. | 🟢 Supported. | |
77+
| **`string_decoder`** | 🟢 Supported. | 🟢 Supported. | |
78+
| **`zlib`** | 🟢 Supported. | 🟢 Supported; includes Brotli. | CF adds Brotli. |
79+
| **`querystring`** | 🟢 Supported. | 🟢 Supported. | |
80+
81+
### Utilities and Diagnostics
82+
83+
| Module | secure-exec | CF Workers (`nodejs_compat`) | Notes |
84+
| --- | --- | --- | --- |
85+
| **`path`** | 🟢 Supported. | 🟢 Supported. | |
86+
| **`url`** | 🟢 Supported. | 🟢 Supported. | |
87+
| **`util`** | 🟢 Supported. | 🟢 Supported. | |
88+
| **`assert`** | 🟢 Supported. | 🟢 Supported. | |
89+
| **`events`** | 🟢 Supported. | 🟢 Supported. | |
90+
| **`module`** | 🟢 `createRequire`, `Module` basics, builtin resolution. | 🟡 Limited surface. | **secure-exec**: CJS/ESM with `createRequire`. |
91+
| **`console`** | 🟢 Circular-safe bounded formatting; drop-by-default with `onStdio` hook. | 🟢 Supported; output routed to Workers Logs / Tail Workers. | |
92+
| **`async_hooks`** | ⚪ TBD. | 🔴 Non-functional stub. | |
93+
| **`perf_hooks`** | ⚪ TBD. | 🟡 Limited surface. | |
94+
| **`diagnostics_channel`** | ⚪ TBD. | 🟢 Supported. | |
95+
| **`readline`** | ⚪ TBD. | 🔴 Non-functional stub. | |
96+
| **`tty`** | 🔴 `isatty()` returns `false`; `ReadStream`/`WriteStream` throw. | 🔴 Stub-like. | Both platforms are essentially non-functional beyond `isatty()`. |
97+
| **`constants`** | 🟢 Supported. | 🟢 Supported. | |
98+
| **`punycode`** | Not listed. | 🟢 Supported (deprecated). | |
99+
100+
### Unsupported in Both
101+
102+
| Module | secure-exec | CF Workers | Notes |
103+
| --- | --- | --- | --- |
104+
| **`wasi`** | ⛔ Unsupported | ⛔ Unsupported | |
105+
| **`inspector`** | ⛔ Unsupported | 🟡 Partial (Chrome DevTools) | CF has limited inspector via DevTools. |
106+
| **`repl`** | ⛔ Unsupported | 🔴 Stub | |
107+
| **`trace_events`** | ⛔ Unsupported | ⛔ Unsupported | |
108+
| **`domain`** | ⛔ Unsupported | ⛔ Unsupported | |
109+
110+
---
111+
112+
## Execution Model Comparison
113+
114+
| Capability | secure-exec | CF Workers / WfP / Dynamic Dispatch |
115+
| --- | --- | --- |
116+
| **Isolation** | V8 isolate. | V8 isolate per Worker invocation. |
117+
| **Permission model** | Deny-by-default for `fs`, `network`, `childProcess`, `env`. Fine-grained per-domain policies. | No granular permission model. WfP adds `request.cf` restriction and cache isolation. |
118+
| **Memory limits** | Configurable `memoryLimit` (MB). | 128 MB per Worker (platform-managed). |
119+
| **CPU time limits** | Configurable `cpuTimeLimitMs` with exit code 124. | 10ms (free) / 30s (paid) CPU time; WfP operators can set custom limits. |
120+
| **Timing mitigation** | `freeze` mode (deterministic clocks) or `off` (real-time). | I/O-gated coarsening — `Date.now()` and `performance.now()` only advance after I/O to mitigate Spectre-class side channels. |
121+
| **Module loading** | CJS + ESM with package.json `type` field semantics; `node_modules` overlay. | ES modules primary; CJS via `nodejs_compat`; no `node_modules` overlay (bundled at deploy). |
122+
| **Subprocess execution** | Bound to the system driver; subprocess behavior determined by driver implementation. | Not available. |
123+
| **Filesystem** | System-driver-determined: host filesystem (permission-gated) or virtual filesystem, depending on driver implementation. Read-only `/app/node_modules` overlay. | Ephemeral VFS only; Durable Objects for persistence. |
124+
| **Payload limits** | Configurable size limits on sandbox-to-host transfers. | 128 MB script size; request body limits per plan. |
125+
| **Logging** | Drop-by-default; explicit `onStdio` hook for streaming. | Routed to Workers Logs / Tail Workers. |
126+
127+
---
128+
129+
## Sources
130+
131+
- [Cloudflare Workers Node.js Compatibility Docs](https://developers.cloudflare.com/workers/runtime-apis/nodejs/)
132+
- [A Year of Improving Node.js Compatibility (2025)](https://blog.cloudflare.com/nodejs-workers-2025/)
133+
- [Cloudflare Workers node:http Docs](https://developers.cloudflare.com/workers/runtime-apis/nodejs/http/)
134+
- [Cloudflare Workers node:fs Docs](https://developers.cloudflare.com/workers/runtime-apis/nodejs/fs/)
135+
- [Cloudflare Workers node:crypto Docs](https://developers.cloudflare.com/workers/runtime-apis/nodejs/crypto/)
136+
- [Cloudflare Workers Compatibility Flags](https://developers.cloudflare.com/workers/configuration/compatibility-flags/)
137+
- [Cloudflare Workers Performance and Timers](https://developers.cloudflare.com/workers/runtime-apis/performance/)
138+
- [Mitigating Spectre: Cloudflare Workers Security Model](https://blog.cloudflare.com/mitigating-spectre-and-other-security-threats-the-cloudflare-workers-security-model/)
139+
- [Workers for Platforms Configuration](https://developers.cloudflare.com/cloudflare-for-platforms/workers-for-platforms/get-started/configuration/)
140+
- [Workers for Platforms Limits](https://developers.cloudflare.com/cloudflare-for-platforms/workers-for-platforms/reference/limits/)
141+
- [How Workers for Platforms Works](https://developers.cloudflare.com/cloudflare-for-platforms/workers-for-platforms/how-workers-for-platforms-works/)
142+
- [Dynamic Dispatch Worker](https://developers.cloudflare.com/cloudflare-for-platforms/workers-for-platforms/configuration/dynamic-dispatch/)

docs/docs.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,10 @@
3636
{
3737
"group": "Compatibility",
3838
"pages": ["node-compatability"]
39+
},
40+
{
41+
"group": "Comparisons",
42+
"pages": ["cloudflare-workers-comparison"]
3943
}
4044
]
4145
}

packages/playground/frontend/app.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@ import {
33
allowAll,
44
createBrowserDriver,
55
createBrowserRuntimeDriverFactory,
6-
} from "../../secure-exec/dist/browser-runtime.js";
7-
import type { StdioChannel, StdioEvent } from "../../secure-exec/dist/browser-runtime.js";
6+
} from "secure-exec/browser";
7+
import type { StdioChannel, StdioEvent } from "secure-exec/browser";
88

99
type Language = "nodejs" | "python";
1010
type TypeScriptApi = typeof import("typescript");

packages/playground/package.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@
1111
"setup-vendor": "tsx ./scripts/setup-vendor.ts",
1212
"test": "pnpm exec vitest run ./tests/"
1313
},
14+
"dependencies": {
15+
"secure-exec": "workspace:*"
16+
},
1417
"devDependencies": {
1518
"monaco-editor": "0.52.2",
1619
"pyodide": "0.28.3",

packages/secure-exec-typescript/tests/typescript-tools.integration.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ function createTools(memoryLimit?: number) {
2929
}
3030

3131
describe("@secure-exec/typescript", () => {
32-
it("typechecks a project with node types from node_modules", async () => {
32+
it("typechecks a project with node types from node_modules", { timeout: 15_000 }, async () => {
3333
const { filesystem, tools } = createTools();
3434
await filesystem.mkdir("/root/src");
3535
await filesystem.writeFile(

pnpm-lock.yaml

Lines changed: 4 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)