first commit

This commit is contained in:
2026-05-29 08:20:56 +01:00
commit 949299f58d
6368 changed files with 527176 additions and 0 deletions

View File

@@ -0,0 +1,52 @@
# `ChannelManager`
## Purpose
Owns the lifecycle of every `Channel` registered on a gateway instance. Clients never see a raw `Channel` — every channel call enters the gateway, which delegates here and translates the result into wire frames the daemon dispatches. Keeping the manager separate from the daemon keeps both files under the 300-line cap and lets channel behaviour be unit-tested independently.
## Features
- Lazy channel creation via `getOrCreateChannel(name, allowPatterns?)` — channels are stable across the gateway's lifetime once created.
- `publish` returns the constructed `Message` + the deterministic recipient set; the daemon performs the actual socket fan-out so the manager has no WebSocket dependencies.
- `removeClient(clientId)` is the disconnect hook — sweeps every channel and drops the client's subscriptions in one pass.
- `clear()` for the daemon's shutdown path.
## Usage: Basic Example
```ts
import { ChannelManager } from "@suaveplan/websocket-gateway";
const mgr = new ChannelManager();
mgr.subscribe("events", "alice", "user.*");
const result = mgr.publish("events", "bob", "user.created", { id: "u1" }, Date.now());
```
## Usage: Advanced Example
```ts
import { ChannelManager } from "@suaveplan/websocket-gateway";
const mgr = new ChannelManager();
// Pattern channel
mgr.subscribe("events", "alice", "user.**");
// Exact-only channel
const exact = mgr.getOrCreateChannel("metrics", false);
mgr.publish("events", "bob", "user.signup", null, 1);
// On disconnect
mgr.removeClient("alice");
```
## API Reference
- `getOrCreateChannel(name, allowPatterns = true): Channel`
- `getChannel(name): Channel | undefined`
- `subscribe(channelName, clientId, topic): { subscribed }`
- `unsubscribe(channelName, clientId, topic): { unsubscribed }`
- `publish(channelName, senderId, topic, payload, now): { message, recipients } | null`
- `removeClient(clientId): void`
- `clear(): void`
- `size: number` getter
## Implementation Notes
The manager never constructs channels behind `publish` — only `subscribe` and `getOrCreateChannel` create them. This matches upstream behaviour: publishes to a channel nobody subscribed to are no-ops so observers do not pay for unregistered topics. `removeClient` iterates every channel because the per-client subscription map lives inside each channel — flattening that out into a global per-client index is the future job of a sharded backend; today the linear sweep is fine at the documented N×subscribers ceiling.