driftdetect-dashboard 0.8.1 → 0.8.3

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,189 @@
1
+ /**
2
+ * WebSocket Server
3
+ *
4
+ * Manages WebSocket connections for realtime violation streaming.
5
+ *
6
+ * @requirements 2.1 - Expose a WebSocket endpoint at `/ws` for realtime communication
7
+ * @requirements 2.3 - Broadcast violations to all connected WebSocket clients
8
+ */
9
+ import { WebSocketServer, WebSocket } from 'ws';
10
+ // ============================================================================
11
+ // WebSocket Manager
12
+ // ============================================================================
13
+ export class WebSocketManager {
14
+ wss = null;
15
+ clients = new Set();
16
+ pingInterval = null;
17
+ /**
18
+ * Get the number of connected clients
19
+ */
20
+ get clientCount() {
21
+ return this.clients.size;
22
+ }
23
+ /**
24
+ * Attach WebSocket server to an HTTP server
25
+ * @requirements 2.1 - WebSocket endpoint at /ws
26
+ */
27
+ attach(server) {
28
+ this.wss = new WebSocketServer({
29
+ server,
30
+ path: '/ws',
31
+ });
32
+ this.wss.on('connection', (ws) => {
33
+ this.handleConnection(ws);
34
+ });
35
+ // Start ping interval for connection health
36
+ this.startPingInterval();
37
+ }
38
+ /**
39
+ * Close the WebSocket server and all connections
40
+ */
41
+ close() {
42
+ // Stop ping interval
43
+ if (this.pingInterval) {
44
+ clearInterval(this.pingInterval);
45
+ this.pingInterval = null;
46
+ }
47
+ // Close all client connections
48
+ for (const client of this.clients) {
49
+ client.close(1000, 'Server shutting down');
50
+ }
51
+ this.clients.clear();
52
+ // Close the WebSocket server
53
+ if (this.wss) {
54
+ this.wss.close();
55
+ this.wss = null;
56
+ }
57
+ }
58
+ /**
59
+ * Broadcast a violation to all connected clients
60
+ * @requirements 2.3 - Broadcast violations to all connected clients
61
+ */
62
+ broadcastViolation(violation) {
63
+ this.broadcast({
64
+ type: 'violation',
65
+ payload: violation,
66
+ timestamp: new Date().toISOString(),
67
+ });
68
+ }
69
+ /**
70
+ * Broadcast a pattern update to all connected clients
71
+ */
72
+ broadcastPatternUpdate(update) {
73
+ this.broadcast({
74
+ type: 'pattern_updated',
75
+ payload: update,
76
+ timestamp: new Date().toISOString(),
77
+ });
78
+ }
79
+ /**
80
+ * Broadcast stats update to all connected clients
81
+ */
82
+ broadcastStatsUpdate(stats) {
83
+ this.broadcast({
84
+ type: 'stats_updated',
85
+ payload: stats,
86
+ timestamp: new Date().toISOString(),
87
+ });
88
+ }
89
+ /**
90
+ * Broadcast patterns changed event to all connected clients
91
+ * Triggers client-side data refresh
92
+ */
93
+ broadcastPatternsChanged(payload) {
94
+ this.broadcast({
95
+ type: 'patterns_changed',
96
+ payload,
97
+ timestamp: new Date().toISOString(),
98
+ });
99
+ }
100
+ // ==========================================================================
101
+ // Private Methods
102
+ // ==========================================================================
103
+ /**
104
+ * Handle a new WebSocket connection
105
+ */
106
+ handleConnection(ws) {
107
+ // Add to clients set
108
+ this.clients.add(ws);
109
+ // Send connected message
110
+ this.send(ws, {
111
+ type: 'connected',
112
+ payload: { clientCount: this.clients.size },
113
+ timestamp: new Date().toISOString(),
114
+ });
115
+ // Handle messages from client
116
+ ws.on('message', (data) => {
117
+ this.handleMessage(ws, data);
118
+ });
119
+ // Handle client disconnect
120
+ ws.on('close', () => {
121
+ this.clients.delete(ws);
122
+ });
123
+ // Handle errors
124
+ ws.on('error', (error) => {
125
+ console.error('WebSocket error:', error);
126
+ this.clients.delete(ws);
127
+ });
128
+ }
129
+ /**
130
+ * Handle incoming message from a client
131
+ */
132
+ handleMessage(ws, data) {
133
+ try {
134
+ const message = JSON.parse(data.toString());
135
+ // Handle ping/pong for connection health
136
+ if (message.type === 'ping') {
137
+ this.send(ws, {
138
+ type: 'pong',
139
+ timestamp: new Date().toISOString(),
140
+ });
141
+ }
142
+ }
143
+ catch (error) {
144
+ // Ignore invalid messages
145
+ console.error('Invalid WebSocket message:', error);
146
+ }
147
+ }
148
+ /**
149
+ * Send a message to a specific client
150
+ */
151
+ send(ws, message) {
152
+ if (ws.readyState === WebSocket.OPEN) {
153
+ ws.send(JSON.stringify(message));
154
+ }
155
+ }
156
+ /**
157
+ * Broadcast a message to all connected clients
158
+ */
159
+ broadcast(message) {
160
+ const messageStr = JSON.stringify(message);
161
+ for (const client of this.clients) {
162
+ if (client.readyState === WebSocket.OPEN) {
163
+ client.send(messageStr);
164
+ }
165
+ }
166
+ }
167
+ /**
168
+ * Start ping interval for connection health monitoring
169
+ */
170
+ startPingInterval() {
171
+ // Ping every 30 seconds
172
+ this.pingInterval = setInterval(() => {
173
+ const pingMessage = {
174
+ type: 'ping',
175
+ timestamp: new Date().toISOString(),
176
+ };
177
+ for (const client of this.clients) {
178
+ if (client.readyState === WebSocket.OPEN) {
179
+ client.send(JSON.stringify(pingMessage));
180
+ }
181
+ else {
182
+ // Remove dead connections
183
+ this.clients.delete(client);
184
+ }
185
+ }
186
+ }, 30000);
187
+ }
188
+ }
189
+ //# sourceMappingURL=websocket-server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"websocket-server.js","sourceRoot":"","sources":["../../src/server/websocket-server.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "driftdetect-dashboard",
3
- "version": "0.8.1",
3
+ "version": "0.8.3",
4
4
  "description": "Local web dashboard for Drift architectural drift detection",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {
@@ -34,25 +34,9 @@
34
34
  "files": [
35
35
  "dist"
36
36
  ],
37
- "scripts": {
38
- "build": "pnpm run build:server && pnpm run build:client",
39
- "build:server": "tsc -p tsconfig.server.json",
40
- "build:client": "vite build",
41
- "clean": "rm -rf dist",
42
- "dev": "pnpm run build:server && concurrently -n server,client -c blue,green \"pnpm run dev:backend\" \"pnpm run dev:client\"",
43
- "dev:backend": "node --import tsx scripts/dev-server.ts",
44
- "dev:server": "tsc -p tsconfig.server.json --watch",
45
- "dev:client": "vite",
46
- "lint": "eslint src --ext .ts,.tsx",
47
- "lint:fix": "eslint src --ext .ts,.tsx --fix",
48
- "test": "vitest run",
49
- "test:watch": "vitest",
50
- "test:coverage": "vitest run --coverage",
51
- "typecheck": "tsc --noEmit -p tsconfig.server.json && tsc --noEmit -p tsconfig.client.json"
52
- },
53
37
  "dependencies": {
54
- "driftdetect-core": "^0.8.1",
55
- "driftdetect-galaxy": "^0.8.1",
38
+ "driftdetect-core": "^0.8.2",
39
+ "driftdetect-galaxy": "^0.8.2",
56
40
  "express": "^4.18.2",
57
41
  "open": "^10.0.0",
58
42
  "ws": "^8.16.0"
@@ -91,5 +75,21 @@
91
75
  "peerDependencies": {
92
76
  "react": "^18.2.0",
93
77
  "react-dom": "^18.2.0"
78
+ },
79
+ "scripts": {
80
+ "build": "pnpm run build:server && pnpm run build:client",
81
+ "build:server": "tsc -p tsconfig.server.json",
82
+ "build:client": "vite build",
83
+ "clean": "rm -rf dist",
84
+ "dev": "pnpm run build:server && concurrently -n server,client -c blue,green \"pnpm run dev:backend\" \"pnpm run dev:client\"",
85
+ "dev:backend": "node --import tsx scripts/dev-server.ts",
86
+ "dev:server": "tsc -p tsconfig.server.json --watch",
87
+ "dev:client": "vite",
88
+ "lint": "eslint src --ext .ts,.tsx",
89
+ "lint:fix": "eslint src --ext .ts,.tsx --fix",
90
+ "test": "vitest run",
91
+ "test:watch": "vitest",
92
+ "test:coverage": "vitest run --coverage",
93
+ "typecheck": "tsc --noEmit -p tsconfig.server.json && tsc --noEmit -p tsconfig.client.json"
94
94
  }
95
- }
95
+ }