agent-teams-dashboard 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,62 @@
1
+ import { WebSocketServer, WebSocket } from 'ws';
2
+ import * as cache from './teamsCache.js';
3
+ const HEARTBEAT_INTERVAL = 30_000;
4
+ const PONG_TIMEOUT = 10_000;
5
+ let wss = null;
6
+ function broadcast(event) {
7
+ if (!wss)
8
+ return;
9
+ const data = JSON.stringify(event);
10
+ for (const client of wss.clients) {
11
+ if (client.readyState === WebSocket.OPEN) {
12
+ client.send(data);
13
+ }
14
+ }
15
+ }
16
+ export function initWebSocket(server) {
17
+ wss = new WebSocketServer({ server, path: '/ws' });
18
+ console.log('[ws] WebSocket server attached on /ws');
19
+ wss.on('connection', (ws) => {
20
+ ws.isAlive = true;
21
+ const clientCount = wss.clients.size;
22
+ console.log(`[ws] Client connected (total: ${clientCount})`);
23
+ // Send initial snapshot
24
+ const snapshot = cache.getSnapshot();
25
+ ws.send(JSON.stringify({ type: 'snapshot', data: snapshot }));
26
+ ws.on('pong', () => {
27
+ ws.isAlive = true;
28
+ });
29
+ ws.on('close', () => {
30
+ const remaining = wss.clients.size;
31
+ console.log(`[ws] Client disconnected (total: ${remaining})`);
32
+ });
33
+ });
34
+ // Heartbeat interval
35
+ const heartbeat = setInterval(() => {
36
+ if (!wss)
37
+ return;
38
+ for (const client of wss.clients) {
39
+ const ws = client;
40
+ if (!ws.isAlive) {
41
+ ws.terminate();
42
+ continue;
43
+ }
44
+ ws.isAlive = false;
45
+ ws.ping();
46
+ // Terminate if no pong within timeout
47
+ const pongTimer = setTimeout(() => {
48
+ if (!ws.isAlive)
49
+ ws.terminate();
50
+ }, PONG_TIMEOUT);
51
+ ws.once('pong', () => clearTimeout(pongTimer));
52
+ }
53
+ }, HEARTBEAT_INTERVAL);
54
+ wss.on('close', () => {
55
+ clearInterval(heartbeat);
56
+ });
57
+ // Listen for cache changes and broadcast full snapshot
58
+ cache.onChange.on('change', () => {
59
+ const snap = cache.getSnapshot();
60
+ broadcast({ type: 'snapshot', data: snap });
61
+ });
62
+ }
@@ -0,0 +1 @@
1
+ export {};