Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
a3e4d2f
chore(jco): jco-std -> v0.3.0, jco-transpile -> v0.13.0
vados-cosmonic Sep 8, 2026
14a056a
test(jco): enable integration tests blocked on jco-std release
vados-cosmonic Sep 8, 2026
3e46b8d
test(jco): skip failing release-update cases pending fixes
vados-cosmonic Sep 8, 2026
811e80d
fix(std): accept unwrapped filesystem host results
vados-cosmonic Sep 8, 2026
9e8f8e3
fix(std): accept filesystem bytes from other realms
vados-cosmonic Sep 8, 2026
f556b35
fix(std): accept unwrapped DNS host results
vados-cosmonic Sep 8, 2026
36223c4
test(jco): resolve the published filesystem host adapter
vados-cosmonic Sep 8, 2026
b47714b
test(jco): wire the DNS host adapter and async import
vados-cosmonic Sep 8, 2026
d27e54d
fix(jco): automatically configure async DNS imports
vados-cosmonic Sep 8, 2026
1b8c78f
test(jco): exercise filesystem and DNS with workspace std
vados-cosmonic Sep 8, 2026
eb8b47c
test(jco): resolve cluster and child process host adapters
vados-cosmonic Sep 8, 2026
20bbedf
test(jco): update metadata expectations for merged start shim
vados-cosmonic Sep 8, 2026
7b361a0
test(jco): account for transpile runtime growth in size budget
vados-cosmonic Sep 8, 2026
58a6c1d
test(jco): supply the console host during explicit instantiation
vados-cosmonic Sep 8, 2026
c3db547
fix(std): accept unwrapped direct HTTP host results
vados-cosmonic Sep 8, 2026
9275472
fix(std): translate HTTP headers and wrapped WASI errors
vados-cosmonic Sep 8, 2026
422abf3
test(jco): wire HTTP resources and isolate the socket peer
vados-cosmonic Sep 8, 2026
37e7117
test(jco): use the StarlingMonkey HTTP2 fixture world
vados-cosmonic Sep 8, 2026
0f7c042
test(jco): compare guest builtins with the Node 24 target
vados-cosmonic Sep 8, 2026
81c8053
test(jco): use the globals fixture source and WIT paths
vados-cosmonic Sep 8, 2026
e4f25cf
test(jco): temporarily skip globals and HTTP callback failures
vados-cosmonic Sep 8, 2026
955fd81
docs(jco): explain globals failures and callback resource identity
vados-cosmonic Sep 8, 2026
f6e9ba4
fix(std): dispatch HTTP callbacks by component registration
vados-cosmonic Sep 8, 2026
2efa69d
test(jco): restore HTTP server integration with instance isolation
vados-cosmonic Sep 8, 2026
5daa5c2
docs(jco): describe HTTP callback provider setup and verification
vados-cosmonic Sep 8, 2026
23d7bc7
docs(jco): remove CI fix investigation notes
vados-cosmonic Sep 8, 2026
5b72f71
fix(std): redeem HTTP callbacks as exported resources
vados-cosmonic Sep 8, 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
4 changes: 4 additions & 0 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,10 @@ jobs:
name: build-preview2-shim
path: packages/preview2-shim/dist

# Temporarily exercise unpublished jco-std fixes through the workspace dependency.
- name: Build workspace jco-std
run: pnpm --filter '@bytecodealliance/jco-std' run build:ts

- name: Test jco (node@lts)
if: matrix.node != 'latest'
working-directory: packages/jco
Expand Down
24 changes: 24 additions & 0 deletions docs/src/interop/nodejs-builtins.md
Original file line number Diff line number Diff line change
Expand Up @@ -801,6 +801,30 @@ clients and servers. `wasi-http` implements clients and rejects server
construction immediately because outgoing-handler cannot listen for arbitrary
connections.

For direct servers, instantiate with a provider bound to that component's
callback dispatcher. For example, after transpiling with
`--instantiation async --map jco:node/http@0.1.0=http-host`:

