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,195 @@
# OpenSpec Change: network-plugin-relay
- **Change ID**: network-plugin-relay
- **Package**: `@suaveplan/network-plugin-relay` (new)
- **Status**: PROPOSED
- **Date**: 2026-05-01
---
## Summary
Implement cross-mesh message relay — the "federation layer" that enables Tier 0 hosts of different meshes to route messages to one another. Without this plugin, the network suite only supports intra-mesh communication; peers in Mesh A cannot send messages to peers in Mesh B. This is a P0 gap blocking the user's stated requirement: *"message relaying through the hosts through the nominated tier host to be able to transmit in any pocket mesh on any tier to any other pocket mesh on any tier."*
---
## Why
**User requirement**: *"message relaying through the hosts through the nominated tier host to be able to transmit in any pocket mesh on any tier to any other pocket mesh on any tier"*
**Current state**: ALL existing network proposals handle **intra-mesh** communication only (full mesh within one group). No package addresses **inter-mesh** routing.
**What's missing**:
- Host-to-host backbone network between Tier 0 hosts of different meshes
- Message forwarding/relay logic at the host level
- Cross-mesh addressing scheme (`meshId + peerId` vs just `peerId`)
- Route discovery between meshes
- Concept of a "super-peer" or "federation backbone"
---
## Core components
### 1. `RelayRouter`
Maintains a routing table: `(destinationMeshId, destinationPeerId) → nextHopHostId`. Runs on every Tier 0 host. Updates dynamically from `MeshDirectory` sync events.
```ts
class RelayRouter {
addRoute(destMeshId: string, destPeerId: string, nextHopHostId: string): void;
removeRoute(destMeshId: string, destPeerId: string): void;
resolve(targetMeshId: string, targetPeerId: string): string | null; // returns nextHopHostId
getRoutesForMesh(meshId: string): Map<string, string>;
}
```
### 2. `HostBackboneTransport`
Dedicated transport for Tier 0 ↔ Tier 0 communication. Reuses `WebSocket` or `RTCDataChannel` but is logically separate from peer mesh transport. Negotiates capabilities (max message size, supported compression, crypto suites).
```ts
interface HostBackboneTransport {
connect(hostId: string, address: string): Promise<void>;
disconnect(hostId: string): void;
send(hostId: string, envelope: CrossMeshEnvelope): void;
onMessage(handler: (envelope: CrossMeshEnvelope, fromHostId: string) => void): void;
getConnectedHosts(): string[];
}
```
### 3. `CrossMeshEnvelope`
Extends `MessageEnvelope` with cross-mesh routing metadata:
```ts
interface CrossMeshEnvelope {
// Inherited from MessageEnvelope
id: string;
type: string;
senderId: string;
senderMeshId: string;
targetId: string;
targetMeshId: string;
payload: Uint8Array;
timestamp: number;
headers: Record<string, string>;
// Relay-specific
hopCount: number; // incremented per hop
maxHops: number; // default 16
visitedNodes: string[]; // peerIds / hostIds visited
ttl: number; // ms remaining
}
```
Zod-validated. Dropped when `hopCount >= maxHops`, `ttl <= 0`, or `visitedNodes` contains current node.
### 4. `RelayManager`
Plugin entry point. Intercepts outbound messages where `targetMeshId !== localMeshId` and forwards them via `RelayRouter` → `HostBackboneTransport`. On inbound cross-mesh messages, delivers to local `NetworkBus` scoped to the target peer.
```ts
class RelayManager {
constructor(options: {
router: RelayRouter;
backbone: HostBackboneTransport;
localMeshId: string;
localHostId: string;
maxHops: number;
defaultTtlMs: number;
});
start(): void;
stop(): void;
onOutbound(envelope: MessageEnvelope): CrossMeshEnvelope | null; // null = not relayed
onInbound(envelope: CrossMeshEnvelope): void;
}
```
### 5. `MeshDirectory`
Discovery/registration of known meshes and their Tier 0 hosts. Can be seed-based (static config), server-assisted (via `network-plugin-server-bridge`), or gossip-based (Tier 0 hosts exchange mesh advertisements).
```ts
class MeshDirectory {
registerMesh(meshId: string, tier0HostIds: string[], hostAddresses: Map<string, string>): void;
unregisterMesh(meshId: string): void;
getTier0Hosts(meshId: string): string[];
getHostAddress(hostId: string): string | undefined;
listKnownMeshes(): string[];
on(event: "mesh:added" | "mesh:removed" | "mesh:updated", handler: Function): void;
}
```
---
## Routing rules
1. **Same mesh** — `RelayManager` returns `null`; message stays local.
2. **Different mesh, direct backbone exists** — forward to connected Tier 0 host that advertises the target mesh.
3. **Different mesh, multi-hop required** — `RelayRouter` selects next hop from its table; `hopCount` increments; `visitedNodes` appends current node.
4. **Broadcast across meshes** — `targetMeshId = "*"`, `targetId = "*"`. Relayed to ALL known meshes. Deduplicated at each mesh boundary via `messageId` Bloom filter.
5. **Loop prevention** — Hard drop if `hopCount >= maxHops` or `visitedNodes` contains current node.
---
## Error codes
```ts
const RELAY_CODES = defineCodes("RELAY", [
"ROUTE_NOT_FOUND",
"BACKBONE_CONNECT_FAILED",
"BACKBONE_DISCONNECTED",
"MAX_HOPS_EXCEEDED",
"TTL_EXPIRED",
"LOOP_DETECTED",
"INVALID_ENVELOPE",
"MESH_NOT_REGISTERED",
"HOST_NOT_FOUND",
"RELAY_REJECTED",
] as const);
```
`RelayError extends SuaveplanError<RelayErrorCode>`.
---
## Dependencies
- **Consumes**: `@suaveplan/network` (`NetworkNode`, `NetworkBus`, `MessageEnvelope`, `NetworkPlugin`), `@suaveplan/network-plugin-topology` (tier info for backbone eligibility), `@suaveplan/network-plugin-registry` (peer lists for `MeshDirectory`), `@suaveplan/network-plugin-crypto-messages` (signature verification on cross-mesh envelopes), `@suaveplan/error`, `@suaveplan/events`, `@suaveplan/types`, `zod`, `@opentelemetry/api`.
- **Blocked on**: `network-core` (shipped), `network-plugin-topology`, `network-plugin-registry`.
---
## Verification approach
- `src/router/router.spec-conformance.test.ts` — pins routing table add/remove/resolve, multi-hop resolution.
- `src/backbone/backbone.spec-conformance.test.ts` — pins HostBackboneTransport connect/send/onMessage.
- `src/envelope/envelope.spec-conformance.test.ts` — pins Zod validation, hopCount/ttl/visitedNodes rules.
- `src/manager/manager.spec-conformance.test.ts` — pins outbound intercept, inbound delivery, same-mesh bypass.
- `src/directory/directory.spec-conformance.test.ts` — pins mesh registration, host lookup, event emission.
- `src/loop-prevention/loop-prevention.spec-conformance.test.ts` — pins maxHops drop, ttl drop, visitedNodes drop.
- `tests/integration/relay.spec-conformance.test.ts` — end-to-end: Mesh A peer → Mesh B peer via Tier 0 backbone.
- 100/100/100/100 Istanbul coverage.
---
## Conformance requirements (proposed)
- `NET-61` — `RelayRouter` maintains a routing table from `(destMeshId, destPeerId)` to `nextHopHostId`.
- `NET-62` — `HostBackboneTransport` connects Tier 0 hosts with capability negotiation.
- `NET-63` — `CrossMeshEnvelope` extends `MessageEnvelope` with `senderMeshId`, `targetMeshId`, `hopCount`, `maxHops`, `visitedNodes`, and `ttl`.
- `NET-64` — Cross-mesh messages are dropped when `hopCount >= maxHops`.
- `NET-65` — Cross-mesh messages are dropped when `ttl <= 0`.
- `NET-66` — Cross-mesh messages are dropped when `visitedNodes` contains the current node.
- `NET-67` — `MeshDirectory` registers known meshes and their Tier 0 hosts.
- `NET-68` — Broadcast across meshes (`targetMeshId = "*"`) is relayed to all known meshes and deduplicated at mesh boundaries.
- `NET-69` — `RelayManager` intercepts outbound messages where `targetMeshId !== localMeshId` and forwards them.
- `NET-70` — Inbound cross-mesh envelopes are delivered to the local `NetworkBus` scoped to the target peer.
---
## Out of scope
- Cross-mesh **state synchronization** → `network-plugin-state` handles state sync within a mesh; cross-mesh state is application-level.
- Global DHT for mesh discovery → future hardening; seed-based and server-assisted discovery are sufficient for v1.
- Cross-mesh **host election** → each mesh governs itself; no global host.

