@retrivora-ai/rag-engine 1.3.3 → 1.3.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.
package/dist/index.js CHANGED
@@ -335,10 +335,9 @@ function sanitizeJson(raw) {
335
335
  s = s.replace(/,\s*([}\]])/g, "$1");
336
336
  s = s.replace(/([{,])\s*""\s*(?=[,}])/g, "$1");
337
337
  {
338
+ const stack = [];
338
339
  let inString = false;
339
340
  let escape = false;
340
- let braces = 0;
341
- let brackets = 0;
342
341
  for (const ch of s) {
343
342
  if (escape) {
344
343
  escape = false;
@@ -353,23 +352,21 @@ function sanitizeJson(raw) {
353
352
  continue;
354
353
  }
355
354
  if (inString) continue;
356
- if (ch === "{") braces++;
357
- else if (ch === "}") braces--;
358
- else if (ch === "[") brackets++;
359
- else if (ch === "]") brackets--;
355
+ if (ch === "{" || ch === "[") {
356
+ stack.push(ch);
357
+ } else if (ch === "}") {
358
+ if (stack[stack.length - 1] === "{") stack.pop();
359
+ } else if (ch === "]") {
360
+ if (stack[stack.length - 1] === "[") stack.pop();
361
+ }
360
362
  }
361
363
  if (inString) s += '"';
362
- while (brackets > 0) {
363
- s += "]";
364
- brackets--;
365
- }
366
- while (braces > 0) {
367
- s += "}";
368
- braces--;
364
+ for (let i = stack.length - 1; i >= 0; i--) {
365
+ s += stack[i] === "{" ? "}" : "]";
369
366
  }
370
367
  }
371
368
  const lastClose = Math.max(s.lastIndexOf("}"), s.lastIndexOf("]"));
372
- if (lastClose !== -1 && lastClose < s.length - 1) {
369
+ if (lastClose !== -1 && lastClose < s.length - 1 && /\S/.test(s.slice(lastClose + 1))) {
373
370
  s = s.substring(0, lastClose + 1);
374
371
  }
375
372
  return s;
package/dist/index.mjs CHANGED
@@ -298,10 +298,9 @@ function sanitizeJson(raw) {
298
298
  s = s.replace(/,\s*([}\]])/g, "$1");
299
299
  s = s.replace(/([{,])\s*""\s*(?=[,}])/g, "$1");
300
300
  {
301
+ const stack = [];
301
302
  let inString = false;
302
303
  let escape = false;
303
- let braces = 0;
304
- let brackets = 0;
305
304
  for (const ch of s) {
306
305
  if (escape) {
307
306
  escape = false;
@@ -316,23 +315,21 @@ function sanitizeJson(raw) {
316
315
  continue;
317
316
  }
318
317
  if (inString) continue;
319
- if (ch === "{") braces++;
320
- else if (ch === "}") braces--;
321
- else if (ch === "[") brackets++;
322
- else if (ch === "]") brackets--;
318
+ if (ch === "{" || ch === "[") {
319
+ stack.push(ch);
320
+ } else if (ch === "}") {
321
+ if (stack[stack.length - 1] === "{") stack.pop();
322
+ } else if (ch === "]") {
323
+ if (stack[stack.length - 1] === "[") stack.pop();
324
+ }
323
325
  }
324
326
  if (inString) s += '"';
325
- while (brackets > 0) {
326
- s += "]";
327
- brackets--;
328
- }
329
- while (braces > 0) {
330
- s += "}";
331
- braces--;
327
+ for (let i = stack.length - 1; i >= 0; i--) {
328
+ s += stack[i] === "{" ? "}" : "]";
332
329
  }
333
330
  }
334
331
  const lastClose = Math.max(s.lastIndexOf("}"), s.lastIndexOf("]"));
335
- if (lastClose !== -1 && lastClose < s.length - 1) {
332
+ if (lastClose !== -1 && lastClose < s.length - 1 && /\S/.test(s.slice(lastClose + 1))) {
336
333
  s = s.substring(0, lastClose + 1);
337
334
  }
338
335
  return s;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@retrivora-ai/rag-engine",
3
- "version": "1.3.3",
3
+ "version": "1.3.4",
4
4
  "description": "Retrivora AI is a plug-and-play AI engine for RAG chat experiences — generic vector DB + LLM provider, embeddable or standalone.",
5
5
  "author": "Abhinav Alkuchi",
6
6
  "license": "MIT",
@@ -46,36 +46,45 @@ function sanitizeJson(raw: string): string {
46
46
  // 6. Remove completely empty key-value pairs left by prior cleanup
47
47
  s = s.replace(/([{,])\s*""\s*(?=[,}])/g, '$1');
48
48
 
49
- // 7. Balance braces/brackets: walk char-by-char, track depth, append closers
50
- // Do this BEFORE the lastValidIndex trim so we don't cut valid JSON.
49
+ // 7. Stack-based structure balancer.
50
+ // Walk every character, maintain a stack of openers so we close each
51
+ // unclosed structure with its exact matching closer — in the right order.
52
+ // This is the critical fix: a flat counter approach appends all ]'s then
53
+ // all }'s, which corrupts nested structures like {..., [..., {...}]}.
51
54
  {
55
+ const stack: ('{' | '[')[] = [];
52
56
  let inString = false;
53
57
  let escape = false;
54
- let braces = 0;
55
- let brackets = 0;
56
58
 
57
59
  for (const ch of s) {
58
60
  if (escape) { escape = false; continue; }
59
61
  if (ch === '\\' && inString) { escape = true; continue; }
60
62
  if (ch === '"') { inString = !inString; continue; }
61
63
  if (inString) continue;
62
- if (ch === '{') braces++;
63
- else if (ch === '}') braces--;
64
- else if (ch === '[') brackets++;
65
- else if (ch === ']') brackets--;
64
+
65
+ if (ch === '{' || ch === '[') {
66
+ stack.push(ch);
67
+ } else if (ch === '}') {
68
+ if (stack[stack.length - 1] === '{') stack.pop();
69
+ // mismatched closer — leave stack alone (sanitize step 5 handles trailing commas)
70
+ } else if (ch === ']') {
71
+ if (stack[stack.length - 1] === '[') stack.pop();
72
+ }
66
73
  }
67
74
 
68
- // Close any unclosed string first
75
+ // Close any unterminated string literal first
69
76
  if (inString) s += '"';
70
- // Then close structures in the correct order
71
- while (brackets > 0) { s += ']'; brackets--; }
72
- while (braces > 0) { s += '}'; braces--; }
77
+
78
+ // Close every unclosed opener in reverse (innermost first)
79
+ for (let i = stack.length - 1; i >= 0; i--) {
80
+ s += stack[i] === '{' ? '}' : ']';
81
+ }
73
82
  }
74
83
 
75
- // 8. Trim to the last valid closing char only if there is trailing garbage
76
- // (e.g. a partial second object after the first one ends)
84
+ // 8. Trim trailing garbage that appears after the outermost closing char.
85
+ // Only fires when something non-whitespace follows the last } or ].
77
86
  const lastClose = Math.max(s.lastIndexOf('}'), s.lastIndexOf(']'));
78
- if (lastClose !== -1 && lastClose < s.length - 1) {
87
+ if (lastClose !== -1 && lastClose < s.length - 1 && /\S/.test(s.slice(lastClose + 1))) {
79
88
  s = s.substring(0, lastClose + 1);
80
89
  }
81
90
 
@@ -211,10 +220,7 @@ export function MessageBubble({
211
220
  const mentioned =
212
221
  contentLower.includes(p.name.toLowerCase()) ||
213
222
  (p.brand ? contentLower.includes(p.brand.toLowerCase()) : false);
214
- if (mentioned) {
215
- seen.add(id);
216
- return true;
217
- }
223
+ if (mentioned) { seen.add(id); return true; }
218
224
  return false;
219
225
  });
220
226
  }, [productsFromSources, productsFromContent, message.content]);