wasi-shims: à la carte wasi:sockets UDP over Deno.listenDatagram - #122
Merged
Conversation
Adopted from polymorph-components/polymorph-iroh#69 (that host's exam drives it over loopback QUIC end to end). The five-function udp-socket surface the iroh endpoint links — create, bind, send, receive, get-local-address — with wasmtime-wasi p3 as the behavioral yardstick: the 64 KiB datagram ceiling (both detection paths), the bind-once state machine, send's implicit wildcard bind, invalid-argument for an omitted remote on this connectionless surface, and the IPv4-mapped / deprecated-IPv4-compatible family rejections. Recorded divergences from wasmtime (both rooted in Deno exposing no socket options): non-zero scope-id fails not-supported; IPv6 sockets keep the OS dual-stack default, so the codec parses the ::ffff:a.b.c.d sender spelling. A la carte per the s2 WASI non-goal: a separate export (@deltic/wasi-shims/sockets), never merged into wasiShims() and absent from the release bundle — the root module stays host-agnostic web-platform code, and browsers/wasmtime own their respective UDP stories. When Deno.listenDatagram is absent (no Deno global, or --unstable-net off), create answers not-supported. Divergences from the adopted code: the track key (@0.3 — one provider serves every 0.3.x), a fragment-scoped onCall observer replacing the module-global call log (a published provider must not grow a string per datagram by default; the fragment returns its UdpSocket class so the hook stays per-fragment), globalThis-based feature detection with structural types for the unstable surface (no "unstable" flag needed to check or publish), and a ComponentException passthrough in mapPlatformError — branded errors thrown inside the platform-call try blocks (the codec in receive, capability re-detection in bind/send) no longer double-wrap into kind "other". Gates: test-wasi-shims (20 new tests), publish-check, test-bundle.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The decision
Adopts the
wasi:sockets/typesUDP provider from polymorph-components/polymorph-iroh#69 into the shim package as an à la carte fragment: a separate export (@deltic/wasi-shims/sockets), never merged intowasiShims()and absent from the release bundle. The root module stays host-agnostic web-platform code; Deno-native hosts spread the fragment in:Scope stays in the shim package per the §2 WASI non-goal (docs/architecture.md); this is the "natural upstream home" the source PR named, and the first installment of #4 (UDP for the iroh direct path — the p3 TCP leaves remain open there).
Scope: the linked surface, exactly
The five
udp-socketfunctions the iroh endpoint artifact links —create,bind,send,receive,get-local-address. The unlinked remainder of the WIT resource (connect/disconnect, socket options) stays absent by design: the runtime dispatches only what a plan imports, and a future guest linking more gets a loud trap naming the missing method rather than an untested emulation.Behavioral yardstick is wasmtime-wasi's p3 provider: the 64 KiB datagram ceiling (checked before the OS; EMSGSIZE mapped for the 65508–65535 band), the bind-once state machine,
send's implicit wildcard bind,invalid-argumentfor an omitted remote on this connectionless surface, and the IPv4-mapped / deprecated-IPv4-compatible family rejections. Recorded divergences (module header), both rooted in Deno exposing no socket options: non-zero IPv6 scope-id failsnot-supported; IPv6 sockets keep the OS dual-stack default where wasmtime setsIPV6_V6ONLY(hence the codec parsing the::ffff:a.b.c.dsender spelling).Divergences from the adopted code
wasi:sockets/types@0.3instead of exact@0.3.0— this package is the flagship track-key consumer; one provider serves every 0.3.x the resolver folds onto the track.onCallobserver replaces the module-global call log: a published provider must not grow a string per datagram by default. The fragment returns{ imports, UdpSocket }(mirroringcli()'s{ imports, captured }), so the hook is per-fragment — the source PR's exam assertions (zero-calls in relay scenarios, exact driving sequence) remain expressible.globalThis-based feature detection + structural types for the unstableDeno.listenDatagramsurface: the module evaluates on hosts with noDenoglobal at all and needs no"unstable"config to type-check or publish.createanswersnot-supportedwhere UDP isn't served.mapPlatformErrorpasses branded errors through — fixes a latent double-wrap in the adopted code: branded throws from inside the platform-call try blocks (the address codec inreceive; here also the capability re-detection inbind/send) were demoted tokind: "other". Regression test included.Gates
just test-wasi-shims: 20 new unit tests — the address codec (compressed / full / IPv4-embedded / zoned spellings), the state machine and branded-error contract, the zero-length self-wake datagram, bothdatagram-too-largedetection paths, dispose retiring a parkedreceiveas a branded err, the fragment shape (track key, per-fragmentonCall), and the passthrough regression. The test task gains--allow-net --unstable-net(real loopback sockets).just publish-check: the new./socketssubpath passes the JSR dry-run.just test-bundle: bundle unchanged by design (root graph untouched).Refs #4.