vibex-sh 0.9.7 → 0.9.8
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/index.js +127 -38
- package/package.json +1 -1
package/index.js
CHANGED
|
@@ -437,19 +437,89 @@ async function main() {
|
|
|
437
437
|
let reconnectAttempts = 0;
|
|
438
438
|
const maxReconnectDelay = 5000;
|
|
439
439
|
|
|
440
|
+
// Connection state management
|
|
441
|
+
let connectionState = 'disconnected'; // disconnected, connecting, connected, closing, closed
|
|
442
|
+
let connectionEstablished = false;
|
|
443
|
+
let connectionLock = false;
|
|
444
|
+
let connectionStartTime = null;
|
|
445
|
+
|
|
440
446
|
// Store auth code received from socket
|
|
441
447
|
let receivedAuthCode = authCode;
|
|
442
448
|
|
|
443
449
|
// Track if this is a new session (not reusing an existing one)
|
|
444
450
|
const isNewSession = !options.sessionId;
|
|
445
451
|
|
|
452
|
+
// Graceful shutdown function
|
|
453
|
+
const closeWebSocket = () => {
|
|
454
|
+
return new Promise((resolve) => {
|
|
455
|
+
if (!socket || socket.readyState !== WebSocket.OPEN) {
|
|
456
|
+
if (connectionState === 'connected' || connectionState === 'closing') {
|
|
457
|
+
connectionState = 'closed';
|
|
458
|
+
}
|
|
459
|
+
resolve();
|
|
460
|
+
return;
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
connectionState = 'closing';
|
|
464
|
+
const closeStartTime = Date.now();
|
|
465
|
+
console.log(' 🔄 Initiating graceful WebSocket close...');
|
|
466
|
+
|
|
467
|
+
const closeTimeout = setTimeout(() => {
|
|
468
|
+
const elapsed = Date.now() - closeStartTime;
|
|
469
|
+
console.log(` ⚠️ Close handshake timeout after ${elapsed}ms, forcing exit`);
|
|
470
|
+
connectionState = 'closed';
|
|
471
|
+
resolve();
|
|
472
|
+
}, 2000);
|
|
473
|
+
|
|
474
|
+
// Store original onclose handler
|
|
475
|
+
const originalOnClose = socket.onclose;
|
|
476
|
+
|
|
477
|
+
socket.onclose = (event) => {
|
|
478
|
+
clearTimeout(closeTimeout);
|
|
479
|
+
const elapsed = Date.now() - closeStartTime;
|
|
480
|
+
connectionState = 'closed';
|
|
481
|
+
connectionEstablished = false;
|
|
482
|
+
console.log(` ✓ WebSocket closed gracefully (code: ${event.code}, reason: ${event.reason || 'none'}, time: ${elapsed}ms)`);
|
|
483
|
+
|
|
484
|
+
// Call original handler if it exists
|
|
485
|
+
if (originalOnClose) {
|
|
486
|
+
originalOnClose(event);
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
resolve();
|
|
490
|
+
};
|
|
491
|
+
|
|
492
|
+
socket.close(1000, 'Stream ended');
|
|
493
|
+
});
|
|
494
|
+
};
|
|
495
|
+
|
|
446
496
|
const connectWebSocket = () => {
|
|
497
|
+
// Prevent multiple simultaneous connections
|
|
498
|
+
if (connectionLock) {
|
|
499
|
+
console.log(' ⚠️ Connection already in progress, skipping...');
|
|
500
|
+
return;
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
if (connectionState === 'connected' || connectionState === 'connecting') {
|
|
504
|
+
console.log(` ⚠️ Already ${connectionState}, skipping new connection...`);
|
|
505
|
+
return;
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
connectionLock = true;
|
|
509
|
+
connectionState = 'connecting';
|
|
510
|
+
connectionStartTime = Date.now();
|
|
511
|
+
console.log(' 🔄 Connecting to WebSocket...');
|
|
512
|
+
|
|
447
513
|
try {
|
|
448
514
|
socket = new WebSocket(`${socketUrl}?sessionId=${sessionId}`);
|
|
449
515
|
|
|
450
516
|
socket.onopen = () => {
|
|
517
|
+
const connectTime = Date.now() - connectionStartTime;
|
|
518
|
+
connectionLock = false;
|
|
519
|
+
connectionState = 'connected';
|
|
451
520
|
isConnected = true;
|
|
452
|
-
|
|
521
|
+
connectionEstablished = true;
|
|
522
|
+
console.log(` ✓ Connected to server (${connectTime}ms)\n`);
|
|
453
523
|
reconnectAttempts = 0;
|
|
454
524
|
|
|
455
525
|
// Join session
|
|
@@ -458,17 +528,15 @@ async function main() {
|
|
|
458
528
|
sessionId,
|
|
459
529
|
}));
|
|
460
530
|
|
|
461
|
-
//
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
}
|
|
471
|
-
}, 100);
|
|
531
|
+
// Set hasJoinedSession immediately - HTTP POST doesn't need WebSocket
|
|
532
|
+
hasJoinedSession = true;
|
|
533
|
+
// Process any queued logs immediately
|
|
534
|
+
while (logQueue.length > 0) {
|
|
535
|
+
const logData = logQueue.shift();
|
|
536
|
+
// Send logs via HTTP POST (non-blocking) instead of WebSocket
|
|
537
|
+
// WebSocket is only for receiving logs
|
|
538
|
+
sendLogViaHTTP(logData);
|
|
539
|
+
}
|
|
472
540
|
};
|
|
473
541
|
|
|
474
542
|
socket.onmessage = (event) => {
|
|
@@ -607,11 +675,17 @@ async function main() {
|
|
|
607
675
|
};
|
|
608
676
|
|
|
609
677
|
socket.onclose = (event) => {
|
|
678
|
+
connectionLock = false;
|
|
679
|
+
connectionState = 'closed';
|
|
680
|
+
connectionEstablished = false;
|
|
610
681
|
isConnected = false;
|
|
611
682
|
hasJoinedSession = false;
|
|
683
|
+
|
|
684
|
+
const connectionDuration = connectionStartTime ? Date.now() - connectionStartTime : 0;
|
|
685
|
+
console.log(` 📊 Connection closed (code: ${event.code}, reason: ${event.reason || 'none'}, duration: ${connectionDuration}ms)`);
|
|
612
686
|
|
|
613
|
-
// Reconnect logic
|
|
614
|
-
if (event.code !== 1000
|
|
687
|
+
// Reconnect logic - only if not a normal closure and not already closing
|
|
688
|
+
if (event.code !== 1000 && connectionState !== 'closing') {
|
|
615
689
|
const delay = Math.min(1000 * Math.pow(2, reconnectAttempts), maxReconnectDelay);
|
|
616
690
|
reconnectAttempts++;
|
|
617
691
|
console.log(` ↻ Reconnecting in ${delay}ms (attempt ${reconnectAttempts})...\n`);
|
|
@@ -619,9 +693,14 @@ async function main() {
|
|
|
619
693
|
reconnectTimeout = setTimeout(() => {
|
|
620
694
|
connectWebSocket();
|
|
621
695
|
}, delay);
|
|
696
|
+
} else if (event.code === 1000) {
|
|
697
|
+
console.log(' ✓ Normal closure, no reconnect needed\n');
|
|
622
698
|
}
|
|
623
699
|
};
|
|
624
700
|
} catch (error) {
|
|
701
|
+
connectionLock = false;
|
|
702
|
+
connectionState = 'disconnected';
|
|
703
|
+
connectionEstablished = false;
|
|
625
704
|
console.error(` ✗ Error creating WebSocket: ${error.message}`);
|
|
626
705
|
console.error(` ↻ URL: ${socketUrl}`);
|
|
627
706
|
// Retry connection
|
|
@@ -634,6 +713,7 @@ async function main() {
|
|
|
634
713
|
// Send logs via HTTP POST (non-blocking, same as SDKs)
|
|
635
714
|
// Use Cloudflare Worker endpoint (port 8787 for local, or Worker URL for production)
|
|
636
715
|
// Token is optional - anonymous sessions can send logs without authentication
|
|
716
|
+
// HTTP POST works independently of WebSocket - don't wait for WebSocket connection
|
|
637
717
|
const sendLogViaHTTP = async (logData) => {
|
|
638
718
|
try {
|
|
639
719
|
// Determine ingest URL
|
|
@@ -788,43 +868,52 @@ async function main() {
|
|
|
788
868
|
};
|
|
789
869
|
}
|
|
790
870
|
|
|
791
|
-
// Send logs via HTTP POST
|
|
792
|
-
// WebSocket is only for receiving logs and auth codes
|
|
793
|
-
|
|
794
|
-
sendLogViaHTTP(logData);
|
|
795
|
-
} else {
|
|
796
|
-
logQueue.push(logData);
|
|
797
|
-
}
|
|
871
|
+
// Send logs via HTTP POST immediately - don't wait for WebSocket
|
|
872
|
+
// WebSocket is only for receiving logs and auth codes, not required for sending
|
|
873
|
+
sendLogViaHTTP(logData);
|
|
798
874
|
});
|
|
799
875
|
|
|
800
|
-
rl.on('close', () => {
|
|
876
|
+
rl.on('close', async () => {
|
|
801
877
|
// Wait for queued logs to be sent
|
|
802
878
|
const waitForQueue = () => {
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
if (reconnectTimeout) {
|
|
809
|
-
clearTimeout(reconnectTimeout);
|
|
879
|
+
return new Promise((resolve) => {
|
|
880
|
+
if (logQueue.length === 0) {
|
|
881
|
+
resolve();
|
|
882
|
+
} else {
|
|
883
|
+
setTimeout(() => waitForQueue().then(resolve), 100);
|
|
810
884
|
}
|
|
811
|
-
|
|
812
|
-
} else {
|
|
813
|
-
setTimeout(waitForQueue, 100);
|
|
814
|
-
}
|
|
885
|
+
});
|
|
815
886
|
};
|
|
816
887
|
|
|
817
|
-
waitForQueue();
|
|
888
|
+
await waitForQueue();
|
|
889
|
+
|
|
890
|
+
console.log('\n Stream ended. Closing connection...\n');
|
|
891
|
+
|
|
892
|
+
// Cancel any pending reconnection attempts
|
|
893
|
+
if (reconnectTimeout) {
|
|
894
|
+
clearTimeout(reconnectTimeout);
|
|
895
|
+
reconnectTimeout = null;
|
|
896
|
+
}
|
|
897
|
+
|
|
898
|
+
// Graceful shutdown - wait for close handshake
|
|
899
|
+
await closeWebSocket();
|
|
900
|
+
|
|
901
|
+
// Give a moment for any final cleanup
|
|
902
|
+
setTimeout(() => process.exit(0), 100);
|
|
818
903
|
});
|
|
819
904
|
|
|
820
|
-
process.on('SIGINT', () => {
|
|
905
|
+
process.on('SIGINT', async () => {
|
|
821
906
|
console.log('\n Interrupted. Closing connection...\n');
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
}
|
|
907
|
+
|
|
908
|
+
// Cancel any pending reconnection attempts
|
|
825
909
|
if (reconnectTimeout) {
|
|
826
910
|
clearTimeout(reconnectTimeout);
|
|
911
|
+
reconnectTimeout = null;
|
|
827
912
|
}
|
|
913
|
+
|
|
914
|
+
// Graceful shutdown
|
|
915
|
+
await closeWebSocket();
|
|
916
|
+
|
|
828
917
|
process.exit(0);
|
|
829
918
|
});
|
|
830
919
|
}
|