@juspay/neurolink 9.88.6 → 9.88.7

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.
@@ -337,6 +337,20 @@ function calculateDataQualityScore(columns, warnings, totalRows) {
337
337
  /**
338
338
  * Analyze all columns in parsed CSV data
339
339
  */
340
+ /**
341
+ * Confidence for a CSV processing result, weighted by data quality.
342
+ *
343
+ * The result used to report a static `confidence: 100` regardless of how clean
344
+ * the data was. This ties confidence to `dataQualityScore` so it actually
345
+ * varies with quality factors (ragged rows, high null rate, type
346
+ * inconsistency): a cleanly-parsed CSV stays at 100, a messy one is pulled
347
+ * halfway toward its quality score. It never drops below 50 for a CSV that
348
+ * parsed — the *format* is certain, only the *data* is imperfect.
349
+ */
350
+ function csvResultConfidence(dataQualityScore) {
351
+ const clamped = Math.max(0, Math.min(100, dataQualityScore));
352
+ return Math.round((100 + clamped) / 2);
353
+ }
340
354
  function analyzeColumns(rows) {
341
355
  if (rows.length === 0) {
342
356
  return {
@@ -574,7 +588,7 @@ export class CSVProcessor {
574
588
  content: limitedCSV,
575
589
  mimeType: "text/csv",
576
590
  metadata: {
577
- confidence: 100,
591
+ confidence: csvResultConfidence(dataQualityScore),
578
592
  size: content.length,
579
593
  rowCount,
580
594
  totalLines: limitedLines.length,
@@ -648,7 +662,7 @@ export class CSVProcessor {
648
662
  content: formatted,
649
663
  mimeType: "text/csv",
650
664
  metadata: {
651
- confidence: 100,
665
+ confidence: csvResultConfidence(dataQualityScore),
652
666
  size: content.length,
653
667
  rowCount,
654
668
  columnCount,
@@ -2166,13 +2166,38 @@ class ContentHeuristicStrategy {
2166
2166
  const hasUniformLengths = stdDev / avgLength < 0.75;
2167
2167
  return hasReasonableLengths && noBinaryChars && hasUniformLengths;
2168
2168
  }
2169
- // Count delimiters per line and check consistency
2170
- const delimRegex = delimiter === "|" ? /\|/g : new RegExp(delimiter, "g");
2171
- const counts = lines.map((line) => (line.match(delimRegex) || []).length);
2169
+ // Count delimiters per line and check consistency. Delimiters inside a
2170
+ // double-quoted field are field content, not column separators (RFC 4180)
2171
+ // a naive count inflates rows with quoted delimiters (e.g. `"Smith, John"`),
2172
+ // which used to make consistency collapse and reject a valid CSV.
2173
+ const counts = lines.map((line) => ContentHeuristicStrategy.countDelimitersOutsideQuotes(line, delimiter));
2172
2174
  const firstCount = counts[0];
2173
2175
  const consistentLines = counts.filter((c) => c === firstCount).length;
2174
2176
  return consistentLines / lines.length >= 0.8;
2175
2177
  }
2178
+ /**
2179
+ * Count occurrences of `delimiter` in `line` that fall OUTSIDE double-quoted
2180
+ * fields, honoring RFC-4180 escaped quotes (`""`). Used by CSV detection so a
2181
+ * delimiter embedded in a quoted value is not mistaken for a column break.
2182
+ */
2183
+ static countDelimitersOutsideQuotes(line, delimiter) {
2184
+ let count = 0;
2185
+ let inQuotes = false;
2186
+ for (let i = 0; i < line.length; i++) {
2187
+ const ch = line[i];
2188
+ if (ch === '"') {
2189
+ if (inQuotes && line[i + 1] === '"') {
2190
+ i++; // escaped quote inside a quoted field — skip the pair
2191
+ continue;
2192
+ }
2193
+ inQuotes = !inQuotes;
2194
+ }
2195
+ else if (ch === delimiter && !inQuotes) {
2196
+ count++;
2197
+ }
2198
+ }
2199
+ return count;
2200
+ }
2176
2201
  looksLikeJSON(text) {
2177
2202
  // hasJsonMarkers now does full validation including JSON.parse
2178
2203
  return hasJsonMarkers(text);
@@ -337,6 +337,20 @@ function calculateDataQualityScore(columns, warnings, totalRows) {
337
337
  /**
338
338
  * Analyze all columns in parsed CSV data
339
339
  */
340
+ /**
341
+ * Confidence for a CSV processing result, weighted by data quality.
342
+ *
343
+ * The result used to report a static `confidence: 100` regardless of how clean
344
+ * the data was. This ties confidence to `dataQualityScore` so it actually
345
+ * varies with quality factors (ragged rows, high null rate, type
346
+ * inconsistency): a cleanly-parsed CSV stays at 100, a messy one is pulled
347
+ * halfway toward its quality score. It never drops below 50 for a CSV that
348
+ * parsed — the *format* is certain, only the *data* is imperfect.
349
+ */
350
+ function csvResultConfidence(dataQualityScore) {
351
+ const clamped = Math.max(0, Math.min(100, dataQualityScore));
352
+ return Math.round((100 + clamped) / 2);
353
+ }
340
354
  function analyzeColumns(rows) {
341
355
  if (rows.length === 0) {
342
356
  return {
@@ -574,7 +588,7 @@ export class CSVProcessor {
574
588
  content: limitedCSV,
575
589
  mimeType: "text/csv",
576
590
  metadata: {
577
- confidence: 100,
591
+ confidence: csvResultConfidence(dataQualityScore),
578
592
  size: content.length,
579
593
  rowCount,
580
594
  totalLines: limitedLines.length,
@@ -648,7 +662,7 @@ export class CSVProcessor {
648
662
  content: formatted,
649
663
  mimeType: "text/csv",
650
664
  metadata: {
651
- confidence: 100,
665
+ confidence: csvResultConfidence(dataQualityScore),
652
666
  size: content.length,
653
667
  rowCount,
654
668
  columnCount,
@@ -2166,13 +2166,38 @@ class ContentHeuristicStrategy {
2166
2166
  const hasUniformLengths = stdDev / avgLength < 0.75;
2167
2167
  return hasReasonableLengths && noBinaryChars && hasUniformLengths;
2168
2168
  }
2169
- // Count delimiters per line and check consistency
2170
- const delimRegex = delimiter === "|" ? /\|/g : new RegExp(delimiter, "g");
2171
- const counts = lines.map((line) => (line.match(delimRegex) || []).length);
2169
+ // Count delimiters per line and check consistency. Delimiters inside a
2170
+ // double-quoted field are field content, not column separators (RFC 4180)
2171
+ // a naive count inflates rows with quoted delimiters (e.g. `"Smith, John"`),
2172
+ // which used to make consistency collapse and reject a valid CSV.
2173
+ const counts = lines.map((line) => ContentHeuristicStrategy.countDelimitersOutsideQuotes(line, delimiter));
2172
2174
  const firstCount = counts[0];
2173
2175
  const consistentLines = counts.filter((c) => c === firstCount).length;
2174
2176
  return consistentLines / lines.length >= 0.8;
2175
2177
  }
2178
+ /**
2179
+ * Count occurrences of `delimiter` in `line` that fall OUTSIDE double-quoted
2180
+ * fields, honoring RFC-4180 escaped quotes (`""`). Used by CSV detection so a
2181
+ * delimiter embedded in a quoted value is not mistaken for a column break.
2182
+ */
2183
+ static countDelimitersOutsideQuotes(line, delimiter) {
2184
+ let count = 0;
2185
+ let inQuotes = false;
2186
+ for (let i = 0; i < line.length; i++) {
2187
+ const ch = line[i];
2188
+ if (ch === '"') {
2189
+ if (inQuotes && line[i + 1] === '"') {
2190
+ i++; // escaped quote inside a quoted field — skip the pair
2191
+ continue;
2192
+ }
2193
+ inQuotes = !inQuotes;
2194
+ }
2195
+ else if (ch === delimiter && !inQuotes) {
2196
+ count++;
2197
+ }
2198
+ }
2199
+ return count;
2200
+ }
2176
2201
  looksLikeJSON(text) {
2177
2202
  // hasJsonMarkers now does full validation including JSON.parse
2178
2203
  return hasJsonMarkers(text);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@juspay/neurolink",
3
- "version": "9.88.6",
3
+ "version": "9.88.7",
4
4
  "packageManager": "pnpm@10.15.1",
5
5
  "description": "TypeScript AI SDK with 24+ LLM providers behind one consistent API. MCP-native (58+ servers), voice TTS/STT/realtime, RAG, agents, memory, context compaction. OpenAI · Anthropic · Gemini · Bedrock · Azure · Ollama · DeepSeek · NVIDIA NIM and more.",
6
6
  "author": {