View File

@@ -0,0 +1,21 @@
# Tasks: network-plugin-relay
- [x] 1. Write `openspec/changes/network-plugin-relay/proposal.md`
- [x] 2. Write `openspec/changes/network-plugin-relay/tasks.md`
- [x] 3. Scaffold `packages/network/network-plugin-relay/package.json`, `tsconfig.json`, `vitest.config.ts`
- [x] 4. Implement `src/error-codes.ts` with `RELAY_CODES`
- [x] 5. Implement `src/router/relay-router.ts` — routing table, add/remove/resolve
- [x] 6. Implement `src/backbone/host-backbone-transport.ts` — Tier 0 transport abstraction
- [x] 7. Implement `src/envelope/cross-mesh-envelope.ts` — Zod schema, validation rules
- [x] 8. Implement `src/directory/mesh-directory.ts` — mesh registration, host lookup
- [x] 9. Implement `src/manager/relay-manager.ts` — plugin entry point, outbound intercept, inbound delivery
- [x] 10. Implement `src/loop-prevention/loop-guard.ts` — hopCount, ttl, visitedNodes checks
- [x] 11. Write `src/router/router.spec-conformance.test.ts`
- [x] 12. Write `src/backbone/backbone.spec-conformance.test.ts`
- [x] 13. Write `src/envelope/envelope.spec-conformance.test.ts`
- [x] 14. Write `src/directory/directory.spec-conformance.test.ts`
- [x] 15. Write `src/manager/manager.spec-conformance.test.ts`
- [x] 16. Write `src/loop-prevention/loop-prevention.spec-conformance.test.ts`
- [x] 17. Write `tests/integration/relay.spec-conformance.test.ts` — end-to-end two-mesh relay
- [x] 18. Write `tests/dep-graph.test.ts`
- [x] 19. Run `bunx turbo lint typecheck test --filter=@suaveplan/network-plugin-relay` and achieve 100/100/100/100 coverage