Initial Commit

This commit is contained in:
2026-05-27 23:29:53 +01:00
commit fbc70f96e6
10000 changed files with 1102152 additions and 0 deletions

View File

@@ -0,0 +1,104 @@
# OpenSpec Change: network-transport-websockets-adapter
- **Change ID**: network-transport-websockets-adapter
- **Package**: `@suaveplan/network-transport-websockets` (already exists at `0.1.0`)
- **Category**: universal
- **Target path**: `packages/network/network-transport-websockets` (in place)
- **Status**: PROPOSED
- **Date**: 2026-05-11
- **Parent**: `network-transport-family` (2026-05-11) — Wave 1, audit finding 2.3
---
## Summary
Refactor `@suaveplan/network-transport-websockets` from its current client-server `WebSocketClient` shape into a peer-oriented `Transport` implementation registered as a `NetworkPlugin`. The package was migrated to genesis before the `Transport` contract from `@suaveplan/network` ✅ existed; today it exposes a connect-to-a-server abstraction (typed framing, heartbeat, backpressure queue, adapters) but does NOT implement `connect(peerId)` / `disconnect(peerId)` / `send(peerId, envelope)` / `onMessage` / `getConnectedPeers` / `close`. This change adds a `WebSocketTransport` + `WebSocketPlugin` layer on top of the existing client surface so the package can plug into `network-plugin-transport-manager` ✅ alongside `network-transport-webrtc` ✅.
---
## Why this is needed
Per the audit finding recorded in `openspec/changes/network-transport-family/tasks.md` §2.3:
> `network-transport-websockets` predates the `Transport` contract and exposes a client-server `WebSocketClient` rather than a peer transport. Wiring it as a `NetworkPlugin` requires a non-trivial refactor (per-peer connections, `getConnectedPeers()` aggregation, `transport:connected`/`disconnected` bus emission). Deferred to a dedicated child proposal.
This is that proposal. Three downstream consumers are blocked until it lands:
1. **`network-plugin-transport-manager` ✅** — cannot register WS as a fallback transport without the adapter.
2. **`network-transport-webrtc` ✅** — needs WS as a fallback in its signaling channel.
3. **`websocket-gateway`** (Wave 5) — server-side rooms + presence depends on the transport contract being honoured.
---
## What changes
### New code
- `src/transport/transport.ts` — `WebSocketTransport implements Transport` (from `@suaveplan/network`)
- `connect(peerId, address)` → creates a new `WebSocketClient` keyed by `peerId`
- `disconnect(peerId)` → closes the per-peer client
- `send(peerId, envelope)` → delegates to the per-peer client's framed send
- `onMessage(handler)` → fan-in across every per-peer client
- `getConnectedPeers()` → snapshot of keys
- `close()` → closes every per-peer client
- `src/plugin/plugin.ts` — `WebSocketPlugin implements NetworkPlugin` mirroring `WebRTCPlugin` shape:
- `install(node)` → `node.registerTransport(this.transport)`
- `start()` → no-op (lazy connect)
- `stop()` → close transport + unregister
- `dispose()` → idempotent cleanup
- `src/transport/transport.spec-conformance.test.ts` — runs the `Transport` contract conformance suite
- `src/plugin/plugin.spec-conformance.test.ts` — runs the `NetworkPlugin` lifecycle conformance suite
- Sibling `.md` docs for both modules
### Existing code
- `src/core/client/` — keep. The new `WebSocketTransport` composes per-peer `WebSocketClient` instances.
- `src/core/queue/` + `src/core/heartbeat/` — keep, consumed per-peer.
- `src/adapters/` — keep, injectable through the new transport.
- `src/types/` — extend with `WebSocketTransportConfig` (per-peer client config + transport-level limits).
### Error codes
- Extend the existing `defineCodes("NET_WS", [...])` registry with: `PEER_ALREADY_CONNECTED`, `PEER_UNKNOWN`, `TRANSPORT_CLOSED`, `MAX_PEERS_EXCEEDED`.
### Observability
- Spans: `ws_transport.connect`, `ws_transport.disconnect`, `ws_transport.send`.
- Counters: `ws_transport.peers_connected{outcome}`, `ws_transport.messages_total{direction,outcome}`.
- Gauges: `ws_transport.active_peers`.
---
## Parity Checklist
Migration from upstream is already complete; this is a refactor adding the `Transport` adapter. The original `WebSocketClient` API is preserved.
| Capability | Before | After | Notes |
|---|---|---|---|
| `WebSocketClient` typed framing | ✅ | ✅ | Unchanged. |
| Heartbeat / ping-pong | ✅ | ✅ | Unchanged; runs per-peer. |
| Backpressure queue | ✅ | ✅ | Unchanged; runs per-peer. |
| Injectable transport adapters | ✅ | ✅ | Unchanged. |
| `Transport` contract | 🚫 | ⬆️ | NEW — `WebSocketTransport`. |
| `NetworkPlugin` lifecycle | 🚫 | ⬆️ | NEW — `WebSocketPlugin`. |
| Multi-peer fan-in/fan-out | 🚫 | ⬆️ | NEW — per-peer client registry. |
| `transport:connected`/`disconnected` bus events | 🚫 | ⬆️ | NEW — on bus when a `NetworkBus` is provided via plugin. |
| Backward compatibility | ✅ | ✅ | Existing `WebSocketClient` consumers (none in genesis, but downstream `@suaveplan/network-transport-webrtc` signaling client uses the type) keep working — the new transport composes them. |
---
## Acceptance gate
1. `bunx turbo lint typecheck test --filter=@suaveplan/network-transport-websockets` green.
2. `bunx turbo test:coverage --filter=@suaveplan/network-transport-websockets` at 100/100/100/100 (currently 60 tests pass after the rename; adding the transport+plugin adds another conformance suite).
3. `bun run docs:check --filter=@suaveplan/network-transport-websockets` green.
4. `network-plugin-transport-manager` integration test confirms WS-as-fallback works end-to-end.
5. `openspec/specs/network/spec.md` updated under `## MODIFIED Requirements` if any NET-* requirement is tightened.
---
## Out of scope
- Server-side `websocket-gateway` (Wave 5, separate package).
- TLS / mTLS cert management for production WSS — that's a deployment concern, not a transport concern.
- Custom subprotocols beyond what the existing `WebSocketClient` supports.

