vibex-sh 0.9.2 → 0.9.4
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 +212 -57
- package/package.json +1 -1
package/index.js
CHANGED
|
@@ -9,6 +9,7 @@ import http from 'http';
|
|
|
9
9
|
import https from 'https';
|
|
10
10
|
import { fileURLToPath } from 'url';
|
|
11
11
|
import WebSocket from 'ws';
|
|
12
|
+
import crypto from 'crypto';
|
|
12
13
|
|
|
13
14
|
// Get version from package.json
|
|
14
15
|
const __filename = fileURLToPath(import.meta.url);
|
|
@@ -29,12 +30,11 @@ try {
|
|
|
29
30
|
}
|
|
30
31
|
}
|
|
31
32
|
|
|
32
|
-
|
|
33
|
-
|
|
33
|
+
// Session ID generation is now handled by the server
|
|
34
|
+
// This function is kept for backward compatibility but should not be used for new sessions
|
|
34
35
|
function generateSessionId() {
|
|
35
|
-
//
|
|
36
|
-
//
|
|
37
|
-
// Using crypto for better randomness
|
|
36
|
+
// DEPRECATED: Session IDs should be generated by the server
|
|
37
|
+
// This is only used as a fallback if server creation fails
|
|
38
38
|
const chars = 'abcdefghijklmnopqrstuvwxyz0123456789';
|
|
39
39
|
let result = 'vibex-';
|
|
40
40
|
|
|
@@ -370,41 +370,63 @@ async function main() {
|
|
|
370
370
|
.parse();
|
|
371
371
|
|
|
372
372
|
const options = program.opts();
|
|
373
|
-
|
|
374
|
-
// Normalize session ID - add 'vibex-' prefix if missing
|
|
375
|
-
const rawSessionId = options.sessionId || generateSessionId();
|
|
376
|
-
const sessionId = normalizeSessionId(rawSessionId);
|
|
377
373
|
const { webUrl, socketUrl } = getUrls(options);
|
|
378
374
|
|
|
379
375
|
// Get token from flag, env var, or stored config
|
|
380
376
|
let token = options.token || process.env.VIBEX_TOKEN || await getStoredToken();
|
|
381
377
|
|
|
382
|
-
|
|
378
|
+
let sessionId;
|
|
383
379
|
let authCode = null;
|
|
384
|
-
if (token) {
|
|
385
|
-
// Try to claim session (works for both new and existing sessions)
|
|
386
|
-
// For new sessions, this will create and claim
|
|
387
|
-
// For existing sessions, this will return the auth code if user owns it
|
|
388
|
-
authCode = await claimSession(sessionId, token, webUrl);
|
|
389
|
-
if (authCode && !options.sessionId) {
|
|
390
|
-
// Only show claim message for new sessions
|
|
391
|
-
console.log(' ✓ Session automatically claimed to your account\n');
|
|
392
|
-
}
|
|
393
|
-
}
|
|
394
380
|
|
|
395
|
-
//
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
} else {
|
|
406
|
-
// When reusing a session, show minimal info (no auth code)
|
|
381
|
+
// If session ID is provided, use it (existing session)
|
|
382
|
+
if (options.sessionId) {
|
|
383
|
+
sessionId = normalizeSessionId(options.sessionId);
|
|
384
|
+
|
|
385
|
+
// If token is available, try to claim the session
|
|
386
|
+
if (token) {
|
|
387
|
+
authCode = await claimSession(sessionId, token, webUrl);
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
// When reusing a session, show minimal info
|
|
407
391
|
console.log(` 🔍 Sending logs to session: ${sessionId}\n`);
|
|
392
|
+
} else {
|
|
393
|
+
// No session ID provided - create a new anonymous session
|
|
394
|
+
try {
|
|
395
|
+
const createUrl = `${webUrl}/api/sessions/create-anonymous`;
|
|
396
|
+
const response = await httpRequest(createUrl, {
|
|
397
|
+
method: 'POST',
|
|
398
|
+
headers: { 'Content-Type': 'application/json' },
|
|
399
|
+
});
|
|
400
|
+
|
|
401
|
+
if (!response.ok) {
|
|
402
|
+
const errorData = await response.json();
|
|
403
|
+
console.error(` ✗ Failed to create session: ${errorData.message || 'Unknown error'}`);
|
|
404
|
+
process.exit(1);
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
const data = await response.json();
|
|
408
|
+
sessionId = data.sessionId; // Server-generated unique session ID
|
|
409
|
+
authCode = data.authCode; // Server-generated auth code
|
|
410
|
+
|
|
411
|
+
// If token is available, claim the session
|
|
412
|
+
if (token) {
|
|
413
|
+
const claimAuthCode = await claimSession(sessionId, token, webUrl);
|
|
414
|
+
if (claimAuthCode) {
|
|
415
|
+
authCode = claimAuthCode;
|
|
416
|
+
console.log(' ✓ Session automatically claimed to your account\n');
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
// Print banner for new session
|
|
421
|
+
printBanner(sessionId, webUrl, authCode);
|
|
422
|
+
const localFlag = webUrl.includes('localhost') ? ' --local' : '';
|
|
423
|
+
const sessionSlug = sessionId.replace(/^vibex-/, ''); // Remove prefix for example
|
|
424
|
+
console.log(' 💡 Tip: Use -s to send more logs to this session');
|
|
425
|
+
console.log(` Example: echo '{"cpu": 45, "memory": 78}' | npx vibex-sh -s ${sessionSlug}${localFlag}\n`);
|
|
426
|
+
} catch (error) {
|
|
427
|
+
console.error(` ✗ Error creating session: ${error.message}`);
|
|
428
|
+
process.exit(1);
|
|
429
|
+
}
|
|
408
430
|
}
|
|
409
431
|
|
|
410
432
|
let socket = null;
|
|
@@ -475,14 +497,22 @@ async function main() {
|
|
|
475
497
|
break;
|
|
476
498
|
|
|
477
499
|
case 'error':
|
|
478
|
-
|
|
500
|
+
const errorType = message.error || 'Error';
|
|
501
|
+
const errorMsg = message.message || 'An unexpected error occurred';
|
|
502
|
+
const statusCode = message.statusCode || 0;
|
|
503
|
+
|
|
504
|
+
// Handle specific error types
|
|
505
|
+
if (errorType === 'Rate Limit Exceeded' || statusCode === 429) {
|
|
479
506
|
console.error('\n ⚠️ Rate Limit Exceeded');
|
|
480
|
-
console.error(` ${
|
|
507
|
+
console.error(` ${errorMsg}`);
|
|
508
|
+
if (message.retryAfter) {
|
|
509
|
+
console.error(` ⏱️ Retry after: ${message.retryAfter} seconds`);
|
|
510
|
+
}
|
|
481
511
|
console.error('');
|
|
482
512
|
logQueue.length = 0;
|
|
483
|
-
} else if (
|
|
513
|
+
} else if (errorType === 'History Limit Reached' || (statusCode === 403 && errorMsg.includes('History Limit'))) {
|
|
484
514
|
console.error('\n 🚫 History Limit Reached');
|
|
485
|
-
console.error(` ${
|
|
515
|
+
console.error(` ${errorMsg}`);
|
|
486
516
|
if (message.limit !== undefined && message.current !== undefined) {
|
|
487
517
|
console.error(` Current: ${message.current} / ${message.limit} logs`);
|
|
488
518
|
}
|
|
@@ -493,10 +523,69 @@ async function main() {
|
|
|
493
523
|
console.error('');
|
|
494
524
|
logQueue.length = 0;
|
|
495
525
|
hasJoinedSession = false;
|
|
526
|
+
} else if (statusCode === 401 || errorType === 'Unauthorized') {
|
|
527
|
+
if (errorMsg.includes('expired')) {
|
|
528
|
+
console.error('\n 🔑 Token Expired');
|
|
529
|
+
console.error(' Your authentication token has expired.');
|
|
530
|
+
console.error(' 💡 Run: npx vibex-sh login');
|
|
531
|
+
} else {
|
|
532
|
+
console.error('\n 🔑 Unauthorized');
|
|
533
|
+
console.error(` ${errorMsg}`);
|
|
534
|
+
console.error(' 💡 Run: npx vibex-sh login');
|
|
535
|
+
}
|
|
536
|
+
console.error('');
|
|
537
|
+
logQueue.length = 0;
|
|
538
|
+
hasJoinedSession = false;
|
|
539
|
+
} else if (statusCode === 403 || errorType === 'Forbidden') {
|
|
540
|
+
if (errorMsg.includes('access') || errorMsg.includes('belongs')) {
|
|
541
|
+
console.error('\n 🚫 Access Denied');
|
|
542
|
+
console.error(` ${errorMsg}`);
|
|
543
|
+
console.error(' 💡 This session belongs to another user or is not accessible');
|
|
544
|
+
console.error(' 💡 Make sure you are using the correct token and session ID');
|
|
545
|
+
} else if (errorMsg.includes('archived')) {
|
|
546
|
+
console.error('\n 🚫 Session Archived');
|
|
547
|
+
console.error(` ${errorMsg}`);
|
|
548
|
+
console.error(' 💡 This session is archived and cannot accept new logs');
|
|
549
|
+
} else {
|
|
550
|
+
console.error('\n 🚫 Forbidden');
|
|
551
|
+
console.error(` ${errorMsg}`);
|
|
552
|
+
}
|
|
553
|
+
console.error('');
|
|
554
|
+
logQueue.length = 0;
|
|
555
|
+
hasJoinedSession = false;
|
|
556
|
+
} else if (statusCode === 404 || errorType === 'Not Found') {
|
|
557
|
+
console.error('\n 🔍 Session Not Found');
|
|
558
|
+
console.error(` ${errorMsg}`);
|
|
559
|
+
console.error(' 💡 Make sure the session ID is correct');
|
|
560
|
+
console.error(' 💡 Check if the session exists in your dashboard');
|
|
561
|
+
console.error('');
|
|
562
|
+
logQueue.length = 0;
|
|
563
|
+
hasJoinedSession = false;
|
|
564
|
+
} else if (statusCode === 400 || errorType === 'Bad Request') {
|
|
565
|
+
console.error('\n 📝 Bad Request');
|
|
566
|
+
console.error(` ${errorMsg}`);
|
|
567
|
+
if (errorMsg.includes('sessionId')) {
|
|
568
|
+
console.error(' 💡 Make sure you provided a valid session ID with -s or --session');
|
|
569
|
+
} else if (errorMsg.includes('logs')) {
|
|
570
|
+
console.error(' 💡 Make sure you are sending valid log data');
|
|
571
|
+
}
|
|
572
|
+
console.error('');
|
|
573
|
+
logQueue.length = 0;
|
|
574
|
+
} else if (statusCode >= 500 || errorType === 'Internal Server Error') {
|
|
575
|
+
console.error('\n 🔴 Server Error');
|
|
576
|
+
console.error(` ${errorMsg}`);
|
|
577
|
+
console.error(' 💡 This is a server-side issue. Please try again later.');
|
|
578
|
+
console.error(' 💡 If the problem persists, contact support');
|
|
579
|
+
console.error('');
|
|
580
|
+
logQueue.length = 0;
|
|
496
581
|
} else {
|
|
497
|
-
console.error('\n ✗
|
|
498
|
-
console.error(` ${
|
|
582
|
+
console.error('\n ✗ Error');
|
|
583
|
+
console.error(` ${errorType}: ${errorMsg}`);
|
|
584
|
+
if (statusCode) {
|
|
585
|
+
console.error(` Status Code: ${statusCode}`);
|
|
586
|
+
}
|
|
499
587
|
console.error('');
|
|
588
|
+
logQueue.length = 0;
|
|
500
589
|
}
|
|
501
590
|
break;
|
|
502
591
|
|
|
@@ -544,12 +633,8 @@ async function main() {
|
|
|
544
633
|
|
|
545
634
|
// Send logs via HTTP POST (non-blocking, same as SDKs)
|
|
546
635
|
// Use Cloudflare Worker endpoint (port 8787 for local, or Worker URL for production)
|
|
636
|
+
// Token is optional - anonymous sessions can send logs without authentication
|
|
547
637
|
const sendLogViaHTTP = async (logData) => {
|
|
548
|
-
if (!token) {
|
|
549
|
-
console.error(' ✗ No token available for sending logs');
|
|
550
|
-
return;
|
|
551
|
-
}
|
|
552
|
-
|
|
553
638
|
try {
|
|
554
639
|
// Determine ingest URL
|
|
555
640
|
let ingestUrl;
|
|
@@ -567,12 +652,17 @@ async function main() {
|
|
|
567
652
|
|
|
568
653
|
console.log(` 📤 Sending log to: ${ingestUrl}`);
|
|
569
654
|
|
|
655
|
+
// Build headers - only include Authorization if token exists
|
|
656
|
+
const headers = {
|
|
657
|
+
'Content-Type': 'application/json',
|
|
658
|
+
};
|
|
659
|
+
if (token) {
|
|
660
|
+
headers['Authorization'] = `Bearer ${token}`;
|
|
661
|
+
}
|
|
662
|
+
|
|
570
663
|
const response = await fetch(ingestUrl, {
|
|
571
664
|
method: 'POST',
|
|
572
|
-
headers
|
|
573
|
-
'Authorization': `Bearer ${token}`,
|
|
574
|
-
'Content-Type': 'application/json',
|
|
575
|
-
},
|
|
665
|
+
headers,
|
|
576
666
|
body: JSON.stringify({
|
|
577
667
|
sessionId,
|
|
578
668
|
logs: [logData],
|
|
@@ -581,18 +671,83 @@ async function main() {
|
|
|
581
671
|
|
|
582
672
|
if (!response.ok) {
|
|
583
673
|
const errorData = await response.json().catch(() => ({}));
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
674
|
+
const errorMessage = errorData.message || response.statusText || 'Unknown error';
|
|
675
|
+
|
|
676
|
+
console.error(`\n ✗ HTTP ${response.status}: ${errorMessage}`);
|
|
677
|
+
|
|
678
|
+
// Handle specific error cases
|
|
679
|
+
if (response.status === 401) {
|
|
680
|
+
if (errorMessage.includes('expired')) {
|
|
681
|
+
console.error('\n 🔑 Token Expired');
|
|
682
|
+
console.error(' Your authentication token has expired.');
|
|
683
|
+
console.error(' 💡 Run: npx vibex-sh login');
|
|
684
|
+
console.error('');
|
|
685
|
+
} else if (errorMessage.includes('Invalid') || errorMessage.includes('invalid')) {
|
|
686
|
+
console.error('\n 🔑 Invalid Token');
|
|
687
|
+
console.error(' Your authentication token is invalid or missing.');
|
|
688
|
+
console.error(' 💡 Run: npx vibex-sh login');
|
|
689
|
+
console.error('');
|
|
690
|
+
} else {
|
|
691
|
+
console.error('\n 🔑 Unauthorized');
|
|
692
|
+
console.error(` ${errorMessage}`);
|
|
693
|
+
console.error(' 💡 Run: npx vibex-sh login');
|
|
694
|
+
console.error('');
|
|
695
|
+
}
|
|
696
|
+
} else if (response.status === 400) {
|
|
697
|
+
console.error('\n 📝 Bad Request');
|
|
698
|
+
console.error(` ${errorMessage}`);
|
|
699
|
+
if (errorMessage.includes('sessionId')) {
|
|
700
|
+
console.error(' 💡 Make sure you provided a valid session ID with -s or --session');
|
|
701
|
+
} else if (errorMessage.includes('logs')) {
|
|
702
|
+
console.error(' 💡 Make sure you are sending valid log data');
|
|
703
|
+
}
|
|
588
704
|
console.error('');
|
|
589
|
-
} else if (response.status === 403
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
705
|
+
} else if (response.status === 403) {
|
|
706
|
+
if (errorMessage.includes('History Limit')) {
|
|
707
|
+
console.error('\n 🚫 History Limit Reached');
|
|
708
|
+
console.error(` ${errorMessage}`);
|
|
709
|
+
if (errorData.upgradeRequired) {
|
|
710
|
+
console.error(' 💡 Upgrade to Pro to unlock 30 days retention');
|
|
711
|
+
console.error(' 🌐 Visit: https://vibex.sh/pricing');
|
|
712
|
+
}
|
|
713
|
+
console.error('');
|
|
714
|
+
} else if (errorMessage.includes('access') || errorMessage.includes('belongs')) {
|
|
715
|
+
console.error('\n 🚫 Access Denied');
|
|
716
|
+
console.error(` ${errorMessage}`);
|
|
717
|
+
console.error(' 💡 This session belongs to another user or is not accessible');
|
|
718
|
+
console.error(' 💡 Make sure you are using the correct token and session ID');
|
|
719
|
+
console.error('');
|
|
720
|
+
} else if (errorMessage.includes('archived')) {
|
|
721
|
+
console.error('\n 🚫 Session Archived');
|
|
722
|
+
console.error(` ${errorMessage}`);
|
|
723
|
+
console.error(' 💡 This session is archived and cannot accept new logs');
|
|
724
|
+
console.error('');
|
|
725
|
+
} else {
|
|
726
|
+
console.error('\n 🚫 Forbidden');
|
|
727
|
+
console.error(` ${errorMessage}`);
|
|
728
|
+
console.error('');
|
|
595
729
|
}
|
|
730
|
+
} else if (response.status === 404) {
|
|
731
|
+
console.error('\n 🔍 Session Not Found');
|
|
732
|
+
console.error(` ${errorMessage}`);
|
|
733
|
+
console.error(' 💡 Make sure the session ID is correct');
|
|
734
|
+
console.error(' 💡 Check if the session exists in your dashboard');
|
|
735
|
+
console.error('');
|
|
736
|
+
} else if (response.status === 429) {
|
|
737
|
+
console.error('\n ⚠️ Rate Limit Exceeded');
|
|
738
|
+
console.error(` ${errorMessage}`);
|
|
739
|
+
if (errorData.retryAfter) {
|
|
740
|
+
console.error(` ⏱️ Retry after: ${errorData.retryAfter} seconds`);
|
|
741
|
+
}
|
|
742
|
+
console.error('');
|
|
743
|
+
} else if (response.status >= 500) {
|
|
744
|
+
console.error('\n 🔴 Server Error');
|
|
745
|
+
console.error(` ${errorMessage}`);
|
|
746
|
+
console.error(' 💡 This is a server-side issue. Please try again later.');
|
|
747
|
+
console.error(' 💡 If the problem persists, contact support');
|
|
748
|
+
console.error('');
|
|
749
|
+
} else {
|
|
750
|
+
console.error(` ${errorMessage}`);
|
|
596
751
|
console.error('');
|
|
597
752
|
}
|
|
598
753
|
} else {
|