@juspay/neurolink 9.84.0 → 9.84.2

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.
@@ -444,6 +444,47 @@ function isMetadataLine(lines) {
444
444
  }
445
445
  return false;
446
446
  }
447
+ /**
448
+ * Split CSV text into logical rows for metadata detection and raw row limiting.
449
+ *
450
+ * Supports Unix (LF), Windows (CRLF), and classic Mac (CR) line endings, and is
451
+ * quote-aware: a line ending that appears *inside* a quoted field (RFC 4180) is
452
+ * kept as part of that field rather than treated as a row boundary. A doubled
453
+ * `""` inside quotes is the RFC-4180 escaped quote and does not toggle the quote
454
+ * state. For unquoted input this yields exactly the same result as a plain
455
+ * `split(/\r\n|\n|\r/)`.
456
+ */
457
+ function splitCsvLines(csvString) {
458
+ const rows = [];
459
+ let current = "";
460
+ let inQuotes = false;
461
+ for (let i = 0; i < csvString.length; i++) {
462
+ const ch = csvString[i];
463
+ if (ch === '"') {
464
+ if (inQuotes && csvString[i + 1] === '"') {
465
+ // Escaped quote ("") — stays inside the field, quote state unchanged.
466
+ current += '""';
467
+ i++;
468
+ continue;
469
+ }
470
+ inQuotes = !inQuotes;
471
+ current += ch;
472
+ }
473
+ else if (!inQuotes && (ch === "\n" || ch === "\r")) {
474
+ // Row boundary outside quotes; collapse CRLF into a single boundary.
475
+ if (ch === "\r" && csvString[i + 1] === "\n") {
476
+ i++;
477
+ }
478
+ rows.push(current);
479
+ current = "";
480
+ }
481
+ else {
482
+ current += ch;
483
+ }
484
+ }
485
+ rows.push(current);
486
+ return rows;
487
+ }
447
488
  /**
448
489
  * CSV processor for converting CSV data to LLM-optimized formats
449
490
  *
@@ -483,10 +524,10 @@ export class CSVProcessor {
483
524
  includeHeaders,
484
525
  });
485
526
  const csvString = content.toString("utf-8");
486
- // For raw format, return original CSV with row limit (no parsing needed)
487
- // This preserves the exact original format which works best for LLMs
527
+ // For raw format, return CSV text with row limit (no parsing needed)
528
+ // This preserves the CSV shape while normalizing line endings for row handling.
488
529
  if (formatStyle === "raw") {
489
- const lines = csvString.split("\n");
530
+ const lines = splitCsvLines(csvString);
490
531
  const hasMetadataLine = isMetadataLine(lines);
491
532
  if (hasMetadataLine) {
492
533
  logger.debug("[CSVProcessor] Detected metadata line, skipping first line");
@@ -649,7 +690,10 @@ export class CSVProcessor {
649
690
  let buffer = "";
650
691
  lineReader.on("data", (chunk) => {
651
692
  buffer += chunk.toString();
652
- const lines = buffer.split("\n");
693
+ const splitBuffer = buffer.endsWith("\r")
694
+ ? buffer.slice(0, -1)
695
+ : buffer;
696
+ const lines = splitCsvLines(splitBuffer);
653
697
  if (lines.length >= 2) {
654
698
  firstLines.push(lines[0], lines[1]);
655
699
  lineReader.destroy();
@@ -714,9 +758,11 @@ export class CSVProcessor {
714
758
  maxRows: clampedMaxRows,
715
759
  });
716
760
  // Detect and skip metadata line
717
- const lines = csvString.split("\n");
761
+ const lines = splitCsvLines(csvString);
718
762
  const hasMetadataLine = isMetadataLine(lines);
719
- const csvData = hasMetadataLine ? lines.slice(1).join("\n") : csvString;
763
+ const csvData = hasMetadataLine
764
+ ? lines.slice(1).join("\n")
765
+ : lines.join("\n");
720
766
  if (hasMetadataLine) {
721
767
  logger.debug("[CSVProcessor] Detected metadata line in string, skipping");
722
768
  }
@@ -773,7 +819,10 @@ export class CSVProcessor {
773
819
  }
774
820
  const headers = Object.keys(rows[0]);
775
821
  // Escape backslashes, pipes, and sanitize newlines to keep rows intact
776
- const escapePipe = (str) => str.replace(/\\/g, "\\\\").replace(/\|/g, "\\|").replace(/\r?\n/g, " ");
822
+ const escapePipe = (str) => str
823
+ .replace(/\\/g, "\\\\")
824
+ .replace(/\|/g, "\\|")
825
+ .replace(/\r\n|\n|\r/g, " ");
777
826
  let markdown = "";
778
827
  if (includeHeaders) {
779
828
  markdown = "| " + headers.map(escapePipe).join(" | ") + " |\n";
@@ -828,7 +877,9 @@ export class CSVProcessor {
828
877
  const headers = Object.keys(rows[0]);
829
878
  // Escape CSV values (wrap in quotes if contains comma, quote, or newline)
830
879
  const escapeCSV = (value) => {
831
- if (value.includes(",") || value.includes('"') || value.includes("\n")) {
880
+ if (value.includes(",") ||
881
+ value.includes('"') ||
882
+ /\r\n|\n|\r/.test(value)) {
832
883
  return `"${value.replace(/"/g, '""')}"`;
833
884
  }
834
885
  return value;
@@ -444,6 +444,47 @@ function isMetadataLine(lines) {
444
444
  }
445
445
  return false;
446
446
  }
447
+ /**
448
+ * Split CSV text into logical rows for metadata detection and raw row limiting.
449
+ *
450
+ * Supports Unix (LF), Windows (CRLF), and classic Mac (CR) line endings, and is
451
+ * quote-aware: a line ending that appears *inside* a quoted field (RFC 4180) is
452
+ * kept as part of that field rather than treated as a row boundary. A doubled
453
+ * `""` inside quotes is the RFC-4180 escaped quote and does not toggle the quote
454
+ * state. For unquoted input this yields exactly the same result as a plain
455
+ * `split(/\r\n|\n|\r/)`.
456
+ */
457
+ function splitCsvLines(csvString) {
458
+ const rows = [];
459
+ let current = "";
460
+ let inQuotes = false;
461
+ for (let i = 0; i < csvString.length; i++) {
462
+ const ch = csvString[i];
463
+ if (ch === '"') {
464
+ if (inQuotes && csvString[i + 1] === '"') {
465
+ // Escaped quote ("") — stays inside the field, quote state unchanged.
466
+ current += '""';
467
+ i++;
468
+ continue;
469
+ }
470
+ inQuotes = !inQuotes;
471
+ current += ch;
472
+ }
473
+ else if (!inQuotes && (ch === "\n" || ch === "\r")) {
474
+ // Row boundary outside quotes; collapse CRLF into a single boundary.
475
+ if (ch === "\r" && csvString[i + 1] === "\n") {
476
+ i++;
477
+ }
478
+ rows.push(current);
479
+ current = "";
480
+ }
481
+ else {
482
+ current += ch;
483
+ }
484
+ }
485
+ rows.push(current);
486
+ return rows;
487
+ }
447
488
  /**
448
489
  * CSV processor for converting CSV data to LLM-optimized formats
449
490
  *
@@ -483,10 +524,10 @@ export class CSVProcessor {
483
524
  includeHeaders,
484
525
  });
485
526
  const csvString = content.toString("utf-8");
486
- // For raw format, return original CSV with row limit (no parsing needed)
487
- // This preserves the exact original format which works best for LLMs
527
+ // For raw format, return CSV text with row limit (no parsing needed)
528
+ // This preserves the CSV shape while normalizing line endings for row handling.
488
529
  if (formatStyle === "raw") {
489
- const lines = csvString.split("\n");
530
+ const lines = splitCsvLines(csvString);
490
531
  const hasMetadataLine = isMetadataLine(lines);
491
532
  if (hasMetadataLine) {
492
533
  logger.debug("[CSVProcessor] Detected metadata line, skipping first line");
@@ -649,7 +690,10 @@ export class CSVProcessor {
649
690
  let buffer = "";
650
691
  lineReader.on("data", (chunk) => {
651
692
  buffer += chunk.toString();
652
- const lines = buffer.split("\n");
693
+ const splitBuffer = buffer.endsWith("\r")
694
+ ? buffer.slice(0, -1)
695
+ : buffer;
696
+ const lines = splitCsvLines(splitBuffer);
653
697
  if (lines.length >= 2) {
654
698
  firstLines.push(lines[0], lines[1]);
655
699
  lineReader.destroy();
@@ -714,9 +758,11 @@ export class CSVProcessor {
714
758
  maxRows: clampedMaxRows,
715
759
  });
716
760
  // Detect and skip metadata line
717
- const lines = csvString.split("\n");
761
+ const lines = splitCsvLines(csvString);
718
762
  const hasMetadataLine = isMetadataLine(lines);
719
- const csvData = hasMetadataLine ? lines.slice(1).join("\n") : csvString;
763
+ const csvData = hasMetadataLine
764
+ ? lines.slice(1).join("\n")
765
+ : lines.join("\n");
720
766
  if (hasMetadataLine) {
721
767
  logger.debug("[CSVProcessor] Detected metadata line in string, skipping");
722
768
  }
@@ -773,7 +819,10 @@ export class CSVProcessor {
773
819
  }
774
820
  const headers = Object.keys(rows[0]);
775
821
  // Escape backslashes, pipes, and sanitize newlines to keep rows intact
776
- const escapePipe = (str) => str.replace(/\\/g, "\\\\").replace(/\|/g, "\\|").replace(/\r?\n/g, " ");
822
+ const escapePipe = (str) => str
823
+ .replace(/\\/g, "\\\\")
824
+ .replace(/\|/g, "\\|")
825
+ .replace(/\r\n|\n|\r/g, " ");
777
826
  let markdown = "";
778
827
  if (includeHeaders) {
779
828
  markdown = "| " + headers.map(escapePipe).join(" | ") + " |\n";
@@ -828,7 +877,9 @@ export class CSVProcessor {
828
877
  const headers = Object.keys(rows[0]);
829
878
  // Escape CSV values (wrap in quotes if contains comma, quote, or newline)
830
879
  const escapeCSV = (value) => {
831
- if (value.includes(",") || value.includes('"') || value.includes("\n")) {
880
+ if (value.includes(",") ||
881
+ value.includes('"') ||
882
+ /\r\n|\n|\r/.test(value)) {
832
883
  return `"${value.replace(/"/g, '""')}"`;
833
884
  }
834
885
  return value;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@juspay/neurolink",
3
- "version": "9.84.0",
3
+ "version": "9.84.2",
4
4
  "packageManager": "pnpm@10.15.1",
5
5
  "description": "Universal AI Development Platform with working MCP integration, multi-provider support, voice (TTS/STT/realtime), and professional CLI. 58+ external MCP servers discoverable, multimodal file processing, RAG pipelines. Build, test, and deploy AI applications with 21+ providers: OpenAI, Anthropic, Google AI Studio, Google Vertex, AWS Bedrock, Azure OpenAI, Mistral, LiteLLM, SageMaker, Hugging Face, Ollama, OpenAI-compatible, OpenRouter, DeepSeek, NVIDIA NIM, LM Studio, llama.cpp, plus voice (OpenAI TTS, ElevenLabs, Deepgram, Azure Speech).",
6
6
  "author": {
@@ -44,6 +44,7 @@
44
44
  "build:react-hooks": "npx tsc --jsx react-jsx --module nodenext --moduleResolution nodenext --target esnext --esModuleInterop --skipLibCheck --outDir dist --declaration false src/lib/client/reactHooks.tsx",
45
45
  "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json && tsc --noEmit --strict",
46
46
  "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch",
47
+ "typecheck": "tsc --noEmit",
47
48
  "modelServer": "tsx scripts/modelServer.ts",
48
49
  "lint": "prettier --check . && NODE_OPTIONS='--max-old-space-size=8192' eslint .",
49
50
  "format": "prettier --write .",
@@ -341,7 +342,7 @@
341
342
  "@modelcontextprotocol/sdk": "^1.27.1",
342
343
  "@opentelemetry/api-logs": "^0.214.0",
343
344
  "@opentelemetry/context-async-hooks": "^2.6.1",
344
- "@opentelemetry/core": "^2.6.0",
345
+ "@opentelemetry/core": "^2.8.0",
345
346
  "@opentelemetry/exporter-logs-otlp-http": "^0.214.0",
346
347
  "@opentelemetry/exporter-metrics-otlp-http": "^0.214.0",
347
348
  "@opentelemetry/exporter-trace-otlp-http": "^0.214.0",
@@ -476,7 +477,7 @@
476
477
  "esbuild": "^0.28.1",
477
478
  "eslint": "^10.0.2",
478
479
  "husky": "^9.1.7",
479
- "js-yaml": "^4.1.1",
480
+ "js-yaml": "^4.2.0",
480
481
  "lint-staged": "^16.3.0",
481
482
  "playwright": "^1.58.2",
482
483
  "prettier": "^3.8.1",