diff --git a/packages/@n8n/nodes-langchain/nodes/tools/ToolHttpRequest/utils.ts b/packages/@n8n/nodes-langchain/nodes/tools/ToolHttpRequest/utils.ts index 59578d06693..e0d019e933c 100644 --- a/packages/@n8n/nodes-langchain/nodes/tools/ToolHttpRequest/utils.ts +++ b/packages/@n8n/nodes-langchain/nodes/tools/ToolHttpRequest/utils.ts @@ -712,22 +712,12 @@ export const configureToolFunction = ( if (value) { let parsedValue; try { - parsedValue = jsonParse(value); + parsedValue = jsonParse(value, { repairJSON: true }); } catch (error) { - let recoveredData = ''; - try { - recoveredData = value - .replace(/'/g, '"') // Replace single quotes with double quotes - .replace(/(['"])?([a-zA-Z0-9_]+)(['"])?:/g, '"$2":') // Wrap keys in double quotes - .replace(/,\s*([\]}])/g, '$1') // Remove trailing commas from objects - .replace(/,+$/, ''); // Remove trailing comma - parsedValue = jsonParse(recoveredData); - } catch (err) { - throw new NodeOperationError( - ctx.getNode(), - `Could not replace placeholders in ${key}: ${error.message}`, - ); - } + throw new NodeOperationError( + ctx.getNode(), + `Could not replace placeholders in ${key}: ${error.message}`, + ); } options[key as 'qs' | 'headers' | 'body'] = parsedValue; } diff --git a/packages/frontend/editor-ui/src/app/App.vue b/packages/frontend/editor-ui/src/app/App.vue index 3a421fe0b5a..e6e8bbeae94 100644 --- a/packages/frontend/editor-ui/src/app/App.vue +++ b/packages/frontend/editor-ui/src/app/App.vue @@ -127,6 +127,7 @@ watch( setLanguage(newLocale); axios.defaults.headers.common['Accept-Language'] = newLocale; + void locale.use(newLocale); }, { immediate: true }, diff --git a/packages/nodes-base/nodes/Set/test/v2/raw.test.ts b/packages/nodes-base/nodes/Set/test/v2/raw.test.ts index 0f96ffe25d9..44b673a2e4c 100644 --- a/packages/nodes-base/nodes/Set/test/v2/raw.test.ts +++ b/packages/nodes-base/nodes/Set/test/v2/raw.test.ts @@ -129,7 +129,7 @@ describe('test Set2, rawMode/json Mode', () => { const output = await execute.call(fakeExecuteFunction, item, 0, options, {}, node); expect(output).toEqual({ - json: { error: "The 'JSON Output' in item 0 contains invalid JSON" }, + json: { error: "The 'JSON Output' in item 0 does not contain a valid JSON object" }, pairedItem: { item: 0 }, }); }); diff --git a/packages/nodes-base/nodes/Set/v2/helpers/__tests__/utils.test.ts b/packages/nodes-base/nodes/Set/v2/helpers/__tests__/utils.test.ts index 9821fe4cccb..8be358ec65c 100644 --- a/packages/nodes-base/nodes/Set/v2/helpers/__tests__/utils.test.ts +++ b/packages/nodes-base/nodes/Set/v2/helpers/__tests__/utils.test.ts @@ -9,9 +9,9 @@ import type { } from 'n8n-workflow'; import { NodeOperationError } from 'n8n-workflow'; -import { prepareReturnItem } from '../utils'; import type { SetNodeOptions } from '../interfaces'; import { INCLUDE } from '../interfaces'; +import { parseJsonParameter, prepareReturnItem } from '../utils'; describe('prepareReturnItem', () => { const mockNode = mock({ @@ -448,3 +448,44 @@ describe('prepareReturnItem', () => { }); }); }); + +describe('parseJsonParameter', () => { + const mockNode = mock({ + name: 'Set Node', + typeVersion: 3.4, + }); + + describe('Valid JSON input', () => { + it('should parse valid JSON string', () => { + const result = parseJsonParameter('{"key": "value"}', mockNode, 0); + expect(result).toEqual({ key: 'value' }); + }); + + it('should parse valid JSON object directly', () => { + const input = { key: 'value' }; + const result = parseJsonParameter(input, mockNode, 0); + expect(result).toEqual(input); + }); + + it('should parse complex valid JSON', () => { + const json = '{"nested": {"key": "value"}, "array": [1, 2, 3]}'; + const result = parseJsonParameter(json, mockNode, 0); + expect(result).toEqual({ nested: { key: 'value' }, array: [1, 2, 3] }); + }); + }); + + describe('JSON repair', () => { + it('should repair JSON string', () => { + const result = parseJsonParameter('{key: "value"}', mockNode, 0); + expect(result).toEqual({ key: 'value' }); + }); + }); + + describe('Error cases', () => { + it('should throw error for invalid JSON that cannot be recovered', () => { + expect(() => parseJsonParameter('{key1: "value",, key2: "value2"}', mockNode, 0)).toThrow( + "The 'JSON Output' in item 0 contains invalid JSON", + ); + }); + }); +}); diff --git a/packages/nodes-base/nodes/Set/v2/helpers/utils.ts b/packages/nodes-base/nodes/Set/v2/helpers/utils.ts index cc0cbcc4a5f..ef12c0463f2 100644 --- a/packages/nodes-base/nodes/Set/v2/helpers/utils.ts +++ b/packages/nodes-base/nodes/Set/v2/helpers/utils.ts @@ -137,23 +137,11 @@ export const parseJsonParameter = ( if (typeof jsonData === 'string') { try { - returnData = jsonParse(jsonData); + returnData = jsonParse(jsonData, { repairJSON: true }); } catch (error) { - let recoveredData = ''; - try { - recoveredData = jsonData - .replace(/'/g, '"') // Replace single quotes with double quotes - .replace(/(['"])?([a-zA-Z0-9_]+)(['"])?:/g, '"$2":') // Wrap keys in double quotes - .replace(/,\s*([\]}])/g, '$1') // Remove trailing commas from objects - .replace(/,+$/, ''); // Remove trailing comma - returnData = jsonParse(recoveredData); - } catch (err) { - const description = - recoveredData === jsonData ? jsonData : `${recoveredData};\n Original input: ${jsonData}`; - throw new NodeOperationError(node, `The ${location} in item ${i} contains invalid JSON`, { - description, - }); - } + throw new NodeOperationError(node, `The ${location} in item ${i} contains invalid JSON`, { + description: jsonData, + }); } } else { returnData = jsonData; diff --git a/packages/workflow/package.json b/packages/workflow/package.json index ba30ef32bd5..514a939f7a6 100644 --- a/packages/workflow/package.json +++ b/packages/workflow/package.json @@ -67,6 +67,7 @@ "title-case": "3.0.3", "transliteration": "2.3.5", "xml2js": "catalog:", - "zod": "catalog:" + "zod": "catalog:", + "jsonrepair": "catalog:" } } diff --git a/packages/workflow/src/utils.ts b/packages/workflow/src/utils.ts index 06f5a21a672..6dc0946d407 100644 --- a/packages/workflow/src/utils.ts +++ b/packages/workflow/src/utils.ts @@ -2,6 +2,7 @@ import { ApplicationError } from '@n8n/errors'; import { parse as esprimaParse, Syntax } from 'esprima-next'; import type { Node as SyntaxNode, ExpressionStatement } from 'esprima-next'; import FormData from 'form-data'; +import { jsonrepair } from 'jsonrepair'; import merge from 'lodash/merge'; import { ALPHABET } from './constants'; @@ -109,7 +110,7 @@ type MutuallyExclusive = | (T & { [k in Exclude]?: never }) | (U & { [k in Exclude]?: never }); -type JSONParseOptions = { acceptJSObject?: boolean } & MutuallyExclusive< +type JSONParseOptions = { acceptJSObject?: boolean; repairJSON?: boolean } & MutuallyExclusive< { errorMessage?: string }, { fallbackValue?: T } >; @@ -120,6 +121,7 @@ type JSONParseOptions = { acceptJSObject?: boolean } & MutuallyExclusive< * @param {string} jsonString - The JSON string to parse. * @param {Object} [options] - Optional settings for parsing the JSON string. Either `fallbackValue` or `errorMessage` can be set, but not both. * @param {boolean} [options.acceptJSObject=false] - If true, attempts to recover from common JSON format errors by parsing the JSON string as a JavaScript Object. + * @param {boolean} [options.repairJSON=false] - If true, attempts to repair common JSON format errors by repairing the JSON string. * @param {string} [options.errorMessage] - A custom error message to throw if the JSON string cannot be parsed. * @param {*} [options.fallbackValue] - A fallback value to return if the JSON string cannot be parsed. * @returns {Object} - The parsed object, or the fallback value if parsing fails and `fallbackValue` is set. @@ -136,6 +138,14 @@ export const jsonParse = (jsonString: string, options?: JSONParseOptions): // Ignore this error and return the original error or the fallback value } } + if (options?.repairJSON) { + try { + const jsonStringCleaned = jsonrepair(jsonString); + return JSON.parse(jsonStringCleaned) as T; + } catch (e) { + // Ignore this error and return the original error or the fallback value + } + } if (options?.fallbackValue !== undefined) { if (options.fallbackValue instanceof Function) { return options.fallbackValue(); diff --git a/packages/workflow/test/utils.test.ts b/packages/workflow/test/utils.test.ts index 33332131f96..778d0d03f00 100644 --- a/packages/workflow/test/utils.test.ts +++ b/packages/workflow/test/utils.test.ts @@ -109,6 +109,136 @@ describe('jsonParse', () => { it('optionally returns a `fallbackValue`', () => { expect(jsonParse('', { fallbackValue: { foo: 'bar' } })).toEqual({ foo: 'bar' }); }); + + describe('JSON repair', () => { + describe('Recovery edge cases', () => { + it('should handle simple object with single quotes', () => { + const result = jsonParse("{name: 'John', age: 30}", { repairJSON: true }); + expect(result).toEqual({ name: 'John', age: 30 }); + }); + + it('should handle nested objects with single quotes', () => { + const result = jsonParse("{user: {name: 'John', active: true},}", { repairJSON: true }); + expect(result).toEqual({ user: { name: 'John', active: true } }); + }); + + it('should handle empty string values', () => { + const result = jsonParse("{key: ''}", { repairJSON: true }); + expect(result).toEqual({ key: '' }); + }); + + it('should handle numeric string values', () => { + const result = jsonParse("{key: '123'}", { repairJSON: true }); + expect(result).toEqual({ key: '123' }); + }); + + it('should handle multiple keys with trailing comma', () => { + const result = jsonParse("{a: '1', b: '2', c: '3',}", { repairJSON: true }); + expect(result).toEqual({ a: '1', b: '2', c: '3' }); + }); + + it('should recover single quotes around strings', () => { + const result = jsonParse("{key: 'value'}", { repairJSON: true }); + expect(result).toEqual({ key: 'value' }); + }); + + it('should recover unquoted keys', () => { + const result = jsonParse("{myKey: 'value'}", { repairJSON: true }); + expect(result).toEqual({ myKey: 'value' }); + }); + + it('should recover trailing commas in objects', () => { + const result = jsonParse("{key: 'value',}", { repairJSON: true }); + expect(result).toEqual({ key: 'value' }); + }); + + it('should recover trailing commas in nested objects', () => { + const result = jsonParse("{outer: {inner: 'value',},}", { repairJSON: true }); + expect(result).toEqual({ outer: { inner: 'value' } }); + }); + + it('should recover multiple issues at once', () => { + const result = jsonParse("{key1: 'value1', key2: 'value2',}", { repairJSON: true }); + expect(result).toEqual({ key1: 'value1', key2: 'value2' }); + }); + + it('should recover numeric values with single quotes', () => { + const result = jsonParse("{key: '123'}", { repairJSON: true }); + expect(result).toEqual({ key: '123' }); + }); + + it('should recover boolean values with single quotes', () => { + const result = jsonParse("{key: 'true'}", { repairJSON: true }); + expect(result).toEqual({ key: 'true' }); + }); + + it('should handle urls', () => { + const result = jsonParse('{"key": "https://example.com",}', { repairJSON: true }); + expect(result).toEqual({ key: 'https://example.com' }); + }); + + it('should handle ipv6 addresses', () => { + const result = jsonParse('{"key": "2a01:c50e:3544:bd00:4df0:7609:251a:f6d0",}', { + repairJSON: true, + }); + expect(result).toEqual({ key: '2a01:c50e:3544:bd00:4df0:7609:251a:f6d0' }); + }); + + it('should handle single quotes containing double quotes', () => { + const result = jsonParse('{key: \'value with "quotes" inside\'}', { repairJSON: true }); + expect(result).toEqual({ key: 'value with "quotes" inside' }); + }); + + it('should handle escaped single quotes', () => { + const result = jsonParse("{key: 'it\\'s escaped'}", { repairJSON: true }); + expect(result).toEqual({ key: "it's escaped" }); + }); + + it('should handle keys containing hyphens', () => { + const result = jsonParse("{key-with-dash: 'value'}", { repairJSON: true }); + expect(result).toEqual({ 'key-with-dash': 'value' }); + }); + + it('should handle keys containing dots', () => { + const result = jsonParse("{key.name: 'value'}", { repairJSON: true }); + expect(result).toEqual({ 'key.name': 'value' }); + }); + + it('should handle unquoted string values', () => { + const result = jsonParse('{key: value}', { repairJSON: true }); + expect(result).toEqual({ key: 'value' }); + }); + + it('should handle unquoted multi-word values', () => { + const result = jsonParse('{key: some text}', { repairJSON: true }); + expect(result).toEqual({ key: 'some text' }); + }); + + it('should handle input with double quotes mixed with single quotes', () => { + const result = jsonParse('{key: "value with \'single\' quotes"}', { repairJSON: true }); + expect(result).toEqual({ key: "value with 'single' quotes" }); + }); + + it('should handle keys starting with numbers', () => { + const result = jsonParse("{123key: 'value'}", { repairJSON: true }); + expect(result).toEqual({ '123key': 'value' }); + }); + + it('should handle nested objects containing quotes', () => { + const result = jsonParse("{outer: {inner: 'value with \"quotes\"', other: 'test'},}", { + repairJSON: true, + }); + expect(result).toEqual({ outer: { inner: 'value with "quotes"', other: 'test' } }); + }); + + it('should handle complex nested quote conflicts', () => { + const result = jsonParse("{key: 'value with \"quotes\" inside', nested: {inner: 'test'}}", { + repairJSON: true, + }); + expect(result).toEqual({ key: 'value with "quotes" inside', nested: { inner: 'test' } }); + }); + }); + }); }); describe('jsonStringify', () => { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index c6a3ccc190c..8ee9717766b 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -81,6 +81,9 @@ catalogs: js-base64: specifier: 3.7.2 version: 3.7.2 + jsonrepair: + specifier: 3.13.1 + version: 3.13.1 jsonwebtoken: specifier: 9.0.2 version: 9.0.2 @@ -1063,7 +1066,7 @@ importers: version: 12.1.0 '@getzep/zep-cloud': specifier: 1.0.12 - version: 1.0.12(@langchain/core@0.3.68(@opentelemetry/api@1.9.0)(@opentelemetry/sdk-trace-base@1.30.1(@opentelemetry/api@1.9.0))(openai@5.12.2(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.25.67)))(encoding@0.1.13)(langchain@0.3.33(ca377405f102dc2905a39d54ecb4d621)) + version: 1.0.12(@langchain/core@0.3.68(@opentelemetry/api@1.9.0)(@opentelemetry/sdk-trace-base@1.30.1(@opentelemetry/api@1.9.0))(openai@5.12.2(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.25.67)))(encoding@0.1.13)(langchain@0.3.33(5cc28a029307bb3da1dcaf370c8a2b8d)) '@getzep/zep-js': specifier: 0.9.0 version: 0.9.0 @@ -1090,7 +1093,7 @@ importers: version: 0.3.4(@langchain/core@0.3.68(@opentelemetry/api@1.9.0)(@opentelemetry/sdk-trace-base@1.30.1(@opentelemetry/api@1.9.0))(openai@5.12.2(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.25.67)))(encoding@0.1.13) '@langchain/community': specifier: 'catalog:' - version: 0.3.50(ba725e6da5f3cda58245f84e6fe2ecaf) + version: 0.3.50(071f2de44c6bccc3a8cd2fadf2db3e78) '@langchain/core': specifier: 'catalog:' version: 0.3.68(@opentelemetry/api@1.9.0)(@opentelemetry/sdk-trace-base@1.30.1(@opentelemetry/api@1.9.0))(openai@5.12.2(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.25.67)) @@ -1213,7 +1216,7 @@ importers: version: 23.0.1(bufferutil@4.0.9)(utf-8-validate@5.0.10) langchain: specifier: 0.3.33 - version: 0.3.33(ca377405f102dc2905a39d54ecb4d621) + version: 0.3.33(5cc28a029307bb3da1dcaf370c8a2b8d) lodash: specifier: 'catalog:' version: 4.17.21 @@ -3304,6 +3307,9 @@ importers: js-base64: specifier: 'catalog:' version: 3.7.2(patch_hash=bb02fdf69495c7b0768791b60ab6e1a002053b8decd19a174f5755691e5c9500) + jsonrepair: + specifier: 'catalog:' + version: 3.13.1 jssha: specifier: 3.3.1 version: 3.3.1 @@ -13081,6 +13087,10 @@ packages: resolution: {integrity: sha512-p/nXbhSEcu3pZRdkW1OfJhpsVtW1gd4Wa1fnQc9YLiTfAjn0312eMKimbdIQzuZl9aa9xUGaRlP9T/CJE/ditQ==} engines: {node: '>=0.10.0'} + jsonrepair@3.13.1: + resolution: {integrity: sha512-WJeiE0jGfxYmtLwBTEk8+y/mYcaleyLXWaqp5bJu0/ZTSeG0KQq/wWQ8pmnkKenEdN6pdnn6QtcoSUkbqDHWNw==} + hasBin: true + jsonschema@1.4.1: resolution: {integrity: sha512-S6cATIPVv1z0IlxdN+zUk5EPjkGCdnhN4wVSBlvoUO1tOLJootbo9CquNJmbIh4yikWHiUedhRYrNPn1arpEmQ==} @@ -17575,8 +17585,8 @@ packages: vue-component-type-helpers@2.2.12: resolution: {integrity: sha512-YbGqHZ5/eW4SnkPNR44mKVc6ZKQoRs/Rux1sxC6rdwXb4qpbOSYfDr9DsTHolOTGmIKgM9j141mZbBeg05R1pw==} - vue-component-type-helpers@3.1.4: - resolution: {integrity: sha512-Uws7Ew1OzTTqHW8ZVl/qLl/HB+jf08M0NdFONbVWAx0N4gMLK8yfZDgeB77hDnBmaigWWEn5qP8T9BG59jIeyQ==} + vue-component-type-helpers@3.1.5: + resolution: {integrity: sha512-7V3yJuNWW7/1jxCcI1CswnpDsvs02Qcx/N43LkV+ZqhLj2PKj50slUflHAroNkN4UWiYfzMUUUXiNuv9khmSpQ==} vue-demi@0.14.10: resolution: {integrity: sha512-nMZBOwuzabUO0nLgIcc6rycZEebF6eeUfaiQx9+WSk8e29IbLvPU9feI6tqW4kTo3hvoYAJkMh8n8D0fuISphg==} @@ -20944,7 +20954,7 @@ snapshots: '@gar/promisify@1.1.3': optional: true - '@getzep/zep-cloud@1.0.12(@langchain/core@0.3.68(@opentelemetry/api@1.9.0)(@opentelemetry/sdk-trace-base@1.30.1(@opentelemetry/api@1.9.0))(openai@5.12.2(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.25.67)))(encoding@0.1.13)(langchain@0.3.33(ca377405f102dc2905a39d54ecb4d621))': + '@getzep/zep-cloud@1.0.12(@langchain/core@0.3.68(@opentelemetry/api@1.9.0)(@opentelemetry/sdk-trace-base@1.30.1(@opentelemetry/api@1.9.0))(openai@5.12.2(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.25.67)))(encoding@0.1.13)(langchain@0.3.33(5cc28a029307bb3da1dcaf370c8a2b8d))': dependencies: form-data: 4.0.4 node-fetch: 2.7.0(encoding@0.1.13) @@ -20953,7 +20963,7 @@ snapshots: zod: 3.25.67 optionalDependencies: '@langchain/core': 0.3.68(@opentelemetry/api@1.9.0)(@opentelemetry/sdk-trace-base@1.30.1(@opentelemetry/api@1.9.0))(openai@5.12.2(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.25.67)) - langchain: 0.3.33(ca377405f102dc2905a39d54ecb4d621) + langchain: 0.3.33(5cc28a029307bb3da1dcaf370c8a2b8d) transitivePeerDependencies: - encoding @@ -21639,7 +21649,7 @@ snapshots: - aws-crt - encoding - '@langchain/community@0.3.50(ba725e6da5f3cda58245f84e6fe2ecaf)': + '@langchain/community@0.3.50(071f2de44c6bccc3a8cd2fadf2db3e78)': dependencies: '@browserbasehq/stagehand': 1.9.0(@playwright/test@1.56.0)(bufferutil@4.0.9)(deepmerge@4.3.1)(dotenv@16.6.1)(encoding@0.1.13)(openai@5.12.2(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.25.67))(utf-8-validate@5.0.10)(zod@3.25.67) '@ibm-cloud/watsonx-ai': 1.1.2 @@ -21651,7 +21661,7 @@ snapshots: flat: 5.0.2 ibm-cloud-sdk-core: 5.3.2 js-yaml: 4.1.0 - langchain: 0.3.33(ca377405f102dc2905a39d54ecb4d621) + langchain: 0.3.33(5cc28a029307bb3da1dcaf370c8a2b8d) langsmith: 0.3.55(@opentelemetry/api@1.9.0)(@opentelemetry/sdk-trace-base@1.30.1(@opentelemetry/api@1.9.0))(openai@5.12.2(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.25.67)) openai: 5.12.2(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.25.67) uuid: 10.0.0 @@ -21666,7 +21676,7 @@ snapshots: '@azure/search-documents': 12.1.0 '@azure/storage-blob': 12.26.0 '@browserbasehq/sdk': 2.6.0(encoding@0.1.13) - '@getzep/zep-cloud': 1.0.12(@langchain/core@0.3.68(@opentelemetry/api@1.9.0)(@opentelemetry/sdk-trace-base@1.30.1(@opentelemetry/api@1.9.0))(openai@5.12.2(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.25.67)))(encoding@0.1.13)(langchain@0.3.33(ca377405f102dc2905a39d54ecb4d621)) + '@getzep/zep-cloud': 1.0.12(@langchain/core@0.3.68(@opentelemetry/api@1.9.0)(@opentelemetry/sdk-trace-base@1.30.1(@opentelemetry/api@1.9.0))(openai@5.12.2(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.25.67)))(encoding@0.1.13)(langchain@0.3.33(5cc28a029307bb3da1dcaf370c8a2b8d)) '@getzep/zep-js': 0.9.0 '@google-ai/generativelanguage': 3.4.0(encoding@0.1.13) '@google-cloud/storage': 7.12.1(encoding@0.1.13) @@ -23990,7 +24000,7 @@ snapshots: storybook: 9.1.7(@testing-library/dom@10.4.0)(bufferutil@4.0.9)(prettier@3.6.2)(utf-8-validate@5.0.10)(vite@7.0.0(@types/node@20.19.21)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.89.2)(terser@5.16.1)(tsx@4.19.3)) type-fest: 2.19.0 vue: 3.5.13(typescript@5.9.2) - vue-component-type-helpers: 3.1.4 + vue-component-type-helpers: 3.1.5 '@stylistic/eslint-plugin@5.0.0(eslint@9.29.0(jiti@2.6.1))': dependencies: @@ -25798,6 +25808,14 @@ snapshots: transitivePeerDependencies: - debug + axios@1.12.0(debug@4.4.3): + dependencies: + follow-redirects: 1.15.11(debug@4.4.3) + form-data: 4.0.4 + proxy-from-env: 1.1.0 + transitivePeerDependencies: + - debug + b4a@1.6.7: {} babel-jest@29.6.2(@babel/core@7.28.4): @@ -28574,6 +28592,10 @@ snapshots: optionalDependencies: debug: 4.4.1(supports-color@8.1.1) + follow-redirects@1.15.11(debug@4.4.3): + optionalDependencies: + debug: 4.4.3 + for-each@0.3.5: dependencies: is-callable: 1.2.7 @@ -29276,7 +29298,7 @@ snapshots: '@types/debug': 4.1.12 '@types/node': 20.19.21 '@types/tough-cookie': 4.0.5 - axios: 1.12.0(debug@4.4.1) + axios: 1.12.0(debug@4.4.3) camelcase: 6.3.0 debug: 4.4.3 dotenv: 16.6.1 @@ -29286,7 +29308,7 @@ snapshots: isstream: 0.1.2 jsonwebtoken: 9.0.2 mime-types: 2.1.35 - retry-axios: 2.6.0(axios@1.12.0(debug@4.4.3)) + retry-axios: 2.6.0(axios@1.12.0) tough-cookie: 4.1.4 transitivePeerDependencies: - supports-color @@ -30658,6 +30680,8 @@ snapshots: jsonpointer@5.0.1: {} + jsonrepair@3.13.1: {} + jsonschema@1.4.1: {} jsonwebtoken@9.0.2: @@ -30743,7 +30767,7 @@ snapshots: kuler@2.0.0: {} - langchain@0.3.33(ca377405f102dc2905a39d54ecb4d621): + langchain@0.3.33(5cc28a029307bb3da1dcaf370c8a2b8d): dependencies: '@langchain/core': 0.3.68(@opentelemetry/api@1.9.0)(@opentelemetry/sdk-trace-base@1.30.1(@opentelemetry/api@1.9.0))(openai@5.12.2(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.25.67)) '@langchain/openai': 0.6.16(@langchain/core@0.3.68(@opentelemetry/api@1.9.0)(@opentelemetry/sdk-trace-base@1.30.1(@opentelemetry/api@1.9.0))(openai@5.12.2(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.25.67)))(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10)) @@ -33636,7 +33660,7 @@ snapshots: onetime: 5.1.2 signal-exit: 3.0.7 - retry-axios@2.6.0(axios@1.12.0(debug@4.4.3)): + retry-axios@2.6.0(axios@1.12.0): dependencies: axios: 1.12.0(debug@4.4.1) @@ -35971,7 +35995,7 @@ snapshots: vue-component-type-helpers@2.2.12: {} - vue-component-type-helpers@3.1.4: {} + vue-component-type-helpers@3.1.5: {} vue-demi@0.14.10(vue@3.5.13(typescript@5.9.2)): dependencies: diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index ca50c706426..1044ba14be6 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -34,6 +34,7 @@ catalog: https-proxy-agent: 7.0.6 iconv-lite: 0.6.3 js-base64: 3.7.2 + jsonrepair: 3.13.1 jsonwebtoken: 9.0.2 lodash: 4.17.21 luxon: 3.4.4 @@ -78,4 +79,3 @@ catalogs: vue-markdown-render: ^2.2.1 vue-router: ^4.5.0 vue-tsc: ^2.2.8 -