```js
import { instantiate } from './component.js';
import { WASIShim } from '@bytecodealliance/preview2-shim/instantiation';
import { createHttpHost } from '@bytecodealliance/jco-std/wasi/0.2.x/node/24.x.x/http/host/node';

let instance;
const imports = new WASIShim().getImportObject();
imports['http-host'] = createHttpHost(() => instance.httpCallbacks);
instance = await instantiate(undefined, imports);
// Await application exports that create or control servers.
await instance.start();
```

Create a separate provider for each component instance. The server holds a
callback registration ID; handlers stay in the guest and run through the
exported dispatcher. The provider serializes callback entry and drains accepted
callbacks before close completes. Closing releases the guest registration;
listening again registers the same server's handler again. Direct client-only
applications can continue mapping the Node provider module without this factory.

> [!WARNING]
> All modes currently buffer complete request and response bodies.

Expand Down
5 changes: 4 additions & 1 deletion packages/jco-std/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -608,7 +608,10 @@ When the selected world is missing a required import or callback export, Jco
edits that world in place, adds generated comments and declarations, installs
the corresponding WIT packages under `wit/deps`, and prints a warning. Direct
servers use an imported host-owned `server` resource plus an exported
guest-owned request-listener resource. Jco re-bundles a small entry wrapper so
callback dispatcher. Each server passes a guest registration ID to its host;
the guest retains its handler while listening and releases it after close.
Node hosts use `createHttpHost(() => instance.httpCallbacks)` from the opt-in
provider to bind callbacks to one component instance. Jco re-bundles a small entry wrapper so
the callback implementation is present on the final component export. Existing
declarations and dependency files are preserved, aliases are recognized, and
repeated componentization does not add duplicates. Use `--world-name` when the
Expand Down
5 changes: 5 additions & 0 deletions packages/jco-std/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,11 @@
"browser": "./dist/wasi/0.2.x/node/24.x.x/http/core.js",
"default": "./dist/wasi/0.2.x/node/24.x.x/http/core.js"
},
"./wasi/0.2.x/node/24.x.x/http/impl/direct": {
"types": "./dist/wasi/0.2.x/node/24.x.x/http/impl/direct.d.ts",
"browser": "./dist/wasi/0.2.x/node/24.x.x/http/impl/direct.js",
"default": "./dist/wasi/0.2.x/node/24.x.x/http/impl/direct.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",
Expand Down
53 changes: 26 additions & 27 deletions packages/jco-std/src/wasi/0.2.x/node/24.x.x/dns/core.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
* share state between callback and promise facades, and make cancellation explicit.
*/
import { dnsError, invalidArgType, invalidArgValue, unsupported } from "./errors.js";
import { callHost } from "../internal/host-error.js";
import type { HostImports } from "../internal/wit-types.js";
import type {
AnyRecord,
CaaRecord,
Expand Down Expand Up @@ -105,11 +107,8 @@ function isRecord(value: unknown): value is Record<string, unknown> {
return typeof value === "object" && value !== null;
}

function hostResult<T>(response: DnsResult<T>): T {
if (response.tag === "err") {
throw dnsError(response.val);
}
return response.val;
function hostResult<T>(operation: () => T | DnsResult<T>): T {
return callHost(operation, dnsError);
}

function hostFamily(value: DnsFamily): DnsHostFamily {
Expand Down Expand Up @@ -332,7 +331,7 @@ function resolveOperation(rrtype: string): ResolveOperation {
}

function resolveHost(
host: DnsHost,
host: HostImports<DnsHost>,
operation: ResolveOperation,
hostname: string,
ttl: boolean,
Expand All @@ -341,37 +340,37 @@ function resolveHost(
const configuration = hostResolver(resolver);
switch (operation) {
case "resolve4": {
const records = hostResult(host.resolve4(hostname, ttl, configuration));
const records = hostResult(() => host.resolve4(hostname, ttl, configuration));
return ttl ? records : records.map((record) => record.address);
}
case "resolve6": {
const records = hostResult(host.resolve6(hostname, ttl, configuration));
const records = hostResult(() => host.resolve6(hostname, ttl, configuration));
return ttl ? records : records.map((record) => record.address);
}
case "resolveAny":
return hostResult(host.resolveAny(hostname, configuration)).map(anyRecord);
return hostResult(() => host.resolveAny(hostname, configuration)).map(anyRecord);
case "resolveCaa":
return hostResult(host.resolveCaa(hostname, configuration));
return hostResult(() => host.resolveCaa(hostname, configuration));
case "resolveCname":
return hostResult(host.resolveCname(hostname, configuration));
return hostResult(() => host.resolveCname(hostname, configuration));
case "resolveMx":
return hostResult(host.resolveMx(hostname, configuration));
return hostResult(() => host.resolveMx(hostname, configuration));
case "resolveNaptr":
return hostResult(host.resolveNaptr(hostname, configuration));
return hostResult(() => host.resolveNaptr(hostname, configuration));
case "resolveNs":
return hostResult(host.resolveNs(hostname, configuration));
return hostResult(() => host.resolveNs(hostname, configuration));
case "resolvePtr":
return hostResult(host.resolvePtr(hostname, configuration));
return hostResult(() => host.resolvePtr(hostname, configuration));
case "resolveSoa":
return hostResult(host.resolveSoa(hostname, configuration));
return hostResult(() => host.resolveSoa(hostname, configuration));
case "resolveSrv":
return hostResult(host.resolveSrv(hostname, configuration));
return hostResult(() => host.resolveSrv(hostname, configuration));
case "resolveTlsa":
return hostResult(host.resolveTlsa(hostname, configuration)).map(tlsaRecord);
return hostResult(() => host.resolveTlsa(hostname, configuration)).map(tlsaRecord);
case "resolveTxt":
return hostResult(host.resolveTxt(hostname, configuration));
return hostResult(() => host.resolveTxt(hostname, configuration));
case "reverse":
return hostResult(host.reverse(hostname, configuration));
return hostResult(() => host.reverse(hostname, configuration));
}
}

Expand Down Expand Up @@ -496,19 +495,19 @@ export interface DnsModules {
};
}

export function createDns(host: DnsHost): DnsModules {
export function createDns(host: HostImports<DnsHost>): DnsModules {
let defaultOrder: DnsResultOrder = "verbatim";
let defaultServers: string[] | undefined;

function servers(): string[] {
return (defaultServers ??= hostResult(host.getServers())).slice();
return (defaultServers ??= hostResult(() => host.getServers())).slice();
}

function setServers(serversValue: string[]): void {
if (!Array.isArray(serversValue)) {
throw invalidArgType("servers", "Array");
}
const validated = hostResult(host.validateServers(serversValue));
const validated = hostResult(() => host.validateServers(serversValue));
defaultServers = validated.slice();
}

Expand All @@ -526,7 +525,7 @@ export function createDns(host: DnsHost): DnsModules {
hostname: string,
options: ParsedLookupOptions,
): LookupAddress | LookupAddress[] {
const addresses = hostResult(
const addresses = hostResult(() =>
host.lookup(hostname, {
family: hostFamily(options.family),
hints: options.hints,
Expand Down Expand Up @@ -584,7 +583,7 @@ export function createDns(host: DnsHost): DnsModules {
if (!Array.isArray(value)) {
throw invalidArgType("servers", "Array");
}
this.configuration.servers = hostResult(host.validateServers(value));
this.configuration.servers = hostResult(() => host.validateServers(value));
}

setLocalAddress(ipv4 = "0.0.0.0", ipv6 = "::0"): void {
Expand Down Expand Up @@ -839,7 +838,7 @@ export function createDns(host: DnsHost): DnsModules {
let result: { hostname: string; service: string } | undefined;
let error: DnsError | undefined;
try {
result = hostResult(host.lookupService(address, numericPort));
result = hostResult(() => host.lookupService(address, numericPort));
} catch (caught) {
error = caught instanceof Error ? (caught as DnsError) : new Error(String(caught));
}
Expand Down Expand Up @@ -909,7 +908,7 @@ export function createDns(host: DnsHost): DnsModules {
if (!Number.isInteger(numericPort) || numericPort < 0 || numericPort > 65535) {
throw invalidArgValue("port", port);
}
return promiseCall(() => hostResult(host.lookupService(address, numericPort)));
return promiseCall(() => hostResult(() => host.lookupService(address, numericPort)));
},
resolve: promiseResolver.resolve.bind(promiseResolver),
resolve4: promiseResolver.resolve4.bind(promiseResolver),
Expand Down
Loading
Loading