@soffit/protocol
v0.0.1
Published
Soffit wire contract: Effect Schema types for UI IR, deploy, and worker RPC
Readme
@soffit/protocol
Versioned Effect Schema contracts for Soffit’s worker ↔ control plane wire.
Planes (Compose / Interval patterns)
Inspired by Compose (typed multi-plane events: sdk↔server vs browser↔server) and Interval (outbound host process + duplex CALL/RESPONSE schemas) — clean-room design, not binary-compatible.
| Plane | Transport | Auth |
| --- | --- | --- |
| worker → control | WebSocket outbound from soffit dev | SOFFIT_API_KEY on upgrade + WorkerHello |
| control → worker | Same socket | Invokes only after hello |
| browser → control | HTTPS / HTMX | Dashboard session cookie |
The browser never speaks to the worker. Your DB credentials stay in the user project process.
Core message tags
Worker → control: WorkerHello · UIPatch · ActionResult · Heartbeat
Control → worker: InvokeApp · InvokeAction · ProtocolReject
All frames are validated with Effect Schema encode/decode (codec.ts). Invalid JSON or shapes throw ContractError / return ProtocolReject without crashing the server.
Usage
import {
decodeWorkerToServerJson,
encodeServerToWorkerJson,
decodeDeployRequest,
PROTOCOL_VERSION,
} from "@soffit/protocol";HTTP deploy uses DeployRequest / DeployManifest (same package).
Optional envelope: { v, dir: "w2c"|"c2w", id, body } — Interval-style framing; bare tagged bodies also accepted.
Backend availability
If the worker (user backend / soffit dev) is disconnected:
- Deployed metadata may still appear on the control plane (last successful deploy).
- Invokes fail with a clear error (
No worker connected for project …). - No business data can be read or written — secrets and DB access never leave the worker.
See root README.md → Backend scenarios.
Reliability (finished layer)
Inspired by Interval host connection maps + WS ping, and Compose ping-timeout / reconnect / deploy drain:
| Tag | Direction | Role |
| --- | --- | --- |
| Heartbeat | worker → control | Liveness pulse |
| ServerPing | control → worker | Active probe; reply with Heartbeat |
| ReconnectRequired | control → worker | Drain / deploy: reconnect after afterMs |
| ProtocolReject | control → worker | Invalid frame without crash |
Silent workers are evicted when lastSeenAt exceeds SOFFIT_WORKER_STALE_MS. See docs/networking.md.
