diff --git a/experiments/iroh-relay-ws/host/bridge.ts b/experiments/iroh-relay-ws/host/bridge.ts index ae850ba..307538c 100644 --- a/experiments/iroh-relay-ws/host/bridge.ts +++ b/experiments/iroh-relay-ws/host/bridge.ts @@ -61,7 +61,7 @@ async function open(socket: UdpSocket, url: string, protocols: string[]): Promis return; } bridgeStats.wsIn++; - const bytes = message.tag === "binary" ? message.val : enc.encode(message.val); + const bytes = message.kind === "binary" ? message.value : enc.encode(message.value); pushDatagram(socket, frame(TAG_MESSAGE, bytes)); } } catch (err) { @@ -93,7 +93,7 @@ registerBridge(1, (socket: UdpSocket, { data }: OutgoingDatagram) => { // `slice` detaches from any shared buffer; chain preserves ordering. const bytes = payload.slice(); conn.sendChain = conn.sendChain - .then(() => conn.ws.send({ tag: "binary", val: bytes })) + .then(() => conn.ws.send({ kind: "binary", value: bytes })) .catch((err) => { console.error(`[bridge] ws send failed: ${describeErr(err)}`); pushDatagram(socket, new Uint8Array([TAG_CLOSED])); diff --git a/experiments/iroh-relay-ws/host/deno.json b/experiments/iroh-relay-ws/host/deno.json index 16374b7..053dfd2 100644 --- a/experiments/iroh-relay-ws/host/deno.json +++ b/experiments/iroh-relay-ws/host/deno.json @@ -1,5 +1,5 @@ { - "//": "MODULE-IDENTITY CONSTRAINT: deltic's wasi-shims and the sibling deltic host modules (.deps/{websocket,webrtc}) import @deltic/runtime/embedder by bare specifier internally; this file maps that specifier ONCE for the whole module graph, so `instanceof WitError` holds across every boundary. This is the ONE deno config for all three experiments (iroh-relay-ws, iroh-blobs, ping-demo): the others pass --config pointing here. deltic arrives as exactly-pinned JSR prereleases (0.1.0-pre.g names one upstream commit; @deltic/translator ships the translator wasm for the SAME commit); the version matches host-deltic/deno.json by repo convention (exam-deltic asserts it; see host-deltic/README.md, 'The pin'). minimumDependencyAge keeps Deno's default supply-chain gate for everything else while letting same-day @deltic prereleases resolve. The npm mappings serve the webrtc module's bare specifiers under Deno; a browser build resolves the RTCPeerConnection global instead. compilerOptions.lib carries dom next to deno.ns so the browser entries (browser-entry.ts, ping-demo's demo.ts/overlay.ts) type-check in the same graph as the Deno drivers.", + "//": "MODULE-IDENTITY CONSTRAINT: deltic's wasi-shims and the sibling deltic host modules (.deps/{websocket,webrtc}) import @deltic/runtime/embedder by bare specifier internally; this file maps that specifier ONCE for the whole module graph, so `instanceof ComponentException` holds across every boundary. This is the ONE deno config for all three experiments (iroh-relay-ws, iroh-blobs, ping-demo): the others pass --config pointing here. deltic arrives as exactly-pinned JSR prereleases (0.1.0-pre.g names one upstream commit; @deltic/translator ships the translator wasm for the SAME commit); the version matches host-deltic/deno.json by repo convention (exam-deltic asserts it; see host-deltic/README.md, 'The pin'). minimumDependencyAge keeps Deno's default supply-chain gate for everything else while letting same-day @deltic prereleases resolve. The npm mappings serve the webrtc module's bare specifiers under Deno; a browser build resolves the RTCPeerConnection global instead. compilerOptions.lib carries dom next to deno.ns so the browser entries (browser-entry.ts, ping-demo's demo.ts/overlay.ts) type-check in the same graph as the Deno drivers.", "nodeModulesDir": "auto", "minimumDependencyAge": { "age": "P1D", @@ -9,10 +9,10 @@ "lib": ["dom", "dom.iterable", "dom.asynciterable", "deno.ns"] }, "imports": { - "@deltic/runtime/embedder": "jsr:@deltic/runtime@0.1.0-pre.ga67ee83/embedder", - "@deltic/runtime/shim": "jsr:@deltic/runtime@0.1.0-pre.ga67ee83/shim", - "@deltic/translator": "jsr:@deltic/translator@0.1.0-pre.ga67ee83", - "@deltic/wasi-shims": "jsr:@deltic/wasi-shims@0.1.0-pre.ga67ee83", + "@deltic/runtime/embedder": "jsr:@deltic/runtime@0.1.0-pre.g078aa15/embedder", + "@deltic/runtime/shim": "jsr:@deltic/runtime@0.1.0-pre.g078aa15/shim", + "@deltic/translator": "jsr:@deltic/translator@0.1.0-pre.g078aa15", + "@deltic/wasi-shims": "jsr:@deltic/wasi-shims@0.1.0-pre.g078aa15", "node-datachannel": "npm:node-datachannel@0.32.3", "node-datachannel/polyfill": "npm:node-datachannel@0.32.3/polyfill", "werift": "npm:werift@0.22.2" diff --git a/experiments/iroh-relay-ws/host/deno.lock b/experiments/iroh-relay-ws/host/deno.lock index 7ee9e88..3b5b89a 100644 --- a/experiments/iroh-relay-ws/host/deno.lock +++ b/experiments/iroh-relay-ws/host/deno.lock @@ -1,28 +1,36 @@ { "version": "5", "specifiers": { - "jsr:@deltic/runtime@0.1.0-pre.ga67ee83": "0.1.0-pre.ga67ee83", - "jsr:@deltic/runtime@~0.1.0-pre.ga67ee83": "0.1.0-pre.ga67ee83", - "jsr:@deltic/translator@0.1.0-pre.ga67ee83": "0.1.0-pre.ga67ee83", - "jsr:@deltic/wasi-shims@0.1.0-pre.ga67ee83": "0.1.0-pre.ga67ee83", + "jsr:@deltic/protocol@0.2": "0.2.0", + "jsr:@deltic/runtime@0.1.0-pre.g078aa15": "0.1.0-pre.g078aa15", + "jsr:@deltic/runtime@~0.1.0-pre.g078aa15": "0.1.0-pre.g078aa15", + "jsr:@deltic/translator@0.1.0-pre.g078aa15": "0.1.0-pre.g078aa15", + "jsr:@deltic/wasi-shims@0.1.0-pre.g078aa15": "0.1.0-pre.g078aa15", "npm:node-datachannel@0.32.3": "0.32.3", "npm:playwright@^1.62.1": "1.62.1", "npm:werift@0.22.2": "0.22.2" }, "jsr": { - "@deltic/runtime@0.1.0-pre.ga67ee83": { - "integrity": "2a2b0949031747a2340dc186299e654ea9f361ae39ac6bd633019940682db4ed" + "@deltic/protocol@0.2.0": { + "integrity": "028be6a3623c5e910598aa7a199209b85e8931ae484ac7f6638d610ddb0e19fa" }, - "@deltic/translator@0.1.0-pre.ga67ee83": { - "integrity": "e4f1bb219e56b62262b0c9665e3f6646aa13883b2cfbb9d6306f69d19974d412", + "@deltic/runtime@0.1.0-pre.g078aa15": { + "integrity": "5e64f8dc6d32190ecd394d6ad9881eb0fa97b6598b1e7f2ef1d52cff4674287c", "dependencies": [ - "jsr:@deltic/runtime@~0.1.0-pre.ga67ee83" + "jsr:@deltic/protocol" ] }, - "@deltic/wasi-shims@0.1.0-pre.ga67ee83": { - "integrity": "a5754e65d50873e675695a51279989e22b3771e31f16a84a09feb15905c574a7", + "@deltic/translator@0.1.0-pre.g078aa15": { + "integrity": "7125f99ac46af4a69f1c432def2b7ea4be63509c3a7ebae83537357615ec33ef", "dependencies": [ - "jsr:@deltic/runtime@~0.1.0-pre.ga67ee83" + "jsr:@deltic/runtime@~0.1.0-pre.g078aa15" + ] + }, + "@deltic/wasi-shims@0.1.0-pre.g078aa15": { + "integrity": "fba2081f804eaaccf95e31cdd634fd85a2d724f6be7f62578ddc26aef03524a1", + "dependencies": [ + "jsr:@deltic/protocol", + "jsr:@deltic/runtime@~0.1.0-pre.g078aa15" ] } }, @@ -613,9 +621,9 @@ }, "workspace": { "dependencies": [ - "jsr:@deltic/runtime@0.1.0-pre.ga67ee83", - "jsr:@deltic/translator@0.1.0-pre.ga67ee83", - "jsr:@deltic/wasi-shims@0.1.0-pre.ga67ee83", + "jsr:@deltic/runtime@0.1.0-pre.g078aa15", + "jsr:@deltic/translator@0.1.0-pre.g078aa15", + "jsr:@deltic/wasi-shims@0.1.0-pre.g078aa15", "npm:node-datachannel@0.32.3", "npm:werift@0.22.2" ], diff --git a/experiments/iroh-relay-ws/host/errors.ts b/experiments/iroh-relay-ws/host/errors.ts index a23fdbf..5ac5c15 100644 --- a/experiments/iroh-relay-ws/host/errors.ts +++ b/experiments/iroh-relay-ws/host/errors.ts @@ -1,15 +1,16 @@ -// Render an error for a log line, unwrapping deltic's branded WIT error -// payloads (the sibling host modules throw `WitError<{tag, val?}>`). +// Render an error for a log line, unwrapping deltic's branded +// `ComponentException<{kind, value?}>` payloads (the sibling host modules +// throw these). -import { WitError } from "@deltic/runtime/embedder"; +import { ComponentException } from "@deltic/runtime/embedder"; export function describeErr(err: unknown): string { - if (err instanceof WitError) { - const p = err.payload as { tag?: string; val?: unknown } | undefined; - if (p !== undefined && typeof p === "object" && "tag" in (p as object)) { - return `${p.tag}${p.val === undefined ? "" : `(${String(p.val)})`}`; + if (err instanceof ComponentException) { + const p = err.payload as { kind?: string; value?: unknown } | undefined; + if (p !== undefined && typeof p === "object" && "kind" in (p as object)) { + return `${p.kind}${p.value === undefined ? "" : `(${String(p.value)})`}`; } - return `WitError(${String(p)})`; + return `ComponentException(${String(p)})`; } return err instanceof Error ? `${err.name}: ${err.message}` : String(err); } diff --git a/experiments/iroh-relay-ws/host/harness.ts b/experiments/iroh-relay-ws/host/harness.ts index 1693f3d..f19aa7f 100644 --- a/experiments/iroh-relay-ws/host/harness.ts +++ b/experiments/iroh-relay-ws/host/harness.ts @@ -9,7 +9,7 @@ // deltic's wasi-shims and this package import `@deltic/runtime/embedder` // by bare specifier; the `deno.json` next to this file maps that // specifier once for the whole module graph, so there is exactly one -// `WitError` module instance and `instanceof` holds across every +// `ComponentException` module instance and `instanceof` holds across every // boundary — including the branded errors sockets.ts throws. import type { ComponentArtifacts } from "@deltic/runtime/embedder"; diff --git a/experiments/iroh-relay-ws/host/sockets.ts b/experiments/iroh-relay-ws/host/sockets.ts index 924a522..b18c6ad 100644 --- a/experiments/iroh-relay-ws/host/sockets.ts +++ b/experiments/iroh-relay-ws/host/sockets.ts @@ -22,7 +22,7 @@ // Environment-portable: standard globals only; works under Deno and in // browsers. -import { WitError } from "@deltic/runtime/embedder"; +import { ComponentException } from "@deltic/runtime/embedder"; import { Pollable } from "@deltic/wasi-shims"; // --------------------------------------------------------------------------- @@ -43,8 +43,8 @@ export interface Ipv4SocketAddress { address: [number, number, number, number]; } export type IpSocketAddress = - | { tag: "ipv4"; val: Ipv4SocketAddress } - | { tag: "ipv6"; val: { port: number; flowInfo: number; address: number[]; scopeId: number } }; + | { kind: "ipv4"; value: Ipv4SocketAddress } + | { kind: "ipv6"; value: { port: number; flowInfo: number; address: number[]; scopeId: number } }; /** `wasi:sockets/udp.incoming-datagram` (record, camelCase fields). */ export interface IncomingDatagram { @@ -79,8 +79,8 @@ const theNetwork = new Network(); /** The relay-ws bridge's well-known synthetic address (see the guest's * datagram-pipe use of iroh-relay's wasi `connect()`). */ export const BRIDGE_ADDR: IpSocketAddress = { - tag: "ipv4", - val: { port: 1, address: [127, 0, 0, 1] }, + kind: "ipv4", + value: { port: 1, address: [127, 0, 0, 1] }, }; let nextEphemeralPort = 0xc000; @@ -104,7 +104,7 @@ export function registerBridge(port: number, cb: BridgeFn): void { const addrRoutes = new Map(); const addrKey = (remoteAddress: IpSocketAddress): string => - `${(remoteAddress.val.address as number[]).join(".")}:${remoteAddress.val.port}`; + `${(remoteAddress.value.address as number[]).join(".")}:${remoteAddress.value.port}`; /** Bridge hook: claim guest datagrams to one synthetic address. */ export function registerAddrRoute( @@ -168,12 +168,12 @@ export class OutgoingDatagramStream { send(datagrams: OutgoingDatagram[]): bigint { for (const d of datagrams) { stats.datagramsOut++; - const route = d.remoteAddress?.val ? addrRoutes.get(addrKey(d.remoteAddress)) : undefined; + const route = d.remoteAddress?.value ? addrRoutes.get(addrKey(d.remoteAddress)) : undefined; if (route) { route(this.#sock, d); continue; } - const port = d.remoteAddress?.val?.port; + const port = d.remoteAddress?.value?.port; const bridge = port === undefined ? undefined : bridges.get(port); if (bridge) { bridge(this.#sock, d); @@ -223,18 +223,18 @@ export class UdpSocket { this.#pendingBind = localAddress; } finishBind(): void { - if (this.#pendingBind === null) throw new WitError("not-in-progress"); + if (this.#pendingBind === null) throw new ComponentException("not-in-progress"); let addr = this.#pendingBind; this.#pendingBind = null; - if (addr.val.port === 0) { + if (addr.value.port === 0) { addr = { - tag: addr.tag, - val: { ...addr.val, port: nextEphemeralPort++ }, + kind: addr.kind, + value: { ...addr.value, port: nextEphemeralPort++ }, } as IpSocketAddress; } this.localAddr = addr; this.bound = true; - socketsByPort.set(addr.val.port, this); + socketsByPort.set(addr.value.port, this); } stream( _remote?: IpSocketAddress, @@ -242,11 +242,11 @@ export class UdpSocket { return [new IncomingDatagramStream(this), new OutgoingDatagramStream(this)]; } localAddress(): IpSocketAddress { - if (!this.bound || this.localAddr === null) throw new WitError("invalid-state"); + if (!this.bound || this.localAddr === null) throw new ComponentException("invalid-state"); return this.localAddr; } remoteAddress(): IpSocketAddress { - throw new WitError("invalid-state"); + throw new ComponentException("invalid-state"); } addressFamily(): AddressFamily { return this.family; @@ -274,7 +274,7 @@ export class UdpSocket { // TCP + name lookup: linked by the libc baseline, never functional. const unsupported = (): never => { - throw new WitError("not-supported"); + throw new ComponentException("not-supported"); }; export class TcpSocket { @@ -317,7 +317,7 @@ export class TcpSocket { export class ResolveAddressStream { resolveNextAddress(): never { - throw new WitError("permanent-resolver-failure"); + throw new ComponentException("permanent-resolver-failure"); } subscribe(): Pollable { return ready(); @@ -352,7 +352,7 @@ export function syntheticNetImports(): Record { "wasi:sockets/ip-name-lookup@0.2": { ResolveAddressStream, resolveAddresses: (): never => { - throw new WitError("permanent-resolver-failure"); + throw new ComponentException("permanent-resolver-failure"); }, }, }; diff --git a/experiments/iroh-relay-ws/host/webrtc-bridge.ts b/experiments/iroh-relay-ws/host/webrtc-bridge.ts index fa97320..38e87b5 100644 --- a/experiments/iroh-relay-ws/host/webrtc-bridge.ts +++ b/experiments/iroh-relay-ws/host/webrtc-bridge.ts @@ -41,8 +41,8 @@ import { import { describeErr } from "./errors.ts"; const WEBRTC_FROM: IpSocketAddress = { - tag: "ipv4", - val: { port: 2, address: [127, 0, 0, 1] }, + kind: "ipv4", + value: { port: 2, address: [127, 0, 0, 1] }, }; const TAG_REGISTER = 0x00; const TAG_ASSIGNED = 0x01; @@ -89,7 +89,7 @@ const t0 = Date.now(); const ts = (): string => `t+${Date.now() - t0}ms`; function synFrom(peer: Peer): IpSocketAddress { - return { tag: "ipv4", val: { port: SYN_PORT, address: peer.synAddr } }; + return { kind: "ipv4", value: { port: SYN_PORT, address: peer.synAddr } }; } /** Forward one raw datagram from `srcHex` toward `dstHex`, buffering while @@ -143,7 +143,7 @@ registerBridge(2, (socket: UdpSocket, { data }: OutgoingDatagram) => { registerAddrRoute(peer.synAddr, SYN_PORT, (senderSocket, d) => { let srcHex = senderSocket.overlayOwner; if (!srcHex) { - const port = senderSocket.localAddress().val.port; + const port = senderSocket.localAddress().value.port; for (const [otherHex, other] of peers) { if (other.udpPort === port) { srcHex = senderSocket.overlayOwner = otherHex; @@ -218,7 +218,7 @@ function pumpChannel(channel: DataChannel, ownerHex: string, remoteHex: string): return; } webrtcStats.in++; - const bytes = message.tag === "binary" ? message.val : new TextEncoder().encode(message.val); + const bytes = message.kind === "binary" ? message.value : new TextEncoder().encode(message.value); const owner = peers.get(ownerHex); const remote = peers.get(remoteHex); if (!owner || !remote) continue; @@ -269,7 +269,7 @@ async function establish(key: string, link: Link, a: string, b: string): Promise link.send = (fromHex, bytes) => { const channel = chans[fromHex]; sendChains[fromHex] = sendChains[fromHex] - .then(() => channel.send({ tag: "binary", val: bytes })) + .then(() => channel.send({ kind: "binary", value: bytes })) .catch((err) => console.error(`[webrtc-bridge] send failed: ${describeErr(err)}`)); }; link.state = "open"; diff --git a/experiments/ping-demo/web/demo.ts b/experiments/ping-demo/web/demo.ts index 4ffdf57..e4a7618 100644 --- a/experiments/ping-demo/web/demo.ts +++ b/experiments/ping-demo/web/demo.ts @@ -83,7 +83,7 @@ function setStatus(state: string, text: string): void { let guestSocket: any = null; const encoder = new TextEncoder(); const decoder = new TextDecoder(); -const GUEST_FROM = { tag: "ipv4" as const, val: { port: 3, address: [127, 0, 0, 1] as [number, number, number, number] } }; +const GUEST_FROM = { kind: "ipv4" as const, value: { port: 3, address: [127, 0, 0, 1] as [number, number, number, number] } }; function sendToGuest(obj: unknown): void { if (!guestSocket) return; diff --git a/experiments/ping-demo/web/overlay.ts b/experiments/ping-demo/web/overlay.ts index 7e2ae21..8be6d25 100644 --- a/experiments/ping-demo/web/overlay.ts +++ b/experiments/ping-demo/web/overlay.ts @@ -33,7 +33,7 @@ import { } from "../../iroh-relay-ws/host/sockets.ts"; import { describeErr } from "../../iroh-relay-ws/host/errors.ts"; -const CONTROL_FROM: IpSocketAddress = { tag: "ipv4", val: { port: 2, address: [127, 0, 0, 1] } }; +const CONTROL_FROM: IpSocketAddress = { kind: "ipv4", value: { port: 2, address: [127, 0, 0, 1] } }; const TAG_REGISTER = 0x00; const TAG_ASSIGNED = 0x01; const TAG_READY = 0x02; @@ -105,7 +105,7 @@ export function beginUpgrade( { remoteIdHex, initiator, sendSignal, onStatus = () => {} }: UpgradeOptions, ): Upgrade { const remote = synAddr(remoteIdHex); - const remoteFrom: IpSocketAddress = { tag: "ipv4", val: remote }; + const remoteFrom: IpSocketAddress = { kind: "ipv4", value: remote }; const config = new PeerConnectionConfig(); config.setIceServers(STUN); @@ -126,7 +126,7 @@ export function beginUpgrade( if (channel) { overlayStats.out++; sendChain = sendChain - .then(() => channel!.send({ tag: "binary", val: bytes })) + .then(() => channel!.send({ kind: "binary", value: bytes })) .catch((err) => console.error(`[overlay] send failed: ${describeErr(err)}`)); } else if (backlog.length < 64) { backlog.push(bytes); @@ -147,7 +147,7 @@ export function beginUpgrade( } overlayStats.in++; const bytes = - message.tag === "binary" ? message.val : new TextEncoder().encode(message.val); + message.kind === "binary" ? message.value : new TextEncoder().encode(message.value); const sock = self_ && socketByLocalPort(self_.udpPort); if (sock) pushDatagram(sock, bytes, remoteFrom); } @@ -180,7 +180,7 @@ export function beginUpgrade( for (const bytes of backlog.splice(0)) { overlayStats.out++; sendChain = sendChain - .then(() => channel!.send({ tag: "binary", val: bytes })) + .then(() => channel!.send({ kind: "binary", value: bytes })) .catch(() => {}); } // Readiness gates the guest's add_external_addr. diff --git a/host-deltic/README.md b/host-deltic/README.md index 3878e53..35410f6 100644 --- a/host-deltic/README.md +++ b/host-deltic/README.md @@ -89,10 +89,10 @@ module under its own package-shaped `deno.json` (name + exports) resolves its bare specifiers against THAT config — before the `.deps` pins converged on JSR-consuming sibling revisions, the webcrypto module silently rode a raw pinned-tag embedder while everything else used the -JSR one, and `instanceof WitError` did not hold across its boundary. +JSR one, and `instanceof ComponentException` did not hold across its boundary. Identity therefore rests on every config in the graph — this one and each pinned sibling's — naming the SAME `jsr:@deltic/*` version, so the -resolver dedupes to one `WitError`/`Stream` module instance. Two gates +resolver dedupes to one `ComponentException`/`Stream` module instance. Two gates in `just exam-deltic` keep it true: the pin grep (this repo's configs agree) and `scripts/deltic-identity-gate.ts` (the RESOLVED run-endpoint graph carries exactly one `@deltic/runtime` and no raw URLs). Bumping a diff --git a/host-deltic/deno.json b/host-deltic/deno.json index 7ce4d0c..4825dac 100644 --- a/host-deltic/deno.json +++ b/host-deltic/deno.json @@ -1,14 +1,14 @@ { - "//": "MODULE-IDENTITY CONSTRAINT: deltic's wasi-shims and the sibling deltic host modules (.deps/{websocket,webrtc,webcrypto}) import @deltic/runtime/embedder by bare specifier internally; this file maps that specifier ONCE for the whole module graph, so `instanceof WitError` holds across every boundary. deltic arrives as exactly-pinned JSR prereleases (0.1.0-pre.g names one upstream commit; @deltic/translator ships the translator wasm for the SAME commit, so the plan-format coupling is self-consistent per graph); deno.lock carries integrity, enforced with --frozen. The version matches experiments/iroh-relay-ws/host/deno.json by repo convention (see README.md, 'The pin'; exam-deltic asserts it). minimumDependencyAge keeps Deno's default supply-chain gate for everything else while letting same-day @deltic prereleases resolve. The npm mappings serve the webrtc module's bare specifiers, which resolve against this config as the entry import map.", + "//": "MODULE-IDENTITY CONSTRAINT: deltic's wasi-shims and the sibling deltic host modules (.deps/{websocket,webrtc,webcrypto}) import @deltic/runtime/embedder by bare specifier internally; this file maps that specifier ONCE for the whole module graph, so `instanceof ComponentException` holds across every boundary. deltic arrives as exactly-pinned JSR prereleases (0.1.0-pre.g names one upstream commit; @deltic/translator ships the translator wasm for the SAME commit, so the plan-format coupling is self-consistent per graph); deno.lock carries integrity, enforced with --frozen. The version matches experiments/iroh-relay-ws/host/deno.json by repo convention (see README.md, 'The pin'; exam-deltic asserts it). minimumDependencyAge keeps Deno's default supply-chain gate for everything else while letting same-day @deltic prereleases resolve. The npm mappings serve the webrtc module's bare specifiers, which resolve against this config as the entry import map.", "nodeModulesDir": "auto", "minimumDependencyAge": { "age": "P1D", "exclude": ["jsr:@deltic/*"] }, "imports": { - "@deltic/runtime/embedder": "jsr:@deltic/runtime@0.1.0-pre.ga67ee83/embedder", - "@deltic/translator": "jsr:@deltic/translator@0.1.0-pre.ga67ee83", - "@deltic/wasi-shims": "jsr:@deltic/wasi-shims@0.1.0-pre.ga67ee83", + "@deltic/runtime/embedder": "jsr:@deltic/runtime@0.1.0-pre.g078aa15/embedder", + "@deltic/translator": "jsr:@deltic/translator@0.1.0-pre.g078aa15", + "@deltic/wasi-shims": "jsr:@deltic/wasi-shims@0.1.0-pre.g078aa15", "@polymorph/webcrypto-deltic": "../.deps/webcrypto/js/deltic/src/mod.ts", "node-datachannel": "npm:node-datachannel@0.32.3", "node-datachannel/polyfill": "npm:node-datachannel@0.32.3/polyfill", diff --git a/host-deltic/deno.lock b/host-deltic/deno.lock index 02f7134..ad1e674 100644 --- a/host-deltic/deno.lock +++ b/host-deltic/deno.lock @@ -1,27 +1,35 @@ { "version": "5", "specifiers": { - "jsr:@deltic/runtime@0.1.0-pre.ga67ee83": "0.1.0-pre.ga67ee83", - "jsr:@deltic/runtime@~0.1.0-pre.ga67ee83": "0.1.0-pre.ga67ee83", - "jsr:@deltic/translator@0.1.0-pre.ga67ee83": "0.1.0-pre.ga67ee83", - "jsr:@deltic/wasi-shims@0.1.0-pre.ga67ee83": "0.1.0-pre.ga67ee83", + "jsr:@deltic/protocol@0.2": "0.2.0", + "jsr:@deltic/runtime@0.1.0-pre.g078aa15": "0.1.0-pre.g078aa15", + "jsr:@deltic/runtime@~0.1.0-pre.g078aa15": "0.1.0-pre.g078aa15", + "jsr:@deltic/translator@0.1.0-pre.g078aa15": "0.1.0-pre.g078aa15", + "jsr:@deltic/wasi-shims@0.1.0-pre.g078aa15": "0.1.0-pre.g078aa15", "npm:node-datachannel@0.32.3": "0.32.3", "npm:werift@0.22.2": "0.22.2" }, "jsr": { - "@deltic/runtime@0.1.0-pre.ga67ee83": { - "integrity": "2a2b0949031747a2340dc186299e654ea9f361ae39ac6bd633019940682db4ed" + "@deltic/protocol@0.2.0": { + "integrity": "028be6a3623c5e910598aa7a199209b85e8931ae484ac7f6638d610ddb0e19fa" }, - "@deltic/translator@0.1.0-pre.ga67ee83": { - "integrity": "e4f1bb219e56b62262b0c9665e3f6646aa13883b2cfbb9d6306f69d19974d412", + "@deltic/runtime@0.1.0-pre.g078aa15": { + "integrity": "5e64f8dc6d32190ecd394d6ad9881eb0fa97b6598b1e7f2ef1d52cff4674287c", "dependencies": [ - "jsr:@deltic/runtime@~0.1.0-pre.ga67ee83" + "jsr:@deltic/protocol" ] }, - "@deltic/wasi-shims@0.1.0-pre.ga67ee83": { - "integrity": "a5754e65d50873e675695a51279989e22b3771e31f16a84a09feb15905c574a7", + "@deltic/translator@0.1.0-pre.g078aa15": { + "integrity": "7125f99ac46af4a69f1c432def2b7ea4be63509c3a7ebae83537357615ec33ef", "dependencies": [ - "jsr:@deltic/runtime@~0.1.0-pre.ga67ee83" + "jsr:@deltic/runtime@~0.1.0-pre.g078aa15" + ] + }, + "@deltic/wasi-shims@0.1.0-pre.g078aa15": { + "integrity": "fba2081f804eaaccf95e31cdd634fd85a2d724f6be7f62578ddc26aef03524a1", + "dependencies": [ + "jsr:@deltic/protocol", + "jsr:@deltic/runtime@~0.1.0-pre.g078aa15" ] } }, @@ -593,16 +601,16 @@ }, "workspace": { "dependencies": [ - "jsr:@deltic/runtime@0.1.0-pre.ga67ee83", - "jsr:@deltic/translator@0.1.0-pre.ga67ee83", - "jsr:@deltic/wasi-shims@0.1.0-pre.ga67ee83", + "jsr:@deltic/runtime@0.1.0-pre.g078aa15", + "jsr:@deltic/translator@0.1.0-pre.g078aa15", + "jsr:@deltic/wasi-shims@0.1.0-pre.g078aa15", "npm:node-datachannel@0.32.3", "npm:werift@0.22.2" ], "links": { "jsr:@polymorph/webcrypto-deltic@0.0.0": { "dependencies": [ - "jsr:@deltic/runtime@0.1.0-pre.ga67ee83" + "jsr:@deltic/runtime@0.1.0-pre.g078aa15" ] } } diff --git a/host-deltic/src/harness.ts b/host-deltic/src/harness.ts index 236e9e7..1feec89 100644 --- a/host-deltic/src/harness.ts +++ b/host-deltic/src/harness.ts @@ -9,12 +9,12 @@ // MODULE-IDENTITY CONSTRAINT: deltic's wasi-shims and the sibling host // modules import `@deltic/runtime/embedder` by bare specifier internally; // this package's `deno.json` maps that specifier ONCE for the whole module -// graph, so there is exactly one `WitError`/`Stream` module instance and -// `instanceof` holds across every boundary. +// graph, so there is exactly one `ComponentException`/`Stream` module +// instance and `instanceof` holds across every boundary. import { defaultTranslator } from "@deltic/translator"; import type { ComponentArtifacts } from "@deltic/runtime/embedder"; -import { instantiate, WitError } from "@deltic/runtime/embedder"; +import { instantiate, ComponentException } from "@deltic/runtime/embedder"; import { wasiShims } from "@deltic/wasi-shims"; import { webcryptoImports } from "@polymorph/webcrypto-deltic"; import { websocketImports } from "../../.deps/websocket/js/deltic/websocket.ts"; @@ -263,9 +263,9 @@ export function deadline(promise: Promise, ms: number, what: string): Prom /** Render a rejection, unwrapping the branded WIT error payload. */ export function describeError(err: unknown): string { - if (err instanceof WitError) { - const p = err.payload as { tag?: string; val?: unknown } | undefined; - return `WitError ${p?.tag ?? "?"}${p?.val === undefined ? "" : `(${String(p.val)})`}`; + if (err instanceof ComponentException) { + const p = err.payload as { kind?: string; value?: unknown } | undefined; + return `ComponentException ${p?.kind ?? "?"}${p?.value === undefined ? "" : `(${String(p.value)})`}`; } return err instanceof Error ? `${err.name}: ${err.message}` : String(err); } diff --git a/host-deltic/src/run-endpoint.ts b/host-deltic/src/run-endpoint.ts index 55b745a..61bb1f6 100644 --- a/host-deltic/src/run-endpoint.ts +++ b/host-deltic/src/run-endpoint.ts @@ -56,7 +56,7 @@ import { startRelay, utf8, } from "./harness.ts"; -import { WitError } from "@deltic/runtime/embedder"; +import { ComponentException } from "@deltic/runtime/embedder"; import { resetUdpCallLog, udpCallLog } from "./sockets.ts"; import type { CloseInfo, @@ -150,8 +150,8 @@ async function echoOnce(relay: Relay, options: EchoOptions): Promise // The dial hints. A `webrtc` entry is an UPGRADE HINT, not a dial target: // the handshake runs on the relay and the packets move to the data channel // once it opens (wit/iroh.wit's transport-addr docs). - const addrs: TransportAddr[] = [{ tag: "relay", val: relay.url }]; - if (options.webrtc) addrs.push({ tag: "webrtc", val: relay.url }); + const addrs: TransportAddr[] = [{ kind: "relay", value: relay.url }]; + if (options.webrtc) addrs.push({ kind: "webrtc", value: relay.url }); // The server's accept. Parked BEFORE the dial it is the jco#13 shape (a // cross-task wakeup delivered to a task that parked first); deferred it @@ -329,7 +329,7 @@ async function terminalProbeOnce(relay: Relay): Promise { const serverId = await sep.id(); const conn = await deadline( - cep.connect({ endpointId: serverId, addrs: [{ tag: "relay", val: relay.url }] }, ALPN), + cep.connect({ endpointId: serverId, addrs: [{ kind: "relay", value: relay.url }] }, ALPN), 60_000, "connect", ); @@ -370,9 +370,9 @@ async function readOutcome(recv: RecvStream): Promise { try { chunk = await deadline(recv.read(65536), 30_000, "read to terminal"); } catch (err) { - if (err instanceof WitError) { - const p = err.payload as { tag?: string; val?: unknown } | undefined; - return p?.tag === "reset" ? `reset(${p.val})` : p?.tag ?? "unknown"; + if (err instanceof ComponentException) { + const p = err.payload as { kind?: string; value?: unknown } | undefined; + return p?.kind === "reset" ? `reset(${p.value})` : p?.kind ?? "unknown"; } throw err; } diff --git a/host-deltic/src/sockets.ts b/host-deltic/src/sockets.ts index 859f4fc..696d791 100644 --- a/host-deltic/src/sockets.ts +++ b/host-deltic/src/sockets.ts @@ -26,7 +26,7 @@ // extension once deltic's wasi-shims grow p3 `wasi:sockets` providers // (lann/deltic#4); this file is where that provider would be wired. -import { WitError } from "@deltic/runtime/embedder"; +import { ComponentException } from "@deltic/runtime/embedder"; /** `wasi:sockets/types@0.3.0`'s `ip-address-family` enum. */ export type IpAddressFamily = "ipv4" | "ipv6"; @@ -58,10 +58,10 @@ export interface Ipv6SocketAddress { scopeId: number; } -/** The `ip-socket-address` variant, in `{ tag, val }` form. */ +/** The `ip-socket-address` variant, in `{ kind, value }` form. */ export type IpSocketAddress = - | { tag: "ipv4"; val: Ipv4SocketAddress } - | { tag: "ipv6"; val: Ipv6SocketAddress }; + | { kind: "ipv4"; value: Ipv4SocketAddress } + | { kind: "ipv6"; value: Ipv6SocketAddress }; /** * The `error-code` variant. Only the cases this stub can produce are @@ -69,21 +69,21 @@ export type IpSocketAddress = * exhaustively against the real WIT vocabulary. */ export type SocketErrorCode = - | { tag: "access-denied" } - | { tag: "not-supported" } - | { tag: "invalid-argument" } - | { tag: "out-of-memory" } - | { tag: "timeout" } - | { tag: "invalid-state" } - | { tag: "address-not-bindable" } - | { tag: "address-in-use" } - | { tag: "remote-unreachable" } - | { tag: "connection-refused" } - | { tag: "connection-broken" } - | { tag: "connection-reset" } - | { tag: "connection-aborted" } - | { tag: "datagram-too-large" } - | { tag: "other"; val?: string }; + | { kind: "access-denied" } + | { kind: "not-supported" } + | { kind: "invalid-argument" } + | { kind: "out-of-memory" } + | { kind: "timeout" } + | { kind: "invalid-state" } + | { kind: "address-not-bindable" } + | { kind: "address-in-use" } + | { kind: "remote-unreachable" } + | { kind: "connection-refused" } + | { kind: "connection-broken" } + | { kind: "connection-reset" } + | { kind: "connection-aborted" } + | { kind: "datagram-too-large" } + | { kind: "other"; value?: string }; const callLog: string[] = []; @@ -99,11 +99,12 @@ export function resetUdpCallLog(): void { function refuse(what: string): never { callLog.push(what); - // A host import signals a WIT `err` by throwing a BRANDED `WitError` - // (contracts/embedder-api.md, "Error model"): an unbranded throw would - // become a trap naming the import instead of a guest-visible err. - const payload: SocketErrorCode = { tag: "not-supported" }; - throw new WitError(payload, `wasi:sockets/types@0.3.0: ${what} is not provided by this host`); + // A host import signals a WIT `err` by throwing a BRANDED + // `ComponentException` (contracts/embedder-api.md, "Error model"): an + // unbranded throw would become a trap naming the import instead of a + // guest-visible err. + const payload: SocketErrorCode = { kind: "not-supported" }; + throw new ComponentException(payload, `wasi:sockets/types@0.3.0: ${what} is not provided by this host`); } /** diff --git a/host-deltic/src/types.ts b/host-deltic/src/types.ts index b44ff06..52212b8 100644 --- a/host-deltic/src/types.ts +++ b/host-deltic/src/types.ts @@ -4,8 +4,8 @@ // // * resource -> PascalCase class, methods camelCase, statics static // * every export is Promise-shaped; `result` in RETURN position -// resolves T or rejects `WitError` (so no `{tag}` unwrapping here) -// * enums -> kebab-case string literal unions; variants -> `{ tag, val }` +// resolves T or rejects `ComponentException` (so no `{kind}` unwrapping here) +// * enums -> kebab-case string literal unions; variants -> `{ kind, value }` // * `list` -> Uint8Array; `option` (outermost) -> `T | undefined` // * record fields camelCase; option-typed fields are optional properties // @@ -22,10 +22,10 @@ export interface CustomAddr { } export type TransportAddr = - | { tag: "relay"; val: string } - | { tag: "ip"; val: string } - | { tag: "webrtc"; val: string } - | { tag: "custom"; val: CustomAddr }; + | { kind: "relay"; value: string } + | { kind: "ip"; value: string } + | { kind: "webrtc"; value: string } + | { kind: "custom"; value: CustomAddr }; export interface EndpointAddr { endpointId: EndpointId; @@ -45,11 +45,11 @@ export type PathKind = "relay" | "ip" | "webrtc"; /** `polymorph:iroh/types@0.1.0`'s `error` variant. */ export type IrohError = - | { tag: "closed" } - | { tag: "reset"; val: bigint } - | { tag: "connect-failed"; val: string } - | { tag: "invalid-argument"; val: string } - | { tag: "other"; val: string }; + | { kind: "closed" } + | { kind: "reset"; value: bigint } + | { kind: "connect-failed"; value: string } + | { kind: "invalid-argument"; value: string } + | { kind: "other"; value: string }; /** The `identity` resource: a non-extractable Ed25519 key pair. */ export interface Identity { diff --git a/scripts/deltic-identity-gate.ts b/scripts/deltic-identity-gate.ts index b19c4cc..2b8763d 100644 --- a/scripts/deltic-identity-gate.ts +++ b/scripts/deltic-identity-gate.ts @@ -6,7 +6,7 @@ // JSR-consuming sibling revisions): a sibling host module's own // package-shaped deno.json mapped @deltic/runtime/embedder to a raw // pinned-tag URL, so the graph carried TWO embedder module instances and -// `instanceof WitError` silently stopped holding across that sibling's +// `instanceof ComponentException` silently stopped holding across that sibling's // boundary. Config greps can't see this — only the resolved graph can — // so the exam pipes `deno info --json` through this assert. // diff --git a/scripts/setup.sh b/scripts/setup.sh index 17aa453..6671e86 100755 --- a/scripts/setup.sh +++ b/scripts/setup.sh @@ -16,11 +16,11 @@ JUST_VERSION="${JUST_VERSION:-1.54.0}" WAC_VERSION="${WAC_VERSION:-0.10.1}" WEBRTC_REPO=https://github.com/polymorph-components/polymorph-webrtc-datachannels.git -WEBRTC_PIN=5dc3d4184d2ab82b98aa0ff82a218f9ed1e080eb +WEBRTC_PIN=6612fbdc973843b68cc839b50a18d38bdacf938e WEBCRYPTO_REPO=https://github.com/polymorph-components/polymorph-webcrypto.git -WEBCRYPTO_PIN=a0c924d3f10cc598e9ea2e754dc4f13f162dc749 +WEBCRYPTO_PIN=eba5f31a1a656d66a016f40077546123cff87259 WEBSOCKET_REPO=https://github.com/polymorph-components/polymorph-websocket.git -WEBSOCKET_PIN=a3b7fb1d0231c110b0bebb493276d23308642537 +WEBSOCKET_PIN=fa36ee8664a2f2b2e6ee5d6152321ac42b15b5d0 IROH_REPO=https://github.com/n0-computer/iroh.git IROH_PIN=816dd70c056b813dcb5cbfb6a9a15e12d04b72b1 # v1.0.3 TLS_REPO=https://github.com/polymorph-components/polymorph-tls.git