Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
53 commits
Select commit Hold shift + click to select a range
974b08d
fix(std): match Node 24 in the node:http agent
vados-cosmonic Sep 4, 2026
6d8396c
fix(std): give agent: false requests a fresh node:http agent
vados-cosmonic Sep 4, 2026
d8eb97a
fix(std): reject non-object node:http server options
vados-cosmonic Sep 4, 2026
d66f497
feat(std): add the node:https shim
vados-cosmonic Sep 4, 2026
0af5c0f
test(std): add node:https unit tests
vados-cosmonic Sep 4, 2026
3c3b457
feat(jco): resolve node:https through the builtin plugin
vados-cosmonic Sep 4, 2026
9f6e7e1
docs(std): document node:https
vados-cosmonic Sep 4, 2026
5cb6216
test(jco): add node:https plugin and guest tests
vados-cosmonic Sep 4, 2026
192a783
fix(p2-shim): correct DNS records and network exports
vados-cosmonic Sep 7, 2026
17c60aa
feat(p2-shim): add opt-in TLS over owned IO streams
vados-cosmonic Sep 7, 2026
49cf7ac
test(p2-shim): cover TLS ownership and DNS address records
vados-cosmonic Sep 7, 2026
729da7c
feat(std): support HTTPS over wasi:tls
vados-cosmonic Sep 7, 2026
d56012f
test(std): cover TLS capability and handshake semantics
vados-cosmonic Sep 7, 2026
77760ea
feat(jco): wire wasi:tls into HTTPS componentization
vados-cosmonic Sep 7, 2026
7123f22
test(jco): cover TLS mappings and WIT feature resolution
vados-cosmonic Sep 7, 2026
558d3f9
test(jco): execute HTTPS components over WASI TLS
vados-cosmonic Sep 7, 2026
a4898e9
docs(std): explain TLS capability for socket transport
vados-cosmonic Sep 7, 2026
4a64893
docs(p2-shim): describe opt-in TLS provider
vados-cosmonic Sep 7, 2026
0ab8510
docs(jco): document HTTPS TLS capability and provider setup
vados-cosmonic Sep 7, 2026
69f2bea
docs(jco): clarify TLS belongs to the sockets implementation
vados-cosmonic Sep 7, 2026
ee9ca4f
refactor(std): group TLS under the sockets implementation
vados-cosmonic Sep 7, 2026
89474bb
test(std): update imports for sockets implementation folder
vados-cosmonic Sep 7, 2026
cccbc1b
fix(jco): identify TLS failures in the QuickJS snapshot linker
vados-cosmonic Sep 7, 2026
7b637d9
test(jco): update HTTPS fixture imports and linker diagnostic
vados-cosmonic Sep 7, 2026
5758639
docs(std): note the QuickJS TLS snapshot limitation
vados-cosmonic Sep 7, 2026
6b727fd
docs(jco): treat QuickJS TLS linking as a backend limitation
vados-cosmonic Sep 7, 2026
cee25de
docs(jco): remove the TLS certificate fixture README
vados-cosmonic Sep 7, 2026
a368cfb
refactor(jco): generate tests without filename suffixes
vados-cosmonic Sep 7, 2026
7005377
test(jco): remove redundant test filename suffixes
vados-cosmonic Sep 7, 2026
a5233ee
test(transpile): remove Web IDL fixture filename suffixes
vados-cosmonic Sep 7, 2026
c63caad
test(node-fs): remove redundant test filename suffixes
vados-cosmonic Sep 7, 2026
4526148
test(p2-shim): remove the filesystem test filename suffix
vados-cosmonic Sep 7, 2026
9d0c4e3
test(p3-shim): discover tests by folder instead of suffix
vados-cosmonic Sep 7, 2026
78052a5
test(rolldown-plugin-jco): remove test filename suffixes
vados-cosmonic Sep 7, 2026
0700fff
chore(std): omit unused wit-deps metadata from TLS WIT
vados-cosmonic Sep 7, 2026
6586af3
chore(jco): omit unused wit-deps metadata from TLS WIT
vados-cosmonic Sep 7, 2026
b8cb0b5
docs(jco): reference the renamed HTTPS test suite
vados-cosmonic Sep 7, 2026
f65e31a
build(tests): run WebIDL fixture builds through Node.js
vados-cosmonic Sep 7, 2026
aa0e5d5
refactor(std): align the local TLS contract with WASI IO 0.2.12
vados-cosmonic Sep 7, 2026
d90849a
build(std): regenerate TLS bindings against WASI IO 0.2.12
vados-cosmonic Sep 7, 2026
835c4a3
refactor(std): pass socket streams directly to TLS
vados-cosmonic Sep 7, 2026
be7e70d
test(std): exercise TLS without stream version adaptation
vados-cosmonic Sep 7, 2026
73f08af
refactor(jco): vendor the local TLS contract without IO bridges
vados-cosmonic Sep 7, 2026
30bebd2
refactor(jco): remove TLS-specific componentization handling
vados-cosmonic Sep 7, 2026
a6bb0be
test(jco): verify TLS WIT without feature preprocessing
vados-cosmonic Sep 7, 2026
72027c0
refactor(p2-shim): expose generic IO integration for host providers
vados-cosmonic Sep 7, 2026
65ad0be
refactor(std): own the opt-in Node TLS provider
vados-cosmonic Sep 7, 2026
09a6a85
test(p2-shim): cover host IO extension failure and ownership
vados-cosmonic Sep 7, 2026
36b4198
test(std): port TLS lifecycle coverage and fixtures
vados-cosmonic Sep 7, 2026
d2c603b
test(jco): run HTTPS components with the jco-std TLS host
vados-cosmonic Sep 7, 2026
c6c8307
docs(std): document the local TLS host provider
vados-cosmonic Sep 7, 2026
7b1d7e8
docs(p2-shim): describe host IO integration
vados-cosmonic Sep 7, 2026
917b10e
docs(jco): map HTTPS to the standard-library TLS provider
vados-cosmonic Sep 7, 2026
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: 8 additions & 3 deletions crates/xtask/src/generate/webidl_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ const IDL_VERSION_MINOR: u64 = 0;
const IDL_VERSION_PATCH: u64 = 1;

pub(crate) fn run() -> Result<()> {
for file in read_dir("packages/jco/test/fixtures/idl")? {
for file in read_dir("packages/jco/test/fixtures/wit/idl")? {
let file = file?;
let file_name = file.file_name();
let file_name_str = file_name.to_string_lossy().to_string();
Expand Down Expand Up @@ -55,7 +55,12 @@ pub(crate) fn run() -> Result<()> {
},
)?;

let wit_str = wit.to_string();
// Preserve the fixture's existing workaround for the window.window name
// collision until webidl2wit disambiguates resource and method names.
let wit_str = wit.to_string().replace(
" window: func() -> window-proxy;",
" get-window: func() -> window-proxy;",
);

let world_definition = if interface_name == "console" {
format!(
Expand All @@ -72,7 +77,7 @@ pub(crate) fn run() -> Result<()> {
.to_string()
};

let output_file = format!("packages/jco/test/fixtures/idl/{name}.wit");
let output_file = format!("packages/jco/test/fixtures/wit/idl/{name}.wit");
write(
&output_file,
format!(
Expand Down
191 changes: 136 additions & 55 deletions docs/src/interop/nodejs-builtins.md

Large diffs are not rendered by default.

3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@
"lint:fix": "pnpm run -r lint:fix",
"test:setup:puppeteer": "node scripts/install-puppeteer.mjs",
"test:setup:firefox": "node scripts/install-puppeteer.mjs firefox",
"test:examples": "pnpm run -r all"
"test:examples": "pnpm run -r all",
"build:test:idl": "node scripts/create-idl-component.mjs"
},
"devDependencies": {
"@actions/github": "^6.0.1",
Expand Down
2 changes: 1 addition & 1 deletion packages/jco-node-fs/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
"lint": "cargo clippy --all-targets -- -D warnings",
"prepare-release": "napi prepublish -t npm --no-gh-release --skip-optional-publish --root-publisher pnpm",
"pretest": "pnpm run build:debug",
"test": "node --test test/*.test.js"
"test": "node --test test/*.js"
},
"devDependencies": {
"@napi-rs/cli": "^3.4.1",
Expand Down
59 changes: 47 additions & 12 deletions packages/jco-std/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ Below is a list of utilties provided by `@bytecodealliance/jco-std`:
| `wasi/0.2.x/node/24.x.x/fs` | `node:fs` and `node:fs/promises` over an explicit host capability |
| `wasi/0.2.x/node/24.x.x/http` | `node:http` API with direct, WASI sockets, and WASI HTTP implementations |
| `wasi/0.2.x/node/24.x.x/http2` | `node:http2` API with direct and cleartext WASI sockets implementations |
| `wasi/0.2.x/node/24.x.x/https` | `node:https` API sharing the `node:http` core and implementations |
| `wasi/0.2.x/node/24.x.x/os` | `node:os` guest adapter over an explicit host capability |
| `wasi/0.2.x/node/24.x.x/path` | `node:path` adapter, Node 24 on WASI p2 |
| `wasi/0.2.x/node/24.x.x/string-decoder` | Guest-local `node:string_decoder` implementation for Node 24 |
Expand Down Expand Up @@ -63,7 +64,8 @@ Below is a list of utilties provided by `@bytecodealliance/jco-std`:
| `wasi/0.2.x/node/24.x.x/http/impl/wasi-sockets` | `node:http` implementation over WASI Preview 2 sockets |
| `wasi/0.2.x/node/24.x.x/http/impl/wasi-http` | `node:http` implementation over WASI Preview 2 HTTP |
| `wasi/0.2.x/node/24.x.x/http/host` | Deny-by-default host for `jco:node/http` |
| `wasi/0.2.x/node/24.x.x/http/host/node` | Opt-in host over the runtime's real `node:http` |
| `wasi/0.2.x/node/24.x.x/http/host/node` | Opt-in host over the runtime's real `node:http` and `node:https` |
| `wasi/0.2.x/node/24.x.x/https/core` | `node:https` core shared by the selectable implementations |
| `wasi/0.2.x/node/24.x.x/os/host` | Deny-by-default host for `jco:node/os` |
| `wasi/0.2.x/node/24.x.x/os/host/node` | Opt-in host over the runtime's real `node:os` |
| `node/path` | Legacy unversioned alias for `wasi/0.2.x/node/24.x.x/path` |
Expand Down Expand Up @@ -146,8 +148,8 @@ Jco can bundle the following Node.js APIs into JavaScript WebAssembly components
`@bytecodealliance/jco-std/wasi/0.2.x/node/24.x.x/inspector` and the
application-provided `jco:node/inspector@0.1.0` capability, with the host
calling back into the component through a guest-exported callbacks interface;
- the `node:http` API, with selectable direct, `wasi:sockets`, and `wasi:http`
implementations;
- the `node:http` and `node:https` APIs, with selectable direct,
`wasi:sockets`, and `wasi:http` implementations;
- `node:buffer`, with its modern core provided by Jco's audited unenv
compatibility layer;
- `node:querystring`, provided by Jco's audited unenv compatibility layer;
Expand Down Expand Up @@ -577,7 +579,19 @@ const server = createServer((request, response) => {
server.listen(8080, "127.0.0.1");
```

Bundle it and select how `node:http` reaches the host:
`node:https` is the same core with the `https:` profile, port 443, and a
TLS-aware `Agent`. Servers take Node's TLS options and clients take the
`tls.connect` subset (`ca`, `cert`, `key`, `rejectUnauthorized`, `servername`,
`ALPNProtocols`, and so on), which cross the boundary as a typed record:

```js
import { createServer, get } from "node:https";

createServer({ key, cert }, (request, response) => response.end("secure")).listen(8443);
get("https://localhost:8443/", { ca: cert }, (response) => response.resume());
```

Bundle it and select how `node:http` and `node:https` reach the host:

```console
jco componentize component.js --wit wit --bundle \
Expand All @@ -589,12 +603,32 @@ jco componentize component.js --wit wit --bundle \
- `direct` (the default), which adds `jco:node/http@0.1.0`; its default provider
throws `ERR_JCO_HTTP_ADAPTER_REQUIRED`, and a Node application can explicitly
map `wasi/0.2.x/node/24.x.x/http/host/node` when transpiling. It supports
clients and servers through real `node:http`;
- `wasi-sockets`, which implements HTTP/1.1 in the guest using only Preview 2
socket and IO capabilities, including TCP servers; and
clients and servers through real `node:http`, and terminates TLS for
`node:https` through real `node:https`;
- `wasi-sockets`, which implements HTTP/1.1 in the guest over Preview 2 TCP.
TLS connections implicitly require the additional `wasi:tls` capability;
`node:https` adds its import automatically. Verified HTTPS clients work with
an explicit host provider; HTTPS servers remain unsupported by the pinned
client-only TLS interface; and
- `wasi-http`, which translates requests to Preview 2
`wasi:http/outgoing-handler`. It rejects `Server` construction immediately
because an outgoing-handler cannot listen for arbitrary inbound connections.
`wasi:http/outgoing-handler`, including `https` URLs, though per-request TLS
options are refused because the outgoing-handler owns certificate
validation. It rejects `Server` construction immediately because an
outgoing-handler cannot listen for arbitrary inbound connections.

For HTTPS over sockets, explicitly map `wasi:tls/types@0.2.0-draft` to
`@bytecodealliance/jco-std/wasi/0.2.x/node/24.x.x/tls/host/node`. TLS support is backend-independent.
The [local TLS contract](wit/tls-0.2.0-draft/README.md) shares `wasi:io@0.2.12`
resources with sockets directly. The default mapping denies TLS before connecting. The Node provider wraps the existing TCP streams, validates the
certificate chain and hostname, and offers HTTP/1.1 ALPN. The draft accepts only
`servername` (and `rejectUnauthorized: true`); other per-request TLS settings,
including `ca`, are rejected. Hosts can configure trust with `createTlsProvider`.
See the [provider example](../../docs/src/interop/nodejs-builtins.md#https).

> [!NOTE]
> `componentize-qjs` 0.4.3 currently fails to link the TLS interface's shared IO
> resources during snapshot initialization. StarlingMonkey is a workaround for
> this build-time issue.

When the selected world is missing a required import or callback export, Jco
edits that world in place, adds generated comments and declarations, installs
Expand All @@ -608,9 +642,10 @@ WIT package defines multiple worlds.

The initial implementation buffers each request and response at the
implementation boundary. Client and server objects retain Node-style callbacks
and events inside the guest. Connection pooling, upgrades, CONNECT tunnels,
HTTPS, and persistent HTTP/1.1 connections in the `wasi-sockets` implementation
are not implemented; unavailable operations throw explicit errors.
and events inside the guest. Connection pooling, upgrades, CONNECT proxy
tunnels, and persistent HTTP/1.1 connections in the `wasi-sockets`
implementation are not implemented; unavailable operations throw explicit
errors.

### HTTP/2

Expand Down
40 changes: 34 additions & 6 deletions packages/jco-std/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@
},
"files": [
"dist",
"wit/node-0.1.0"
"wit/node-0.1.0",
"wit/tls-0.2.0-draft"
],
"type": "module",
"exports": {
Expand Down Expand Up @@ -115,9 +116,9 @@
"default": "./dist/wasi/0.2.x/node/24.x.x/http/core.js"
},
"./wasi/0.2.x/node/24.x.x/http/impl/wasi-sockets": {
"types": "./dist/wasi/0.2.x/node/24.x.x/http/impl/wasi-sockets.d.ts",
"browser": "./dist/wasi/0.2.x/node/24.x.x/http/impl/wasi-sockets.js",
"default": "./dist/wasi/0.2.x/node/24.x.x/http/impl/wasi-sockets.js"
"types": "./dist/wasi/0.2.x/node/24.x.x/http/impl/wasi-sockets/index.d.ts",
"browser": "./dist/wasi/0.2.x/node/24.x.x/http/impl/wasi-sockets/index.js",
"default": "./dist/wasi/0.2.x/node/24.x.x/http/impl/wasi-sockets/index.js"
},
"./wasi/0.2.x/node/24.x.x/http/impl/wasi-http": {
"types": "./dist/wasi/0.2.x/node/24.x.x/http/impl/wasi-http.d.ts",
Expand Down Expand Up @@ -167,6 +168,16 @@
"types": "./dist/wasi/0.2.x/node/24.x.x/http2-host-node.d.ts",
"node": "./dist/wasi/0.2.x/node/24.x.x/http2-host-node.js"
},
"./wasi/0.2.x/node/24.x.x/https": {
"types": "./dist/wasi/0.2.x/node/24.x.x/https.d.ts",
"browser": "./dist/wasi/0.2.x/node/24.x.x/https.js",
"default": "./dist/wasi/0.2.x/node/24.x.x/https.js"
},
"./wasi/0.2.x/node/24.x.x/https/core": {
"types": "./dist/wasi/0.2.x/node/24.x.x/https/core.d.ts",
"browser": "./dist/wasi/0.2.x/node/24.x.x/https/core.js",
"default": "./dist/wasi/0.2.x/node/24.x.x/https/core.js"
},
"./wasi/0.2.x/node/24.x.x/path": {
"types": "./dist/wasi/0.2.x/node/24.x.x/path.d.ts",
"browser": "./dist/wasi/0.2.x/node/24.x.x/path.js",
Expand Down Expand Up @@ -337,6 +348,14 @@
"types": "./dist/wasi/0.2.3/http/adapters/hono/middleware/env.d.ts",
"browser": "./dist/wasi/0.2.3/http/adapters/hono/middleware/env.js",
"default": "./dist/wasi/0.2.3/http/adapters/hono/middleware/env.js"
},
"./wasi/0.2.x/node/24.x.x/tls/host": {
"types": "./dist/wasi/0.2.x/node/24.x.x/tls-host.d.ts",
"default": "./dist/wasi/0.2.x/node/24.x.x/tls-host.js"
},
"./wasi/0.2.x/node/24.x.x/tls/host/node": {
"types": "./dist/wasi/0.2.x/node/24.x.x/tls-host-node.d.ts",
"node": "./dist/wasi/0.2.x/node/24.x.x/tls-host-node.js"
}
},
"scripts": {
Expand All @@ -348,11 +367,12 @@
"build:bindings:wasi:http:0.2.6": "WIT_PATH=wit/http-v0m2p6 OUTPUT_DIR_PATH=src/wasi/0.2.6/generated/types node scripts/generate-wasi-bindings.mjs",
"build:bindings:wasi:http:0.2.12": "WIT_PATH=wit/http-v0m2p12 OUTPUT_DIR_PATH=src/wasi/0.2.12/generated/types node scripts/generate-wasi-bindings.mjs",
"build:bindings:wasi:http:0.2.3": "WIT_PATH=wit/http-v0m2p3 OUTPUT_DIR_PATH=src/wasi/0.2.3/generated/types node scripts/generate-wasi-bindings.mjs",
"build:bindings": "pnpm run build:bindings:wasi:http:0.2.3 && pnpm run build:bindings:wasi:http:0.2.6 && pnpm run build:bindings:wasi:http:0.2.12",
"build:bindings": "pnpm run build:bindings:wasi:http:0.2.3 && pnpm run build:bindings:wasi:http:0.2.6 && pnpm run build:bindings:wasi:http:0.2.12 && pnpm run build:bindings:wasi:tls",
"build:ts": "tsc",
"build": "pnpm run setup:jco-transpile:build && pnpm run build:bindings && pnpm run build:ts",
"test": "vitest run -c test/vitest.ts",
"prepack": "pnpm run build"
"prepack": "pnpm run build",
"build:bindings:wasi:tls": "node scripts/generate-tls-bindings.mjs"
},
"dependencies": {
"minimatch": "10.2.6"
Expand All @@ -369,5 +389,13 @@
"typescript": "catalog:",
"vitest": "^4.0.8",
"which": "^5.0.0"
},
"peerDependencies": {
"@bytecodealliance/preview2-shim": "^0.24.0"
},
"peerDependenciesMeta": {
"@bytecodealliance/preview2-shim": {
"optional": true
}
}
}
16 changes: 16 additions & 0 deletions packages/jco-std/scripts/generate-tls-bindings.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// Generate bindings for the documented local TLS contract.
import { generateGuestTypes, writeFiles } from "@bytecodealliance/jco-transpile";
const files = await generateGuestTypes("wit/tls-0.2.0-draft", {
outDir: "src/wasi/0.2.12/generated/types/tls",
});
const decoder = new TextDecoder();
const encoder = new TextEncoder();
for (const [path, contents] of Object.entries(files)) {
files[path] = encoder.encode(
decoder
.decode(contents)
.replace(/[ \t]+$/gm, "")
.trimEnd() + "\n",
);
}
await writeFiles(files);
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
declare module 'wasi:cli/environment@0.2.12' {
/**
* Get the POSIX-style environment variables.
*
*
* Each environment variable is provided as a pair of string variable names
* and string value.
*
*
* Morally, these are a value import, but until value imports are available
* in the component model, this import function should return the same
* values each time it is called.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@
declare module 'wasi:clocks/monotonic-clock@0.2.12' {
/**
* Read the current value of the clock.
*
*
* The clock is monotonic, therefore calling this function repeatedly will
* produce a sequence of non-decreasing values.
*
*
* For completeness, this function traps if it's not possible to represent
* the value of the clock in an `instant`. Consequently, implementations
* should ensure that the starting time is low enough to avoid the
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
declare module 'wasi:config/store@0.2.0-rc.1' {
/**
* Gets a configuration value of type `string` associated with the `key`.
*
*
* The value is returned as an `option<string>`. If the key is not found,
* `Ok(none)` is returned. If an error occurs, an `Err(error)` is returned.
*/
export function get(key: string): string | undefined;
/**
* Gets a list of configuration key-value pairs of type `string`.
*
*
* If an error occurs, an `Err(error)` is returned.
*/
export function getAll(): Array<[string, string]>;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ declare module 'wasi:http/incoming-handler@0.2.12' {
* method, which allows execution to continue after the response has been
* sent. This enables both streaming to the response body, and performing other
* work.
*
*
* The implementor of this function must write a response to the
* `response-outparam` before returning, or else the caller will respond
* with an error on its behalf.
Expand Down
Loading
Loading