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.
Files changed (2) hide show
  1. package/index.js +212 -57
  2. 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
- import crypto from 'crypto';
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
- // Generate secure random session ID with 12 characters (as per security plan)
36
- // Format: vibex-{12 random alphanumeric chars}
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
- // Auto-claim session if token is available and fetch auth code
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
- // For unclaimed sessions, auth code will come from socket.io 'session-auth-code' event
396
- // We'll set it when we receive it from the socket
397
-
398
- // Print banner only once, and show how to reuse session
399
- if (!options.sessionId) {
400
- printBanner(sessionId, webUrl, authCode);
401
- const localFlag = webUrl.includes('localhost') ? ' --local' : '';
402
- const sessionSlug = sessionId.replace(/^vibex-/, ''); // Remove prefix for example
403
- console.log(' 💡 Tip: Use -s to send more logs to this session');
404
- console.log(` Example: echo '{"cpu": 45, "memory": 78}' | npx vibex-sh -s ${sessionSlug}${localFlag}\n`);
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
- if (message.error === 'Rate Limit Exceeded') {
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(` ${message.message || 'Too many requests. Please try again later.'}`);
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 (message.error === 'History Limit Reached') {
513
+ } else if (errorType === 'History Limit Reached' || (statusCode === 403 && errorMsg.includes('History Limit'))) {
484
514
  console.error('\n 🚫 History Limit Reached');
485
- console.error(` ${message.message || 'Session history limit reached'}`);
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 ✗ Server Error');
498
- console.error(` ${message.error || message.message || 'An unexpected error occurred'}`);
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
- console.error(` ✗ HTTP ${response.status}: ${errorData.message || response.statusText}`);
585
- if (response.status === 429) {
586
- console.error('\n ⚠️ Rate Limit Exceeded');
587
- console.error(` ${errorData.message || 'Too many requests. Please try again later.'}`);
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 && errorData.message?.includes('History Limit')) {
590
- console.error('\n 🚫 History Limit Reached');
591
- console.error(` ${errorData.message || 'Session history limit reached'}`);
592
- if (errorData.upgradeRequired) {
593
- console.error(' 💡 Upgrade to Pro to unlock 30 days retention');
594
- console.error(' 🌐 Visit: https://vibex.sh/pricing');
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 {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vibex-sh",
3
- "version": "0.9.2",
3
+ "version": "0.9.4",
4
4
  "description": "Zero-config observability CLI - pipe logs and visualize instantly",
5
5
  "type": "module",
6
6
  "bin": {