View File

@@ -0,0 +1,57 @@
# Tasks — network-transport-websockets-adapter
## Phase 1: Transport implementation
- [ ] 1.1 Author `src/transport/transport.ts` — `WebSocketTransport implements Transport` with per-peer `WebSocketClient` registry.
- [ ] 1.2 Wire `connect`/`disconnect`/`send`/`onMessage`/`getConnectedPeers`/`close`.
- [ ] 1.3 Author sibling `src/transport/transport.md`.
- [ ] 1.4 Author `src/transport/transport.spec-conformance.test.ts` running the `Transport` contract suite from `@suaveplan/network`.
## Phase 2: Plugin wrapper
- [ ] 2.1 Author `src/plugin/plugin.ts` — `WebSocketPlugin implements NetworkPlugin` mirroring `WebRTCPlugin`.
- [ ] 2.2 Author sibling `src/plugin/plugin.md`.
- [ ] 2.3 Author `src/plugin/plugin.spec-conformance.test.ts` for lifecycle idempotency.
## Phase 3: Type + error extensions
- [ ] 3.1 Add `WebSocketTransportConfig` to `src/types/types.ts`.
- [ ] 3.2 Extend `defineCodes("NET_WS", [...])` with `PEER_ALREADY_CONNECTED`, `PEER_UNKNOWN`, `TRANSPORT_CLOSED`, `MAX_PEERS_EXCEEDED`.
## Phase 4: Observability
- [ ] 4.1 Spans: `ws_transport.connect`, `ws_transport.disconnect`, `ws_transport.send`.
- [ ] 4.2 Counters: `ws_transport.peers_connected{outcome}`, `ws_transport.messages_total{direction,outcome}`.
- [ ] 4.3 Gauges: `ws_transport.active_peers`.
## Phase 5: Bus events (optional, when plugin holds a bus reference)
- [ ] 5.1 Emit `transport:connected` / `transport:disconnected` on `NetworkBus`.
- [ ] 5.2 Emit `peer:latency` with EMA-smoothed RTT (re-use the heartbeat path).
## Phase 6: Tests
- [ ] 6.1 Per-peer registry property test (fast-check).
- [ ] 6.2 Multi-peer fan-out test.
- [ ] 6.3 Lifecycle idempotency test (install → install, stop → stop).
- [ ] 6.4 100/100/100/100 coverage gate.
## Phase 7: Integration
- [ ] 7.1 Cross-package integration test with `network-plugin-transport-manager` ✅: register WS as fallback, simulate WebRTC failure, verify WS takes over.
- [ ] 7.2 Update `openspec/specs/network/spec.md` if NET-04 conformance language tightens.
## Phase 8: Verification
- [ ] 8.1 `bunx turbo lint typecheck test --filter=@suaveplan/network-transport-websockets` green.
- [ ] 8.2 `bunx turbo test:coverage --filter=@suaveplan/network-transport-websockets` 100/100/100/100.
- [ ] 8.3 `bun run docs:check --filter=@suaveplan/network-transport-websockets` green.
- [ ] 8.4 `MANIFEST.md` shows new dep on `@suaveplan/network` (for the `Transport` + `NetworkPlugin` types).
## Pre-archive checklist
- [ ] Row 1 — Phase 8 green.
- [ ] Row 2 — Transport conformance test passes against the canonical suite.
- [ ] Row 3 — Integration test with `network-plugin-transport-manager` passes.
- [ ] Row 4 — `STATUS.md` row updated to drop the "(pending Plugin adapter)" suffix.
- [ ] Row 5 — Folder archived.