vibex-sh 0.11.0 → 0.11.1

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 +108 -17
  2. package/package.json +1 -1
package/index.js CHANGED
@@ -17,6 +17,7 @@ const MAX_POLL_ATTEMPTS = 60;
17
17
  const WEBSOCKET_CLOSE_TIMEOUT_MS = 2000;
18
18
  const DEFAULT_WORKER_URL = 'https://ingest.vibex.sh';
19
19
  const DEFAULT_WEB_URL = 'https://vibex.sh';
20
+ const PIPED_INPUT_DELAY_MS = parseInt(process.env.VIBEX_PIPE_DELAY_MS || '300', 10);
20
21
 
21
22
  // Get version from package.json
22
23
  const __filename = fileURLToPath(import.meta.url);
@@ -389,24 +390,38 @@ async function handleInit(options) {
389
390
  ];
390
391
  }
391
392
 
392
- // Filter out mandatory parsers for selection (if any)
393
- const selectableParsers = availableParsers.filter(p => !p.isMandatory);
393
+ // Mandatory parsers that are always included
394
+ const mandatoryParserIds = ['json-in-text', 'raw', 'keyvalue', 'stacktrace', 'smart-pattern'];
394
395
 
395
- console.log(' What kind of logs are these? (Optional - leave empty for auto-detection)');
396
+ // Filter out mandatory parsers for selection (only optional parsers can be selected)
397
+ const selectableParsers = availableParsers.filter(p => !mandatoryParserIds.includes(p.id) && !p.isMandatory);
398
+
399
+ // Pre-select mandatory parsers
400
+ let enabledParsers = [...mandatoryParserIds];
401
+
402
+ console.log(' Mandatory parsers are automatically included:');
403
+ mandatoryParserIds.forEach(id => {
404
+ const parser = availableParsers.find(p => p.id === id);
405
+ if (parser) {
406
+ console.log(` ✓ ${parser.name}`);
407
+ }
408
+ });
409
+ console.log('');
410
+
411
+ console.log(' Select additional optional parsers (leave empty for mandatory only):');
396
412
  if (selectableParsers.length > 0) {
397
- console.log(' Available log types:');
413
+ console.log(' Available optional parsers:');
398
414
  selectableParsers.forEach((p, i) => {
399
415
  console.log(` ${i + 1}. ${p.name} (${p.id})`);
400
416
  });
401
- console.log(' (Leave empty for auto-detection)\n');
417
+ console.log(' (Leave empty for mandatory parsers only)\n');
402
418
  } else {
403
- console.log(' Available log types: (Leave empty for auto-detection)\n');
419
+ console.log(' No additional optional parsers available.\n');
404
420
  }
405
421
 
406
- const answer = await question(' Enter comma-separated numbers or parser IDs (e.g., 1,2 or nginx,apache): ');
422
+ const answer = await question(' Enter comma-separated numbers or parser IDs (e.g., 1,2 or docker,kubernetes): ');
407
423
  rl.close();
408
424
 
