@shykaruu/jarvis-brain 0.4.2 → 0.4.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.
- package/package.json +1 -1
- package/src/comms/websocket.test.ts +29 -21
- package/src/comms/websocket.ts +23 -12
- package/src/sidecar/manager.ts +18 -9
package/package.json
CHANGED
|
@@ -363,10 +363,10 @@ test('WebSocketServer - WebSocket allowed with auth cookie', async () => {
|
|
|
363
363
|
}
|
|
364
364
|
});
|
|
365
365
|
|
|
366
|
-
test('WebSocketServer - sidecar websocket accepts /sidecar path with bearer auth', async () => {
|
|
367
|
-
const authServer = new WebSocketServer(3156);
|
|
368
|
-
authServer.setSidecarManager({
|
|
369
|
-
async validateToken(token: string) {
|
|
366
|
+
test('WebSocketServer - sidecar websocket accepts /sidecar path with bearer auth', async () => {
|
|
367
|
+
const authServer = new WebSocketServer(3156);
|
|
368
|
+
authServer.setSidecarManager({
|
|
369
|
+
async validateToken(token: string) {
|
|
370
370
|
if (token === 'sidecar-token') {
|
|
371
371
|
return { sid: 'sidecar-123' } as any;
|
|
372
372
|
}
|
|
@@ -377,23 +377,31 @@ test('WebSocketServer - sidecar websocket accepts /sidecar path with bearer auth
|
|
|
377
377
|
} as any);
|
|
378
378
|
authServer.start();
|
|
379
379
|
|
|
380
|
-
try {
|
|
381
|
-
const ws = new WebSocket('ws://localhost:3156/sidecar', {
|
|
382
|
-
headers: { Authorization: 'Bearer sidecar-token' },
|
|
383
|
-
} as any);
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
ws.
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
380
|
+
try {
|
|
381
|
+
const ws = new WebSocket('ws://localhost:3156/sidecar', {
|
|
382
|
+
headers: { Authorization: 'Bearer sidecar-token' },
|
|
383
|
+
} as any);
|
|
384
|
+
const received: any[] = [];
|
|
385
|
+
|
|
386
|
+
const connected = await new Promise<boolean>((resolve) => {
|
|
387
|
+
ws.onopen = () => resolve(true);
|
|
388
|
+
ws.onerror = () => resolve(false);
|
|
389
|
+
setTimeout(() => resolve(false), 2000);
|
|
390
|
+
});
|
|
391
|
+
|
|
392
|
+
expect(connected).toBe(true);
|
|
393
|
+
ws.onmessage = (e) => {
|
|
394
|
+
if (typeof e.data === 'string') {
|
|
395
|
+
received.push(JSON.parse(e.data));
|
|
396
|
+
}
|
|
397
|
+
};
|
|
398
|
+
await new Promise((resolve) => setTimeout(resolve, 200));
|
|
399
|
+
expect(received.some(msg => msg.type === 'sidecar_ready')).toBe(true);
|
|
400
|
+
ws.close();
|
|
401
|
+
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
402
|
+
} finally {
|
|
403
|
+
authServer.stop();
|
|
404
|
+
}
|
|
397
405
|
});
|
|
398
406
|
|
|
399
407
|
test('WebSocketServer - sendToClient unicasts JSON', async () => {
|
package/src/comms/websocket.ts
CHANGED
|
@@ -428,7 +428,7 @@ export class WebSocketServer {
|
|
|
428
428
|
// Limit individual WS messages to 16 MB (defense against abusive HMR payloads)
|
|
429
429
|
maxPayloadLength: 16 * 1024 * 1024,
|
|
430
430
|
|
|
431
|
-
open(ws) {
|
|
431
|
+
open(ws) {
|
|
432
432
|
// HMR proxy WebSocket — bridge to dev server
|
|
433
433
|
const proxyTarget = (ws.data as any)?.proxy_target as string | undefined;
|
|
434
434
|
if (proxyTarget) {
|
|
@@ -448,11 +448,21 @@ export class WebSocketServer {
|
|
|
448
448
|
return;
|
|
449
449
|
}
|
|
450
450
|
|
|
451
|
-
const sidecarId = (ws.data as any)?.sidecar_id as string | undefined;
|
|
452
|
-
if (sidecarId && self.sidecarManager) {
|
|
453
|
-
self.sidecarManager.handleSidecarConnect(ws, sidecarId);
|
|
454
|
-
|
|
455
|
-
|
|
451
|
+
const sidecarId = (ws.data as any)?.sidecar_id as string | undefined;
|
|
452
|
+
if (sidecarId && self.sidecarManager) {
|
|
453
|
+
self.sidecarManager.handleSidecarConnect(ws, sidecarId);
|
|
454
|
+
try {
|
|
455
|
+
ws.send(JSON.stringify({
|
|
456
|
+
type: 'sidecar_ready',
|
|
457
|
+
sidecar_id: sidecarId,
|
|
458
|
+
timestamp: Date.now(),
|
|
459
|
+
}));
|
|
460
|
+
} catch (error) {
|
|
461
|
+
console.error('[WebSocketServer] Failed to send sidecar_ready frame:', error);
|
|
462
|
+
try { ws.close(); } catch { /* ignore */ }
|
|
463
|
+
}
|
|
464
|
+
return;
|
|
465
|
+
}
|
|
456
466
|
|
|
457
467
|
self.clients.add(ws);
|
|
458
468
|
console.log('[WebSocketServer] Client connected. Total clients:', self.clients.size);
|
|
@@ -518,7 +528,7 @@ export class WebSocketServer {
|
|
|
518
528
|
}
|
|
519
529
|
},
|
|
520
530
|
|
|
521
|
-
close(ws) {
|
|
531
|
+
close(ws, code, reason) {
|
|
522
532
|
// HMR proxy cleanup
|
|
523
533
|
const proxyUpstream = (ws.data as any)?._proxyUpstream as WebSocket | undefined;
|
|
524
534
|
if (proxyUpstream) {
|
|
@@ -526,11 +536,12 @@ export class WebSocketServer {
|
|
|
526
536
|
return;
|
|
527
537
|
}
|
|
528
538
|
|
|
529
|
-
const sidecarId = (ws.data as any)?.sidecar_id as string | undefined;
|
|
530
|
-
if (sidecarId && self.sidecarManager) {
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
539
|
+
const sidecarId = (ws.data as any)?.sidecar_id as string | undefined;
|
|
540
|
+
if (sidecarId && self.sidecarManager) {
|
|
541
|
+
console.log(`[WebSocketServer] Sidecar socket closed: ${sidecarId} (${code}${reason ? `, ${reason}` : ''})`);
|
|
542
|
+
self.sidecarManager.handleSidecarDisconnect(sidecarId);
|
|
543
|
+
return;
|
|
544
|
+
}
|
|
534
545
|
|
|
535
546
|
self.clients.delete(ws);
|
|
536
547
|
console.log('[WebSocketServer] Client disconnected. Total clients:', self.clients.size);
|
package/src/sidecar/manager.ts
CHANGED
|
@@ -422,20 +422,29 @@ export class SidecarManager implements Service {
|
|
|
422
422
|
if (typeof message === 'string') {
|
|
423
423
|
try {
|
|
424
424
|
const parsed = JSON.parse(message);
|
|
425
|
-
if (parsed.type === 'register') {
|
|
426
|
-
const record = this.getSidecar(sidecarId);
|
|
427
|
-
this.registerConnection({
|
|
428
|
-
id: sidecarId,
|
|
425
|
+
if (parsed.type === 'register') {
|
|
426
|
+
const record = this.getSidecar(sidecarId);
|
|
427
|
+
this.registerConnection({
|
|
428
|
+
id: sidecarId,
|
|
429
429
|
name: record?.name ?? parsed.hostname ?? sidecarId,
|
|
430
430
|
hostname: parsed.hostname ?? 'unknown',
|
|
431
431
|
os: parsed.os ?? 'unknown',
|
|
432
432
|
platform: parsed.platform ?? 'unknown',
|
|
433
433
|
capabilities: parsed.capabilities ?? [],
|
|
434
|
-
unavailableCapabilities: parsed.unavailable_capabilities ?? [],
|
|
435
|
-
connectedAt: new Date(),
|
|
436
|
-
});
|
|
437
|
-
|
|
438
|
-
|
|
434
|
+
unavailableCapabilities: parsed.unavailable_capabilities ?? [],
|
|
435
|
+
connectedAt: new Date(),
|
|
436
|
+
});
|
|
437
|
+
try {
|
|
438
|
+
ws.send(JSON.stringify({
|
|
439
|
+
type: 'sidecar_registered',
|
|
440
|
+
sidecar_id: sidecarId,
|
|
441
|
+
timestamp: Date.now(),
|
|
442
|
+
}));
|
|
443
|
+
} catch (error) {
|
|
444
|
+
console.warn(`[SidecarManager] Failed to send registration ack to ${sidecarId}:`, error);
|
|
445
|
+
}
|
|
446
|
+
return;
|
|
447
|
+
}
|
|
439
448
|
if (parsed.type === 'capabilities_update') {
|
|
440
449
|
this.updateCapabilities(sidecarId, parsed.capabilities ?? [], parsed.unavailable_capabilities ?? []);
|
|
441
450
|
return;
|