@jetstart/core 1.1.3 → 1.2.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.
- package/dist/websocket/handler.d.ts +1 -1
- package/dist/websocket/handler.d.ts.map +1 -1
- package/dist/websocket/handler.js +7 -5
- package/dist/websocket/handler.js.map +1 -1
- package/dist/websocket/manager.d.ts +17 -1
- package/dist/websocket/manager.d.ts.map +1 -1
- package/dist/websocket/manager.js +52 -10
- package/dist/websocket/manager.js.map +1 -1
- package/package.json +2 -2
- package/src/websocket/handler.ts +8 -5
- package/src/websocket/manager.ts +63 -12
|
@@ -17,7 +17,7 @@ export declare class WebSocketHandler {
|
|
|
17
17
|
sendBuildStart(sessionId: string): void;
|
|
18
18
|
sendBuildComplete(sessionId: string, apkUrl: string): void;
|
|
19
19
|
/**
|
|
20
|
-
* Send UI update (DSL-based hot reload)
|
|
20
|
+
* Send UI update (DSL-based hot reload) - SECURE, session-isolated
|
|
21
21
|
*/
|
|
22
22
|
sendUIUpdate(sessionId: string, dslContent: string, screens?: string[]): void;
|
|
23
23
|
private generateHash;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"handler.d.ts","sourceRoot":"","sources":["../../src/websocket/handler.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAUH,OAAO,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAC;AAG9C,qBAAa,gBAAgB;IAIzB,OAAO,CAAC,iBAAiB;IAH3B,OAAO,CAAC,iBAAiB,CAAC,CAA8B;gBAG9C,iBAAiB,EAAE,iBAAiB,EAC5C,OAAO,CAAC,EAAE;QAAE,iBAAiB,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,CAAA;KAAE;IAK/D,aAAa,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI;IAenD,OAAO,CAAC,eAAe;IAIvB,OAAO,CAAC,mBAAmB;IAoB3B,OAAO,CAAC,aAAa;
|
|
1
|
+
{"version":3,"file":"handler.d.ts","sourceRoot":"","sources":["../../src/websocket/handler.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAUH,OAAO,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAC;AAG9C,qBAAa,gBAAgB;IAIzB,OAAO,CAAC,iBAAiB;IAH3B,OAAO,CAAC,iBAAiB,CAAC,CAA8B;gBAG9C,iBAAiB,EAAE,iBAAiB,EAC5C,OAAO,CAAC,EAAE;QAAE,iBAAiB,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,CAAA;KAAE;IAK/D,aAAa,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI;IAenD,OAAO,CAAC,eAAe;IAIvB,OAAO,CAAC,mBAAmB;IAoB3B,OAAO,CAAC,aAAa;IAuBrB,OAAO,CAAC,gBAAgB;IAKxB,cAAc,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI;IAUvC,iBAAiB,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI;IAqB1D;;OAEG;IACH,YAAY,CAAC,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,EAAE,GAAG,IAAI;IAe7E,OAAO,CAAC,YAAY;CAUrB"}
|
|
@@ -50,6 +50,8 @@ class WebSocketHandler {
|
|
|
50
50
|
}
|
|
51
51
|
handleConnect(clientId, message) {
|
|
52
52
|
(0, logger_1.log)(`Client connecting with session: ${message.sessionId}`);
|
|
53
|
+
// Associate this client with the session for isolation
|
|
54
|
+
this.connectionManager.setClientSession(clientId, message.sessionId);
|
|
53
55
|
// Send connected confirmation
|
|
54
56
|
const response = {
|
|
55
57
|
type: 'core:connected',
|
|
@@ -74,7 +76,7 @@ class WebSocketHandler {
|
|
|
74
76
|
timestamp: Date.now(),
|
|
75
77
|
sessionId,
|
|
76
78
|
};
|
|
77
|
-
this.connectionManager.
|
|
79
|
+
this.connectionManager.broadcastToSession(sessionId, message);
|
|
78
80
|
}
|
|
79
81
|
sendBuildComplete(sessionId, apkUrl) {
|
|
80
82
|
const message = {
|
|
@@ -93,10 +95,10 @@ class WebSocketHandler {
|
|
|
93
95
|
},
|
|
94
96
|
downloadUrl: apkUrl,
|
|
95
97
|
};
|
|
96
|
-
this.connectionManager.
|
|
98
|
+
this.connectionManager.broadcastToSession(sessionId, message);
|
|
97
99
|
}
|
|
98
100
|
/**
|
|
99
|
-
* Send UI update (DSL-based hot reload)
|
|
101
|
+
* Send UI update (DSL-based hot reload) - SECURE, session-isolated
|
|
100
102
|
*/
|
|
101
103
|
sendUIUpdate(sessionId, dslContent, screens) {
|
|
102
104
|
const message = {
|
|
@@ -107,9 +109,9 @@ class WebSocketHandler {
|
|
|
107
109
|
screens,
|
|
108
110
|
hash: this.generateHash(dslContent),
|
|
109
111
|
};
|
|
110
|
-
(0, logger_1.log)(`Sending UI update: ${dslContent.length} bytes`);
|
|
112
|
+
(0, logger_1.log)(`Sending UI update to session ${sessionId}: ${dslContent.length} bytes`);
|
|
111
113
|
(0, logger_1.log)(`DSL Content: ${dslContent}`);
|
|
112
|
-
this.connectionManager.
|
|
114
|
+
this.connectionManager.broadcastToSession(sessionId, message);
|
|
113
115
|
}
|
|
114
116
|
generateHash(content) {
|
|
115
117
|
// Simple hash for caching (in production, use crypto.createHash)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"handler.js","sourceRoot":"","sources":["../../src/websocket/handler.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;AAWH,4CAAyD;AAEzD,MAAa,gBAAgB;IAIjB;IAHF,iBAAiB,CAA+B;IAExD,YACU,iBAAoC,EAC5C,OAA6D;QADrD,sBAAiB,GAAjB,iBAAiB,CAAmB;QAG5C,IAAI,CAAC,iBAAiB,GAAG,OAAO,EAAE,iBAAiB,CAAC;IACtD,CAAC;IAED,aAAa,CAAC,QAAgB,EAAE,IAAY;QAC1C,IAAI,CAAC;YACH,MAAM,OAAO,GAAc,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC,CAAC;YACvD,IAAA,YAAG,EAAC,yBAAyB,QAAQ,KAAK,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC;YAE1D,8BAA8B;YAC9B,IAAI,IAAI,CAAC,eAAe,CAAC,OAAO,CAAC,EAAE,CAAC;gBAClC,IAAI,CAAC,mBAAmB,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;YAC9C,CAAC;QAEH,CAAC;QAAC,OAAO,GAAQ,EAAE,CAAC;YAClB,IAAA,cAAQ,EAAC,gCAAgC,QAAQ,KAAK,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC;QACvE,CAAC;IACH,CAAC;IAEO,eAAe,CAAC,OAAkB;QACxC,OAAO,OAAO,CAAC,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC;IAC5C,CAAC;IAEO,mBAAmB,CAAC,QAAgB,EAAE,OAAsB;QAClE,QAAQ,OAAO,CAAC,IAAI,EAAE,CAAC;YACrB,KAAK,gBAAgB;gBACnB,IAAI,CAAC,aAAa,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;gBACtC,MAAM;YACR,KAAK,eAAe;gBAClB,IAAA,YAAG,EAAC,UAAU,QAAQ,YAAY,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;gBACpD,MAAM;YACR,KAAK,YAAY;gBACf,0BAA0B;gBAC1B,MAAM;YACR,KAAK,kBAAkB;gBACrB,uBAAuB;gBACvB,MAAM;YACR,KAAK,mBAAmB;gBACtB,IAAI,CAAC,gBAAgB,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;gBACzC,MAAM;QACV,CAAC;IACH,CAAC;IAEO,aAAa,CAAC,QAAgB,EAAE,OAAmD;QACzF,IAAA,YAAG,EAAC,mCAAmC,OAAO,CAAC,SAAS,EAAE,CAAC,CAAC;QAE5D,8BAA8B;QAC9B,MAAM,QAAQ,GAAyB;YACrC,IAAI,EAAE,gBAAgB;YACtB,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE;YACrB,SAAS,EAAE,OAAO,CAAC,SAAS;YAC5B,WAAW,EAAE,aAAa,EAAE,2CAA2C;SACxE,CAAC;QAEF,IAAI,CAAC,iBAAiB,CAAC,YAAY,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;QAExD,uCAAuC;QACvC,IAAI,IAAI,CAAC,iBAAiB,EAAE,CAAC;YAC3B,IAAA,YAAG,EAAC,yCAAyC,OAAO,CAAC,SAAS,EAAE,CAAC,CAAC;YAClE,IAAI,CAAC,iBAAiB,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;QAC5C,CAAC;IACH,CAAC;IAEO,gBAAgB,CAAC,QAAgB,EAAE,OAAsD;QAC/F,IAAA,YAAG,EAAC,yBAAyB,OAAO,CAAC,MAAM,IAAI,oBAAoB,EAAE,CAAC,CAAC;IACzE,CAAC;IAED,2BAA2B;IAC3B,cAAc,CAAC,SAAiB;QAC9B,MAAM,OAAO,GAA0B;YACrC,IAAI,EAAE,kBAAkB;YACxB,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE;YACrB,SAAS;SACV,CAAC;QAEF,IAAI,CAAC,iBAAiB,CAAC,
|
|
1
|
+
{"version":3,"file":"handler.js","sourceRoot":"","sources":["../../src/websocket/handler.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Connection Manager
|
|
3
|
-
* Manages WebSocket connections
|
|
3
|
+
* Manages WebSocket connections with session isolation
|
|
4
4
|
*/
|
|
5
5
|
import { WebSocket } from 'ws';
|
|
6
6
|
import { CoreMessage } from '@jetstart/shared';
|
|
@@ -9,8 +9,24 @@ export declare class ConnectionManager {
|
|
|
9
9
|
addConnection(ws: WebSocket): string;
|
|
10
10
|
removeConnection(id: string): void;
|
|
11
11
|
getConnection(id: string): WebSocket | undefined;
|
|
12
|
+
/**
|
|
13
|
+
* Associate a client with a session for isolation
|
|
14
|
+
*/
|
|
15
|
+
setClientSession(clientId: string, sessionId: string): void;
|
|
12
16
|
sendToClient(clientId: string, message: CoreMessage): boolean;
|
|
17
|
+
/**
|
|
18
|
+
* Broadcast to all clients (UNSAFE - use broadcastToSession instead)
|
|
19
|
+
* @deprecated Use broadcastToSession for session isolation
|
|
20
|
+
*/
|
|
13
21
|
broadcast(message: CoreMessage): void;
|
|
22
|
+
/**
|
|
23
|
+
* Broadcast to all clients in a specific session (SECURE)
|
|
24
|
+
*/
|
|
25
|
+
broadcastToSession(sessionId: string, message: CoreMessage): void;
|
|
26
|
+
/**
|
|
27
|
+
* Broadcast to ALL clients regardless of session (use with caution)
|
|
28
|
+
*/
|
|
29
|
+
private broadcastToAll;
|
|
14
30
|
getConnectionCount(): number;
|
|
15
31
|
}
|
|
16
32
|
//# sourceMappingURL=manager.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"manager.d.ts","sourceRoot":"","sources":["../../src/websocket/manager.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,IAAI,CAAC;AAE/B,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"manager.d.ts","sourceRoot":"","sources":["../../src/websocket/manager.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,IAAI,CAAC;AAE/B,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAO/C,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,WAAW,CAA4C;IAE/D,aAAa,CAAC,EAAE,EAAE,SAAS,GAAG,MAAM;IAMpC,gBAAgB,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI;IAIlC,aAAa,CAAC,EAAE,EAAE,MAAM,GAAG,SAAS,GAAG,SAAS;IAIhD;;OAEG;IACH,gBAAgB,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,IAAI;IAQ3D,YAAY,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,WAAW,GAAG,OAAO;IAgB7D;;;OAGG;IACH,SAAS,CAAC,OAAO,EAAE,WAAW,GAAG,IAAI;IAKrC;;OAEG;IACH,kBAAkB,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,WAAW,GAAG,IAAI;IAoBjE;;OAEG;IACH,OAAO,CAAC,cAAc;IAiBtB,kBAAkB,IAAI,MAAM;CAG7B"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
/**
|
|
3
3
|
* Connection Manager
|
|
4
|
-
* Manages WebSocket connections
|
|
4
|
+
* Manages WebSocket connections with session isolation
|
|
5
5
|
*/
|
|
6
6
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
7
|
exports.ConnectionManager = void 0;
|
|
@@ -11,22 +11,32 @@ class ConnectionManager {
|
|
|
11
11
|
connections = new Map();
|
|
12
12
|
addConnection(ws) {
|
|
13
13
|
const id = (0, uuid_1.v4)();
|
|
14
|
-
this.connections.set(id, ws);
|
|
14
|
+
this.connections.set(id, { ws, sessionId: undefined });
|
|
15
15
|
return id;
|
|
16
16
|
}
|
|
17
17
|
removeConnection(id) {
|
|
18
18
|
this.connections.delete(id);
|
|
19
19
|
}
|
|
20
20
|
getConnection(id) {
|
|
21
|
-
return this.connections.get(id);
|
|
21
|
+
return this.connections.get(id)?.ws;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Associate a client with a session for isolation
|
|
25
|
+
*/
|
|
26
|
+
setClientSession(clientId, sessionId) {
|
|
27
|
+
const connection = this.connections.get(clientId);
|
|
28
|
+
if (connection) {
|
|
29
|
+
connection.sessionId = sessionId;
|
|
30
|
+
console.log(`[ConnectionManager] Client ${clientId} joined session ${sessionId}`);
|
|
31
|
+
}
|
|
22
32
|
}
|
|
23
33
|
sendToClient(clientId, message) {
|
|
24
|
-
const
|
|
25
|
-
if (!
|
|
34
|
+
const connection = this.connections.get(clientId);
|
|
35
|
+
if (!connection || connection.ws.readyState !== ws_1.WebSocket.OPEN) {
|
|
26
36
|
return false;
|
|
27
37
|
}
|
|
28
38
|
try {
|
|
29
|
-
ws.send(JSON.stringify(message));
|
|
39
|
+
connection.ws.send(JSON.stringify(message));
|
|
30
40
|
return true;
|
|
31
41
|
}
|
|
32
42
|
catch (err) {
|
|
@@ -34,14 +44,46 @@ class ConnectionManager {
|
|
|
34
44
|
return false;
|
|
35
45
|
}
|
|
36
46
|
}
|
|
47
|
+
/**
|
|
48
|
+
* Broadcast to all clients (UNSAFE - use broadcastToSession instead)
|
|
49
|
+
* @deprecated Use broadcastToSession for session isolation
|
|
50
|
+
*/
|
|
37
51
|
broadcast(message) {
|
|
52
|
+
console.warn('[ConnectionManager] WARNING: Using unsafe broadcast() - use broadcastToSession() instead');
|
|
53
|
+
this.broadcastToAll(message);
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Broadcast to all clients in a specific session (SECURE)
|
|
57
|
+
*/
|
|
58
|
+
broadcastToSession(sessionId, message) {
|
|
59
|
+
const data = JSON.stringify(message);
|
|
60
|
+
let sentCount = 0;
|
|
61
|
+
this.connections.forEach((connection, clientId) => {
|
|
62
|
+
// Only send to clients in the same session
|
|
63
|
+
if (connection.sessionId === sessionId && connection.ws.readyState === ws_1.WebSocket.OPEN) {
|
|
64
|
+
try {
|
|
65
|
+
connection.ws.send(data);
|
|
66
|
+
sentCount++;
|
|
67
|
+
console.log(`[ConnectionManager] Sent ${message.type} to client ${clientId} in session ${sessionId}`);
|
|
68
|
+
}
|
|
69
|
+
catch (err) {
|
|
70
|
+
console.error(`Failed to send to ${clientId}:`, err);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
});
|
|
74
|
+
console.log(`[ConnectionManager] Broadcasted ${message.type} to ${sentCount} clients in session ${sessionId}`);
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Broadcast to ALL clients regardless of session (use with caution)
|
|
78
|
+
*/
|
|
79
|
+
broadcastToAll(message) {
|
|
38
80
|
const data = JSON.stringify(message);
|
|
39
|
-
const connectionCount = Array.from(this.connections.values()).filter(
|
|
81
|
+
const connectionCount = Array.from(this.connections.values()).filter(c => c.ws.readyState === ws_1.WebSocket.OPEN).length;
|
|
40
82
|
console.log(`[ConnectionManager] Broadcasting ${message.type} to ${connectionCount} connected clients`);
|
|
41
|
-
this.connections.forEach((
|
|
42
|
-
if (ws.readyState === ws_1.WebSocket.OPEN) {
|
|
83
|
+
this.connections.forEach((connection, clientId) => {
|
|
84
|
+
if (connection.ws.readyState === ws_1.WebSocket.OPEN) {
|
|
43
85
|
try {
|
|
44
|
-
ws.send(data);
|
|
86
|
+
connection.ws.send(data);
|
|
45
87
|
console.log(`[ConnectionManager] Sent ${message.type} to client ${clientId}`);
|
|
46
88
|
}
|
|
47
89
|
catch (err) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"manager.js","sourceRoot":"","sources":["../../src/websocket/manager.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;AAEH,2BAA+B;AAC/B,+BAAoC;
|
|
1
|
+
{"version":3,"file":"manager.js","sourceRoot":"","sources":["../../src/websocket/manager.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jetstart/core",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.2.0",
|
|
4
4
|
"description": "Build server and orchestration for JetStart",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
},
|
|
34
34
|
"homepage": "https://github.com/dev-phantom/jetstart#readme",
|
|
35
35
|
"dependencies": {
|
|
36
|
-
"@jetstart/shared": "^1.
|
|
36
|
+
"@jetstart/shared": "^1.2.0",
|
|
37
37
|
"express": "^4.18.2",
|
|
38
38
|
"ws": "^8.14.2",
|
|
39
39
|
"chokidar": "^3.5.3",
|
package/src/websocket/handler.ts
CHANGED
|
@@ -66,6 +66,9 @@ export class WebSocketHandler {
|
|
|
66
66
|
private handleConnect(clientId: string, message: ClientMessage & { type: 'client:connect' }): void {
|
|
67
67
|
log(`Client connecting with session: ${message.sessionId}`);
|
|
68
68
|
|
|
69
|
+
// Associate this client with the session for isolation
|
|
70
|
+
this.connectionManager.setClientSession(clientId, message.sessionId);
|
|
71
|
+
|
|
69
72
|
// Send connected confirmation
|
|
70
73
|
const response: CoreConnectedMessage = {
|
|
71
74
|
type: 'core:connected',
|
|
@@ -95,7 +98,7 @@ export class WebSocketHandler {
|
|
|
95
98
|
sessionId,
|
|
96
99
|
};
|
|
97
100
|
|
|
98
|
-
this.connectionManager.
|
|
101
|
+
this.connectionManager.broadcastToSession(sessionId, message);
|
|
99
102
|
}
|
|
100
103
|
|
|
101
104
|
sendBuildComplete(sessionId: string, apkUrl: string): void {
|
|
@@ -116,11 +119,11 @@ export class WebSocketHandler {
|
|
|
116
119
|
downloadUrl: apkUrl,
|
|
117
120
|
};
|
|
118
121
|
|
|
119
|
-
this.connectionManager.
|
|
122
|
+
this.connectionManager.broadcastToSession(sessionId, message);
|
|
120
123
|
}
|
|
121
124
|
|
|
122
125
|
/**
|
|
123
|
-
* Send UI update (DSL-based hot reload)
|
|
126
|
+
* Send UI update (DSL-based hot reload) - SECURE, session-isolated
|
|
124
127
|
*/
|
|
125
128
|
sendUIUpdate(sessionId: string, dslContent: string, screens?: string[]): void {
|
|
126
129
|
const message: CoreUIUpdateMessage = {
|
|
@@ -132,9 +135,9 @@ export class WebSocketHandler {
|
|
|
132
135
|
hash: this.generateHash(dslContent),
|
|
133
136
|
};
|
|
134
137
|
|
|
135
|
-
log(`Sending UI update: ${dslContent.length} bytes`);
|
|
138
|
+
log(`Sending UI update to session ${sessionId}: ${dslContent.length} bytes`);
|
|
136
139
|
log(`DSL Content: ${dslContent}`);
|
|
137
|
-
this.connectionManager.
|
|
140
|
+
this.connectionManager.broadcastToSession(sessionId, message);
|
|
138
141
|
}
|
|
139
142
|
|
|
140
143
|
private generateHash(content: string): string {
|
package/src/websocket/manager.ts
CHANGED
|
@@ -1,18 +1,23 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Connection Manager
|
|
3
|
-
* Manages WebSocket connections
|
|
3
|
+
* Manages WebSocket connections with session isolation
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
import { WebSocket } from 'ws';
|
|
7
7
|
import { v4 as uuidv4 } from 'uuid';
|
|
8
8
|
import { CoreMessage } from '@jetstart/shared';
|
|
9
9
|
|
|
10
|
+
interface ClientConnection {
|
|
11
|
+
ws: WebSocket;
|
|
12
|
+
sessionId?: string; // Session ID for isolation
|
|
13
|
+
}
|
|
14
|
+
|
|
10
15
|
export class ConnectionManager {
|
|
11
|
-
private connections: Map<string,
|
|
16
|
+
private connections: Map<string, ClientConnection> = new Map();
|
|
12
17
|
|
|
13
18
|
addConnection(ws: WebSocket): string {
|
|
14
19
|
const id = uuidv4();
|
|
15
|
-
this.connections.set(id, ws);
|
|
20
|
+
this.connections.set(id, { ws, sessionId: undefined });
|
|
16
21
|
return id;
|
|
17
22
|
}
|
|
18
23
|
|
|
@@ -21,18 +26,29 @@ export class ConnectionManager {
|
|
|
21
26
|
}
|
|
22
27
|
|
|
23
28
|
getConnection(id: string): WebSocket | undefined {
|
|
24
|
-
return this.connections.get(id);
|
|
29
|
+
return this.connections.get(id)?.ws;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Associate a client with a session for isolation
|
|
34
|
+
*/
|
|
35
|
+
setClientSession(clientId: string, sessionId: string): void {
|
|
36
|
+
const connection = this.connections.get(clientId);
|
|
37
|
+
if (connection) {
|
|
38
|
+
connection.sessionId = sessionId;
|
|
39
|
+
console.log(`[ConnectionManager] Client ${clientId} joined session ${sessionId}`);
|
|
40
|
+
}
|
|
25
41
|
}
|
|
26
42
|
|
|
27
43
|
sendToClient(clientId: string, message: CoreMessage): boolean {
|
|
28
|
-
const
|
|
29
|
-
|
|
30
|
-
if (!
|
|
44
|
+
const connection = this.connections.get(clientId);
|
|
45
|
+
|
|
46
|
+
if (!connection || connection.ws.readyState !== WebSocket.OPEN) {
|
|
31
47
|
return false;
|
|
32
48
|
}
|
|
33
49
|
|
|
34
50
|
try {
|
|
35
|
-
ws.send(JSON.stringify(message));
|
|
51
|
+
connection.ws.send(JSON.stringify(message));
|
|
36
52
|
return true;
|
|
37
53
|
} catch (err) {
|
|
38
54
|
console.error(`Failed to send message to ${clientId}:`, err);
|
|
@@ -40,15 +56,50 @@ export class ConnectionManager {
|
|
|
40
56
|
}
|
|
41
57
|
}
|
|
42
58
|
|
|
59
|
+
/**
|
|
60
|
+
* Broadcast to all clients (UNSAFE - use broadcastToSession instead)
|
|
61
|
+
* @deprecated Use broadcastToSession for session isolation
|
|
62
|
+
*/
|
|
43
63
|
broadcast(message: CoreMessage): void {
|
|
64
|
+
console.warn('[ConnectionManager] WARNING: Using unsafe broadcast() - use broadcastToSession() instead');
|
|
65
|
+
this.broadcastToAll(message);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Broadcast to all clients in a specific session (SECURE)
|
|
70
|
+
*/
|
|
71
|
+
broadcastToSession(sessionId: string, message: CoreMessage): void {
|
|
72
|
+
const data = JSON.stringify(message);
|
|
73
|
+
let sentCount = 0;
|
|
74
|
+
|
|
75
|
+
this.connections.forEach((connection, clientId) => {
|
|
76
|
+
// Only send to clients in the same session
|
|
77
|
+
if (connection.sessionId === sessionId && connection.ws.readyState === WebSocket.OPEN) {
|
|
78
|
+
try {
|
|
79
|
+
connection.ws.send(data);
|
|
80
|
+
sentCount++;
|
|
81
|
+
console.log(`[ConnectionManager] Sent ${message.type} to client ${clientId} in session ${sessionId}`);
|
|
82
|
+
} catch (err) {
|
|
83
|
+
console.error(`Failed to send to ${clientId}:`, err);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
console.log(`[ConnectionManager] Broadcasted ${message.type} to ${sentCount} clients in session ${sessionId}`);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Broadcast to ALL clients regardless of session (use with caution)
|
|
93
|
+
*/
|
|
94
|
+
private broadcastToAll(message: CoreMessage): void {
|
|
44
95
|
const data = JSON.stringify(message);
|
|
45
|
-
const connectionCount = Array.from(this.connections.values()).filter(
|
|
96
|
+
const connectionCount = Array.from(this.connections.values()).filter(c => c.ws.readyState === WebSocket.OPEN).length;
|
|
46
97
|
console.log(`[ConnectionManager] Broadcasting ${message.type} to ${connectionCount} connected clients`);
|
|
47
98
|
|
|
48
|
-
this.connections.forEach((
|
|
49
|
-
if (ws.readyState === WebSocket.OPEN) {
|
|
99
|
+
this.connections.forEach((connection, clientId) => {
|
|
100
|
+
if (connection.ws.readyState === WebSocket.OPEN) {
|
|
50
101
|
try {
|
|
51
|
-
ws.send(data);
|
|
102
|
+
connection.ws.send(data);
|
|
52
103
|
console.log(`[ConnectionManager] Sent ${message.type} to client ${clientId}`);
|
|
53
104
|
} catch (err) {
|
|
54
105
|
console.error(`Failed to broadcast to ${clientId}:`, err);
|