409
- let enabledParsers = [];
410
425
  if (answer.trim()) {
411
426
  const selections = answer.split(',').map(s => s.trim());
412
427
  selections.forEach(sel => {
@@ -424,7 +439,9 @@ async function handleInit(options) {
424
439
  const parserFlag = options.parser || options.parsers;
425
440
  if (parserFlag) {
426
441
  if (typeof parserFlag === 'string') {
427
- enabledParsers = parserFlag.split(',').map(p => p.trim());
442
+ // Add optional parsers from flag, but always include mandatory
443
+ const flagParsers = parserFlag.split(',').map(p => p.trim());
444
+ enabledParsers = [...new Set([...mandatoryParserIds, ...flagParsers])];
428
445
  }
429
446
  }
430
447
 
@@ -466,10 +483,18 @@ async function handleInit(options) {
466
483
 
467
484
  console.log('\n ✅ Session created successfully!\n');
468
485
  printBanner(createdSessionId, createdAuthCode);
469
- if (enabledParsers.length > 0) {
470
- console.log(` 📋 Log Types: ${enabledParsers.join(', ')}`);
471
- } else {
472
- console.log(' 📋 Log Types: Auto-detection (default parsers)');
486
+
487
+ // Separate mandatory and optional parsers for display
488
+ const mandatoryIncluded = enabledParsers.filter(id => mandatoryParserIds.includes(id));
489
+ const optionalIncluded = enabledParsers.filter(id => !mandatoryParserIds.includes(id));
490
+
491
+ if (mandatoryIncluded.length > 0) {
492
+ console.log(` 📋 Mandatory parsers: ${mandatoryIncluded.join(', ')}`);
493
+ }
494
+ if (optionalIncluded.length > 0) {
495
+ console.log(` 📋 Optional parsers: ${optionalIncluded.join(', ')}`);
496
+ } else if (mandatoryIncluded.length === mandatoryParserIds.length) {
497
+ console.log(' 📋 Using mandatory parsers only');
473
498
  }
474
499
  console.log(`\n 💡 Use this session ID: ${createdSessionId}`);
475
500
  console.log(` Example: echo '{"cpu": 45}' | npx vibex-sh -s ${createdSessionId}\n`);
@@ -1036,6 +1061,56 @@ async function handleSendLogs(options) {
1036
1061
  process.exit(0);
1037
1062
  }
1038
1063
 
1064
+ // Rate limiting queue for piped input
1065
+ const pipedLogQueue = [];
1066
+ let isProcessingQueue = false;
1067
+ let queueProcessingTimeout = null;
1068
+
1069
+ const processPipedLogQueue = async () => {
1070
+ if (isProcessingQueue) {
1071
+ return;
1072
+ }
1073
+
1074
+ if (pipedLogQueue.length === 0) {
1075
+ return;
1076
+ }
1077
+
1078
+ isProcessingQueue = true;
1079
+
1080
+ try {
1081
+ while (pipedLogQueue.length > 0) {
1082
+ const logData = pipedLogQueue.shift();
1083
+ await sendLogViaHTTP(logData);
1084
+
1085
+ // Wait before sending the next log (only if there are more logs in queue)
1086
+ if (pipedLogQueue.length > 0) {
1087
+ await new Promise(resolve => setTimeout(resolve, PIPED_INPUT_DELAY_MS));
1088
+ }
1089
+ }
1090
+ } finally {
1091
+ isProcessingQueue = false;
1092
+ }
1093
+ };
1094
+
1095
+ const queuePipedLog = (logData) => {
1096
+ pipedLogQueue.push(logData);
1097
+
1098
+ // Start processing if not already processing
1099
+ if (!isProcessingQueue) {
1100
+ // Clear any existing timeout
1101
+ if (queueProcessingTimeout) {
1102
+ clearTimeout(queueProcessingTimeout);
1103
+ queueProcessingTimeout = null;
1104
+ }
1105
+ // Process queue with a small initial delay to batch rapid inputs
1106
+ queueProcessingTimeout = setTimeout(() => {
1107
+ processPipedLogQueue().catch((error) => {
1108
+ console.error(' ✗ Error processing log queue:', error.message);
1109
+ });
1110
+ }, 10);
1111
+ }
1112
+ };
1113
+
1039
1114
  const rl = readline.createInterface({
1040
1115
  input: process.stdin,
1041
1116
  output: process.stdout,
@@ -1086,13 +1161,29 @@ async function handleSendLogs(options) {
1086
1161
  };
1087
1162
  }
1088
1163
 
1089
- // Send logs via HTTP POST immediately - don't wait for WebSocket
1090
- // WebSocket is only for receiving logs and auth codes, not required for sending
1091
- sendLogViaHTTP(logData);
1164
+ // Queue logs for rate-limited sending when input is piped
1165
+ // This prevents overwhelming rate limits when piping large files
1166
+ queuePipedLog(logData);
1092
1167
  });
1093
1168
 
1094
1169
  rl.on('close', async () => {
1095
- // Wait for queued logs to be sent
1170
+ // Clear any pending queue processing timeout
1171
+ if (queueProcessingTimeout) {
1172
+ clearTimeout(queueProcessingTimeout);
1173
+ queueProcessingTimeout = null;
1174
+ }
1175
+
1176
+ // Process any remaining logs in the piped queue
1177
+ // Keep processing until queue is empty and not currently processing
1178
+ while (pipedLogQueue.length > 0 || isProcessingQueue) {
1179
+ await processPipedLogQueue();
1180
+ // Small delay to allow processing to complete
1181
+ if (pipedLogQueue.length > 0 || isProcessingQueue) {
1182
+ await new Promise(resolve => setTimeout(resolve, 50));
1183
+ }
1184
+ }
1185
+
1186
+ // Wait for queued logs to be sent (WebSocket queue)
1096
1187
  const waitForQueue = () => {
1097
1188
  return new Promise((resolve) => {
1098
1189
  if (logQueue.length === 0) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vibex-sh",
3
- "version": "0.11.0",
3
+ "version": "0.11.1",
4
4
  "description": "Zero-config observability CLI - pipe logs and visualize instantly",
5
5
  "type": "module",
6
6
  "bin": {