Skip to content

feat(net): add bounded fetch(net) module - #246

Merged
doodlewind merged 1 commit into
pocket-stack:mainfrom
siwei-yuan:codex/feat-net-surface
Aug 9, 2026
Merged

feat(net): add bounded fetch(net) module#246
doodlewind merged 1 commit into
pocket-stack:mainfrom
siwei-yuan:codex/feat-net-surface

Conversation

@siwei-yuan

Copy link
Copy Markdown
Contributor

Summary

  • add a spec-pinned globalThis.net module and framework-neutral fetch() SDK
  • add the transport-neutral pocket-net Rust core with bounded handles, tick-batched completions, response ownership, portable errors, and a host-owned HttpTransport seam
  • add deterministic sim and browser-fetch host adapters, lazy service pumping across Solid/Vue Vapor/Octane, capability/export codegen, tests, and docs

Design

NET v1 is intentionally a bounded whole-response HTTP client rather than a complete WHATWG Fetch implementation. It supports common app methods, headers, string/byte bodies, timeout and per-request maxBytes; it omits streams, cookies, cache, Request/Headers, AbortSignal, WebSocket, servers, and raw sockets.

Concrete DNS/TLS/HTTP libraries remain host-owned. pocket-net does not depend on ureq, reqwest, ESP-IDF, or a runtime executor; downstream hosts implement HttpTransport::start/cancel/drain. Network workers never call QuickJS, and the guest polls once per tick only while requests are pending. One poll drains the complete visible batch.

Verification

  • bun run test — 11/11 stages green
  • bunx tsc --noEmit
  • cargo test -p pocket-net --manifest-path engine/Cargo.toml — 5 passed
  • cargo clippy -p pocket-net --all-targets --manifest-path engine/Cargo.toml -- -D warnings
  • cargo check --workspace --manifest-path engine/Cargo.toml
  • bun run site:build
  • bun tests/contract.ts

@siwei-yuan siwei-yuan changed the title feat(net): add bounded fetch module feat(net): add bounded fetch(net) module Aug 7, 2026
@siwei-yuan
siwei-yuan marked this pull request as ready for review August 7, 2026 09:48

@doodlewind doodlewind left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the feat!

@doodlewind
doodlewind merged commit 9fe1556 into pocket-stack:main Aug 9, 2026
2 checks passed
@doodlewind

Copy link
Copy Markdown
Collaborator

Verdict: merge. Reviewed against the module discipline audio (#217) established and the data modules (#231/#238) follow; everything below was run, not read.

Verified

  • bun run test: 11/11 stages green on the branch head, and again on a local merge with current main (one run tripped this machine's known symbian-runtime Gatekeeper flake; the stage passes in isolation and the full re-run is green).
  • bunx tsc --noEmit clean; cargo test -p pocket-net 5/5; cargo clippy -p pocket-net --all-targets -- -D warnings clean.
  • bun tests/contract.ts all green — engine/core/src/spec.rs and the package.json exports block match their generators byte-for-byte, so bun run gen / gen-rust.ts were really run.
  • Only overlap with main since this branch's base is the package.json version field; the merge is clean.

Design conformance

  • Spec-first: contracts/spec/net.ts carries the four-part boundary (ops / events / data contract / frame contract), append-only numeric op codes, and the borrow-ownership rules for start/take.
  • Frame contract holds: transports never call QuickJS; completions stage in host memory and cross only at a tick boundary (begin_tick / beginFrame / sim tick()); Promise reactions run in the guest turn's normal job drain. The tests pin the load-bearing facts — no settle before a tick boundary, exactly one poll() per tick while pending, the pump unregisters at zero pending.
  • Capability: net.http registered with no stock target advertising it — the audio.pcm precedent; a target appends it when its host ships the module.
  • Transport seam: HttpTransport is start/cancel/drain only; the core owns validation, limits, handles and bodies, and the crate tests include a live QuickJS mount round-trip.

Two deliberate deviations, accepted

  1. net.poll() drains the whole tick batch as one JSON array, where audio.poll() drains one event per call. The batch form is pinned in the spec and buys one FFI crossing per tick; accepted as this module's documented convention.
  2. runServicePumps() adds a new frame-loop phase to all three frameworks. It is realm-scoped, a no-op when idle, and the right home for future async modules; accepted as shared infrastructure.

Follow-ups (not blockers; landing separately since this branch has maintainer edits disabled)

  1. Fold the hand-rolled UTF-8 codecs (framework/src/net-api.ts, hosts/sim/net.ts) into the shared framework/src/bytes.ts the data modules introduce.
  2. Give pocket-net the same mount default-feature split as pocket-fs, so default-features = false drops pocket-mod/rquickjs for firmware with its own QuickJS wiring.

Also noted for the record: v1 ships no consumer app, and HttpTransport has not yet been exercised by an embedded client (esp_http_client, ureq) — the browser adapter is the only physical transport today. Fine for v1; the sim and reference core carry the contract.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants