@juspay/neurolink 9.88.5 → 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.
- package/CHANGELOG.md +12 -0
- package/dist/browser/neurolink.min.js +310 -310
- package/dist/core/constants.d.ts +1 -0
- package/dist/core/constants.js +3 -0
- package/dist/lib/core/constants.d.ts +1 -0
- package/dist/lib/core/constants.js +3 -0
- package/dist/lib/utils/csvProcessor.js +16 -2
- package/dist/lib/utils/fileDetector.js +28 -3
- package/dist/lib/utils/pdfProcessor.js +6 -0
- package/dist/utils/csvProcessor.js +16 -2
- package/dist/utils/fileDetector.js +28 -3
- package/dist/utils/pdfProcessor.js +6 -0
- package/package.json +1 -1
package/dist/core/constants.d.ts
CHANGED
package/dist/core/constants.js
CHANGED
|
@@ -217,6 +217,9 @@ export const PDF_LIMITS = {
|
|
|
217
217
|
MAX_SIZE_MB: 20,
|
|
218
218
|
// Default maximum pages for image conversion
|
|
219
219
|
DEFAULT_MAX_PAGES: 20,
|
|
220
|
+
// Upper bound for the render scale factor. Above this, a single page can
|
|
221
|
+
// allocate hundreds of MB; scale <= 0 produces a degenerate viewport.
|
|
222
|
+
MAX_SCALE: 10,
|
|
220
223
|
};
|
|
221
224
|
// Performance and System Limits
|
|
222
225
|
export const SYSTEM_LIMITS = {
|
|
@@ -217,6 +217,9 @@ export const PDF_LIMITS = {
|
|
|
217
217
|
MAX_SIZE_MB: 20,
|
|
218
218
|
// Default maximum pages for image conversion
|
|
219
219
|
DEFAULT_MAX_PAGES: 20,
|
|
220
|
+
// Upper bound for the render scale factor. Above this, a single page can
|
|
221
|
+
// allocate hundreds of MB; scale <= 0 produces a degenerate viewport.
|
|
222
|
+
MAX_SCALE: 10,
|
|
220
223
|
};
|
|
221
224
|
// Performance and System Limits
|
|
222
225
|
export const SYSTEM_LIMITS = {
|
|
@@ -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:
|
|
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:
|
|
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
|
-
|
|
2171
|
-
|
|
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);
|
|
@@ -267,6 +267,12 @@ export class PDFProcessor {
|
|
|
267
267
|
if (format !== "png") {
|
|
268
268
|
throw new Error(`Invalid format: "${format}". Only "png" format is currently supported.`);
|
|
269
269
|
}
|
|
270
|
+
// 0b. Validate the render scale. A non-finite or non-positive scale yields a
|
|
271
|
+
// degenerate viewport (blank/zero-dimension render), and an excessive scale
|
|
272
|
+
// can allocate hundreds of MB per page — reject both with a clear message.
|
|
273
|
+
if (!Number.isFinite(scale) || scale <= 0 || scale > PDF_LIMITS.MAX_SCALE) {
|
|
274
|
+
throw new Error(`Invalid scale: ${scale}. Scale must be a finite number greater than 0 and at most ${PDF_LIMITS.MAX_SCALE}.`);
|
|
275
|
+
}
|
|
270
276
|
// 1. Validate buffer is not empty or too small
|
|
271
277
|
if (!pdfBuffer || pdfBuffer.length < 5) {
|
|
272
278
|
throw new Error("Invalid PDF: Buffer is too small or empty. " +
|
|
@@ -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:
|
|
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:
|
|
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
|
-
|
|
2171
|
-
|
|
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);
|
|
@@ -267,6 +267,12 @@ export class PDFProcessor {
|
|
|
267
267
|
if (format !== "png") {
|
|
268
268
|
throw new Error(`Invalid format: "${format}". Only "png" format is currently supported.`);
|
|
269
269
|
}
|
|
270
|
+
// 0b. Validate the render scale. A non-finite or non-positive scale yields a
|
|
271
|
+
// degenerate viewport (blank/zero-dimension render), and an excessive scale
|
|
272
|
+
// can allocate hundreds of MB per page — reject both with a clear message.
|
|
273
|
+
if (!Number.isFinite(scale) || scale <= 0 || scale > PDF_LIMITS.MAX_SCALE) {
|
|
274
|
+
throw new Error(`Invalid scale: ${scale}. Scale must be a finite number greater than 0 and at most ${PDF_LIMITS.MAX_SCALE}.`);
|
|
275
|
+
}
|
|
270
276
|
// 1. Validate buffer is not empty or too small
|
|
271
277
|
if (!pdfBuffer || pdfBuffer.length < 5) {
|
|
272
278
|
throw new Error("Invalid PDF: Buffer is too small or empty. " +
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@juspay/neurolink",
|
|
3
|
-
"version": "9.88.
|
|
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": {
|