WEFT_OS/docs/architecture/spidermonkey-bridge-assessment.md
Marco Allegretti ad40271d69 docs: add SpiderMonkey bridge assessment and WebSocket UI endpoint design
Assesses the original concern that the weft-appd UI endpoint for the
system-ui.html page would require custom SpiderMonkey bindings injected
into Servo.

Conclusion: custom SpiderMonkey bindings are not required. Servo's
standard WebSocket API satisfies all UI endpoint requirements (send
requests, receive push notifications, structured JSON payloads).

Documents:
- What the UI endpoint needs (send/receive structured messages,
  session-scoped, local transport).
- Servo's relevant capabilities: WebSocket implemented, fetch
  implemented, custom embedder APIs not stable/not needed.
- Proposed implementation: tokio-tungstenite WebSocket listener in
  weft-appd on 127.0.0.1; port published to XDG_RUNTIME_DIR for
  discovery; broadcast channel for APP_READY push to all connected
  clients; JSON framing (same Request/Response types via serde_json).
- Scope boundaries: does not replace the Unix socket path (servo-shell
  native IPC); does not require Servo modification.
2026-03-11 08:42:14 +01:00

4.9 KiB

SpiderMonkey Bridge Assessment

Status: Assessment complete — blocker 3 resolved. Decision: Custom SpiderMonkey bindings are not required. WebSocket satisfies the UI endpoint contract.


Context

The weft-appd IPC channel design (see docs/architecture/wasm-servo-channel.md) requires a UI endpoint: a mechanism by which the system UI HTML page running inside Servo can receive notifications from weft-appd (e.g., APP_READY) and send requests (e.g., LAUNCH_APP).

The original concern ("blocker 3") was that satisfying this requirement might need custom SpiderMonkey bindings injected into Servo — functionality that is not stable or exposed as a public Servo API.


What the UI Endpoint Requires

  1. The system-ui.html page must be able to send structured messages to weft-appd (LAUNCH_APP, TERMINATE_APP, QUERY_RUNNING, QUERY_APP_STATE).
  2. The system-ui.html page must be able to receive asynchronous push notifications from weft-appd (LAUNCH_ACK, APP_READY).
  3. Messages must carry a session identifier and structured payload.
  4. The transport must work over a local connection (same machine, session-local).

None of these requirements are specific to SpiderMonkey internals. They describe a generic bidirectional message channel.


Servo's Relevant Capabilities (as of 2025)

Feature Status Notes
WebSocket API (RFC 6455) Implemented servo/components/script/dom/websocket.rs
fetch() Implemented Standard Fetch API
JSON.parse / JSON.stringify Implemented Core JS, SpiderMonkey
addEventListener / dispatchEvent Implemented Full DOM events
ES modules Partially implemented Not required for this use case
Service Workers Not implemented Not required
Custom native APIs via embedder Not stable / no public API This was the original concern

Key finding: WebSocket is implemented in Servo and is the standard API for persistent bidirectional message channels between a web page and a local service.


Proposed Implementation: WebSocket Endpoint in weft-appd

weft-appd already has tokio with the net feature. Adding a WebSocket server alongside the existing Unix socket server requires only the tokio-tungstenite crate (tokio-native WebSocket).

Transport architecture

system-ui.html (Servo)
  └─ WebSocket ws://127.0.0.1:<port>/appd
        │
        │  JSON frames (human-readable, same semantics as MessagePack IPC)
        │
weft-appd WebSocket listener
  └─ shared SessionRegistry (same Arc<Mutex<...>>)

The Unix socket remains the production IPC path for machine-to-machine communication (servo-shell native path). The WebSocket listener is the UI endpoint for Servo.

Message format

The same Request / Response enum used by the MessagePack Unix socket path is also serialized as JSON for the WebSocket channel (using serde_json). The type tag remains SCREAMING_SNAKE_CASE.

Example:

{"type":"LAUNCH_APP","app_id":"com.example.notes","surface_id":0}

Port selection

weft-appd binds on 127.0.0.1 only. The port is resolved in priority order:

  1. WEFT_APPD_WS_PORT environment variable
  2. Default: 7410

The port is written to $XDG_RUNTIME_DIR/weft/appd.wsport at startup so that the system-ui.html can discover it without hardcoding.

Push notifications

The WebSocket connection stays open. weft-appd pushes APP_READY frames to all connected clients when a session transitions to Running. This is implemented with a tokio::sync::broadcast channel that the WebSocket handler subscribes to.


What This Assessment Does Not Cover

  • Servo's Wayland EGL surface stability: covered in docs/architecture/winit-wayland-audit.md.
  • Servo DPI / HiDPI rendering: not assessed; deferred.
  • Content Security Policy interactions with ws://127.0.0.1: system-ui.html is served from the local filesystem (file://) or a bundled origin. CSP headers are controlled by WEFT, so ws://127.0.0.1 can be explicitly allowed.
  • Servo WebSocket reconnect on compositor restart: not designed; out of scope for initial implementation.

Blocker 3 Resolution

The original concern was that the UI endpoint would require injecting custom SpiderMonkey bindings into Servo, which is not a stable operation.

This concern is resolved. The UI endpoint is implemented entirely via the standard WebSocket API, which Servo ships as a fully functional implementation. No custom SpiderMonkey bindings are needed. The WEFT codebase does not modify Servo's internals for this feature.

Implementation required:

  1. Add tokio-tungstenite + serde_json to weft-appd.
  2. Add broadcast::Sender<Response> to run() for push notifications.
  3. Start a WebSocket listener task alongside the existing Unix socket listener.
  4. Update system-ui.html to connect via WebSocket and handle APP_READY events.

This work is scoped and ready to implement.