driftdetect-dashboard 0.7.0 → 0.8.1
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.
- package/dist/client/assets/{GalaxyTab-Bc9PKsMk.js → GalaxyTab-BsAmWarF.js} +4 -4
- package/dist/client/assets/{GalaxyTab-Bc9PKsMk.js.map → GalaxyTab-BsAmWarF.js.map} +1 -1
- package/dist/client/assets/main-CVl-4C5E.css +2 -0
- package/dist/client/assets/main-QuEZvA3i.js +59 -0
- package/dist/client/assets/main-QuEZvA3i.js.map +1 -0
- package/dist/client/assets/{sfxr-CO3_Kukg.js → sfxr-Cr89uVKo.js} +2 -2
- package/dist/client/assets/{sfxr-CO3_Kukg.js.map → sfxr-Cr89uVKo.js.map} +1 -1
- package/dist/client/index.html +2 -2
- package/dist/server/api-routes.d.ts.map +1 -1
- package/dist/server/quality-gates-api.d.ts.map +1 -0
- package/package.json +21 -21
- package/LICENSE +0 -21
- package/dist/client/assets/main-BdVQNGtK.js +0 -59
- package/dist/client/assets/main-BdVQNGtK.js.map +0 -1
- package/dist/client/assets/main-NejYwKFb.css +0 -2
- package/dist/server/api-routes.d.ts +0 -50
- package/dist/server/api-routes.js +0 -634
- package/dist/server/api-routes.js.map +0 -1
- package/dist/server/dashboard-server.d.ts +0 -64
- package/dist/server/dashboard-server.js +0 -154
- package/dist/server/dashboard-server.js.map +0 -1
- package/dist/server/drift-data-reader.d.ts +0 -522
- package/dist/server/drift-data-reader.js +0 -1550
- package/dist/server/drift-data-reader.js.map +0 -1
- package/dist/server/express-app.d.ts +0 -24
- package/dist/server/express-app.js +0 -74
- package/dist/server/express-app.js.map +0 -1
- package/dist/server/galaxy-data-transformer.d.ts +0 -178
- package/dist/server/galaxy-data-transformer.js +0 -562
- package/dist/server/galaxy-data-transformer.js.map +0 -1
- package/dist/server/index.d.ts +0 -20
- package/dist/server/index.js +0 -14
- package/dist/server/index.js.map +0 -1
- package/dist/server/pattern-watcher.d.ts +0 -55
- package/dist/server/pattern-watcher.d.ts.map +0 -1
- package/dist/server/pattern-watcher.js +0 -157
- package/dist/server/pattern-watcher.js.map +0 -1
- package/dist/server/websocket-server.d.ts +0 -83
- package/dist/server/websocket-server.js +0 -189
- package/dist/server/websocket-server.js.map +0 -1
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Pattern Watcher
|
|
3
|
-
*
|
|
4
|
-
* Watches the .drift/patterns/ directory for changes and emits events
|
|
5
|
-
* when patterns are added, updated, or removed.
|
|
6
|
-
*
|
|
7
|
-
* @requirements Phase 5 - Dashboard auto-refresh when watch mode updates patterns
|
|
8
|
-
*/
|
|
9
|
-
import { EventEmitter } from 'node:events';
|
|
10
|
-
export interface PatternChangeEvent {
|
|
11
|
-
type: 'created' | 'updated' | 'deleted';
|
|
12
|
-
category: string;
|
|
13
|
-
status: string;
|
|
14
|
-
timestamp: string;
|
|
15
|
-
}
|
|
16
|
-
export interface PatternWatcherOptions {
|
|
17
|
-
/** Path to the .drift directory */
|
|
18
|
-
driftDir: string;
|
|
19
|
-
/** Debounce delay in milliseconds (default: 500) */
|
|
20
|
-
debounceMs?: number;
|
|
21
|
-
}
|
|
22
|
-
export declare class PatternWatcher extends EventEmitter {
|
|
23
|
-
private readonly driftDir;
|
|
24
|
-
private readonly patternsDir;
|
|
25
|
-
private readonly debounceMs;
|
|
26
|
-
private watchers;
|
|
27
|
-
private debounceTimers;
|
|
28
|
-
private isWatching;
|
|
29
|
-
constructor(options: PatternWatcherOptions);
|
|
30
|
-
/**
|
|
31
|
-
* Start watching for pattern changes
|
|
32
|
-
*/
|
|
33
|
-
start(): void;
|
|
34
|
-
/**
|
|
35
|
-
* Stop watching for pattern changes
|
|
36
|
-
*/
|
|
37
|
-
stop(): void;
|
|
38
|
-
/**
|
|
39
|
-
* Check if currently watching
|
|
40
|
-
*/
|
|
41
|
-
get watching(): boolean;
|
|
42
|
-
/**
|
|
43
|
-
* Watch a directory for changes
|
|
44
|
-
*/
|
|
45
|
-
private watchDirectory;
|
|
46
|
-
/**
|
|
47
|
-
* Debounce file change events
|
|
48
|
-
*/
|
|
49
|
-
private debounceChange;
|
|
50
|
-
/**
|
|
51
|
-
* Handle a file change event
|
|
52
|
-
*/
|
|
53
|
-
private handleFileChange;
|
|
54
|
-
}
|
|
55
|
-
//# sourceMappingURL=pattern-watcher.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"pattern-watcher.d.ts","sourceRoot":"","sources":["../../src/server/pattern-watcher.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAIH,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAM3C,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,SAAS,GAAG,SAAS,GAAG,SAAS,CAAC;IACxC,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,qBAAqB;IACpC,mCAAmC;IACnC,QAAQ,EAAE,MAAM,CAAC;IACjB,oDAAoD;IACpD,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAMD,qBAAa,cAAe,SAAQ,YAAY;IAC9C,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;IAClC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAS;IACrC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;IACpC,OAAO,CAAC,QAAQ,CAAsB;IACtC,OAAO,CAAC,cAAc,CAA0C;IAChE,OAAO,CAAC,UAAU,CAAkB;gBAExB,OAAO,EAAE,qBAAqB;IAO1C;;OAEG;IACH,KAAK,IAAI,IAAI;IAsBb;;OAEG;IACH,IAAI,IAAI,IAAI;IAsBZ;;OAEG;IACH,IAAI,QAAQ,IAAI,OAAO,CAEtB;IAMD;;OAEG;IACH,OAAO,CAAC,cAAc;IAyCtB;;OAEG;IACH,OAAO,CAAC,cAAc;IActB;;OAEG;IACH,OAAO,CAAC,gBAAgB;CA+BzB"}
|
|
@@ -1,157 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Pattern Watcher
|
|
3
|
-
*
|
|
4
|
-
* Watches the .drift/patterns/ directory for changes and emits events
|
|
5
|
-
* when patterns are added, updated, or removed.
|
|
6
|
-
*
|
|
7
|
-
* @requirements Phase 5 - Dashboard auto-refresh when watch mode updates patterns
|
|
8
|
-
*/
|
|
9
|
-
import * as fs from 'node:fs';
|
|
10
|
-
import * as path from 'node:path';
|
|
11
|
-
import { EventEmitter } from 'node:events';
|
|
12
|
-
// ============================================================================
|
|
13
|
-
// Pattern Watcher
|
|
14
|
-
// ============================================================================
|
|
15
|
-
export class PatternWatcher extends EventEmitter {
|
|
16
|
-
driftDir;
|
|
17
|
-
patternsDir;
|
|
18
|
-
debounceMs;
|
|
19
|
-
watchers = [];
|
|
20
|
-
debounceTimers = new Map();
|
|
21
|
-
isWatching = false;
|
|
22
|
-
constructor(options) {
|
|
23
|
-
super();
|
|
24
|
-
this.driftDir = options.driftDir;
|
|
25
|
-
this.patternsDir = path.join(options.driftDir, 'patterns');
|
|
26
|
-
this.debounceMs = options.debounceMs ?? 500;
|
|
27
|
-
}
|
|
28
|
-
/**
|
|
29
|
-
* Start watching for pattern changes
|
|
30
|
-
*/
|
|
31
|
-
start() {
|
|
32
|
-
if (this.isWatching) {
|
|
33
|
-
return;
|
|
34
|
-
}
|
|
35
|
-
this.isWatching = true;
|
|
36
|
-
// Watch the patterns directory and subdirectories
|
|
37
|
-
const statusDirs = ['discovered', 'approved', 'ignored'];
|
|
38
|
-
for (const status of statusDirs) {
|
|
39
|
-
const statusDir = path.join(this.patternsDir, status);
|
|
40
|
-
this.watchDirectory(statusDir, status);
|
|
41
|
-
}
|
|
42
|
-
// Also watch the index directory for file-map changes
|
|
43
|
-
const indexDir = path.join(this.driftDir, 'index');
|
|
44
|
-
this.watchDirectory(indexDir, 'index');
|
|
45
|
-
this.emit('started');
|
|
46
|
-
}
|
|
47
|
-
/**
|
|
48
|
-
* Stop watching for pattern changes
|
|
49
|
-
*/
|
|
50
|
-
stop() {
|
|
51
|
-
if (!this.isWatching) {
|
|
52
|
-
return;
|
|
53
|
-
}
|
|
54
|
-
this.isWatching = false;
|
|
55
|
-
// Close all watchers
|
|
56
|
-
for (const watcher of this.watchers) {
|
|
57
|
-
watcher.close();
|
|
58
|
-
}
|
|
59
|
-
this.watchers = [];
|
|
60
|
-
// Clear all debounce timers
|
|
61
|
-
for (const timer of this.debounceTimers.values()) {
|
|
62
|
-
clearTimeout(timer);
|
|
63
|
-
}
|
|
64
|
-
this.debounceTimers.clear();
|
|
65
|
-
this.emit('stopped');
|
|
66
|
-
}
|
|
67
|
-
/**
|
|
68
|
-
* Check if currently watching
|
|
69
|
-
*/
|
|
70
|
-
get watching() {
|
|
71
|
-
return this.isWatching;
|
|
72
|
-
}
|
|
73
|
-
// ==========================================================================
|
|
74
|
-
// Private Methods
|
|
75
|
-
// ==========================================================================
|
|
76
|
-
/**
|
|
77
|
-
* Watch a directory for changes
|
|
78
|
-
*/
|
|
79
|
-
watchDirectory(dirPath, status) {
|
|
80
|
-
// Ensure directory exists
|
|
81
|
-
if (!fs.existsSync(dirPath)) {
|
|
82
|
-
try {
|
|
83
|
-
fs.mkdirSync(dirPath, { recursive: true });
|
|
84
|
-
}
|
|
85
|
-
catch {
|
|
86
|
-
// Directory might be created later
|
|
87
|
-
return;
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
try {
|
|
91
|
-
const watcher = fs.watch(dirPath, (eventType, filename) => {
|
|
92
|
-
if (!filename || !filename.endsWith('.json')) {
|
|
93
|
-
return;
|
|
94
|
-
}
|
|
95
|
-
// Skip temp files
|
|
96
|
-
if (filename.endsWith('.tmp') || filename.startsWith('.')) {
|
|
97
|
-
return;
|
|
98
|
-
}
|
|
99
|
-
const filePath = path.join(dirPath, filename);
|
|
100
|
-
const category = filename.replace('.json', '');
|
|
101
|
-
// Debounce to avoid multiple events for the same file
|
|
102
|
-
this.debounceChange(filePath, () => {
|
|
103
|
-
this.handleFileChange(filePath, category, status, eventType);
|
|
104
|
-
});
|
|
105
|
-
});
|
|
106
|
-
this.watchers.push(watcher);
|
|
107
|
-
watcher.on('error', (error) => {
|
|
108
|
-
console.error(`Watcher error for ${dirPath}:`, error);
|
|
109
|
-
});
|
|
110
|
-
}
|
|
111
|
-
catch (error) {
|
|
112
|
-
console.error(`Failed to watch ${dirPath}:`, error);
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
/**
|
|
116
|
-
* Debounce file change events
|
|
117
|
-
*/
|
|
118
|
-
debounceChange(key, callback) {
|
|
119
|
-
const existing = this.debounceTimers.get(key);
|
|
120
|
-
if (existing) {
|
|
121
|
-
clearTimeout(existing);
|
|
122
|
-
}
|
|
123
|
-
const timer = setTimeout(() => {
|
|
124
|
-
this.debounceTimers.delete(key);
|
|
125
|
-
callback();
|
|
126
|
-
}, this.debounceMs);
|
|
127
|
-
this.debounceTimers.set(key, timer);
|
|
128
|
-
}
|
|
129
|
-
/**
|
|
130
|
-
* Handle a file change event
|
|
131
|
-
*/
|
|
132
|
-
handleFileChange(filePath, category, status, eventType) {
|
|
133
|
-
// Determine the change type
|
|
134
|
-
let changeType;
|
|
135
|
-
if (!fs.existsSync(filePath)) {
|
|
136
|
-
changeType = 'deleted';
|
|
137
|
-
}
|
|
138
|
-
else if (eventType === 'rename') {
|
|
139
|
-
// 'rename' can mean created or deleted
|
|
140
|
-
changeType = 'created';
|
|
141
|
-
}
|
|
142
|
-
else {
|
|
143
|
-
changeType = 'updated';
|
|
144
|
-
}
|
|
145
|
-
const event = {
|
|
146
|
-
type: changeType,
|
|
147
|
-
category,
|
|
148
|
-
status,
|
|
149
|
-
timestamp: new Date().toISOString(),
|
|
150
|
-
};
|
|
151
|
-
console.log(`[PatternWatcher] Detected ${changeType}: ${status}/${category}.json`);
|
|
152
|
-
this.emit('change', event);
|
|
153
|
-
// Also emit specific events
|
|
154
|
-
this.emit(changeType, event);
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
//# sourceMappingURL=pattern-watcher.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"pattern-watcher.js","sourceRoot":"","sources":["../../src/server/pattern-watcher.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAC9B,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAClC,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAoB3C,+EAA+E;AAC/E,kBAAkB;AAClB,+EAA+E;AAE/E,MAAM,OAAO,cAAe,SAAQ,YAAY;IAC7B,QAAQ,CAAS;IACjB,WAAW,CAAS;IACpB,UAAU,CAAS;IAC5B,QAAQ,GAAmB,EAAE,CAAC;IAC9B,cAAc,GAAgC,IAAI,GAAG,EAAE,CAAC;IACxD,UAAU,GAAY,KAAK,CAAC;IAEpC,YAAY,OAA8B;QACxC,KAAK,EAAE,CAAC;QACR,IAAI,CAAC,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC;QACjC,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAC;QAC3D,IAAI,CAAC,UAAU,GAAG,OAAO,CAAC,UAAU,IAAI,GAAG,CAAC;IAC9C,CAAC;IAED;;OAEG;IACH,KAAK;QACH,IAAI,IAAI,CAAC,UAAU,EAAE,CAAC;YACpB,OAAO;QACT,CAAC;QAED,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC;QAEvB,kDAAkD;QAClD,MAAM,UAAU,GAAG,CAAC,YAAY,EAAE,UAAU,EAAE,SAAS,CAAC,CAAC;QAEzD,KAAK,MAAM,MAAM,IAAI,UAAU,EAAE,CAAC;YAChC,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC;YACtD,IAAI,CAAC,cAAc,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;QACzC,CAAC;QAED,sDAAsD;QACtD,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;QACnD,IAAI,CAAC,cAAc,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;QAEvC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IACvB,CAAC;IAED;;OAEG;IACH,IAAI;QACF,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,CAAC;YACrB,OAAO;QACT,CAAC;QAED,IAAI,CAAC,UAAU,GAAG,KAAK,CAAC;QAExB,qBAAqB;QACrB,KAAK,MAAM,OAAO,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;YACpC,OAAO,CAAC,KAAK,EAAE,CAAC;QAClB,CAAC;QACD,IAAI,CAAC,QAAQ,GAAG,EAAE,CAAC;QAEnB,4BAA4B;QAC5B,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,cAAc,CAAC,MAAM,EAAE,EAAE,CAAC;YACjD,YAAY,CAAC,KAAK,CAAC,CAAC;QACtB,CAAC;QACD,IAAI,CAAC,cAAc,CAAC,KAAK,EAAE,CAAC;QAE5B,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IACvB,CAAC;IAED;;OAEG;IACH,IAAI,QAAQ;QACV,OAAO,IAAI,CAAC,UAAU,CAAC;IACzB,CAAC;IAED,6EAA6E;IAC7E,kBAAkB;IAClB,6EAA6E;IAE7E;;OAEG;IACK,cAAc,CAAC,OAAe,EAAE,MAAc;QACpD,0BAA0B;QAC1B,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;YAC5B,IAAI,CAAC;gBACH,EAAE,CAAC,SAAS,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;YAC7C,CAAC;YAAC,MAAM,CAAC;gBACP,mCAAmC;gBACnC,OAAO;YACT,CAAC;QACH,CAAC;QAED,IAAI,CAAC;YACH,MAAM,OAAO,GAAG,EAAE,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC,SAAS,EAAE,QAAQ,EAAE,EAAE;gBACxD,IAAI,CAAC,QAAQ,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC;oBAC7C,OAAO;gBACT,CAAC;gBAED,kBAAkB;gBAClB,IAAI,QAAQ,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,QAAQ,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;oBAC1D,OAAO;gBACT,CAAC;gBAED,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;gBAC9C,MAAM,QAAQ,GAAG,QAAQ,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;gBAE/C,sDAAsD;gBACtD,IAAI,CAAC,cAAc,CAAC,QAAQ,EAAE,GAAG,EAAE;oBACjC,IAAI,CAAC,gBAAgB,CAAC,QAAQ,EAAE,QAAQ,EAAE,MAAM,EAAE,SAAS,CAAC,CAAC;gBAC/D,CAAC,CAAC,CAAC;YACL,CAAC,CAAC,CAAC;YAEH,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YAE5B,OAAO,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,KAAK,EAAE,EAAE;gBAC5B,OAAO,CAAC,KAAK,CAAC,qBAAqB,OAAO,GAAG,EAAE,KAAK,CAAC,CAAC;YACxD,CAAC,CAAC,CAAC;QACL,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,KAAK,CAAC,mBAAmB,OAAO,GAAG,EAAE,KAAK,CAAC,CAAC;QACtD,CAAC;IACH,CAAC;IAED;;OAEG;IACK,cAAc,CAAC,GAAW,EAAE,QAAoB;QACtD,MAAM,QAAQ,GAAG,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAC9C,IAAI,QAAQ,EAAE,CAAC;YACb,YAAY,CAAC,QAAQ,CAAC,CAAC;QACzB,CAAC;QAED,MAAM,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE;YAC5B,IAAI,CAAC,cAAc,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YAChC,QAAQ,EAAE,CAAC;QACb,CAAC,EAAE,IAAI,CAAC,UAAU,CAAC,CAAC;QAEpB,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;IACtC,CAAC;IAED;;OAEG;IACK,gBAAgB,CACtB,QAAgB,EAChB,QAAgB,EAChB,MAAc,EACd,SAAiB;QAEjB,4BAA4B;QAC5B,IAAI,UAAsC,CAAC;QAE3C,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;YAC7B,UAAU,GAAG,SAAS,CAAC;QACzB,CAAC;aAAM,IAAI,SAAS,KAAK,QAAQ,EAAE,CAAC;YAClC,uCAAuC;YACvC,UAAU,GAAG,SAAS,CAAC;QACzB,CAAC;aAAM,CAAC;YACN,UAAU,GAAG,SAAS,CAAC;QACzB,CAAC;QAED,MAAM,KAAK,GAAuB;YAChC,IAAI,EAAE,UAAU;YAChB,QAAQ;YACR,MAAM;YACN,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;SACpC,CAAC;QAEF,OAAO,CAAC,GAAG,CAAC,6BAA6B,UAAU,KAAK,MAAM,IAAI,QAAQ,OAAO,CAAC,CAAC;QACnF,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;QAE3B,4BAA4B;QAC5B,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,KAAK,CAAC,CAAC;IAC/B,CAAC;CACF"}
|
|
@@ -1,83 +0,0 @@
|
|
|
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 type { Server } from 'http';
|
|
10
|
-
import type { DashboardViolation } from './drift-data-reader.js';
|
|
11
|
-
export type WebSocketMessageType = 'violation' | 'pattern_updated' | 'patterns_changed' | 'stats_updated' | 'ping' | 'pong' | 'connected';
|
|
12
|
-
export interface WebSocketMessage {
|
|
13
|
-
type: WebSocketMessageType;
|
|
14
|
-
payload?: unknown;
|
|
15
|
-
timestamp: string;
|
|
16
|
-
}
|
|
17
|
-
export interface PatternUpdatePayload {
|
|
18
|
-
id: string;
|
|
19
|
-
status: string;
|
|
20
|
-
action: 'approved' | 'ignored' | 'deleted';
|
|
21
|
-
}
|
|
22
|
-
export interface PatternsChangedPayload {
|
|
23
|
-
type: 'created' | 'updated' | 'deleted';
|
|
24
|
-
category: string;
|
|
25
|
-
status: string;
|
|
26
|
-
}
|
|
27
|
-
export declare class WebSocketManager {
|
|
28
|
-
private wss;
|
|
29
|
-
private clients;
|
|
30
|
-
private pingInterval;
|
|
31
|
-
/**
|
|
32
|
-
* Get the number of connected clients
|
|
33
|
-
*/
|
|
34
|
-
get clientCount(): number;
|
|
35
|
-
/**
|
|
36
|
-
* Attach WebSocket server to an HTTP server
|
|
37
|
-
* @requirements 2.1 - WebSocket endpoint at /ws
|
|
38
|
-
*/
|
|
39
|
-
attach(server: Server): void;
|
|
40
|
-
/**
|
|
41
|
-
* Close the WebSocket server and all connections
|
|
42
|
-
*/
|
|
43
|
-
close(): void;
|
|
44
|
-
/**
|
|
45
|
-
* Broadcast a violation to all connected clients
|
|
46
|
-
* @requirements 2.3 - Broadcast violations to all connected clients
|
|
47
|
-
*/
|
|
48
|
-
broadcastViolation(violation: DashboardViolation): void;
|
|
49
|
-
/**
|
|
50
|
-
* Broadcast a pattern update to all connected clients
|
|
51
|
-
*/
|
|
52
|
-
broadcastPatternUpdate(update: PatternUpdatePayload): void;
|
|
53
|
-
/**
|
|
54
|
-
* Broadcast stats update to all connected clients
|
|
55
|
-
*/
|
|
56
|
-
broadcastStatsUpdate(stats: unknown): void;
|
|
57
|
-
/**
|
|
58
|
-
* Broadcast patterns changed event to all connected clients
|
|
59
|
-
* Triggers client-side data refresh
|
|
60
|
-
*/
|
|
61
|
-
broadcastPatternsChanged(payload: PatternsChangedPayload): void;
|
|
62
|
-
/**
|
|
63
|
-
* Handle a new WebSocket connection
|
|
64
|
-
*/
|
|
65
|
-
private handleConnection;
|
|
66
|
-
/**
|
|
67
|
-
* Handle incoming message from a client
|
|
68
|
-
*/
|
|
69
|
-
private handleMessage;
|
|
70
|
-
/**
|
|
71
|
-
* Send a message to a specific client
|
|
72
|
-
*/
|
|
73
|
-
private send;
|
|
74
|
-
/**
|
|
75
|
-
* Broadcast a message to all connected clients
|
|
76
|
-
*/
|
|
77
|
-
private broadcast;
|
|
78
|
-
/**
|
|
79
|
-
* Start ping interval for connection health monitoring
|
|
80
|
-
*/
|
|
81
|
-
private startPingInterval;
|
|
82
|
-
}
|
|
83
|
-
//# sourceMappingURL=websocket-server.d.ts.map
|
|
@@ -1,189 +0,0 @@
|
|
|
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
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"websocket-server.js","sourceRoot":"","sources":["../../src/server/websocket-server.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,eAAe,EAAE,SAAS,EAAgB,MAAM,IAAI,CAAC;AAmC9D,+EAA+E;AAC/E,oBAAoB;AACpB,+EAA+E;AAE/E,MAAM,OAAO,gBAAgB;IACnB,GAAG,GAA2B,IAAI,CAAC;IACnC,OAAO,GAAmB,IAAI,GAAG,EAAE,CAAC;IACpC,YAAY,GAA0B,IAAI,CAAC;IAEnD;;OAEG;IACH,IAAI,WAAW;QACb,OAAO,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC;IAC3B,CAAC;IAED;;;OAGG;IACH,MAAM,CAAC,MAAc;QACnB,IAAI,CAAC,GAAG,GAAG,IAAI,eAAe,CAAC;YAC7B,MAAM;YACN,IAAI,EAAE,KAAK;SACZ,CAAC,CAAC;QAEH,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,YAAY,EAAE,CAAC,EAAa,EAAE,EAAE;YAC1C,IAAI,CAAC,gBAAgB,CAAC,EAAE,CAAC,CAAC;QAC5B,CAAC,CAAC,CAAC;QAEH,4CAA4C;QAC5C,IAAI,CAAC,iBAAiB,EAAE,CAAC;IAC3B,CAAC;IAED;;OAEG;IACH,KAAK;QACH,qBAAqB;QACrB,IAAI,IAAI,CAAC,YAAY,EAAE,CAAC;YACtB,aAAa,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;YACjC,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC;QAC3B,CAAC;QAED,+BAA+B;QAC/B,KAAK,MAAM,MAAM,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;YAClC,MAAM,CAAC,KAAK,CAAC,IAAI,EAAE,sBAAsB,CAAC,CAAC;QAC7C,CAAC;QACD,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;QAErB,6BAA6B;QAC7B,IAAI,IAAI,CAAC,GAAG,EAAE,CAAC;YACb,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC;YACjB,IAAI,CAAC,GAAG,GAAG,IAAI,CAAC;QAClB,CAAC;IACH,CAAC;IAED;;;OAGG;IACH,kBAAkB,CAAC,SAA6B;QAC9C,IAAI,CAAC,SAAS,CAAC;YACb,IAAI,EAAE,WAAW;YACjB,OAAO,EAAE,SAAS;YAClB,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;SACpC,CAAC,CAAC;IACL,CAAC;IAED;;OAEG;IACH,sBAAsB,CAAC,MAA4B;QACjD,IAAI,CAAC,SAAS,CAAC;YACb,IAAI,EAAE,iBAAiB;YACvB,OAAO,EAAE,MAAM;YACf,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;SACpC,CAAC,CAAC;IACL,CAAC;IAED;;OAEG;IACH,oBAAoB,CAAC,KAAc;QACjC,IAAI,CAAC,SAAS,CAAC;YACb,IAAI,EAAE,eAAe;YACrB,OAAO,EAAE,KAAK;YACd,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;SACpC,CAAC,CAAC;IACL,CAAC;IAED;;;OAGG;IACH,wBAAwB,CAAC,OAA+B;QACtD,IAAI,CAAC,SAAS,CAAC;YACb,IAAI,EAAE,kBAAkB;YACxB,OAAO;YACP,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;SACpC,CAAC,CAAC;IACL,CAAC;IAED,6EAA6E;IAC7E,kBAAkB;IAClB,6EAA6E;IAE7E;;OAEG;IACK,gBAAgB,CAAC,EAAa;QACpC,qBAAqB;QACrB,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAErB,yBAAyB;QACzB,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE;YACZ,IAAI,EAAE,WAAW;YACjB,OAAO,EAAE,EAAE,WAAW,EAAE,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE;YAC3C,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;SACpC,CAAC,CAAC;QAEH,8BAA8B;QAC9B,EAAE,CAAC,EAAE,CAAC,SAAS,EAAE,CAAC,IAAa,EAAE,EAAE;YACjC,IAAI,CAAC,aAAa,CAAC,EAAE,EAAE,IAAI,CAAC,CAAC;QAC/B,CAAC,CAAC,CAAC;QAEH,2BAA2B;QAC3B,EAAE,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE;YAClB,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;QAC1B,CAAC,CAAC,CAAC;QAEH,gBAAgB;QAChB,EAAE,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,KAAK,EAAE,EAAE;YACvB,OAAO,CAAC,KAAK,CAAC,kBAAkB,EAAE,KAAK,CAAC,CAAC;YACzC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;QAC1B,CAAC,CAAC,CAAC;IACL,CAAC;IAED;;OAEG;IACK,aAAa,CAAC,EAAa,EAAE,IAAa;QAChD,IAAI,CAAC;YACH,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAqB,CAAC;YAEhE,yCAAyC;YACzC,IAAI,OAAO,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;gBAC5B,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE;oBACZ,IAAI,EAAE,MAAM;oBACZ,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;iBACpC,CAAC,CAAC;YACL,CAAC;QACH,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,0BAA0B;YAC1B,OAAO,CAAC,KAAK,CAAC,4BAA4B,EAAE,KAAK,CAAC,CAAC;QACrD,CAAC;IACH,CAAC;IAED;;OAEG;IACK,IAAI,CAAC,EAAa,EAAE,OAAyB;QACnD,IAAI,EAAE,CAAC,UAAU,KAAK,SAAS,CAAC,IAAI,EAAE,CAAC;YACrC,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC;QACnC,CAAC;IACH,CAAC;IAED;;OAEG;IACK,SAAS,CAAC,OAAyB;QACzC,MAAM,UAAU,GAAG,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;QAE3C,KAAK,MAAM,MAAM,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;YAClC,IAAI,MAAM,CAAC,UAAU,KAAK,SAAS,CAAC,IAAI,EAAE,CAAC;gBACzC,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;YAC1B,CAAC;QACH,CAAC;IACH,CAAC;IAED;;OAEG;IACK,iBAAiB;QACvB,wBAAwB;QACxB,IAAI,CAAC,YAAY,GAAG,WAAW,CAAC,GAAG,EAAE;YACnC,MAAM,WAAW,GAAqB;gBACpC,IAAI,EAAE,MAAM;gBACZ,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;aACpC,CAAC;YAEF,KAAK,MAAM,MAAM,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;gBAClC,IAAI,MAAM,CAAC,UAAU,KAAK,SAAS,CAAC,IAAI,EAAE,CAAC;oBACzC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC,CAAC;gBAC3C,CAAC;qBAAM,CAAC;oBACN,0BAA0B;oBAC1B,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;gBAC9B,CAAC;YACH,CAAC;QACH,CAAC,EAAE,KAAK,CAAC,CAAC;IACZ,CAAC;CACF"}
|