From 267fe49d51b7b8bcc80489b0f9f1a585986bc525 Mon Sep 17 00:00:00 2001 From: "aikido-autofix[bot]" <119856028+aikido-autofix[bot]@users.noreply.github.com> Date: Mon, 11 May 2026 20:15:47 +0100 Subject: [PATCH 01/29] fix: Fix 15 security issues in fast-xml-builder, basic-ftp, fast-uri and 5 more (#30169) Co-authored-by: aikido-autofix[bot] <119856028+aikido-autofix[bot]@users.noreply.github.com> Co-authored-by: Declan Carroll --- package.json | 6 +- packages/@n8n/nodes-langchain/package.json | 14 +- pnpm-lock.yaml | 345 ++++++++++----------- pnpm-workspace.yaml | 3 +- 4 files changed, 171 insertions(+), 197 deletions(-) diff --git a/package.json b/package.json index f2e0769d16e..d7d598c716e 100644 --- a/package.json +++ b/package.json @@ -166,9 +166,11 @@ "@xmldom/xmldom": "0.8.13", "langsmith": "0.5.19", "yaml@<=2.8.3": "2.8.3", - "hono": "4.12.16", "axios": "1.16.0", - "fast-xml-parser": "5.7.2" + "fast-xml-parser": "5.7.2", + "hono": "4.12.18", + "@anthropic-ai/sdk@<=0.91.1": "0.91.1", + "uuid@<=13.0.1": "13.0.1" }, "patchedDependencies": { "bull@4.16.4": "patches/bull@4.16.4.patch", diff --git a/packages/@n8n/nodes-langchain/package.json b/packages/@n8n/nodes-langchain/package.json index d8cc8bb5b81..ff6893a273c 100644 --- a/packages/@n8n/nodes-langchain/package.json +++ b/packages/@n8n/nodes-langchain/package.json @@ -205,6 +205,7 @@ }, "devDependencies": { "@n8n/eslint-plugin-community-nodes": "workspace:*", + "@n8n/vitest-config": "workspace:*", "@types/basic-auth": "catalog:", "@types/cheerio": "^0.22.15", "@types/html-to-text": "^9.0.1", @@ -213,10 +214,9 @@ "@types/pg": "^8.15.6", "@types/sanitize-html": "^2.11.0", "@types/temp": "^0.9.1", + "@vitest/coverage-v8": "catalog:", "fast-glob": "catalog:", "n8n-core": "workspace:*", - "@n8n/vitest-config": "workspace:*", - "@vitest/coverage-v8": "catalog:", "vitest": "catalog:", "vitest-mock-extended": "catalog:" }, @@ -227,11 +227,12 @@ "@getzep/zep-cloud": "1.0.6", "@getzep/zep-js": "0.9.0", "@google-cloud/resource-manager": "5.3.0", - "@google/generative-ai": "0.24.0", "@google/genai": "1.19.0", + "@google/generative-ai": "0.24.0", "@huggingface/inference": "4.0.5", "@langchain/anthropic": "catalog:", "@langchain/aws": "1.0.3", + "@langchain/classic": "1.0.27", "@langchain/cohere": "1.0.1", "@langchain/community": "catalog:", "@langchain/core": "catalog:", @@ -247,9 +248,9 @@ "@langchain/redis": "1.0.1", "@langchain/textsplitters": "1.0.1", "@langchain/weaviate": "1.0.1", - "@microsoft/agents-a365-runtime": "0.1.0-preview.113", "@microsoft/agents-a365-notifications": "0.1.0-preview.113", "@microsoft/agents-a365-observability": "0.1.0-preview.113", + "@microsoft/agents-a365-runtime": "0.1.0-preview.113", "@microsoft/agents-a365-tooling": "0.1.0-preview.113", "@microsoft/agents-a365-tooling-extensions-langchain": "0.1.0-preview.113", "@microsoft/agents-activity": "1.2.3", @@ -264,10 +265,9 @@ "@n8n/json-schema-to-zod": "workspace:*", "@n8n/typeorm": "catalog:", "@n8n/typescript-config": "workspace:*", - "vm2": "catalog:", "@pinecone-database/pinecone": "^5.0.2", "@qdrant/js-client-rest": "^1.16.2", - "@supabase/supabase-js": "2.49.9", + "@supabase/supabase-js": "catalog:", "@xata.io/client": "0.28.4", "@zilliz/milvus2-sdk-node": "^2.5.7", "basic-auth": "catalog:", @@ -283,7 +283,6 @@ "js-tiktoken": "catalog:", "jsdom": "23.0.1", "langchain": "catalog:", - "@langchain/classic": "1.0.27", "lodash": "catalog:", "mammoth": "1.12.0", "mime-types": "catalog:", @@ -298,6 +297,7 @@ "sqlite3": "5.1.7", "temp": "0.9.4", "tmp-promise": "3.0.3", + "vm2": "catalog:", "weaviate-client": "3.9.0", "zod": "catalog:", "zod-to-json-schema": "3.23.3" diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 2f71713a50a..c146aaae128 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -105,6 +105,9 @@ catalogs: '@rudderstack/rudder-sdk-node': specifier: 3.0.5 version: 3.0.5 + '@supabase/supabase-js': + specifier: 2.50.0 + version: 2.50.0 '@testcontainers/k3s': specifier: ^11.13.0 version: 11.13.0 @@ -457,9 +460,11 @@ overrides: '@xmldom/xmldom': 0.8.13 langsmith: 0.5.19 yaml@<=2.8.3: 2.8.3 - hono: 4.12.16 axios: 1.16.0 fast-xml-parser: 5.7.2 + hono: 4.12.18 + '@anthropic-ai/sdk@<=0.91.1': 0.91.1 + uuid@<=13.0.1: 13.0.1 patchedDependencies: '@lezer/highlight': @@ -705,7 +710,7 @@ importers: version: 1.0.27(@langchain/core@1.1.41(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.213.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@6.34.0(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)))(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.213.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(cheerio@1.0.0)(openai@6.34.0(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)) '@langchain/community': specifier: 'catalog:' - version: 1.1.27(eda736f6c818f128b670206c8d2822df) + version: 1.1.27(c9a60e7ac4d70846d24c187ff47dea5e) '@langchain/core': specifier: 'catalog:' version: 1.1.41(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.213.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@6.34.0(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)) @@ -2077,7 +2082,7 @@ importers: version: 1.0.1(@langchain/core@1.1.41(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.213.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@6.34.0(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)))(encoding@0.1.13) '@langchain/community': specifier: 'catalog:' - version: 1.1.27(9a33d502a76e23e4d14d11cb4afe5d89) + version: 1.1.27(dc13b8a57dd722a7e537a40aec8cb772) '@langchain/core': specifier: 'catalog:' version: 1.1.41(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.213.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@6.34.0(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)) @@ -2175,8 +2180,8 @@ importers: specifier: ^1.16.2 version: 1.16.2(typescript@6.0.2) '@supabase/supabase-js': - specifier: 2.49.9 - version: 2.49.9(bufferutil@4.0.9)(utf-8-validate@5.0.10) + specifier: 'catalog:' + version: 2.50.0(bufferutil@4.0.9)(utf-8-validate@5.0.10) '@xata.io/client': specifier: 0.28.4 version: 0.28.4(typescript@6.0.2) @@ -5095,11 +5100,8 @@ packages: engines: {node: '>=18.0.0'} hasBin: true - '@anthropic-ai/sdk@0.27.3': - resolution: {integrity: sha512-IjLt0gd3L4jlOfilxVXTifn42FnVffMgDC04RJK1KDZpmkBWLv0XC92MVVmkxrFZNS/7l3xWgP/I3nqtX1sQHw==} - - '@anthropic-ai/sdk@0.90.0': - resolution: {integrity: sha512-MzZtPabJF1b0FTDl6Z6H5ljphPwACLGP13lu8MTiB8jXaW/YXlpOp+Po2cVou3MPM5+f5toyLnul9whKCy7fBg==} + '@anthropic-ai/sdk@0.91.1': + resolution: {integrity: sha512-LAmu761tSN9r66ixvmciswUj/ZC+1Q4iAfpedTfSVLeswRwnY3n2Nb6Tsk+cLPP28aLOPWeMgIuTuCcMC6W/iw==} hasBin: true peerDependencies: zod: 3.25.67 @@ -7168,7 +7170,7 @@ packages: resolution: {integrity: sha512-TsQLe4i2gvoTtrHje625ngThGBySOgSK3Xo2XRYOdqGN1teR8+I7vchQC46uLJi8OF62YTYA3AhSpumtkhsaKQ==} engines: {node: '>=18.14.1'} peerDependencies: - hono: 4.12.16 + hono: 4.12.18 '@huggingface/inference@4.0.5': resolution: {integrity: sha512-/Qc45BGrN+FBA3JfdeoHfafxfNShH/dxvOsXbBdcxyxIRIYOyefeiXSlShZGVCaiqYpm+10na28D0YtvjKPTlw==} @@ -11207,8 +11209,8 @@ packages: peerDependencies: eslint: '>=9.0.0' - '@supabase/auth-js@2.69.1': - resolution: {integrity: sha512-FILtt5WjCNzmReeRLq5wRs3iShwmnWgBvxHfqapC/VoljJl+W8hDAyFmf1NVw3zH+ZjZ05AKxiKxVeb0HNWRMQ==} + '@supabase/auth-js@2.70.0': + resolution: {integrity: sha512-BaAK/tOAZFJtzF1sE3gJ2FwTjLf4ky3PSvcvLGEgEmO4BSBkwWKu8l67rLLIBZPDnCyV7Owk2uPyKHa0kj5QGg==} '@supabase/functions-js@2.4.4': resolution: {integrity: sha512-WL2p6r4AXNGwop7iwvul2BvOtuJ1YQy8EbOd0dhG1oN1q8el/BIRSFCFnWAMM/vJJlHWLi4ad22sKbKr9mvjoA==} @@ -11220,14 +11222,14 @@ packages: '@supabase/postgrest-js@1.19.4': resolution: {integrity: sha512-O4soKqKtZIW3olqmbXXbKugUtByD2jPa8kL2m2c1oozAO11uCcGrRhkZL0kVxjBLrXHE0mdSkFsMj7jDSfyNpw==} - '@supabase/realtime-js@2.11.9': - resolution: {integrity: sha512-fLseWq8tEPCO85x3TrV9Hqvk7H4SGOqnFQ223NPJSsxjSYn0EmzU1lvYO6wbA0fc8DE94beCAiiWvGvo4g33lQ==} + '@supabase/realtime-js@2.11.10': + resolution: {integrity: sha512-SJKVa7EejnuyfImrbzx+HaD9i6T784khuw1zP+MBD7BmJYChegGxYigPzkKX8CK8nGuDntmeSD3fvriaH0EGZA==} '@supabase/storage-js@2.7.1': resolution: {integrity: sha512-asYHcyDR1fKqrMpytAS1zjyEfvxuOIp1CIXX7ji4lHHcJKqyk+sLl/Vxgm4sN6u8zvuUtae9e4kDxQP2qrwWBA==} - '@supabase/supabase-js@2.49.9': - resolution: {integrity: sha512-lB2A2X8k1aWAqvlpO4uZOdfvSuZ2s0fCMwJ1Vq6tjWsi3F+au5lMbVVn92G0pG8gfmis33d64Plkm6eSDs6jRA==} + '@supabase/supabase-js@2.50.0': + resolution: {integrity: sha512-M1Gd5tPaaghYZ9OjeO1iORRqbTWFEz/cF3pPubRnMPzA+A8SiUsXXWDP+DWsASZcjEcVEcVQIAF38i5wrijYOg==} '@supercharge/promise-pool@3.1.0': resolution: {integrity: sha512-gB3NukbIcYzRtPoE6dx9svQYPodxvnfQlaaQd8N/z87E6WaMfRE7o5HwB+LZ+KeM0nsNAq1n4TmBtfz1VCUR+Q==} @@ -13105,8 +13107,8 @@ packages: resolution: {integrity: sha512-NF+epuEdnUYVlGuhaxbbq+dvJttwLnGY+YixlXlME5KpQ5W3CnXA5cVTneY3SPbPDRkcjMbifrwmFYcClgOZeg==} engines: {node: '>= 0.8'} - basic-ftp@5.3.0: - resolution: {integrity: sha512-5K9eNNn7ywHPsYnFwjKgYH8Hf8B5emh7JKcPaVjjrMJFQQwGpwowEnZNEtHs7DfR7hCZsmaK3VA4HUK0YarT+w==} + basic-ftp@5.3.1: + resolution: {integrity: sha512-bopVNp6ugyA150DDuZfPFdt1KZ5a94ZDiwX4hMgZDzF+GttD80lEy8kj98kbyhLXnPvhtIo93mdnLIjpCAeeOw==} engines: {node: '>=10.0.0'} bcrypt-pbkdf@1.0.2: @@ -15324,14 +15326,14 @@ packages: resolution: {integrity: sha512-7OnTFAVPefgw2eBJ1xj2PGGR9FwYzSUso9decayHgCDX4sJkHLdcsYTytTg+tYv+wKF3U8gJuSBz2jJpQV4u/g==} engines: {node: '>=16.1.0'} - fast-uri@3.0.1: - resolution: {integrity: sha512-MWipKbbYiYI0UC7cl8m/i/IWTqfC8YXsqjzybjddLsFjStroQzsHXkc73JutMvBiXmOvapk+axIl79ig5t55Bw==} + fast-uri@3.1.2: + resolution: {integrity: sha512-rVjf7ArG3LTk+FS6Yw81V1DLuZl1bRbNrev6Tmd/9RaroeeRRJhAt7jg/6YFxbvAQXUCavSoZhPPj6oOx+5KjQ==} fast-wrap-ansi@0.2.0: resolution: {integrity: sha512-rLV8JHxTyhVmFYhBJuMujcrHqOT2cnO5Zxj37qROj23CP39GXubJRBUFF0z8KFK77Uc0SukZUf7JZhsVEQ6n8w==} - fast-xml-builder@1.1.5: - resolution: {integrity: sha512-4TJn/8FKLeslLAH3dnohXqE3QSoxkhvaMzepOIZytwJXZO69Bfz0HBdDHzOTOon6G59Zrk6VQ2bEiv1t61rfkA==} + fast-xml-builder@1.1.7: + resolution: {integrity: sha512-Yh7/7rQuMXICNr0oMYDR2yHP6oUvmQsTToFeOWj/kIDhAwQ+c4Ol/lbcwOmEM5OHYQmh6S6EQSQ1sljCKP36bQ==} fast-xml-parser@5.7.2: resolution: {integrity: sha512-P7oW7tLbYnhOLQk/Gv7cZgzgMPP/XN03K02/Jy6Y/NHzyIAIpxuZIM/YqAkfiXFPxA2CTm7NtCijK9EDu09u2w==} @@ -15959,7 +15961,7 @@ packages: '@standard-community/standard-json': ^0.3.5 '@standard-community/standard-openapi': ^0.2.9 '@types/json-schema': ^7.0.15 - hono: 4.12.16 + hono: 4.12.18 openapi-types: ^12.1.3 peerDependenciesMeta: '@hono/standard-validator': @@ -15967,8 +15969,8 @@ packages: hono: optional: true - hono@4.12.16: - resolution: {integrity: sha512-jN0ZewiNAWSe5khM3EyCmBb250+b40wWbwNILNfEvq84VREWwOIkuUsFONk/3i3nqkz7Oe1PcpM2mwQEK2L9Kg==} + hono@4.12.18: + resolution: {integrity: sha512-RWzP96k/yv0PQfyXnWjs6zot20TqfpfsNXhOnev8d1InAxubW93L11/oNUc3tQqn2G0bSdAOBpX+2uDFHV7kdQ==} engines: {node: '>=16.9.0'} hookable@5.5.3: @@ -19741,6 +19743,7 @@ packages: resolution: {integrity: sha512-gv6vLGcmAOg96/fgo3d9tvA4dJNZL3fMyBqVRrGxQ+Q/o4k9QzbJ3NQF9cOO/71wRodoXhaPgphvMFU68qVAJQ==} deprecated: |- You or someone you depend on is using Q, the JavaScript Promise library that gave JavaScript developers strong feelings about promises. They can almost certainly migrate to the native JavaScript promise now. Thank you literally everyone for joining me in this bet against the odds. Be excellent to each other. + (For a CapTP with native promises, see @endo/eventual-send and @endo/captp) qrcode.vue@3.3.4: @@ -21923,22 +21926,8 @@ packages: deprecated: uuid@10 and below is no longer supported. For ESM codebases, update to uuid@latest. For CommonJS codebases, use uuid@11 (but be aware this version will likely be deprecated in 2028). hasBin: true - uuid@11.1.0: - resolution: {integrity: sha512-0/A9rDy9P7cJ+8w1c9WD9V//9Wj15Ce2MPz8Ri6032usz+NfePxx5AcN3bN+r6ZL6jEo066/yNYB3tn4pQEx+A==} - hasBin: true - - uuid@13.0.0: - resolution: {integrity: sha512-XQegIaBTVUjSHliKqcnFqYypAd4S+WCYt5NIeRs6w/UAry7z8Y9j5ZwRRL4kzq9U3sD6v+85er9FvkEaBpji2w==} - hasBin: true - - uuid@8.3.2: - resolution: {integrity: sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==} - deprecated: uuid@10 and below is no longer supported. For ESM codebases, update to uuid@latest. For CommonJS codebases, use uuid@11 (but be aware this version will likely be deprecated in 2028). - hasBin: true - - uuid@9.0.1: - resolution: {integrity: sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==} - deprecated: uuid@10 and below is no longer supported. For ESM codebases, update to uuid@latest. For CommonJS codebases, use uuid@11 (but be aware this version will likely be deprecated in 2028). + uuid@13.0.1: + resolution: {integrity: sha512-9ezox2roIft6ExBVTVqibSd5dc5/47Sw/uY6b4SjQUT2TzQ0tltNquWA46y4xPQmdZYqvnio22SgWd41M86+jw==} hasBin: true v-code-diff@1.13.1: @@ -22734,7 +22723,7 @@ snapshots: debug: 4.4.3(supports-color@8.1.1) lodash.clonedeep: 4.5.0 slugify: 1.6.6 - uuid: 9.0.1 + uuid: 13.0.1 transitivePeerDependencies: - supports-color @@ -22745,7 +22734,7 @@ snapshots: body-parser: 2.2.1 cors: 2.8.5 express: 4.22.1 - uuid: 11.1.0 + uuid: 13.0.1 transitivePeerDependencies: - supports-color @@ -22984,19 +22973,7 @@ snapshots: shell-quote: 1.8.3 zod: 3.25.67 - '@anthropic-ai/sdk@0.27.3(encoding@0.1.13)': - dependencies: - '@types/node': 20.19.21 - '@types/node-fetch': 2.6.13 - abort-controller: 3.0.0 - agentkeepalive: 4.6.0 - form-data-encoder: 1.7.2 - formdata-node: 4.4.1 - node-fetch: 2.7.0(encoding@0.1.13) - transitivePeerDependencies: - - encoding - - '@anthropic-ai/sdk@0.90.0(zod@3.25.67)': + '@anthropic-ai/sdk@0.91.1(zod@3.25.67)': dependencies: json-schema-to-ts: 3.1.1 optionalDependencies: @@ -23275,7 +23252,7 @@ snapshots: '@smithy/util-utf8': 4.2.2 '@types/uuid': 9.0.8 tslib: 2.8.1 - uuid: 9.0.1 + uuid: 13.0.1 transitivePeerDependencies: - aws-crt @@ -23383,7 +23360,7 @@ snapshots: '@smithy/util-waiter': 4.0.3 '@types/uuid': 9.0.8 tslib: 2.8.1 - uuid: 9.0.1 + uuid: 13.0.1 transitivePeerDependencies: - aws-crt @@ -23429,7 +23406,7 @@ snapshots: '@smithy/util-utf8': 4.2.0 '@types/uuid': 9.0.8 tslib: 2.8.1 - uuid: 9.0.1 + uuid: 13.0.1 transitivePeerDependencies: - aws-crt @@ -24660,7 +24637,7 @@ snapshots: http-proxy-agent: 5.0.0 https-proxy-agent: 5.0.1 tslib: 2.8.1 - uuid: 8.3.2 + uuid: 13.0.1 transitivePeerDependencies: - supports-color @@ -24777,7 +24754,7 @@ snapshots: dependencies: '@azure/msal-common': 15.13.3 jsonwebtoken: 9.0.3 - uuid: 8.3.2 + uuid: 13.0.1 '@azure/search-documents@12.1.0': dependencies: @@ -26079,7 +26056,7 @@ snapshots: '@browserbasehq/stagehand@1.14.0(@playwright/test@1.58.0)(bufferutil@4.0.9)(deepmerge@4.3.1)(dotenv@17.3.1)(encoding@0.1.13)(openai@6.34.0(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)': dependencies: - '@anthropic-ai/sdk': 0.27.3(encoding@0.1.13) + '@anthropic-ai/sdk': 0.91.1(zod@3.25.67) '@browserbasehq/sdk': 2.6.0(encoding@0.1.13) '@playwright/test': 1.58.0 deepmerge: 4.3.1 @@ -26841,7 +26818,7 @@ snapshots: p-limit: 3.1.0 retry-request: 7.0.2(encoding@0.1.13) teeny-request: 9.0.0(encoding@0.1.13) - uuid: 8.3.2 + uuid: 13.0.1 transitivePeerDependencies: - encoding - supports-color @@ -26887,9 +26864,9 @@ snapshots: protobufjs: 7.5.5 yargs: 17.7.2 - '@hono/node-server@1.19.13(hono@4.12.16)': + '@hono/node-server@1.19.13(hono@4.12.18)': dependencies: - hono: 4.12.16 + hono: 4.12.18 '@huggingface/inference@4.0.5': dependencies: @@ -27527,7 +27504,7 @@ snapshots: '@langchain/anthropic@1.3.27(@langchain/core@1.1.41(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.213.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@6.34.0(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)))': dependencies: - '@anthropic-ai/sdk': 0.90.0(zod@3.25.67) + '@anthropic-ai/sdk': 0.91.1(zod@3.25.67) '@langchain/core': 1.1.41(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.213.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@6.34.0(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)) zod: 3.25.67 @@ -27550,7 +27527,7 @@ snapshots: js-yaml: 4.1.1 jsonpointer: 5.0.1 openapi-types: 12.1.3 - uuid: 10.0.0 + uuid: 13.0.1 yaml: 2.8.3 zod: 3.25.67 optionalDependencies: @@ -27567,12 +27544,12 @@ snapshots: dependencies: '@langchain/core': 1.1.41(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.213.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@6.34.0(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)) cohere-ai: 7.14.0(encoding@0.1.13) - uuid: 10.0.0 + uuid: 13.0.1 transitivePeerDependencies: - aws-crt - encoding - '@langchain/community@1.1.27(9a33d502a76e23e4d14d11cb4afe5d89)': + '@langchain/community@1.1.27(c9a60e7ac4d70846d24c187ff47dea5e)': dependencies: '@browserbasehq/stagehand': 1.14.0(@playwright/test@1.58.0)(bufferutil@4.0.9)(deepmerge@4.3.1)(dotenv@17.3.1)(encoding@0.1.13)(openai@6.34.0(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 @@ -27586,7 +27563,57 @@ snapshots: langsmith: 0.5.19(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.213.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@6.34.0(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)) math-expression-evaluator: 2.0.7 openai: 6.34.0(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.25.67) - uuid: 10.0.0 + uuid: 13.0.1 + zod: 3.25.67 + optionalDependencies: + '@aws-crypto/sha256-js': 5.2.0 + '@aws-sdk/credential-provider-node': 3.936.0 + '@browserbasehq/sdk': 2.6.0(encoding@0.1.13) + '@getzep/zep-cloud': 1.0.6(2003b72c02d3482f7ce12b49a2ef08f6) + '@google-cloud/storage': 7.12.1(encoding@0.1.13) + '@libsql/client': 0.17.2(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10) + '@mozilla/readability': 0.6.0 + '@smithy/protocol-http': 5.3.12 + '@smithy/util-utf8': 4.2.2 + '@supabase/supabase-js': 2.50.0(bufferutil@4.0.9)(utf-8-validate@5.0.10) + '@zilliz/milvus2-sdk-node': 2.5.7 + chromadb: 3.2.0 + crypto-js: 4.2.0 + epub2: 3.0.2(ts-toolbelt@9.6.0) + fast-xml-parser: 5.7.2 + google-auth-library: 10.1.0 + html-to-text: 9.0.5 + ignore: 7.0.5 + ioredis: 5.3.2 + jsdom: 23.0.1(bufferutil@4.0.9)(utf-8-validate@5.0.10) + jsonwebtoken: 9.0.3 + lodash: 4.18.1 + mammoth: 1.12.0 + pdf-parse: 2.4.5 + pg: 8.17.0 + puppeteer: 24.41.0(bufferutil@4.0.9)(typescript@6.0.2)(utf-8-validate@5.0.10) + ws: 8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10) + transitivePeerDependencies: + - '@opentelemetry/api' + - '@opentelemetry/exporter-trace-otlp-proto' + - '@opentelemetry/sdk-trace-base' + - peggy + + '@langchain/community@1.1.27(dc13b8a57dd722a7e537a40aec8cb772)': + dependencies: + '@browserbasehq/stagehand': 1.14.0(@playwright/test@1.58.0)(bufferutil@4.0.9)(deepmerge@4.3.1)(dotenv@17.3.1)(encoding@0.1.13)(openai@6.34.0(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 + '@langchain/classic': 1.0.27(@langchain/core@1.1.41(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.213.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@6.34.0(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)))(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.213.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(cheerio@1.0.0)(openai@6.34.0(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)) + '@langchain/core': 1.1.41(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.213.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@6.34.0(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)) + '@langchain/openai': 1.4.1(@langchain/core@1.1.41(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.213.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@6.34.0(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)))(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10)) + binary-extensions: 2.2.0 + flat: 5.0.2 + ibm-cloud-sdk-core: 5.3.2 + js-yaml: 4.1.1 + langsmith: 0.5.19(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.213.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@6.34.0(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)) + math-expression-evaluator: 2.0.7 + openai: 6.34.0(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.25.67) + uuid: 13.0.1 zod: 3.25.67 optionalDependencies: '@aws-crypto/sha256-js': 5.2.0 @@ -27603,7 +27630,7 @@ snapshots: '@qdrant/js-client-rest': 1.16.2(typescript@6.0.2) '@smithy/protocol-http': 5.3.12 '@smithy/util-utf8': 4.2.2 - '@supabase/supabase-js': 2.49.9(bufferutil@4.0.9)(utf-8-validate@5.0.10) + '@supabase/supabase-js': 2.50.0(bufferutil@4.0.9)(utf-8-validate@5.0.10) '@xata.io/client': 0.28.4(typescript@6.0.2) '@zilliz/milvus2-sdk-node': 2.5.7 cheerio: 1.0.0 @@ -27634,56 +27661,6 @@ snapshots: - '@opentelemetry/sdk-trace-base' - peggy - '@langchain/community@1.1.27(eda736f6c818f128b670206c8d2822df)': - dependencies: - '@browserbasehq/stagehand': 1.14.0(@playwright/test@1.58.0)(bufferutil@4.0.9)(deepmerge@4.3.1)(dotenv@17.3.1)(encoding@0.1.13)(openai@6.34.0(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 - '@langchain/classic': 1.0.27(@langchain/core@1.1.41(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.213.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@6.34.0(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)))(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.213.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(cheerio@1.0.0)(openai@6.34.0(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)) - '@langchain/core': 1.1.41(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.213.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@6.34.0(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)) - '@langchain/openai': 1.4.1(@langchain/core@1.1.41(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.213.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@6.34.0(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)))(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10)) - binary-extensions: 2.2.0 - flat: 5.0.2 - ibm-cloud-sdk-core: 5.3.2 - js-yaml: 4.1.1 - langsmith: 0.5.19(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.213.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@6.34.0(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)) - math-expression-evaluator: 2.0.7 - openai: 6.34.0(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.25.67) - uuid: 10.0.0 - zod: 3.25.67 - optionalDependencies: - '@aws-crypto/sha256-js': 5.2.0 - '@aws-sdk/credential-provider-node': 3.936.0 - '@browserbasehq/sdk': 2.6.0(encoding@0.1.13) - '@getzep/zep-cloud': 1.0.6(2003b72c02d3482f7ce12b49a2ef08f6) - '@google-cloud/storage': 7.12.1(encoding@0.1.13) - '@libsql/client': 0.17.2(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10) - '@mozilla/readability': 0.6.0 - '@smithy/protocol-http': 5.3.12 - '@smithy/util-utf8': 4.2.2 - '@supabase/supabase-js': 2.49.9(bufferutil@4.0.9)(utf-8-validate@5.0.10) - '@zilliz/milvus2-sdk-node': 2.5.7 - chromadb: 3.2.0 - crypto-js: 4.2.0 - epub2: 3.0.2(ts-toolbelt@9.6.0) - fast-xml-parser: 5.7.2 - google-auth-library: 10.1.0 - html-to-text: 9.0.5 - ignore: 7.0.5 - ioredis: 5.3.2 - jsdom: 23.0.1(bufferutil@4.0.9)(utf-8-validate@5.0.10) - jsonwebtoken: 9.0.3 - lodash: 4.18.1 - mammoth: 1.12.0 - pdf-parse: 2.4.5 - pg: 8.17.0 - puppeteer: 24.41.0(bufferutil@4.0.9)(typescript@6.0.2)(utf-8-validate@5.0.10) - ws: 8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10) - transitivePeerDependencies: - - '@opentelemetry/api' - - '@opentelemetry/exporter-trace-otlp-proto' - - '@opentelemetry/sdk-trace-base' - - peggy - '@langchain/core@1.1.41(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.213.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@6.34.0(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))': dependencies: '@cfworker/json-schema': 4.1.0 @@ -27695,7 +27672,7 @@ snapshots: langsmith: 0.5.19(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.213.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@6.34.0(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)) mustache: 4.2.0 p-queue: 6.6.2 - uuid: 11.1.0 + uuid: 13.0.1 zod: 3.25.67 transitivePeerDependencies: - '@opentelemetry/api' @@ -27707,7 +27684,7 @@ snapshots: '@langchain/google-common@2.1.24(@langchain/core@1.1.41(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.213.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@6.34.0(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)))': dependencies: '@langchain/core': 1.1.41(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.213.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@6.34.0(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)) - uuid: 10.0.0 + uuid: 13.0.1 '@langchain/google-gauth@2.1.24(@langchain/core@1.1.41(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.213.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@6.34.0(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)))': dependencies: @@ -27721,7 +27698,7 @@ snapshots: dependencies: '@google/generative-ai': 0.24.0 '@langchain/core': 1.1.41(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.213.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@6.34.0(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)) - uuid: 11.1.0 + uuid: 13.0.1 '@langchain/google-vertexai@2.1.24(@langchain/core@1.1.41(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.213.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@6.34.0(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)))': dependencies: @@ -27740,13 +27717,13 @@ snapshots: '@langchain/langgraph-checkpoint@1.0.0(@langchain/core@1.1.41(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.213.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@6.34.0(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)))': dependencies: '@langchain/core': 1.1.41(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.213.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@6.34.0(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)) - uuid: 10.0.0 + uuid: 13.0.1 '@langchain/langgraph-sdk@1.0.2(@langchain/core@1.1.41(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.213.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@6.34.0(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)))(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': dependencies: p-queue: 6.6.2 p-retry: 4.6.2 - uuid: 9.0.1 + uuid: 13.0.1 optionalDependencies: '@langchain/core': 1.1.41(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.213.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@6.34.0(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)) react: 18.2.0 @@ -27757,7 +27734,7 @@ snapshots: '@types/json-schema': 7.0.15 p-queue: 9.1.0 p-retry: 7.1.1 - uuid: 13.0.0 + uuid: 13.0.1 optionalDependencies: '@langchain/core': 1.1.41(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.213.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@6.34.0(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)) react: 18.2.0 @@ -27769,7 +27746,7 @@ snapshots: '@langchain/core': 1.1.41(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.213.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@6.34.0(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)) '@langchain/langgraph-checkpoint': 1.0.0(@langchain/core@1.1.41(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.213.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@6.34.0(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))) '@langchain/langgraph-sdk': 1.0.2(@langchain/core@1.1.41(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.213.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@6.34.0(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)))(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - uuid: 10.0.0 + uuid: 13.0.1 zod: 3.25.67 optionalDependencies: zod-to-json-schema: 3.25.1(zod@3.25.67) @@ -27783,7 +27760,7 @@ snapshots: '@langchain/langgraph-checkpoint': 1.0.0(@langchain/core@1.1.41(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.213.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@6.34.0(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))) '@langchain/langgraph-sdk': 1.7.2(@langchain/core@1.1.41(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.213.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@6.34.0(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)))(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(vue@3.5.26(typescript@6.0.2)) '@standard-schema/spec': 1.1.0 - uuid: 10.0.0 + uuid: 13.0.1 zod: 3.25.67 optionalDependencies: zod-to-json-schema: 3.23.3(zod@3.25.67) @@ -27800,7 +27777,7 @@ snapshots: '@langchain/langgraph-checkpoint': 1.0.0(@langchain/core@1.1.41(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.213.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@6.34.0(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))) '@langchain/langgraph-sdk': 1.7.2(@langchain/core@1.1.41(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.213.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@6.34.0(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)))(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(vue@3.5.26(typescript@6.0.2)) '@standard-schema/spec': 1.1.0 - uuid: 10.0.0 + uuid: 13.0.1 zod: 3.25.67 optionalDependencies: zod-to-json-schema: 3.25.1(zod@3.25.67) @@ -27828,7 +27805,7 @@ snapshots: dependencies: '@langchain/core': 1.1.41(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.213.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@6.34.0(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)) '@mistralai/mistralai': 1.10.0 - uuid: 10.0.0 + uuid: 13.0.1 '@langchain/mongodb@1.0.1(@aws-sdk/credential-providers@3.808.0)(@langchain/core@1.1.41(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.213.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@6.34.0(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)))(gcp-metadata@5.3.0)(socks@2.8.3)': dependencies: @@ -27847,7 +27824,7 @@ snapshots: dependencies: '@langchain/core': 1.1.41(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.213.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@6.34.0(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)) ollama: 0.6.3 - uuid: 10.0.0 + uuid: 13.0.1 '@langchain/openai@1.4.1(@langchain/core@1.1.41(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.213.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@6.34.0(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)))(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10))': dependencies: @@ -27872,13 +27849,13 @@ snapshots: '@langchain/core': 1.1.41(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.213.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@6.34.0(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)) '@pinecone-database/pinecone': 5.1.2 flat: 5.0.2 - uuid: 10.0.0 + uuid: 13.0.1 '@langchain/qdrant@1.0.1(@langchain/core@1.1.41(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.213.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@6.34.0(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)))(typescript@6.0.2)': dependencies: '@langchain/core': 1.1.41(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.213.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@6.34.0(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)) '@qdrant/js-client-rest': 1.16.2(typescript@6.0.2) - uuid: 10.0.0 + uuid: 13.0.1 transitivePeerDependencies: - typescript @@ -27895,7 +27872,7 @@ snapshots: '@langchain/weaviate@1.0.1(@langchain/core@1.1.41(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.213.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@6.34.0(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)))(encoding@0.1.13)': dependencies: '@langchain/core': 1.1.41(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.213.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@6.34.0(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)) - uuid: 10.0.0 + uuid: 13.0.1 weaviate-client: 3.9.0(encoding@0.1.13) transitivePeerDependencies: - encoding @@ -28044,8 +28021,8 @@ snapshots: dotenv: 17.3.1 execa: 9.6.1 gray-matter: 4.0.3 - hono: 4.12.16 - hono-openapi: 1.3.0(@standard-community/standard-json@0.3.5(@standard-schema/spec@1.1.0)(@types/json-schema@7.0.15)(quansync@0.2.11)(zod-to-json-schema@3.25.1(zod@3.25.67))(zod@3.25.67))(@standard-community/standard-openapi@0.2.9(@standard-community/standard-json@0.3.5(@standard-schema/spec@1.1.0)(@types/json-schema@7.0.15)(quansync@0.2.11)(zod-to-json-schema@3.25.1(zod@3.25.67))(zod@3.25.67))(@standard-schema/spec@1.1.0)(openapi-types@12.1.3)(zod@3.25.67))(@types/json-schema@7.0.15)(hono@4.12.16)(openapi-types@12.1.3) + hono: 4.12.18 + hono-openapi: 1.3.0(@standard-community/standard-json@0.3.5(@standard-schema/spec@1.1.0)(@types/json-schema@7.0.15)(quansync@0.2.11)(zod-to-json-schema@3.25.1(zod@3.25.67))(zod@3.25.67))(@standard-community/standard-openapi@0.2.9(@standard-community/standard-json@0.3.5(@standard-schema/spec@1.1.0)(@types/json-schema@7.0.15)(quansync@0.2.11)(zod-to-json-schema@3.25.1(zod@3.25.67))(zod@3.25.67))(@standard-schema/spec@1.1.0)(openapi-types@12.1.3)(zod@3.25.67))(@types/json-schema@7.0.15)(hono@4.12.18)(openapi-types@12.1.3) ignore: 7.0.5 js-tiktoken: 1.0.21 json-schema: 0.4.0 @@ -28085,7 +28062,7 @@ snapshots: '@modelcontextprotocol/sdk': 1.28.0(zod@3.25.67) exit-hook: 5.1.0 fast-deep-equal: 3.1.3 - uuid: 13.0.0 + uuid: 13.0.1 zod: 3.25.67 transitivePeerDependencies: - '@cfworker/json-schema' @@ -28246,9 +28223,9 @@ snapshots: '@microsoft/agents-a365-runtime': 0.1.0-preview.113 '@microsoft/agents-a365-tooling': 0.1.0-preview.113(zod@3.25.67) '@microsoft/agents-hosting': 1.2.3 - hono: 4.12.16 + hono: 4.12.18 langchain: 1.2.30(@langchain/core@1.1.41(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.213.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@6.34.0(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)))(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.213.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@6.34.0(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.25.67))(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(vue@3.5.26(typescript@6.0.2))(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod-to-json-schema@3.23.3(zod@3.25.67)) - uuid: 9.0.1 + uuid: 13.0.1 optionalDependencies: '@langchain/langgraph': 1.2.2(@langchain/core@1.1.41(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.213.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@6.34.0(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)))(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(vue@3.5.26(typescript@6.0.2))(zod-to-json-schema@3.23.3(zod@3.25.67))(zod@3.25.67) transitivePeerDependencies: @@ -28274,7 +28251,7 @@ snapshots: '@microsoft/agents-hosting': 1.2.3 '@modelcontextprotocol/sdk': 1.26.0(zod@3.25.67) express: 5.2.1 - hono: 4.12.16 + hono: 4.12.18 transitivePeerDependencies: - '@cfworker/json-schema' - debug @@ -28284,7 +28261,7 @@ snapshots: '@microsoft/agents-activity@1.2.3': dependencies: debug: 4.4.3(supports-color@8.1.1) - uuid: 11.1.0 + uuid: 13.0.1 zod: 3.25.67 transitivePeerDependencies: - supports-color @@ -28353,7 +28330,7 @@ snapshots: '@modelcontextprotocol/sdk@1.26.0(zod@3.25.67)': dependencies: - '@hono/node-server': 1.19.13(hono@4.12.16) + '@hono/node-server': 1.19.13(hono@4.12.18) ajv: 8.18.0 ajv-formats: 3.0.1(ajv@8.18.0) content-type: 1.0.5 @@ -28363,7 +28340,7 @@ snapshots: eventsource-parser: 3.0.6 express: 5.2.1 express-rate-limit: 8.2.2(express@5.2.1) - hono: 4.12.16 + hono: 4.12.18 jose: 6.1.3 json-schema-typed: 8.0.2 pkce-challenge: 5.0.0(patch_hash=651e785d0b7bbf5be9210e1e895c39a16dc3ce8a5a3843b4819565fb6e175b90) @@ -28375,7 +28352,7 @@ snapshots: '@modelcontextprotocol/sdk@1.28.0(zod@3.25.67)': dependencies: - '@hono/node-server': 1.19.13(hono@4.12.16) + '@hono/node-server': 1.19.13(hono@4.12.18) ajv: 8.18.0 ajv-formats: 3.0.1(ajv@8.18.0) content-type: 1.0.5 @@ -28385,7 +28362,7 @@ snapshots: eventsource-parser: 3.0.6 express: 5.2.1 express-rate-limit: 8.2.2(express@5.2.1) - hono: 4.12.16 + hono: 4.12.18 jose: 6.2.2 json-schema-typed: 8.0.2 pkce-challenge: 5.0.0(patch_hash=651e785d0b7bbf5be9210e1e895c39a16dc3ce8a5a3843b4819565fb6e175b90) @@ -28452,7 +28429,7 @@ snapshots: sha.js: 2.4.12 tarn: 3.0.2 tslib: 2.8.1 - uuid: 9.0.1 + uuid: 13.0.1 optionalDependencies: '@sentry/node': 10.36.0 mysql2: 3.17.0 @@ -30322,7 +30299,7 @@ snapshots: ms: 2.1.3 remove-trailing-slash: 0.1.1 tslib: 2.8.1 - uuid: 11.1.0 + uuid: 13.0.1 optionalDependencies: bull: 4.16.5 transitivePeerDependencies: @@ -30915,7 +30892,7 @@ snapshots: '@smithy/util-middleware': 4.2.5 '@smithy/util-retry': 4.2.5 tslib: 2.8.1 - uuid: 9.0.1 + uuid: 13.0.1 '@smithy/middleware-retry@4.4.12': dependencies: @@ -31614,7 +31591,7 @@ snapshots: estraverse: 5.3.0 picomatch: 4.0.4 - '@supabase/auth-js@2.69.1': + '@supabase/auth-js@2.70.0': dependencies: '@supabase/node-fetch': 2.6.15 @@ -31630,7 +31607,7 @@ snapshots: dependencies: '@supabase/node-fetch': 2.6.15 - '@supabase/realtime-js@2.11.9(bufferutil@4.0.9)(utf-8-validate@5.0.10)': + '@supabase/realtime-js@2.11.10(bufferutil@4.0.9)(utf-8-validate@5.0.10)': dependencies: '@supabase/node-fetch': 2.6.15 '@types/phoenix': 1.6.6 @@ -31644,13 +31621,13 @@ snapshots: dependencies: '@supabase/node-fetch': 2.6.15 - '@supabase/supabase-js@2.49.9(bufferutil@4.0.9)(utf-8-validate@5.0.10)': + '@supabase/supabase-js@2.50.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)': dependencies: - '@supabase/auth-js': 2.69.1 + '@supabase/auth-js': 2.70.0 '@supabase/functions-js': 2.4.4 '@supabase/node-fetch': 2.6.15 '@supabase/postgrest-js': 1.19.4 - '@supabase/realtime-js': 2.11.9(bufferutil@4.0.9)(utf-8-validate@5.0.10) + '@supabase/realtime-js': 2.11.10(bufferutil@4.0.9)(utf-8-validate@5.0.10) '@supabase/storage-js': 2.7.1 transitivePeerDependencies: - bufferutil @@ -33331,7 +33308,7 @@ snapshots: ajv@8.18.0: dependencies: fast-deep-equal: 3.1.3 - fast-uri: 3.0.1 + fast-uri: 3.1.2 json-schema-traverse: 1.0.0 require-from-string: 2.0.2 @@ -33929,7 +33906,7 @@ snapshots: dependencies: safe-buffer: 5.1.2 - basic-ftp@5.3.0: {} + basic-ftp@5.3.1: {} bcrypt-pbkdf@1.0.2: dependencies: @@ -34191,7 +34168,7 @@ snapshots: lodash: 4.18.1 msgpackr: 1.11.2 semver: 7.7.2 - uuid: 8.3.2 + uuid: 13.0.1 transitivePeerDependencies: - supports-color @@ -34203,7 +34180,7 @@ snapshots: lodash: 4.18.1 msgpackr: 1.11.2 semver: 7.7.3 - uuid: 8.3.2 + uuid: 13.0.1 transitivePeerDependencies: - supports-color optional: true @@ -35522,7 +35499,7 @@ snapshots: docker-modem: 5.0.6 protobufjs: 7.5.5 tar-fs: 2.1.4 - uuid: 10.0.0 + uuid: 13.0.1 transitivePeerDependencies: - supports-color @@ -36714,20 +36691,20 @@ snapshots: '@babel/runtime': 7.28.4 tslib: 2.8.1 - fast-uri@3.0.1: {} + fast-uri@3.1.2: {} fast-wrap-ansi@0.2.0: dependencies: fast-string-width: 3.0.2 - fast-xml-builder@1.1.5: + fast-xml-builder@1.1.7: dependencies: path-expression-matcher: 1.5.0 fast-xml-parser@5.7.2: dependencies: '@nodable/entities': 2.1.0 - fast-xml-builder: 1.1.5 + fast-xml-builder: 1.1.7 path-expression-matcher: 1.5.0 strnum: 2.2.3 @@ -37144,7 +37121,7 @@ snapshots: get-uri@6.0.5: dependencies: - basic-ftp: 5.3.0 + basic-ftp: 5.3.1 data-uri-to-buffer: 6.0.2 debug: 4.4.3(supports-color@8.1.1) transitivePeerDependencies: @@ -37321,7 +37298,7 @@ snapshots: proto3-json-serializer: 2.0.2 protobufjs: 7.5.5 retry-request: 7.0.2(encoding@0.1.13) - uuid: 9.0.1 + uuid: 13.0.1 transitivePeerDependencies: - encoding - supports-color @@ -37485,16 +37462,16 @@ snapshots: dependencies: parse-passwd: 1.0.0 - hono-openapi@1.3.0(@standard-community/standard-json@0.3.5(@standard-schema/spec@1.1.0)(@types/json-schema@7.0.15)(quansync@0.2.11)(zod-to-json-schema@3.25.1(zod@3.25.67))(zod@3.25.67))(@standard-community/standard-openapi@0.2.9(@standard-community/standard-json@0.3.5(@standard-schema/spec@1.1.0)(@types/json-schema@7.0.15)(quansync@0.2.11)(zod-to-json-schema@3.25.1(zod@3.25.67))(zod@3.25.67))(@standard-schema/spec@1.1.0)(openapi-types@12.1.3)(zod@3.25.67))(@types/json-schema@7.0.15)(hono@4.12.16)(openapi-types@12.1.3): + hono-openapi@1.3.0(@standard-community/standard-json@0.3.5(@standard-schema/spec@1.1.0)(@types/json-schema@7.0.15)(quansync@0.2.11)(zod-to-json-schema@3.25.1(zod@3.25.67))(zod@3.25.67))(@standard-community/standard-openapi@0.2.9(@standard-community/standard-json@0.3.5(@standard-schema/spec@1.1.0)(@types/json-schema@7.0.15)(quansync@0.2.11)(zod-to-json-schema@3.25.1(zod@3.25.67))(zod@3.25.67))(@standard-schema/spec@1.1.0)(openapi-types@12.1.3)(zod@3.25.67))(@types/json-schema@7.0.15)(hono@4.12.18)(openapi-types@12.1.3): dependencies: '@standard-community/standard-json': 0.3.5(@standard-schema/spec@1.1.0)(@types/json-schema@7.0.15)(quansync@0.2.11)(zod-to-json-schema@3.25.1(zod@3.25.67))(zod@3.25.67) '@standard-community/standard-openapi': 0.2.9(@standard-community/standard-json@0.3.5(@standard-schema/spec@1.1.0)(@types/json-schema@7.0.15)(quansync@0.2.11)(zod-to-json-schema@3.25.1(zod@3.25.67))(zod@3.25.67))(@standard-schema/spec@1.1.0)(openapi-types@12.1.3)(zod@3.25.67) '@types/json-schema': 7.0.15 openapi-types: 12.1.3 optionalDependencies: - hono: 4.12.16 + hono: 4.12.18 - hono@4.12.16: {} + hono@4.12.18: {} hookable@5.5.3: {} @@ -37681,7 +37658,7 @@ snapshots: hyperid@3.3.0: dependencies: buffer: 5.7.1 - uuid: 8.3.2 + uuid: 13.0.1 uuid-parse: 1.1.0 ibm-cloud-sdk-core@5.3.2: @@ -38160,7 +38137,7 @@ snapshots: istanbul-lib-coverage: 3.2.2 p-map: 3.0.0 rimraf: 3.0.2 - uuid: 8.3.2 + uuid: 13.0.1 istanbul-lib-report@3.0.1: dependencies: @@ -38511,7 +38488,7 @@ snapshots: dependencies: mkdirp: 1.0.4 strip-ansi: 6.0.1 - uuid: 8.3.2 + uuid: 13.0.1 xml: 1.0.1 jest-leak-detector@29.6.2: @@ -39197,7 +39174,7 @@ snapshots: '@langchain/langgraph': 1.2.2(@langchain/core@1.1.41(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.213.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@6.34.0(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)))(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(vue@3.5.26(typescript@6.0.2))(zod-to-json-schema@3.23.3(zod@3.25.67))(zod@3.25.67) '@langchain/langgraph-checkpoint': 1.0.0(@langchain/core@1.1.41(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.213.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@6.34.0(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))) langsmith: 0.5.19(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.213.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@6.34.0(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)) - uuid: 11.1.0 + uuid: 13.0.1 zod: 3.25.67 transitivePeerDependencies: - '@angular/core' @@ -39218,7 +39195,7 @@ snapshots: '@langchain/langgraph': 1.2.2(@langchain/core@1.1.41(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.213.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@6.34.0(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)))(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(vue@3.5.26(typescript@6.0.2))(zod-to-json-schema@3.25.1(zod@3.25.67))(zod@3.25.67) '@langchain/langgraph-checkpoint': 1.0.0(@langchain/core@1.1.41(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.213.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@6.34.0(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))) langsmith: 0.5.19(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.213.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@6.34.0(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)) - uuid: 11.1.0 + uuid: 13.0.1 zod: 3.25.67 transitivePeerDependencies: - '@angular/core' @@ -39247,7 +39224,7 @@ snapshots: langsmith@0.5.19(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.213.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@6.34.0(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)): dependencies: p-queue: 6.6.2 - uuid: 10.0.0 + uuid: 13.0.1 optionalDependencies: '@opentelemetry/api': 1.9.0 '@opentelemetry/exporter-trace-otlp-proto': 0.213.0(@opentelemetry/api@1.9.0) @@ -39271,7 +39248,7 @@ snapshots: asn1: 0.2.6 debug: 4.3.4 strict-event-emitter-types: 2.0.0 - uuid: 9.0.1 + uuid: 13.0.1 transitivePeerDependencies: - supports-color @@ -40147,7 +40124,7 @@ snapshots: dependencies: '@types/uuid': 8.3.4 nanoid: 3.3.11 - uuid: 8.3.2 + uuid: 13.0.1 minimalistic-assert@1.0.1: {} @@ -43034,7 +43011,7 @@ snapshots: node-forge: 1.4.0 node-rsa: 1.1.1 pako: 1.0.11 - uuid: 8.3.2 + uuid: 13.0.1 xml: 1.0.1 xml-crypto: 6.1.2 xml-escape: 1.1.0 @@ -43522,7 +43499,7 @@ snapshots: python-struct: 1.1.3 simple-lru-cache: 0.0.2 toml: 3.0.0 - uuid: 8.3.2 + uuid: 13.0.1 winston: 3.14.2 wiremock-rest-client: 1.11.0(encoding@0.1.13) transitivePeerDependencies: @@ -44223,7 +44200,7 @@ snapshots: https-proxy-agent: 5.0.1 node-fetch: 2.7.0(encoding@0.1.13) stream-events: 1.0.5 - uuid: 9.0.1 + uuid: 13.0.1 transitivePeerDependencies: - encoding - supports-color @@ -45013,13 +44990,7 @@ snapshots: uuid@10.0.0: {} - uuid@11.1.0: {} - - uuid@13.0.0: {} - - uuid@8.3.2: {} - - uuid@9.0.1: {} + uuid@13.0.1: {} v-code-diff@1.13.1(patch_hash=21588de80e591bbc1e5a068d9bce311db5254686443652945d2c7887fdafe9d9)(vue@3.5.26(typescript@6.0.2)): dependencies: @@ -45422,7 +45393,7 @@ snapshots: nice-grpc: 2.1.12 nice-grpc-client-middleware-retry: 3.1.11 nice-grpc-common: 2.0.2 - uuid: 9.0.1 + uuid: 13.0.1 transitivePeerDependencies: - encoding diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index bb6a037960e..a4a65c624e3 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -48,6 +48,7 @@ catalog: '@openrouter/ai-sdk-provider': ^2.8.0 '@rudderstack/rudder-sdk-node': 3.0.5 '@sentry/node': ^10.36.0 + '@supabase/supabase-js': 2.50.0 '@testcontainers/k3s': ^11.13.0 '@testcontainers/kafka': ^11.13.0 '@testcontainers/mysql': ^11.13.0 @@ -62,8 +63,8 @@ catalog: '@types/uuid': ^10.0.0 '@types/xml2js': ^0.4.14 '@vitest/coverage-v8': 4.1.1 - axios: 1.16.0 agent-browser: 0.26.0 + axios: 1.16.0 basic-auth: 2.0.1 callsites: 3.1.0 chokidar: 4.0.3 From 94e403300b44d2f25f4d88dd3d9d1300adfea3bc Mon Sep 17 00:00:00 2001 From: Dawid Myslak Date: Mon, 11 May 2026 22:04:15 +0200 Subject: [PATCH 02/29] feat(Asana Trigger Node): Add webhook request verification (#29258) --- .../nodes/Asana/AsanaTrigger.node.ts | 23 +-- .../nodes/Asana/AsanaTriggerHelpers.ts | 40 +++++ .../Asana/test/AsanaTrigger.node.test.ts | 149 ++++++++++++++++++ .../Asana/test/AsanaTriggerHelpers.test.ts | 122 ++++++++++++++ 4 files changed, 318 insertions(+), 16 deletions(-) create mode 100644 packages/nodes-base/nodes/Asana/AsanaTriggerHelpers.ts create mode 100644 packages/nodes-base/nodes/Asana/test/AsanaTrigger.node.test.ts create mode 100644 packages/nodes-base/nodes/Asana/test/AsanaTriggerHelpers.test.ts diff --git a/packages/nodes-base/nodes/Asana/AsanaTrigger.node.ts b/packages/nodes-base/nodes/Asana/AsanaTrigger.node.ts index 6a30bcfba56..5604ac84344 100644 --- a/packages/nodes-base/nodes/Asana/AsanaTrigger.node.ts +++ b/packages/nodes-base/nodes/Asana/AsanaTrigger.node.ts @@ -10,12 +10,9 @@ import type { } from 'n8n-workflow'; import { NodeConnectionTypes, NodeOperationError } from 'n8n-workflow'; +import { verifySignature } from './AsanaTriggerHelpers'; import { asanaApiRequest, getWorkspaces } from './GenericFunctions'; -// import { -// createHmac, -// } from 'crypto'; - export class AsanaTrigger implements INodeType { description: INodeTypeDescription = { displayName: 'Asana Trigger', @@ -209,6 +206,12 @@ export class AsanaTrigger implements INodeType { }; } + if (!verifySignature.call(this)) { + const res = this.getResponseObject(); + res.status(401).send('Unauthorized').end(); + return { noWebhookResponse: true }; + } + // Is regular webhook call // Check if it contains any events if ( @@ -221,18 +224,6 @@ export class AsanaTrigger implements INodeType { return {}; } - // TODO: Had to be deactivated as it is currently not possible to get the secret - // in production mode as the static data overwrites each other because the - // two exist at the same time (create webhook [with webhookId] and receive - // webhook [with secret]) - // // Check if the request is valid - // // (if the signature matches to data and hookSecret) - // const computedSignature = createHmac('sha256', webhookData.hookSecret as string).update(JSON.stringify(req.body)).digest('hex'); - // if (headerData['x-hook-signature'] !== computedSignature) { - // // Signature is not valid so ignore call - // return {}; - // } - return { workflowData: [this.helpers.returnJsonArray(req.body.events as IDataObject[])], }; diff --git a/packages/nodes-base/nodes/Asana/AsanaTriggerHelpers.ts b/packages/nodes-base/nodes/Asana/AsanaTriggerHelpers.ts new file mode 100644 index 00000000000..c7c9f489a5b --- /dev/null +++ b/packages/nodes-base/nodes/Asana/AsanaTriggerHelpers.ts @@ -0,0 +1,40 @@ +import { createHmac } from 'crypto'; +import type { IWebhookFunctions } from 'n8n-workflow'; + +import { verifySignature as verifySignatureGeneric } from '../../utils/webhook-signature-verification'; + +/** + * Verifies the Asana webhook signature. + * + * Asana signs webhooks using HMAC SHA-256: + * 1. Compute an HMAC SHA-256 of the raw request body using the shared secret + * received during the initial handshake (X-Hook-Secret header) + * 2. Encode the digest as a hexadecimal string + * 3. Compare against the value of the `X-Hook-Signature` header + * + * @returns true if the signature is valid, or no secret has been stored yet + * (backward compatibility with webhooks created before verification + * was introduced); false otherwise. + */ +export function verifySignature(this: IWebhookFunctions): boolean { + const req = this.getRequestObject(); + const webhookData = this.getWorkflowStaticData('node'); + const secret = webhookData.hookSecret; + + return verifySignatureGeneric({ + getExpectedSignature: () => { + if (!secret || typeof secret !== 'string' || !req.rawBody) { + return null; + } + const hmac = createHmac('sha256', secret); + const payload = Buffer.isBuffer(req.rawBody) ? req.rawBody : Buffer.from(req.rawBody); + hmac.update(payload); + return hmac.digest('hex'); + }, + skipIfNoExpectedSignature: !secret || typeof secret !== 'string', + getActualSignature: () => { + const receivedSignature = req.header('x-hook-signature'); + return typeof receivedSignature === 'string' ? receivedSignature : null; + }, + }); +} diff --git a/packages/nodes-base/nodes/Asana/test/AsanaTrigger.node.test.ts b/packages/nodes-base/nodes/Asana/test/AsanaTrigger.node.test.ts new file mode 100644 index 00000000000..8c11acd0850 --- /dev/null +++ b/packages/nodes-base/nodes/Asana/test/AsanaTrigger.node.test.ts @@ -0,0 +1,149 @@ +import type { IWebhookFunctions } from 'n8n-workflow'; + +import { AsanaTrigger } from '../AsanaTrigger.node'; +import { verifySignature } from '../AsanaTriggerHelpers'; + +jest.mock('../AsanaTriggerHelpers'); +jest.mock('../GenericFunctions'); + +describe('AsanaTrigger', () => { + let trigger: AsanaTrigger; + let mockWebhookFunctions: Pick< + jest.Mocked, + | 'getBodyData' + | 'getHeaderData' + | 'getRequestObject' + | 'getResponseObject' + | 'getWorkflowStaticData' + | 'helpers' + >; + + beforeEach(() => { + jest.clearAllMocks(); + trigger = new AsanaTrigger(); + + mockWebhookFunctions = { + getBodyData: jest.fn(), + getHeaderData: jest.fn(), + getRequestObject: jest.fn(), + getResponseObject: jest.fn(), + getWorkflowStaticData: jest.fn(), + helpers: { + returnJsonArray: jest.fn((data) => data), + } as any, + }; + }); + + describe('webhook', () => { + it('should complete the handshake when X-Hook-Secret header is present', async () => { + const handshakeSecret = 'asana-handshake-secret'; + const mockResponse = { + set: jest.fn().mockReturnThis(), + status: jest.fn().mockReturnThis(), + end: jest.fn(), + }; + const webhookData: any = {}; + + mockWebhookFunctions.getBodyData.mockReturnValue({}); + mockWebhookFunctions.getHeaderData.mockReturnValue({ + 'x-hook-secret': handshakeSecret, + }); + mockWebhookFunctions.getRequestObject.mockReturnValue({} as any); + mockWebhookFunctions.getResponseObject.mockReturnValue(mockResponse as any); + mockWebhookFunctions.getWorkflowStaticData.mockReturnValue(webhookData); + + const result = await trigger.webhook.call( + mockWebhookFunctions as unknown as IWebhookFunctions, + ); + + expect(webhookData.hookSecret).toBe(handshakeSecret); + expect(mockResponse.set).toHaveBeenCalledWith('X-Hook-Secret', handshakeSecret); + expect(mockResponse.status).toHaveBeenCalledWith(200); + expect(verifySignature).not.toHaveBeenCalled(); + expect(result).toEqual({ noWebhookResponse: true }); + }); + + it('should return 401 when signature verification fails', async () => { + const mockResponse = { + status: jest.fn().mockReturnThis(), + send: jest.fn().mockReturnThis(), + end: jest.fn(), + }; + + (verifySignature as jest.Mock).mockReturnValue(false); + mockWebhookFunctions.getBodyData.mockReturnValue({}); + mockWebhookFunctions.getHeaderData.mockReturnValue({}); + mockWebhookFunctions.getRequestObject.mockReturnValue({} as any); + mockWebhookFunctions.getResponseObject.mockReturnValue(mockResponse as any); + mockWebhookFunctions.getWorkflowStaticData.mockReturnValue({}); + + const result = await trigger.webhook.call( + mockWebhookFunctions as unknown as IWebhookFunctions, + ); + + expect(verifySignature).toHaveBeenCalled(); + expect(mockResponse.status).toHaveBeenCalledWith(401); + expect(mockResponse.send).toHaveBeenCalledWith('Unauthorized'); + expect(result).toEqual({ noWebhookResponse: true }); + }); + + it('should process events when signature verification passes', async () => { + const events = [{ action: 'changed', resource: { gid: '1' } }]; + + (verifySignature as jest.Mock).mockReturnValue(true); + mockWebhookFunctions.getBodyData.mockReturnValue({ events }); + mockWebhookFunctions.getHeaderData.mockReturnValue({}); + mockWebhookFunctions.getRequestObject.mockReturnValue({ + body: { events }, + } as any); + mockWebhookFunctions.getWorkflowStaticData.mockReturnValue({ + hookSecret: 'secret', + }); + + const result = await trigger.webhook.call( + mockWebhookFunctions as unknown as IWebhookFunctions, + ); + + expect(verifySignature).toHaveBeenCalled(); + expect(result.workflowData).toBeDefined(); + expect(result.workflowData?.[0]).toEqual(events); + }); + + it('should process events when no secret is configured (backward compatibility)', async () => { + const events = [{ action: 'added' }]; + + (verifySignature as jest.Mock).mockReturnValue(true); + mockWebhookFunctions.getBodyData.mockReturnValue({ events }); + mockWebhookFunctions.getHeaderData.mockReturnValue({}); + mockWebhookFunctions.getRequestObject.mockReturnValue({ + body: { events }, + } as any); + mockWebhookFunctions.getWorkflowStaticData.mockReturnValue({}); + + const result = await trigger.webhook.call( + mockWebhookFunctions as unknown as IWebhookFunctions, + ); + + expect(verifySignature).toHaveBeenCalled(); + expect(result.workflowData).toBeDefined(); + expect(result.workflowData?.[0]).toEqual(events); + }); + + it('should return empty result when events array is empty after verification', async () => { + (verifySignature as jest.Mock).mockReturnValue(true); + mockWebhookFunctions.getBodyData.mockReturnValue({ events: [] }); + mockWebhookFunctions.getHeaderData.mockReturnValue({}); + mockWebhookFunctions.getRequestObject.mockReturnValue({ + body: { events: [] }, + } as any); + mockWebhookFunctions.getWorkflowStaticData.mockReturnValue({}); + + const result = await trigger.webhook.call( + mockWebhookFunctions as unknown as IWebhookFunctions, + ); + + expect(verifySignature).toHaveBeenCalled(); + expect(result).toEqual({}); + }); + }); +}); diff --git a/packages/nodes-base/nodes/Asana/test/AsanaTriggerHelpers.test.ts b/packages/nodes-base/nodes/Asana/test/AsanaTriggerHelpers.test.ts new file mode 100644 index 00000000000..a1fc7313465 --- /dev/null +++ b/packages/nodes-base/nodes/Asana/test/AsanaTriggerHelpers.test.ts @@ -0,0 +1,122 @@ +import { createHmac } from 'crypto'; + +import { verifySignature } from '../AsanaTriggerHelpers'; + +describe('AsanaTriggerHelpers', () => { + let mockWebhookFunctions: any; + const testSecret = 'test-secret-key-12345'; + const testPayload = Buffer.from('{"events":[{"action":"changed"}]}'); + + beforeEach(() => { + jest.clearAllMocks(); + + mockWebhookFunctions = { + getRequestObject: jest.fn(), + getWorkflowStaticData: jest.fn(), + }; + }); + + describe('verifySignature', () => { + it('should return true if no secret is configured (backward compatibility)', () => { + mockWebhookFunctions.getWorkflowStaticData.mockReturnValue({}); + mockWebhookFunctions.getRequestObject.mockReturnValue({ + header: jest.fn().mockReturnValue(null), + rawBody: testPayload, + }); + + const result = verifySignature.call(mockWebhookFunctions); + + expect(result).toBe(true); + }); + + it('should return true if signatures match', () => { + const hmac = createHmac('sha256', testSecret); + hmac.update(testPayload); + const expectedSignature = hmac.digest('hex'); + + mockWebhookFunctions.getWorkflowStaticData.mockReturnValue({ + hookSecret: testSecret, + }); + mockWebhookFunctions.getRequestObject.mockReturnValue({ + header: jest.fn().mockImplementation((header) => { + if (header === 'x-hook-signature') return expectedSignature; + return null; + }), + rawBody: testPayload, + }); + + const result = verifySignature.call(mockWebhookFunctions); + + expect(result).toBe(true); + }); + + it('should return false if signatures do not match', () => { + const wrongSignature = '0'.repeat(64); + + mockWebhookFunctions.getWorkflowStaticData.mockReturnValue({ + hookSecret: testSecret, + }); + mockWebhookFunctions.getRequestObject.mockReturnValue({ + header: jest.fn().mockImplementation((header) => { + if (header === 'x-hook-signature') return wrongSignature; + return null; + }), + rawBody: testPayload, + }); + + const result = verifySignature.call(mockWebhookFunctions); + + expect(result).toBe(false); + }); + + it('should return false if signature header is missing', () => { + mockWebhookFunctions.getWorkflowStaticData.mockReturnValue({ + hookSecret: testSecret, + }); + mockWebhookFunctions.getRequestObject.mockReturnValue({ + header: jest.fn().mockReturnValue(null), + rawBody: testPayload, + }); + + const result = verifySignature.call(mockWebhookFunctions); + + expect(result).toBe(false); + }); + + it('should return true if rawBody is a string and signature matches', () => { + const stringPayload = '{"events":[{"action":"changed"}]}'; + const hmac = createHmac('sha256', testSecret); + hmac.update(Buffer.from(stringPayload)); + const expectedSignature = hmac.digest('hex'); + + mockWebhookFunctions.getWorkflowStaticData.mockReturnValue({ + hookSecret: testSecret, + }); + mockWebhookFunctions.getRequestObject.mockReturnValue({ + header: jest.fn().mockImplementation((header: string) => { + if (header === 'x-hook-signature') return expectedSignature; + return null; + }), + rawBody: stringPayload, + }); + + const result = verifySignature.call(mockWebhookFunctions); + + expect(result).toBe(true); + }); + + it('should return false if raw body is missing when secret is set', () => { + mockWebhookFunctions.getWorkflowStaticData.mockReturnValue({ + hookSecret: testSecret, + }); + mockWebhookFunctions.getRequestObject.mockReturnValue({ + header: jest.fn().mockReturnValue('any'), + rawBody: undefined, + }); + + const result = verifySignature.call(mockWebhookFunctions); + + expect(result).toBe(false); + }); + }); +}); From da41470311a03a15beb5d7361c0385b7dd9acc12 Mon Sep 17 00:00:00 2001 From: Dawid Myslak Date: Mon, 11 May 2026 22:54:07 +0200 Subject: [PATCH 03/29] feat(Acuity Scheduling Trigger Node): Add webhook request verification (#29261) Co-authored-by: Claude Opus 4.7 --- .../AcuitySchedulingTrigger.node.ts | 7 ++ .../AcuitySchedulingTriggerHelpers.ts | 41 ++++++++ .../test/AcuitySchedulingTrigger.node.test.ts | 97 +++++++++++++++++++ .../AcuitySchedulingTriggerHelpers.test.ts | 93 ++++++++++++++++++ 4 files changed, 238 insertions(+) create mode 100644 packages/nodes-base/nodes/AcuityScheduling/AcuitySchedulingTriggerHelpers.ts create mode 100644 packages/nodes-base/nodes/AcuityScheduling/test/AcuitySchedulingTrigger.node.test.ts create mode 100644 packages/nodes-base/nodes/AcuityScheduling/test/AcuitySchedulingTriggerHelpers.test.ts diff --git a/packages/nodes-base/nodes/AcuityScheduling/AcuitySchedulingTrigger.node.ts b/packages/nodes-base/nodes/AcuityScheduling/AcuitySchedulingTrigger.node.ts index bb4af8a7db4..81f9251978f 100644 --- a/packages/nodes-base/nodes/AcuityScheduling/AcuitySchedulingTrigger.node.ts +++ b/packages/nodes-base/nodes/AcuityScheduling/AcuitySchedulingTrigger.node.ts @@ -8,6 +8,7 @@ import type { } from 'n8n-workflow'; import { NodeConnectionTypes } from 'n8n-workflow'; +import { verifySignature } from './AcuitySchedulingTriggerHelpers'; import { acuitySchedulingApiRequest } from './GenericFunctions'; export class AcuitySchedulingTrigger implements INodeType { @@ -161,6 +162,12 @@ export class AcuitySchedulingTrigger implements INodeType { }; async webhook(this: IWebhookFunctions): Promise { + if (!(await verifySignature.call(this))) { + const res = this.getResponseObject(); + res.status(401).send('Unauthorized').end(); + return { noWebhookResponse: true }; + } + const req = this.getRequestObject(); const resolveData = this.getNodeParameter('resolveData', false) as boolean; diff --git a/packages/nodes-base/nodes/AcuityScheduling/AcuitySchedulingTriggerHelpers.ts b/packages/nodes-base/nodes/AcuityScheduling/AcuitySchedulingTriggerHelpers.ts new file mode 100644 index 00000000000..5a094c99ff2 --- /dev/null +++ b/packages/nodes-base/nodes/AcuityScheduling/AcuitySchedulingTriggerHelpers.ts @@ -0,0 +1,41 @@ +import { createHmac } from 'crypto'; +import type { IWebhookFunctions } from 'n8n-workflow'; + +import { verifySignature as verifySignatureGeneric } from '../../utils/webhook-signature-verification'; + +export async function verifySignature(this: IWebhookFunctions): Promise { + const authentication = this.getNodeParameter('authentication', 'apiKey') as string; + + // OAuth2 flows do not expose an API key that can be used as the shared secret, + // so verification is skipped to remain backward compatible. + if (authentication !== 'apiKey') { + return true; + } + + const req = this.getRequestObject(); + + let apiKey: string | undefined; + try { + const credentials = await this.getCredentials('acuitySchedulingApi'); + apiKey = typeof credentials?.apiKey === 'string' ? credentials.apiKey : undefined; + } catch { + return true; + } + + return verifySignatureGeneric({ + getExpectedSignature: () => { + if (!apiKey || !req.rawBody) { + return null; + } + const hmac = createHmac('sha256', apiKey); + const payload = Buffer.isBuffer(req.rawBody) ? req.rawBody : Buffer.from(req.rawBody); + hmac.update(payload); + return hmac.digest('base64'); + }, + skipIfNoExpectedSignature: !apiKey, + getActualSignature: () => { + const signature = req.header('x-acuity-signature'); + return typeof signature === 'string' ? signature : null; + }, + }); +} diff --git a/packages/nodes-base/nodes/AcuityScheduling/test/AcuitySchedulingTrigger.node.test.ts b/packages/nodes-base/nodes/AcuityScheduling/test/AcuitySchedulingTrigger.node.test.ts new file mode 100644 index 00000000000..558f96c14c8 --- /dev/null +++ b/packages/nodes-base/nodes/AcuityScheduling/test/AcuitySchedulingTrigger.node.test.ts @@ -0,0 +1,97 @@ +import type { IDataObject, IWebhookFunctions } from 'n8n-workflow'; + +import { AcuitySchedulingTrigger } from '../AcuitySchedulingTrigger.node'; +import { verifySignature } from '../AcuitySchedulingTriggerHelpers'; +import { acuitySchedulingApiRequest } from '../GenericFunctions'; + +jest.mock('../AcuitySchedulingTriggerHelpers', () => ({ + verifySignature: jest.fn(), +})); + +jest.mock('../GenericFunctions', () => ({ + acuitySchedulingApiRequest: jest.fn(), +})); + +const mockedVerifySignature = jest.mocked(verifySignature); +const mockedAcuitySchedulingApiRequest = jest.mocked(acuitySchedulingApiRequest); + +describe('AcuitySchedulingTrigger', () => { + let trigger: AcuitySchedulingTrigger; + let response: { status: jest.Mock; send: jest.Mock; end: jest.Mock }; + let ctx: IWebhookFunctions; + const requestBody: IDataObject = { action: 'appointment.scheduled', id: 123 }; + + const buildContext = (body: IDataObject = requestBody): IWebhookFunctions => { + response = { + status: jest.fn().mockReturnThis(), + send: jest.fn().mockReturnThis(), + end: jest.fn().mockReturnThis(), + }; + return { + getRequestObject: jest.fn().mockReturnValue({ body }), + getResponseObject: jest.fn().mockReturnValue(response), + getNodeParameter: jest.fn(), + helpers: { + returnJsonArray: jest.fn().mockImplementation((data: IDataObject) => [data]), + }, + } as unknown as IWebhookFunctions; + }; + + beforeEach(() => { + jest.clearAllMocks(); + trigger = new AcuitySchedulingTrigger(); + ctx = buildContext(); + mockedVerifySignature.mockResolvedValue(true); + }); + + describe('webhook', () => { + it('triggers workflow when signature is valid and resolveData is false', async () => { + (ctx.getNodeParameter as jest.Mock).mockImplementation((name: string) => + name === 'resolveData' ? false : undefined, + ); + + const result = await trigger.webhook.call(ctx); + + expect(mockedVerifySignature).toHaveBeenCalled(); + expect(result).toEqual({ workflowData: [[requestBody]] }); + }); + + it('returns 401 when signature is invalid', async () => { + mockedVerifySignature.mockResolvedValue(false); + + const result = await trigger.webhook.call(ctx); + + expect(response.status).toHaveBeenCalledWith(401); + expect(response.send).toHaveBeenCalledWith('Unauthorized'); + expect(response.end).toHaveBeenCalled(); + expect(result).toEqual({ noWebhookResponse: true }); + expect(mockedAcuitySchedulingApiRequest).not.toHaveBeenCalled(); + }); + + it('triggers workflow when no signing secret is configured (backward compat)', async () => { + mockedVerifySignature.mockResolvedValue(true); + (ctx.getNodeParameter as jest.Mock).mockImplementation((name: string) => + name === 'resolveData' ? false : undefined, + ); + + const result = await trigger.webhook.call(ctx); + + expect(result).toEqual({ workflowData: [[requestBody]] }); + }); + + it('resolves data via API when resolveData is true', async () => { + ctx = buildContext({ id: 123 }); + (ctx.getNodeParameter as jest.Mock).mockImplementation((name: string) => { + if (name === 'resolveData') return true; + if (name === 'event') return 'appointment.scheduled'; + return undefined; + }); + mockedAcuitySchedulingApiRequest.mockResolvedValue({ id: 123, name: 'Resolved' }); + + const result = await trigger.webhook.call(ctx); + + expect(mockedAcuitySchedulingApiRequest).toHaveBeenCalledWith('GET', '/appointments/123', {}); + expect(result).toEqual({ workflowData: [[{ id: 123, name: 'Resolved' }]] }); + }); + }); +}); diff --git a/packages/nodes-base/nodes/AcuityScheduling/test/AcuitySchedulingTriggerHelpers.test.ts b/packages/nodes-base/nodes/AcuityScheduling/test/AcuitySchedulingTriggerHelpers.test.ts new file mode 100644 index 00000000000..e69560fb819 --- /dev/null +++ b/packages/nodes-base/nodes/AcuityScheduling/test/AcuitySchedulingTriggerHelpers.test.ts @@ -0,0 +1,93 @@ +import { createHmac } from 'crypto'; +import { mock } from 'jest-mock-extended'; +import type { IWebhookFunctions } from 'n8n-workflow'; + +import { verifySignature } from '../AcuitySchedulingTriggerHelpers'; + +describe('AcuitySchedulingTriggerHelpers', () => { + describe('verifySignature', () => { + const apiKey = 'test-acuity-api-key'; + const rawBody = '{"action":"appointment.scheduled","id":"123","calendarID":"1"}'; + const validSignature = createHmac('sha256', apiKey) + .update(Buffer.from(rawBody)) + .digest('base64'); + + type BuildOpts = { + authentication?: string; + credentials?: Record; + signatureHeader?: string | null; + body?: Buffer | string | undefined; + throwOnGetCredentials?: boolean; + }; + const buildContext = (opts: BuildOpts = {}) => { + const authentication = opts.authentication ?? 'apiKey'; + const signatureHeader = opts.signatureHeader ?? null; + const body = 'body' in opts ? opts.body : Buffer.from(rawBody); + const ctx = mock(); + ctx.getNodeParameter.mockReturnValue(authentication); + if (opts.throwOnGetCredentials) { + ctx.getCredentials.mockRejectedValue(new Error('not found')); + } else { + ctx.getCredentials.mockResolvedValue(opts.credentials ?? { apiKey }); + } + ctx.getRequestObject.mockReturnValue({ + header: jest.fn().mockImplementation((name: string) => { + if (name === 'x-acuity-signature') return signatureHeader; + return null; + }), + rawBody: body, + } as never); + return ctx; + }; + + it('returns true when no api key is configured (backward compat)', async () => { + const ctx = buildContext({ credentials: { apiKey: '' } }); + + expect(await verifySignature.call(ctx)).toBe(true); + }); + + it('returns true when authentication is OAuth2 (no api key available)', async () => { + const ctx = buildContext({ authentication: 'oAuth2' }); + + expect(await verifySignature.call(ctx)).toBe(true); + // eslint-disable-next-line @typescript-eslint/unbound-method + expect(ctx.getCredentials).not.toHaveBeenCalled(); + }); + + it('returns true when signature is valid', async () => { + const ctx = buildContext({ signatureHeader: validSignature }); + + expect(await verifySignature.call(ctx)).toBe(true); + }); + + it('returns false when signature is invalid', async () => { + const ctx = buildContext({ signatureHeader: 'invalid-signature' }); + + expect(await verifySignature.call(ctx)).toBe(false); + }); + + it('returns false when signature header is missing', async () => { + const ctx = buildContext({ signatureHeader: null }); + + expect(await verifySignature.call(ctx)).toBe(false); + }); + + it('returns false when raw body is missing', async () => { + const ctx = buildContext({ signatureHeader: validSignature, body: undefined }); + + expect(await verifySignature.call(ctx)).toBe(false); + }); + + it('returns true when getCredentials throws (backward compat)', async () => { + const ctx = buildContext({ throwOnGetCredentials: true }); + + expect(await verifySignature.call(ctx)).toBe(true); + }); + + it('handles string raw body the same as buffer', async () => { + const ctx = buildContext({ signatureHeader: validSignature, body: rawBody }); + + expect(await verifySignature.call(ctx)).toBe(true); + }); + }); +}); From 133a5aa0adae69f86f1603bd9ad85c852c0ccdf5 Mon Sep 17 00:00:00 2001 From: Dawid Myslak Date: Mon, 11 May 2026 23:27:33 +0200 Subject: [PATCH 04/29] feat(Onfleet Trigger Node): Add webhook request verification (#29485) --- .../credentials/OnfleetApi.credentials.ts | 9 ++ .../nodes/Onfleet/OnfleetTrigger.node.ts | 8 ++ .../nodes/Onfleet/OnfleetTriggerHelpers.ts | 33 +++++ .../Onfleet/test/OnfleetTrigger.node.test.ts | 88 ++++++++++++- .../test/OnfleetTriggerHelpers.test.ts | 123 ++++++++++++++++++ 5 files changed, 254 insertions(+), 7 deletions(-) create mode 100644 packages/nodes-base/nodes/Onfleet/OnfleetTriggerHelpers.ts create mode 100644 packages/nodes-base/nodes/Onfleet/test/OnfleetTriggerHelpers.test.ts diff --git a/packages/nodes-base/credentials/OnfleetApi.credentials.ts b/packages/nodes-base/credentials/OnfleetApi.credentials.ts index 944dc358da1..2fb7aeeac74 100644 --- a/packages/nodes-base/credentials/OnfleetApi.credentials.ts +++ b/packages/nodes-base/credentials/OnfleetApi.credentials.ts @@ -15,5 +15,14 @@ export class OnfleetApi implements ICredentialType { typeOptions: { password: true }, default: '', }, + { + displayName: 'Signing Secret', + name: 'signingSecret', + type: 'string', + typeOptions: { password: true }, + default: '', + description: + 'Used to verify webhook authenticity. Found in Onfleet under Settings → API & Webhooks.', + }, ]; } diff --git a/packages/nodes-base/nodes/Onfleet/OnfleetTrigger.node.ts b/packages/nodes-base/nodes/Onfleet/OnfleetTrigger.node.ts index 453d65ad084..eff5c034a63 100644 --- a/packages/nodes-base/nodes/Onfleet/OnfleetTrigger.node.ts +++ b/packages/nodes-base/nodes/Onfleet/OnfleetTrigger.node.ts @@ -11,6 +11,7 @@ import { NodeApiError, NodeConnectionTypes, NodeOperationError } from 'n8n-workf import { eventDisplay, eventNameField } from './descriptions/OnfleetWebhookDescription'; import { onfleetApiRequest } from './GenericFunctions'; +import { verifySignature } from './OnfleetTriggerHelpers'; import { webhookMapping } from './WebhookMapping'; export class OnfleetTrigger implements INodeType { @@ -142,6 +143,13 @@ export class OnfleetTrigger implements INodeType { return { noWebhookResponse: true }; } + const isSignatureValid = await verifySignature.call(this); + if (!isSignatureValid) { + const res = this.getResponseObject(); + res.status(401).send('Unauthorized').end(); + return { noWebhookResponse: true }; + } + const returnData: IDataObject = this.getBodyData(); return { diff --git a/packages/nodes-base/nodes/Onfleet/OnfleetTriggerHelpers.ts b/packages/nodes-base/nodes/Onfleet/OnfleetTriggerHelpers.ts new file mode 100644 index 00000000000..d3b36002ffc --- /dev/null +++ b/packages/nodes-base/nodes/Onfleet/OnfleetTriggerHelpers.ts @@ -0,0 +1,33 @@ +import { createHmac } from 'crypto'; +import type { IWebhookFunctions } from 'n8n-workflow'; + +import { verifySignature as verifySignatureGeneric } from '../../utils/webhook-signature-verification'; + +export async function verifySignature(this: IWebhookFunctions): Promise { + try { + const credential = await this.getCredentials('onfleetApi'); + const req = this.getRequestObject(); + const signingSecret = credential.signingSecret; + + return verifySignatureGeneric({ + getExpectedSignature: () => { + if (!signingSecret || typeof signingSecret !== 'string' || !req.rawBody) { + return null; + } + + const secretBuffer = Buffer.from(signingSecret, 'hex'); + const hmac = createHmac('sha512', secretBuffer); + const payload = Buffer.isBuffer(req.rawBody) ? req.rawBody : Buffer.from(req.rawBody); + hmac.update(payload); + return hmac.digest('hex'); + }, + skipIfNoExpectedSignature: !signingSecret || typeof signingSecret !== 'string', + getActualSignature: () => { + const sig = req.header('x-onfleet-signature'); + return typeof sig === 'string' ? sig : null; + }, + }); + } catch (error) { + return false; + } +} diff --git a/packages/nodes-base/nodes/Onfleet/test/OnfleetTrigger.node.test.ts b/packages/nodes-base/nodes/Onfleet/test/OnfleetTrigger.node.test.ts index 293c1b1616a..7690b28753e 100644 --- a/packages/nodes-base/nodes/Onfleet/test/OnfleetTrigger.node.test.ts +++ b/packages/nodes-base/nodes/Onfleet/test/OnfleetTrigger.node.test.ts @@ -1,3 +1,4 @@ +import { createHmac } from 'crypto'; import type { IWebhookFunctions } from 'n8n-workflow'; import { OnfleetTrigger } from '../OnfleetTrigger.node'; @@ -6,6 +7,15 @@ describe('Onfleet Trigger Node', () => { let node: OnfleetTrigger; let mockWebhookFunctions: IWebhookFunctions; + const testSecretHex = 'a'.repeat(64); + const testBody = '{"taskId":"task123","actionContext":"COMPLETE"}'; + + const computeSignature = (secretHex: string, body: string): string => { + const hmac = createHmac('sha512', Buffer.from(secretHex, 'hex')); + hmac.update(Buffer.from(body)); + return hmac.digest('hex'); + }; + beforeEach(() => { node = new OnfleetTrigger(); mockWebhookFunctions = { @@ -13,6 +23,7 @@ describe('Onfleet Trigger Node', () => { getRequestObject: jest.fn(), getResponseObject: jest.fn(), getBodyData: jest.fn(), + getCredentials: jest.fn(), helpers: { returnJsonArray: jest.fn().mockImplementation((data) => [{ json: data }]), }, @@ -48,19 +59,24 @@ describe('Onfleet Trigger Node', () => { }); describe('default webhook', () => { - it('should process incoming webhook data', async () => { - const mockRequestData = { - taskId: 'task123', - workerId: 'worker456', - actionContext: 'COMPLETE', - }; + const mockRequestData = { + taskId: 'task123', + workerId: 'worker456', + actionContext: 'COMPLETE', + }; + it('should process the request when no signing secret is configured (backward compatibility)', async () => { const mockRequest = { query: {}, + header: jest.fn().mockReturnValue(undefined), + rawBody: Buffer.from(testBody), }; (mockWebhookFunctions.getWebhookName as jest.Mock).mockReturnValue('default'); (mockWebhookFunctions.getRequestObject as jest.Mock).mockReturnValue(mockRequest); + (mockWebhookFunctions.getCredentials as jest.Mock).mockResolvedValue({ + apiKey: 'test-api-key', + }); (mockWebhookFunctions.getBodyData as jest.Mock).mockReturnValue(mockRequestData); const result = await node.webhook.call(mockWebhookFunctions); @@ -68,7 +84,65 @@ describe('Onfleet Trigger Node', () => { expect(result).toEqual({ workflowData: [[{ json: mockRequestData }]], }); - expect(mockWebhookFunctions.helpers.returnJsonArray).toHaveBeenCalledWith(mockRequestData); + }); + + it('should process the request when the signature is valid', async () => { + const validSignature = computeSignature(testSecretHex, testBody); + const mockRequest = { + query: {}, + header: jest.fn().mockImplementation((header: string) => { + if (header === 'x-onfleet-signature') return validSignature; + return undefined; + }), + rawBody: Buffer.from(testBody), + }; + + (mockWebhookFunctions.getWebhookName as jest.Mock).mockReturnValue('default'); + (mockWebhookFunctions.getRequestObject as jest.Mock).mockReturnValue(mockRequest); + (mockWebhookFunctions.getCredentials as jest.Mock).mockResolvedValue({ + apiKey: 'test-api-key', + signingSecret: testSecretHex, + }); + (mockWebhookFunctions.getBodyData as jest.Mock).mockReturnValue(mockRequestData); + + const result = await node.webhook.call(mockWebhookFunctions); + + expect(result).toEqual({ + workflowData: [[{ json: mockRequestData }]], + }); + }); + + it('should respond with 401 and not trigger the workflow when the signature is invalid', async () => { + const mockRequest = { + query: {}, + header: jest.fn().mockImplementation((header: string) => { + if (header === 'x-onfleet-signature') return 'f'.repeat(128); + return undefined; + }), + rawBody: Buffer.from(testBody), + }; + + const mockResponse = { + status: jest.fn().mockReturnThis(), + send: jest.fn().mockReturnThis(), + end: jest.fn().mockReturnThis(), + }; + + (mockWebhookFunctions.getWebhookName as jest.Mock).mockReturnValue('default'); + (mockWebhookFunctions.getRequestObject as jest.Mock).mockReturnValue(mockRequest); + (mockWebhookFunctions.getResponseObject as jest.Mock).mockReturnValue(mockResponse); + (mockWebhookFunctions.getCredentials as jest.Mock).mockResolvedValue({ + apiKey: 'test-api-key', + signingSecret: testSecretHex, + }); + + const result = await node.webhook.call(mockWebhookFunctions); + + expect(mockResponse.status).toHaveBeenCalledWith(401); + expect(mockResponse.send).toHaveBeenCalledWith('Unauthorized'); + expect(mockResponse.end).toHaveBeenCalled(); + expect(result).toEqual({ noWebhookResponse: true }); + expect(mockWebhookFunctions.getBodyData).not.toHaveBeenCalled(); }); }); }); diff --git a/packages/nodes-base/nodes/Onfleet/test/OnfleetTriggerHelpers.test.ts b/packages/nodes-base/nodes/Onfleet/test/OnfleetTriggerHelpers.test.ts new file mode 100644 index 00000000000..b08511b4ed9 --- /dev/null +++ b/packages/nodes-base/nodes/Onfleet/test/OnfleetTriggerHelpers.test.ts @@ -0,0 +1,123 @@ +import { createHmac } from 'crypto'; + +import { verifySignature } from '../OnfleetTriggerHelpers'; + +describe('OnfleetTriggerHelpers', () => { + const testSecretHex = 'a'.repeat(64); + const testBody = '{"taskId":"task123","actionContext":"COMPLETE"}'; + + const computeSignature = (secretHex: string, body: string): string => { + const hmac = createHmac('sha512', Buffer.from(secretHex, 'hex')); + hmac.update(Buffer.from(body)); + return hmac.digest('hex'); + }; + + const validSignature = computeSignature(testSecretHex, testBody); + + let mockWebhookFunctions: any; + + beforeEach(() => { + jest.clearAllMocks(); + + mockWebhookFunctions = { + getCredentials: jest.fn(), + getRequestObject: jest.fn(), + }; + + mockWebhookFunctions.getRequestObject.mockReturnValue({ + header: jest.fn().mockImplementation((header: string) => { + if (header === 'x-onfleet-signature') return validSignature; + return undefined; + }), + rawBody: Buffer.from(testBody), + }); + }); + + describe('verifySignature', () => { + it('returns true when no credentials are provided (backward compatibility)', async () => { + mockWebhookFunctions.getCredentials.mockResolvedValue({}); + + const result = await verifySignature.call(mockWebhookFunctions); + + expect(result).toBe(true); + expect(mockWebhookFunctions.getCredentials).toHaveBeenCalledWith('onfleetApi'); + }); + + it('returns true when no signing secret is configured (backward compatibility)', async () => { + mockWebhookFunctions.getCredentials.mockResolvedValue({ + apiKey: 'test-api-key', + }); + + const result = await verifySignature.call(mockWebhookFunctions); + + expect(result).toBe(true); + }); + + it('returns true when signature is valid', async () => { + mockWebhookFunctions.getCredentials.mockResolvedValue({ + apiKey: 'test-api-key', + signingSecret: testSecretHex, + }); + + const result = await verifySignature.call(mockWebhookFunctions); + + expect(result).toBe(true); + }); + + it('returns false when signature is invalid', async () => { + mockWebhookFunctions.getCredentials.mockResolvedValue({ + signingSecret: testSecretHex, + }); + + mockWebhookFunctions.getRequestObject.mockReturnValue({ + header: jest.fn().mockImplementation((header: string) => { + if (header === 'x-onfleet-signature') return 'f'.repeat(128); + return undefined; + }), + rawBody: Buffer.from(testBody), + }); + + const result = await verifySignature.call(mockWebhookFunctions); + + expect(result).toBe(false); + }); + + it('returns false when signature header is missing', async () => { + mockWebhookFunctions.getCredentials.mockResolvedValue({ + signingSecret: testSecretHex, + }); + + mockWebhookFunctions.getRequestObject.mockReturnValue({ + header: jest.fn().mockReturnValue(undefined), + rawBody: Buffer.from(testBody), + }); + + const result = await verifySignature.call(mockWebhookFunctions); + + expect(result).toBe(false); + }); + + it('returns false when raw body is missing', async () => { + mockWebhookFunctions.getCredentials.mockResolvedValue({ + signingSecret: testSecretHex, + }); + + mockWebhookFunctions.getRequestObject.mockReturnValue({ + header: jest.fn().mockReturnValue(validSignature), + rawBody: undefined, + }); + + const result = await verifySignature.call(mockWebhookFunctions); + + expect(result).toBe(false); + }); + + it('returns false when getCredentials throws', async () => { + mockWebhookFunctions.getCredentials.mockRejectedValue(new Error('credentials not found')); + + const result = await verifySignature.call(mockWebhookFunctions); + + expect(result).toBe(false); + }); + }); +}); From 7fdd98aa7273006ab87671b83e86da2f01f420c3 Mon Sep 17 00:00:00 2001 From: Romeo Balta <7095569+romeobalta@users.noreply.github.com> Date: Mon, 11 May 2026 22:32:14 +0100 Subject: [PATCH 05/29] feat(editor): Add proactive starter experiment (no-changelog) (#30252) --- .../frontend/@n8n/i18n/src/locales/en.json | 2 + .../src/app/constants/experiments.ts | 4 + .../InstanceAiProactiveStarterMessage.test.ts | 40 ++++ .../InstanceAiProactiveStarterMessage.vue | 175 ++++++++++++++++++ .../instanceAiProactiveAgent/index.ts | 2 + ...InstanceAiProactiveAgentExperiment.test.ts | 30 +++ .../useInstanceAiProactiveAgentExperiment.ts | 16 ++ .../ai/instanceAi/InstanceAiEmptyView.vue | 63 ++++++- .../__tests__/InstanceAiEmptyView.test.ts | 26 ++- 9 files changed, 355 insertions(+), 3 deletions(-) create mode 100644 packages/frontend/editor-ui/src/experiments/instanceAiProactiveAgent/components/InstanceAiProactiveStarterMessage.test.ts create mode 100644 packages/frontend/editor-ui/src/experiments/instanceAiProactiveAgent/components/InstanceAiProactiveStarterMessage.vue create mode 100644 packages/frontend/editor-ui/src/experiments/instanceAiProactiveAgent/index.ts create mode 100644 packages/frontend/editor-ui/src/experiments/instanceAiProactiveAgent/useInstanceAiProactiveAgentExperiment.test.ts create mode 100644 packages/frontend/editor-ui/src/experiments/instanceAiProactiveAgent/useInstanceAiProactiveAgentExperiment.ts diff --git a/packages/frontend/@n8n/i18n/src/locales/en.json b/packages/frontend/@n8n/i18n/src/locales/en.json index 445fdea0154..af23a30c62f 100644 --- a/packages/frontend/@n8n/i18n/src/locales/en.json +++ b/packages/frontend/@n8n/i18n/src/locales/en.json @@ -1189,6 +1189,8 @@ "duplicateWorkflowDialog.errors.forbidden.message": "This action is forbidden. Do you have the correct permissions?", "duplicateWorkflowDialog.errors.generic.title": "Duplicate workflow failed", "editor.mainHeader.githubButton.label": "Star n8n-io/n8n on GitHub", + "experiments.instanceAiProactiveAgent.message": "Hey, I can build your first workflow in a few minutes. Do you know what you want to automate, or do you want help with ideas?", + "experiments.instanceAiProactiveAgent.typingLabel": "AI Assistant is typing", "experiments.personalizedTemplatesV3.browseAllTemplates": "Browse our template library", "experiments.personalizedTemplatesV3.couldntFind": "Need something different?", "experiments.personalizedTemplatesV3.exploreTemplates": "Get started with HubSpot workflows:", diff --git a/packages/frontend/editor-ui/src/app/constants/experiments.ts b/packages/frontend/editor-ui/src/app/constants/experiments.ts index 1cd18b8263d..653add26191 100644 --- a/packages/frontend/editor-ui/src/app/constants/experiments.ts +++ b/packages/frontend/editor-ui/src/app/constants/experiments.ts @@ -94,6 +94,9 @@ export const CODE_WORKFLOW_BUILDER_EXPERIMENT = createExperiment('071_coding_wor }); export const AI_BUILDER_SETUP_WIZARD_EXPERIMENT = createExperiment('079_ai_builder_setup_wizard'); +export const INSTANCE_AI_PROACTIVE_AGENT_EXPERIMENT = createExperiment( + '082_instance_ai_proactive_agent', +); export const AA_EXPERIMENT_CHECK = createExperiment('078_experiment_check_aa'); export const CHAT_HUB_SEMANTIC_SEARCH_EXPERIMENT = createExperiment('077_chat_hub_semantic_search'); @@ -122,6 +125,7 @@ export const EXPERIMENTS_TO_TRACK = [ AI_BUILDER_REVIEW_CHANGES_EXPERIMENT.name, MERGE_ASK_BUILD_EXPERIMENT.name, AI_BUILDER_SETUP_WIZARD_EXPERIMENT.name, + INSTANCE_AI_PROACTIVE_AGENT_EXPERIMENT.name, AA_EXPERIMENT_CHECK.name, CHAT_HUB_SEMANTIC_SEARCH_EXPERIMENT.name, FLOATING_CHAT_HUB_PANEL_EXPERIMENT.name, diff --git a/packages/frontend/editor-ui/src/experiments/instanceAiProactiveAgent/components/InstanceAiProactiveStarterMessage.test.ts b/packages/frontend/editor-ui/src/experiments/instanceAiProactiveAgent/components/InstanceAiProactiveStarterMessage.test.ts new file mode 100644 index 00000000000..cd96ee9d3be --- /dev/null +++ b/packages/frontend/editor-ui/src/experiments/instanceAiProactiveAgent/components/InstanceAiProactiveStarterMessage.test.ts @@ -0,0 +1,40 @@ +import { afterEach, beforeEach, describe, it, expect, vi } from 'vitest'; + +import { createComponentRenderer } from '@/__tests__/render'; +import InstanceAiProactiveStarterMessage from './InstanceAiProactiveStarterMessage.vue'; + +const renderComponent = createComponentRenderer(InstanceAiProactiveStarterMessage); + +const PROACTIVE_MESSAGE = + 'Hey, I can build your first workflow in a few minutes. Do you know what you want to automate, or do you want help with ideas?'; +const OLD_PROACTIVE_MESSAGE = + 'I can help with workflow ideas and build the workflow for you. What would you like to automate?'; + +describe('InstanceAiProactiveStarterMessage', () => { + beforeEach(() => { + vi.useFakeTimers(); + }); + + afterEach(() => { + vi.useRealTimers(); + }); + + it('delays, shows typing, then reveals the polished proactive assistant message', async () => { + const { getByTestId, queryByTestId, queryByText } = renderComponent(); + + expect(queryByTestId('instance-ai-proactive-starter')).not.toBeInTheDocument(); + + await vi.advanceTimersByTimeAsync(800); + + expect(getByTestId('instance-ai-proactive-starter')).toBeVisible(); + expect(getByTestId('instance-ai-proactive-typing')).toBeVisible(); + expect(queryByText(PROACTIVE_MESSAGE)).not.toBeInTheDocument(); + + await vi.advanceTimersByTimeAsync(600); + + expect(queryByTestId('instance-ai-proactive-typing')).not.toBeInTheDocument(); + expect(getByTestId('instance-ai-proactive-message')).toHaveTextContent(PROACTIVE_MESSAGE); + expect(queryByText(OLD_PROACTIVE_MESSAGE)).not.toBeInTheDocument(); + expect(queryByTestId('instance-ai-suggestion-build-workflow')).not.toBeInTheDocument(); + }); +}); diff --git a/packages/frontend/editor-ui/src/experiments/instanceAiProactiveAgent/components/InstanceAiProactiveStarterMessage.vue b/packages/frontend/editor-ui/src/experiments/instanceAiProactiveAgent/components/InstanceAiProactiveStarterMessage.vue new file mode 100644 index 00000000000..1acc79e4518 --- /dev/null +++ b/packages/frontend/editor-ui/src/experiments/instanceAiProactiveAgent/components/InstanceAiProactiveStarterMessage.vue @@ -0,0 +1,175 @@ + + + + + diff --git a/packages/frontend/editor-ui/src/experiments/instanceAiProactiveAgent/index.ts b/packages/frontend/editor-ui/src/experiments/instanceAiProactiveAgent/index.ts new file mode 100644 index 00000000000..6357f825336 --- /dev/null +++ b/packages/frontend/editor-ui/src/experiments/instanceAiProactiveAgent/index.ts @@ -0,0 +1,2 @@ +export { useInstanceAiProactiveAgentExperiment } from './useInstanceAiProactiveAgentExperiment'; +export { default as InstanceAiProactiveStarterMessage } from './components/InstanceAiProactiveStarterMessage.vue'; diff --git a/packages/frontend/editor-ui/src/experiments/instanceAiProactiveAgent/useInstanceAiProactiveAgentExperiment.test.ts b/packages/frontend/editor-ui/src/experiments/instanceAiProactiveAgent/useInstanceAiProactiveAgentExperiment.test.ts new file mode 100644 index 00000000000..6e40296c113 --- /dev/null +++ b/packages/frontend/editor-ui/src/experiments/instanceAiProactiveAgent/useInstanceAiProactiveAgentExperiment.test.ts @@ -0,0 +1,30 @@ +import { describe, expect, it, vi, beforeEach } from 'vitest'; +import { INSTANCE_AI_PROACTIVE_AGENT_EXPERIMENT } from '@/app/constants/experiments'; +import { useInstanceAiProactiveAgentExperiment } from './useInstanceAiProactiveAgentExperiment'; + +const getVariant = vi.fn(); + +vi.mock('@/app/stores/posthog.store', () => ({ + usePostHog: vi.fn(() => ({ + getVariant, + })), +})); + +describe('useInstanceAiProactiveAgentExperiment', () => { + beforeEach(() => { + getVariant.mockReset(); + }); + + it.each([ + { variant: INSTANCE_AI_PROACTIVE_AGENT_EXPERIMENT.variant, enabled: true }, + { variant: INSTANCE_AI_PROACTIVE_AGENT_EXPERIMENT.control, enabled: false }, + { variant: undefined, enabled: false }, + ])('returns $enabled when PostHog variant is $variant', ({ variant, enabled }) => { + getVariant.mockReturnValue(variant); + + const { isFeatureEnabled } = useInstanceAiProactiveAgentExperiment(); + + expect(isFeatureEnabled.value).toBe(enabled); + expect(getVariant).toHaveBeenCalledWith(INSTANCE_AI_PROACTIVE_AGENT_EXPERIMENT.name); + }); +}); diff --git a/packages/frontend/editor-ui/src/experiments/instanceAiProactiveAgent/useInstanceAiProactiveAgentExperiment.ts b/packages/frontend/editor-ui/src/experiments/instanceAiProactiveAgent/useInstanceAiProactiveAgentExperiment.ts new file mode 100644 index 00000000000..f4efffe0edd --- /dev/null +++ b/packages/frontend/editor-ui/src/experiments/instanceAiProactiveAgent/useInstanceAiProactiveAgentExperiment.ts @@ -0,0 +1,16 @@ +import { computed } from 'vue'; + +import { INSTANCE_AI_PROACTIVE_AGENT_EXPERIMENT } from '@/app/constants/experiments'; +import { usePostHog } from '@/app/stores/posthog.store'; + +export function useInstanceAiProactiveAgentExperiment() { + const posthogStore = usePostHog(); + + const isFeatureEnabled = computed( + () => + posthogStore.getVariant(INSTANCE_AI_PROACTIVE_AGENT_EXPERIMENT.name) === + INSTANCE_AI_PROACTIVE_AGENT_EXPERIMENT.variant, + ); + + return { isFeatureEnabled }; +} diff --git a/packages/frontend/editor-ui/src/features/ai/instanceAi/InstanceAiEmptyView.vue b/packages/frontend/editor-ui/src/features/ai/instanceAi/InstanceAiEmptyView.vue index 02ddb876872..b4bd131293d 100644 --- a/packages/frontend/editor-ui/src/features/ai/instanceAi/InstanceAiEmptyView.vue +++ b/packages/frontend/editor-ui/src/features/ai/instanceAi/InstanceAiEmptyView.vue @@ -1,5 +1,5 @@ +