Skip to content

[jco-std] backwards/forwards compatibility across WASI 0.2.x releases #1245

@ericgregory

Description

@ericgregory

Summary

@bytecodealliance/jco-std (v0.1.1) ships Hono HTTP adapters only for wasi:http versions 0.2.3 and 0.2.6. The 0.2.x import path (e.g. @bytecodealliance/jco-std/wasi/0.2.x/http/adapters/hono/server) is hardcoded to resolve to the 0.2.6 adapter, which internally imports wasi:http/types@0.2.6 via bare module specifiers.

This means:

  • Upgrading to 0.2.10 (the latest WASI version) fails because jco-std's adapter still imports wasi:http/types@0.2.6, which doesn't exist in a 0.2.10 WIT world.
  • Downgrading to 0.2.3 with the 0.2.x import path also fails for the same reason — the adapter imports @0.2.6 regardless of the WIT world version.

Since the wasi:http types have not changed across these 0.2.x patch versions, jco-std should ideally be version-agnostic within the 0.2.x range, or at least support the latest WASI release.

Steps to Reproduce

Starting from the jco http-server-hono example:

Setup

src/guest/component.ts (unchanged from the example):

import { Hono } from "hono";
import { logger } from 'hono/logger';
import { fire, buildLogger } from '@bytecodealliance/jco-std/wasi/0.2.x/http/adapters/hono/server';

const app = new Hono();
const log = buildLogger();

app.use(logger(log));

app.get("/", (c) => {
    return c.text("Hello World!!!!");
});

fire(app);

export { incomingHandler } from '@bytecodealliance/jco-std/wasi/0.2.x/http/adapters/hono/server';

package.json:

{
  "name": "http-server-hono",
  "type": "module",
  "scripts": {
    "gen:types": "jco types wit/ -o generated/types --world-name component",
    "build:guest:js": "rolldown -c rolldown.config.mjs",
    "build:guest:component": "jco componentize dist/guest/component.js --wit wit/ --world-name component --out dist/component.wasm",
    "build": "npm run gen:types && npm run build:guest:js && npm run build:guest:component"
  },
  "dependencies": {
    "@bytecodealliance/jco-std": "^0.1.1",
    "hono": "^4.10.4"
  },
  "devDependencies": {
    "@bytecodealliance/jco": "^1.15.3",
    "rolldown": "^1.0.0-beta.47"
  }
}

rolldown.config.mjs:

import { defineConfig } from "rolldown";

export default defineConfig({
    input: "src/guest/component.ts",
    external: /wasi:.*/,
    output: {
        file: "dist/guest/component.js",
        format: "esm",
    },
});

Reproduction 1: Upgrade to WASI 0.2.10

wit/component.wit:

package example:http-server-hono;

world component {
    export wasi:http/incoming-handler@0.2.10;
}
$ npm install
$ wkg wit fetch
$ npx rolldown -c rolldown.config.mjs
$ npx jco componentize dist/guest/component.js --wit wit/ --world-name component --out dist/component.wasm

Result:

(jco componentize) Error: Failed to initialize component:
Exception while evaluating top-level script
ReferenceError: Error loading module "wasi:http/types@0.2.6" (resolved path "wasi:http/types@0.2.6"): No such file or directory

Reproduction 2: Downgrade to WASI 0.2.3

wit/component.wit:

package example:http-server-hono;

world component {
    export wasi:http/incoming-handler@0.2.3;
}

Same build commands, same result:

(jco componentize) Error: Failed to initialize component:
Exception while evaluating top-level script
ReferenceError: Error loading module "wasi:http/types@0.2.6" (resolved path "wasi:http/types@0.2.6"): No such file or directory

Working Baseline: WASI 0.2.6

wit/component.wit:

package example:http-server-hono;

world component {
    export wasi:http/incoming-handler@0.2.6;
}
$ npx jco componentize dist/guest/component.js --wit wit/ --world-name component --out dist/component.wasm
OK Successfully written dist/component.wasm.

$ wasmtime serve -S cli=y -S http=y dist/component.wasm
Serving HTTP on http://0.0.0.0:8080/

$ curl http://localhost:8080/
Hello World!!!!

Root Cause

The jco-std package exports map the 0.2.x path to the 0.2.6 adapter:

"./wasi/0.2.x/http/adapters/hono/server": {
    "default": "./dist/0.2.6/http/adapters/hono/server.js"
}

The 0.2.6 adapter internally imports from hardcoded bare module specifiers:

// dist/0.2.6/http/types/request.js
import { IncomingBody } from "wasi:http/types@0.2.6";

// dist/0.2.6/http/types/response.js
import { OutgoingBody, ResponseOutparam, Fields, OutgoingResponse } from 'wasi:http/types@0.2.6';

During jco componentize, the module resolver only has the WASI interfaces declared in the WIT world available. If the WIT declares wasi:http@0.2.10, then wasi:http/types@0.2.6 doesn't exist, and module resolution fails.

Environment

  • @bytecodealliance/jco: 1.16.1
  • @bytecodealliance/jco-std: 0.1.1
  • @bytecodealliance/componentize-js: 0.19.3
  • wasmtime: 39.0.1
  • wkg: 0.13.0
  • Node.js: v24.9.0
  • Platform: macOS (Darwin 25.2.0, aarch64)

Request

jco-std should be backwards and forwards compatible across WASI 0.2.x releases to prevent dependency conflicts.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions