diff --git a/.github/workflows/lint-and-test.yml b/.github/workflows/lint-and-test.yml index 1c3f3708d39..ace6be9a64a 100644 --- a/.github/workflows/lint-and-test.yml +++ b/.github/workflows/lint-and-test.yml @@ -43,6 +43,7 @@ jobs: - name: "Tests" run: | npm run test + npm run test:conversation-flow:coverage build-check: runs-on: diff --git a/package-lock.json b/package-lock.json index 2d28c35d311..038fcb8475b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,14 +8,12 @@ "name": "chat-ui", "version": "0.20.0", "dependencies": { - "@aws-sdk/credential-providers": "^3.925.0", "@huggingface/hub": "^2.2.0", "@huggingface/inference": "^4.11.3", "@iconify-json/bi": "^1.1.21", - "@modelcontextprotocol/sdk": "^1.25.2", + "@modelcontextprotocol/sdk": "^1.26.0", "@resvg/resvg-js": "^2.6.2", "autoprefixer": "^10.4.14", - "aws4": "^1.13.2", "bits-ui": "^2.14.2", "date-fns": "^2.29.3", "dotenv": "^16.5.0", @@ -23,12 +21,10 @@ "handlebars": "^4.7.8", "highlight.js": "^11.7.0", "htmlparser2": "^10.0.0", - "husky": "^9.0.11", "ip-address": "^9.0.5", "jsdom": "^22.0.0", "json5": "^2.2.3", "katex": "^0.16.21", - "lint-staged": "^15.2.7", "marked": "^12.0.1", "mime-types": "^2.1.35", "mongodb": "^5.8.0", @@ -47,7 +43,6 @@ "tailwindcss": "^3.4.0", "undici": "^7.18.2", "uuid": "^10.0.0", - "vitest-browser-svelte": "^0.1.0", "zod": "^3.22.3" }, "devDependencies": { @@ -56,12 +51,11 @@ "@iconify-json/eos-icons": "^1.1.6", "@iconify-json/lucide": "^1.2.77", "@sveltejs/adapter-node": "^5.2.12", - "@sveltejs/kit": "^2.21.1", + "@sveltejs/kit": "^2.50.2", "@sveltejs/vite-plugin-svelte": "^5.0.3", "@tailwindcss/typography": "^0.5.9", "@types/dompurify": "^3.0.5", "@types/js-yaml": "^4.0.9", - "@types/jsdom": "^21.1.1", "@types/katex": "^0.16.7", "@types/mime-types": "^2.1.4", "@types/minimist": "^1.2.5", @@ -71,13 +65,16 @@ "@types/yazl": "^3.3.0", "@typescript-eslint/eslint-plugin": "^6.x", "@typescript-eslint/parser": "^6.x", + "@vitest/coverage-v8": "^3.2.4", "bson-objectid": "^2.0.4", "dompurify": "^3.2.4", "eslint": "^8.28.0", "eslint-config-prettier": "^8.5.0", "eslint-plugin-svelte": "^2.45.1", + "husky": "^9.0.11", "isomorphic-dompurify": "2.13.0", - "js-yaml": "^4.1.0", + "js-yaml": "^4.1.1", + "lint-staged": "^15.2.7", "minimist": "^1.2.8", "mongodb-memory-server": "^10.1.2", "playwright": "^1.55.1", @@ -94,6 +91,7 @@ "vite": "^6.3.5", "vite-node": "^3.0.9", "vitest": "^3.1.4", + "vitest-browser-svelte": "^0.1.0", "yazl": "^3.3.1" } }, @@ -270,945 +268,232 @@ "dev": true, "license": "ISC" }, - "node_modules/@aws-crypto/sha256-browser": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/@aws-crypto/sha256-browser/-/sha256-browser-5.2.0.tgz", - "integrity": "sha512-AXfN/lGotSQwu6HNcEsIASo7kWXZ5HYWvfOmSNKDsEqC4OashTp8alTmaz+F7TC2L083SFv5RdB+qU3Vs1kZqw==", - "license": "Apache-2.0", - "dependencies": { - "@aws-crypto/sha256-js": "^5.2.0", - "@aws-crypto/supports-web-crypto": "^5.2.0", - "@aws-crypto/util": "^5.2.0", - "@aws-sdk/types": "^3.222.0", - "@aws-sdk/util-locate-window": "^3.0.0", - "@smithy/util-utf8": "^2.0.0", - "tslib": "^2.6.2" - } - }, - "node_modules/@aws-crypto/sha256-browser/node_modules/@smithy/is-array-buffer": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-2.2.0.tgz", - "integrity": "sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA==", - "license": "Apache-2.0", + "node_modules/@babel/code-frame": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz", + "integrity": "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==", + "dev": true, + "license": "MIT", "dependencies": { - "tslib": "^2.6.2" + "@babel/helper-validator-identifier": "^7.27.1", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" }, "engines": { - "node": ">=14.0.0" + "node": ">=6.9.0" } }, - "node_modules/@aws-crypto/sha256-browser/node_modules/@smithy/util-buffer-from": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-2.2.0.tgz", - "integrity": "sha512-IJdWBbTcMQ6DA0gdNhh/BwrLkDR+ADW5Kr1aZmd4k3DIF6ezMV4R2NIAmT08wQJ3yUK82thHWmC/TnK/wpMMIA==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/is-array-buffer": "^2.2.0", - "tslib": "^2.6.2" - }, + "node_modules/@babel/helper-string-parser": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", + "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", + "dev": true, + "license": "MIT", "engines": { - "node": ">=14.0.0" + "node": ">=6.9.0" } }, - "node_modules/@aws-crypto/sha256-browser/node_modules/@smithy/util-utf8": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-2.3.0.tgz", - "integrity": "sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/util-buffer-from": "^2.2.0", - "tslib": "^2.6.2" - }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", + "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", + "dev": true, + "license": "MIT", "engines": { - "node": ">=14.0.0" + "node": ">=6.9.0" } }, - "node_modules/@aws-crypto/sha256-js": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/@aws-crypto/sha256-js/-/sha256-js-5.2.0.tgz", - "integrity": "sha512-FFQQyu7edu4ufvIZ+OadFpHHOt+eSTBaYaki44c+akjg7qZg9oOQeLlk77F6tSYqjDAFClrHJk9tMf0HdVyOvA==", - "license": "Apache-2.0", + "node_modules/@babel/parser": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.0.tgz", + "integrity": "sha512-IyDgFV5GeDUVX4YdF/3CPULtVGSXXMLh1xVIgdCgxApktqnQV0r7/8Nqthg+8YLGaAtdyIlo2qIdZrbCv4+7ww==", + "dev": true, + "license": "MIT", "dependencies": { - "@aws-crypto/util": "^5.2.0", - "@aws-sdk/types": "^3.222.0", - "tslib": "^2.6.2" + "@babel/types": "^7.29.0" }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-crypto/supports-web-crypto": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/@aws-crypto/supports-web-crypto/-/supports-web-crypto-5.2.0.tgz", - "integrity": "sha512-iAvUotm021kM33eCdNfwIN//F77/IADDSs58i+MDaOqFrVjZo9bAal0NK7HurRuWLLpF1iLX7gbWrjHjeo+YFg==", - "license": "Apache-2.0", - "dependencies": { - "tslib": "^2.6.2" - } - }, - "node_modules/@aws-crypto/util": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/@aws-crypto/util/-/util-5.2.0.tgz", - "integrity": "sha512-4RkU9EsI6ZpBve5fseQlGNUWKMa1RLPQ1dnjnQoe07ldfIzcsGb5hC5W0Dm7u423KWzawlrpbjXBrXCEv9zazQ==", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/types": "^3.222.0", - "@smithy/util-utf8": "^2.0.0", - "tslib": "^2.6.2" - } - }, - "node_modules/@aws-crypto/util/node_modules/@smithy/is-array-buffer": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-2.2.0.tgz", - "integrity": "sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA==", - "license": "Apache-2.0", - "dependencies": { - "tslib": "^2.6.2" + "bin": { + "parser": "bin/babel-parser.js" }, "engines": { - "node": ">=14.0.0" + "node": ">=6.0.0" } }, - "node_modules/@aws-crypto/util/node_modules/@smithy/util-buffer-from": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-2.2.0.tgz", - "integrity": "sha512-IJdWBbTcMQ6DA0gdNhh/BwrLkDR+ADW5Kr1aZmd4k3DIF6ezMV4R2NIAmT08wQJ3yUK82thHWmC/TnK/wpMMIA==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/is-array-buffer": "^2.2.0", - "tslib": "^2.6.2" - }, + "node_modules/@babel/runtime": { + "version": "7.27.6", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.27.6.tgz", + "integrity": "sha512-vbavdySgbTTrmFE+EsiqUTzlOr5bzlnJtUv9PynGCAKvfQqjIXbvFdumPM/GxMDfyuGMJaJAU6TO4zc1Jf1i8Q==", + "license": "MIT", "engines": { - "node": ">=14.0.0" + "node": ">=6.9.0" } }, - "node_modules/@aws-crypto/util/node_modules/@smithy/util-utf8": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-2.3.0.tgz", - "integrity": "sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A==", - "license": "Apache-2.0", + "node_modules/@babel/types": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.0.tgz", + "integrity": "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==", + "dev": true, + "license": "MIT", "dependencies": { - "@smithy/util-buffer-from": "^2.2.0", - "tslib": "^2.6.2" + "@babel/helper-string-parser": "^7.27.1", + "@babel/helper-validator-identifier": "^7.28.5" }, "engines": { - "node": ">=14.0.0" + "node": ">=6.9.0" } }, - "node_modules/@aws-sdk/client-cognito-identity": { - "version": "3.985.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-cognito-identity/-/client-cognito-identity-3.985.0.tgz", - "integrity": "sha512-PpHgiNGLsnQ2QHh0wx/uhGV3kxlASp2LOl5Z+LQCnu59i8rjAH1decT03QNWcho3Jz4zg9Kcto6VoAxu6OFb2A==", - "license": "Apache-2.0", - "dependencies": { - "@aws-crypto/sha256-browser": "5.2.0", - "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/core": "^3.973.7", - "@aws-sdk/credential-provider-node": "^3.972.6", - "@aws-sdk/middleware-host-header": "^3.972.3", - "@aws-sdk/middleware-logger": "^3.972.3", - "@aws-sdk/middleware-recursion-detection": "^3.972.3", - "@aws-sdk/middleware-user-agent": "^3.972.7", - "@aws-sdk/region-config-resolver": "^3.972.3", - "@aws-sdk/types": "^3.973.1", - "@aws-sdk/util-endpoints": "3.985.0", - "@aws-sdk/util-user-agent-browser": "^3.972.3", - "@aws-sdk/util-user-agent-node": "^3.972.5", - "@smithy/config-resolver": "^4.4.6", - "@smithy/core": "^3.22.1", - "@smithy/fetch-http-handler": "^5.3.9", - "@smithy/hash-node": "^4.2.8", - "@smithy/invalid-dependency": "^4.2.8", - "@smithy/middleware-content-length": "^4.2.8", - "@smithy/middleware-endpoint": "^4.4.13", - "@smithy/middleware-retry": "^4.4.30", - "@smithy/middleware-serde": "^4.2.9", - "@smithy/middleware-stack": "^4.2.8", - "@smithy/node-config-provider": "^4.3.8", - "@smithy/node-http-handler": "^4.4.9", - "@smithy/protocol-http": "^5.3.8", - "@smithy/smithy-client": "^4.11.2", - "@smithy/types": "^4.12.0", - "@smithy/url-parser": "^4.2.8", - "@smithy/util-base64": "^4.3.0", - "@smithy/util-body-length-browser": "^4.2.0", - "@smithy/util-body-length-node": "^4.2.1", - "@smithy/util-defaults-mode-browser": "^4.3.29", - "@smithy/util-defaults-mode-node": "^4.2.32", - "@smithy/util-endpoints": "^3.2.8", - "@smithy/util-middleware": "^4.2.8", - "@smithy/util-retry": "^4.2.8", - "@smithy/util-utf8": "^4.2.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/client-sso": { - "version": "3.985.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.985.0.tgz", - "integrity": "sha512-81J8iE8MuXhdbMfIz4sWFj64Pe41bFi/uqqmqOC5SlGv+kwoyLsyKS/rH2tW2t5buih4vTUxskRjxlqikTD4oQ==", - "license": "Apache-2.0", - "dependencies": { - "@aws-crypto/sha256-browser": "5.2.0", - "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/core": "^3.973.7", - "@aws-sdk/middleware-host-header": "^3.972.3", - "@aws-sdk/middleware-logger": "^3.972.3", - "@aws-sdk/middleware-recursion-detection": "^3.972.3", - "@aws-sdk/middleware-user-agent": "^3.972.7", - "@aws-sdk/region-config-resolver": "^3.972.3", - "@aws-sdk/types": "^3.973.1", - "@aws-sdk/util-endpoints": "3.985.0", - "@aws-sdk/util-user-agent-browser": "^3.972.3", - "@aws-sdk/util-user-agent-node": "^3.972.5", - "@smithy/config-resolver": "^4.4.6", - "@smithy/core": "^3.22.1", - "@smithy/fetch-http-handler": "^5.3.9", - "@smithy/hash-node": "^4.2.8", - "@smithy/invalid-dependency": "^4.2.8", - "@smithy/middleware-content-length": "^4.2.8", - "@smithy/middleware-endpoint": "^4.4.13", - "@smithy/middleware-retry": "^4.4.30", - "@smithy/middleware-serde": "^4.2.9", - "@smithy/middleware-stack": "^4.2.8", - "@smithy/node-config-provider": "^4.3.8", - "@smithy/node-http-handler": "^4.4.9", - "@smithy/protocol-http": "^5.3.8", - "@smithy/smithy-client": "^4.11.2", - "@smithy/types": "^4.12.0", - "@smithy/url-parser": "^4.2.8", - "@smithy/util-base64": "^4.3.0", - "@smithy/util-body-length-browser": "^4.2.0", - "@smithy/util-body-length-node": "^4.2.1", - "@smithy/util-defaults-mode-browser": "^4.3.29", - "@smithy/util-defaults-mode-node": "^4.2.32", - "@smithy/util-endpoints": "^3.2.8", - "@smithy/util-middleware": "^4.2.8", - "@smithy/util-retry": "^4.2.8", - "@smithy/util-utf8": "^4.2.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/core": { - "version": "3.973.7", - "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.973.7.tgz", - "integrity": "sha512-wNZZQQNlJ+hzD49cKdo+PY6rsTDElO8yDImnrI69p2PLBa7QomeUKAJWYp9xnaR38nlHqWhMHZuYLCQ3oSX+xg==", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/types": "^3.973.1", - "@aws-sdk/xml-builder": "^3.972.4", - "@smithy/core": "^3.22.1", - "@smithy/node-config-provider": "^4.3.8", - "@smithy/property-provider": "^4.2.8", - "@smithy/protocol-http": "^5.3.8", - "@smithy/signature-v4": "^5.3.8", - "@smithy/smithy-client": "^4.11.2", - "@smithy/types": "^4.12.0", - "@smithy/util-base64": "^4.3.0", - "@smithy/util-middleware": "^4.2.8", - "@smithy/util-utf8": "^4.2.0", - "tslib": "^2.6.2" - }, + "node_modules/@bcoe/v8-coverage": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-1.0.2.tgz", + "integrity": "sha512-6zABk/ECA/QYSCQ1NGiVwwbQerUCZ+TQbp64Q3AgmfNvurHH0j8TtXa1qbShXA6qqkpAj4V5W8pP6mLe1mcMqA==", + "dev": true, + "license": "MIT", "engines": { - "node": ">=20.0.0" + "node": ">=18" } }, - "node_modules/@aws-sdk/credential-provider-cognito-identity": { - "version": "3.972.3", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-cognito-identity/-/credential-provider-cognito-identity-3.972.3.tgz", - "integrity": "sha512-dW/DqTk90XW7hIngqntAVtJJyrkS51wcLhGz39lOMe0TlSmZl+5R/UGnAZqNbXmWuJHLzxe+MLgagxH41aTsAQ==", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/client-cognito-identity": "3.980.0", - "@aws-sdk/types": "^3.973.1", - "@smithy/property-provider": "^4.2.8", - "@smithy/types": "^4.12.0", - "tslib": "^2.6.2" - }, + "node_modules/@csstools/color-helpers": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@csstools/color-helpers/-/color-helpers-5.1.0.tgz", + "integrity": "sha512-S11EXWJyy0Mz5SYvRmY8nJYTFFd1LCNV+7cXyAgQtOOuzb4EsgfqDufL+9esx72/eLhsRdGZwaldu/h+E4t4BA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", "engines": { - "node": ">=20.0.0" + "node": ">=18" } }, - "node_modules/@aws-sdk/credential-provider-cognito-identity/node_modules/@aws-sdk/client-cognito-identity": { - "version": "3.980.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-cognito-identity/-/client-cognito-identity-3.980.0.tgz", - "integrity": "sha512-nLgMW2drTzv+dTo3ORCcotQPcrUaTQ+xoaDTdSaUXdZO7zbbVyk7ysE5GDTnJdZWcUjHOSB8xfNQhOTTNVPhFw==", - "license": "Apache-2.0", - "dependencies": { - "@aws-crypto/sha256-browser": "5.2.0", - "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/core": "^3.973.5", - "@aws-sdk/credential-provider-node": "^3.972.4", - "@aws-sdk/middleware-host-header": "^3.972.3", - "@aws-sdk/middleware-logger": "^3.972.3", - "@aws-sdk/middleware-recursion-detection": "^3.972.3", - "@aws-sdk/middleware-user-agent": "^3.972.5", - "@aws-sdk/region-config-resolver": "^3.972.3", - "@aws-sdk/types": "^3.973.1", - "@aws-sdk/util-endpoints": "3.980.0", - "@aws-sdk/util-user-agent-browser": "^3.972.3", - "@aws-sdk/util-user-agent-node": "^3.972.3", - "@smithy/config-resolver": "^4.4.6", - "@smithy/core": "^3.22.0", - "@smithy/fetch-http-handler": "^5.3.9", - "@smithy/hash-node": "^4.2.8", - "@smithy/invalid-dependency": "^4.2.8", - "@smithy/middleware-content-length": "^4.2.8", - "@smithy/middleware-endpoint": "^4.4.12", - "@smithy/middleware-retry": "^4.4.29", - "@smithy/middleware-serde": "^4.2.9", - "@smithy/middleware-stack": "^4.2.8", - "@smithy/node-config-provider": "^4.3.8", - "@smithy/node-http-handler": "^4.4.8", - "@smithy/protocol-http": "^5.3.8", - "@smithy/smithy-client": "^4.11.1", - "@smithy/types": "^4.12.0", - "@smithy/url-parser": "^4.2.8", - "@smithy/util-base64": "^4.3.0", - "@smithy/util-body-length-browser": "^4.2.0", - "@smithy/util-body-length-node": "^4.2.1", - "@smithy/util-defaults-mode-browser": "^4.3.28", - "@smithy/util-defaults-mode-node": "^4.2.31", - "@smithy/util-endpoints": "^3.2.8", - "@smithy/util-middleware": "^4.2.8", - "@smithy/util-retry": "^4.2.8", - "@smithy/util-utf8": "^4.2.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-cognito-identity/node_modules/@aws-sdk/util-endpoints": { - "version": "3.980.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.980.0.tgz", - "integrity": "sha512-AjKBNEc+rjOZQE1HwcD9aCELqg1GmUj1rtICKuY8cgwB73xJ4U/kNyqKKpN2k9emGqlfDY2D8itIp/vDc6OKpw==", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/types": "^3.973.1", - "@smithy/types": "^4.12.0", - "@smithy/url-parser": "^4.2.8", - "@smithy/util-endpoints": "^3.2.8", - "tslib": "^2.6.2" - }, + "node_modules/@csstools/css-calc": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@csstools/css-calc/-/css-calc-2.1.4.tgz", + "integrity": "sha512-3N8oaj+0juUw/1H3YwmDDJXCgTB1gKU6Hc/bB502u9zR0q2vd786XJH9QfrKIEgFlZmhZiq6epXl4rHqhzsIgQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-env": { - "version": "3.972.5", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.972.5.tgz", - "integrity": "sha512-LxJ9PEO4gKPXzkufvIESUysykPIdrV7+Ocb9yAhbhJLE4TiAYqbCVUE+VuKP1leGR1bBfjWjYgSV5MxprlX3mQ==", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/core": "^3.973.7", - "@aws-sdk/types": "^3.973.1", - "@smithy/property-provider": "^4.2.8", - "@smithy/types": "^4.12.0", - "tslib": "^2.6.2" + "node": ">=18" }, - "engines": { - "node": ">=20.0.0" + "peerDependencies": { + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-tokenizer": "^3.0.4" } }, - "node_modules/@aws-sdk/credential-provider-http": { - "version": "3.972.7", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-http/-/credential-provider-http-3.972.7.tgz", - "integrity": "sha512-L2uOGtvp2x3bTcxFTpSM+GkwFIPd8pHfGWO1764icMbo7e5xJh0nfhx1UwkXLnwvocTNEf8A7jISZLYjUSNaTg==", - "license": "Apache-2.0", + "node_modules/@csstools/css-color-parser": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@csstools/css-color-parser/-/css-color-parser-3.1.0.tgz", + "integrity": "sha512-nbtKwh3a6xNVIp/VRuXV64yTKnb1IjTAEEh3irzS+HkKjAOYLTGNb9pmVNntZ8iVBHcWDA2Dof0QtPgFI1BaTA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", "dependencies": { - "@aws-sdk/core": "^3.973.7", - "@aws-sdk/types": "^3.973.1", - "@smithy/fetch-http-handler": "^5.3.9", - "@smithy/node-http-handler": "^4.4.9", - "@smithy/property-provider": "^4.2.8", - "@smithy/protocol-http": "^5.3.8", - "@smithy/smithy-client": "^4.11.2", - "@smithy/types": "^4.12.0", - "@smithy/util-stream": "^4.5.11", - "tslib": "^2.6.2" + "@csstools/color-helpers": "^5.1.0", + "@csstools/css-calc": "^2.1.4" }, "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-ini": { - "version": "3.972.5", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.972.5.tgz", - "integrity": "sha512-SdDTYE6jkARzOeL7+kudMIM4DaFnP5dZVeatzw849k4bSXDdErDS188bgeNzc/RA2WGrlEpsqHUKP6G7sVXhZg==", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/core": "^3.973.7", - "@aws-sdk/credential-provider-env": "^3.972.5", - "@aws-sdk/credential-provider-http": "^3.972.7", - "@aws-sdk/credential-provider-login": "^3.972.5", - "@aws-sdk/credential-provider-process": "^3.972.5", - "@aws-sdk/credential-provider-sso": "^3.972.5", - "@aws-sdk/credential-provider-web-identity": "^3.972.5", - "@aws-sdk/nested-clients": "3.985.0", - "@aws-sdk/types": "^3.973.1", - "@smithy/credential-provider-imds": "^4.2.8", - "@smithy/property-provider": "^4.2.8", - "@smithy/shared-ini-file-loader": "^4.4.3", - "@smithy/types": "^4.12.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-login": { - "version": "3.972.5", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-login/-/credential-provider-login-3.972.5.tgz", - "integrity": "sha512-uYq1ILyTSI6ZDCMY5+vUsRM0SOCVI7kaW4wBrehVVkhAxC6y+e9rvGtnoZqCOWL1gKjTMouvsf4Ilhc5NCg1Aw==", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/core": "^3.973.7", - "@aws-sdk/nested-clients": "3.985.0", - "@aws-sdk/types": "^3.973.1", - "@smithy/property-provider": "^4.2.8", - "@smithy/protocol-http": "^5.3.8", - "@smithy/shared-ini-file-loader": "^4.4.3", - "@smithy/types": "^4.12.0", - "tslib": "^2.6.2" + "node": ">=18" }, - "engines": { - "node": ">=20.0.0" + "peerDependencies": { + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-tokenizer": "^3.0.4" } }, - "node_modules/@aws-sdk/credential-provider-node": { - "version": "3.972.6", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.972.6.tgz", - "integrity": "sha512-DZ3CnAAtSVtVz+G+ogqecaErMLgzph4JH5nYbHoBMgBkwTUV+SUcjsjOJwdBJTHu3Dm6l5LBYekZoU2nDqQk2A==", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/credential-provider-env": "^3.972.5", - "@aws-sdk/credential-provider-http": "^3.972.7", - "@aws-sdk/credential-provider-ini": "^3.972.5", - "@aws-sdk/credential-provider-process": "^3.972.5", - "@aws-sdk/credential-provider-sso": "^3.972.5", - "@aws-sdk/credential-provider-web-identity": "^3.972.5", - "@aws-sdk/types": "^3.973.1", - "@smithy/credential-provider-imds": "^4.2.8", - "@smithy/property-provider": "^4.2.8", - "@smithy/shared-ini-file-loader": "^4.4.3", - "@smithy/types": "^4.12.0", - "tslib": "^2.6.2" - }, + "node_modules/@csstools/css-parser-algorithms": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@csstools/css-parser-algorithms/-/css-parser-algorithms-3.0.5.tgz", + "integrity": "sha512-DaDeUkXZKjdGhgYaHNJTV9pV7Y9B3b644jCLs9Upc3VeNGg6LWARAT6O+Q+/COo+2gg/bM5rhpMAtf70WqfBdQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "peer": true, "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-process": { - "version": "3.972.5", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.972.5.tgz", - "integrity": "sha512-HDKF3mVbLnuqGg6dMnzBf1VUOywE12/N286msI9YaK9mEIzdsGCtLTvrDhe3Up0R9/hGFbB+9l21/TwF5L1C6g==", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/core": "^3.973.7", - "@aws-sdk/types": "^3.973.1", - "@smithy/property-provider": "^4.2.8", - "@smithy/shared-ini-file-loader": "^4.4.3", - "@smithy/types": "^4.12.0", - "tslib": "^2.6.2" + "node": ">=18" }, - "engines": { - "node": ">=20.0.0" + "peerDependencies": { + "@csstools/css-tokenizer": "^3.0.4" } }, - "node_modules/@aws-sdk/credential-provider-sso": { - "version": "3.972.5", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.972.5.tgz", - "integrity": "sha512-8urj3AoeNeQisjMmMBhFeiY2gxt6/7wQQbEGun0YV/OaOOiXrIudTIEYF8ZfD+NQI6X1FY5AkRsx6O/CaGiybA==", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/client-sso": "3.985.0", - "@aws-sdk/core": "^3.973.7", - "@aws-sdk/token-providers": "3.985.0", - "@aws-sdk/types": "^3.973.1", - "@smithy/property-provider": "^4.2.8", - "@smithy/shared-ini-file-loader": "^4.4.3", - "@smithy/types": "^4.12.0", - "tslib": "^2.6.2" - }, + "node_modules/@csstools/css-tokenizer": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@csstools/css-tokenizer/-/css-tokenizer-3.0.4.tgz", + "integrity": "sha512-Vd/9EVDiu6PPJt9yAh6roZP6El1xHrdvIVGjyBsHR0RYwNHgL7FJPyIIW4fANJNG6FtyZfvlRPpFI4ZM/lubvw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "peer": true, "engines": { - "node": ">=20.0.0" + "node": ">=18" } }, - "node_modules/@aws-sdk/credential-provider-web-identity": { - "version": "3.972.5", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.972.5.tgz", - "integrity": "sha512-OK3cULuJl6c+RcDZfPpaK5o3deTOnKZbxm7pzhFNGA3fI2hF9yDih17fGRazJzGGWaDVlR9ejZrpDef4DJCEsw==", - "license": "Apache-2.0", + "node_modules/@emnapi/runtime": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.4.3.tgz", + "integrity": "sha512-pBPWdu6MLKROBX05wSNKcNb++m5Er+KQ9QkB+WVM+pW2Kx9hoSrVTnu3BdkI5eBLZoKu/J6mW/B6i6bJB2ytXQ==", + "license": "MIT", + "optional": true, "dependencies": { - "@aws-sdk/core": "^3.973.7", - "@aws-sdk/nested-clients": "3.985.0", - "@aws-sdk/types": "^3.973.1", - "@smithy/property-provider": "^4.2.8", - "@smithy/shared-ini-file-loader": "^4.4.3", - "@smithy/types": "^4.12.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" + "tslib": "^2.4.0" } }, - "node_modules/@aws-sdk/credential-providers": { - "version": "3.985.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-providers/-/credential-providers-3.985.0.tgz", - "integrity": "sha512-mYjWyt0HiU3dYZif7yAJ+DYerSD/0bh7Umw9tUTFhhXrPePGTbJPyJx+vLmEh2dG2hCr7Qpn6DZdY8sB5yOxhQ==", - "license": "Apache-2.0", - "peer": true, - "dependencies": { - "@aws-sdk/client-cognito-identity": "3.985.0", - "@aws-sdk/core": "^3.973.7", - "@aws-sdk/credential-provider-cognito-identity": "^3.972.3", - "@aws-sdk/credential-provider-env": "^3.972.5", - "@aws-sdk/credential-provider-http": "^3.972.7", - "@aws-sdk/credential-provider-ini": "^3.972.5", - "@aws-sdk/credential-provider-login": "^3.972.5", - "@aws-sdk/credential-provider-node": "^3.972.6", - "@aws-sdk/credential-provider-process": "^3.972.5", - "@aws-sdk/credential-provider-sso": "^3.972.5", - "@aws-sdk/credential-provider-web-identity": "^3.972.5", - "@aws-sdk/nested-clients": "3.985.0", - "@aws-sdk/types": "^3.973.1", - "@smithy/config-resolver": "^4.4.6", - "@smithy/core": "^3.22.1", - "@smithy/credential-provider-imds": "^4.2.8", - "@smithy/node-config-provider": "^4.3.8", - "@smithy/property-provider": "^4.2.8", - "@smithy/types": "^4.12.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/middleware-host-header": { - "version": "3.972.3", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-host-header/-/middleware-host-header-3.972.3.tgz", - "integrity": "sha512-aknPTb2M+G3s+0qLCx4Li/qGZH8IIYjugHMv15JTYMe6mgZO8VBpYgeGYsNMGCqCZOcWzuf900jFBG5bopfzmA==", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/types": "^3.973.1", - "@smithy/protocol-http": "^5.3.8", - "@smithy/types": "^4.12.0", - "tslib": "^2.6.2" - }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.5.tgz", + "integrity": "sha512-9o3TMmpmftaCMepOdA5k/yDw8SfInyzWWTjYTFCX3kPSDJMROQTb8jg+h9Cnwnmm1vOzvxN7gIfB5V2ewpjtGA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/middleware-logger": { - "version": "3.972.3", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-logger/-/middleware-logger-3.972.3.tgz", - "integrity": "sha512-Ftg09xNNRqaz9QNzlfdQWfpqMCJbsQdnZVJP55jfhbKi1+FTWxGuvfPoBhDHIovqWKjqbuiew3HuhxbJ0+OjgA==", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/types": "^3.973.1", - "@smithy/types": "^4.12.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/middleware-recursion-detection": { - "version": "3.972.3", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.972.3.tgz", - "integrity": "sha512-PY57QhzNuXHnwbJgbWYTrqIDHYSeOlhfYERTAuc16LKZpTZRJUjzBFokp9hF7u1fuGeE3D70ERXzdbMBOqQz7Q==", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/types": "^3.973.1", - "@aws/lambda-invoke-store": "^0.2.2", - "@smithy/protocol-http": "^5.3.8", - "@smithy/types": "^4.12.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/middleware-user-agent": { - "version": "3.972.7", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.972.7.tgz", - "integrity": "sha512-HUD+geASjXSCyL/DHPQc/Ua7JhldTcIglVAoCV8kiVm99IaFSlAbTvEnyhZwdE6bdFyTL+uIaWLaCFSRsglZBQ==", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/core": "^3.973.7", - "@aws-sdk/types": "^3.973.1", - "@aws-sdk/util-endpoints": "3.985.0", - "@smithy/core": "^3.22.1", - "@smithy/protocol-http": "^5.3.8", - "@smithy/types": "^4.12.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/nested-clients": { - "version": "3.985.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/nested-clients/-/nested-clients-3.985.0.tgz", - "integrity": "sha512-TsWwKzb/2WHafAY0CE7uXgLj0FmnkBTgfioG9HO+7z/zCPcl1+YU+i7dW4o0y+aFxFgxTMG+ExBQpqT/k2ao8g==", - "license": "Apache-2.0", - "dependencies": { - "@aws-crypto/sha256-browser": "5.2.0", - "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/core": "^3.973.7", - "@aws-sdk/middleware-host-header": "^3.972.3", - "@aws-sdk/middleware-logger": "^3.972.3", - "@aws-sdk/middleware-recursion-detection": "^3.972.3", - "@aws-sdk/middleware-user-agent": "^3.972.7", - "@aws-sdk/region-config-resolver": "^3.972.3", - "@aws-sdk/types": "^3.973.1", - "@aws-sdk/util-endpoints": "3.985.0", - "@aws-sdk/util-user-agent-browser": "^3.972.3", - "@aws-sdk/util-user-agent-node": "^3.972.5", - "@smithy/config-resolver": "^4.4.6", - "@smithy/core": "^3.22.1", - "@smithy/fetch-http-handler": "^5.3.9", - "@smithy/hash-node": "^4.2.8", - "@smithy/invalid-dependency": "^4.2.8", - "@smithy/middleware-content-length": "^4.2.8", - "@smithy/middleware-endpoint": "^4.4.13", - "@smithy/middleware-retry": "^4.4.30", - "@smithy/middleware-serde": "^4.2.9", - "@smithy/middleware-stack": "^4.2.8", - "@smithy/node-config-provider": "^4.3.8", - "@smithy/node-http-handler": "^4.4.9", - "@smithy/protocol-http": "^5.3.8", - "@smithy/smithy-client": "^4.11.2", - "@smithy/types": "^4.12.0", - "@smithy/url-parser": "^4.2.8", - "@smithy/util-base64": "^4.3.0", - "@smithy/util-body-length-browser": "^4.2.0", - "@smithy/util-body-length-node": "^4.2.1", - "@smithy/util-defaults-mode-browser": "^4.3.29", - "@smithy/util-defaults-mode-node": "^4.2.32", - "@smithy/util-endpoints": "^3.2.8", - "@smithy/util-middleware": "^4.2.8", - "@smithy/util-retry": "^4.2.8", - "@smithy/util-utf8": "^4.2.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/region-config-resolver": { - "version": "3.972.3", - "resolved": "https://registry.npmjs.org/@aws-sdk/region-config-resolver/-/region-config-resolver-3.972.3.tgz", - "integrity": "sha512-v4J8qYAWfOMcZ4MJUyatntOicTzEMaU7j3OpkRCGGFSL2NgXQ5VbxauIyORA+pxdKZ0qQG2tCQjQjZDlXEC3Ow==", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/types": "^3.973.1", - "@smithy/config-resolver": "^4.4.6", - "@smithy/node-config-provider": "^4.3.8", - "@smithy/types": "^4.12.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/token-providers": { - "version": "3.985.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.985.0.tgz", - "integrity": "sha512-+hwpHZyEq8k+9JL2PkE60V93v2kNhUIv7STFt+EAez1UJsJOQDhc5LpzEX66pNjclI5OTwBROs/DhJjC/BtMjQ==", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/core": "^3.973.7", - "@aws-sdk/nested-clients": "3.985.0", - "@aws-sdk/types": "^3.973.1", - "@smithy/property-provider": "^4.2.8", - "@smithy/shared-ini-file-loader": "^4.4.3", - "@smithy/types": "^4.12.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/types": { - "version": "3.973.1", - "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.973.1.tgz", - "integrity": "sha512-DwHBiMNOB468JiX6+i34c+THsKHErYUdNQ3HexeXZvVn4zouLjgaS4FejiGSi2HyBuzuyHg7SuOPmjSvoU9NRg==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/types": "^4.12.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/util-endpoints": { - "version": "3.985.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.985.0.tgz", - "integrity": "sha512-vth7UfGSUR3ljvaq8V4Rc62FsM7GUTH/myxPWkaEgOrprz1/Pc72EgTXxj+cPPPDAfHFIpjhkB7T7Td0RJx+BA==", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/types": "^3.973.1", - "@smithy/types": "^4.12.0", - "@smithy/url-parser": "^4.2.8", - "@smithy/util-endpoints": "^3.2.8", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/util-locate-window": { - "version": "3.965.4", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-locate-window/-/util-locate-window-3.965.4.tgz", - "integrity": "sha512-H1onv5SkgPBK2P6JR2MjGgbOnttoNzSPIRoeZTNPZYyaplwGg50zS3amXvXqF0/qfXpWEC9rLWU564QTB9bSog==", - "license": "Apache-2.0", - "dependencies": { - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/util-user-agent-browser": { - "version": "3.972.3", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-browser/-/util-user-agent-browser-3.972.3.tgz", - "integrity": "sha512-JurOwkRUcXD/5MTDBcqdyQ9eVedtAsZgw5rBwktsPTN7QtPiS2Ld1jkJepNgYoCufz1Wcut9iup7GJDoIHp8Fw==", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/types": "^3.973.1", - "@smithy/types": "^4.12.0", - "bowser": "^2.11.0", - "tslib": "^2.6.2" - } - }, - "node_modules/@aws-sdk/util-user-agent-node": { - "version": "3.972.5", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.972.5.tgz", - "integrity": "sha512-GsUDF+rXyxDZkkJxUsDxnA67FG+kc5W1dnloCFLl6fWzceevsCYzJpASBzT+BPjwUgREE6FngfJYYYMQUY5fZQ==", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/middleware-user-agent": "^3.972.7", - "@aws-sdk/types": "^3.973.1", - "@smithy/node-config-provider": "^4.3.8", - "@smithy/types": "^4.12.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - }, - "peerDependencies": { - "aws-crt": ">=1.0.0" - }, - "peerDependenciesMeta": { - "aws-crt": { - "optional": true - } - } - }, - "node_modules/@aws-sdk/xml-builder": { - "version": "3.972.4", - "resolved": "https://registry.npmjs.org/@aws-sdk/xml-builder/-/xml-builder-3.972.4.tgz", - "integrity": "sha512-0zJ05ANfYqI6+rGqj8samZBFod0dPPousBjLEqg8WdxSgbMAkRgLyn81lP215Do0rFJ/17LIXwr7q0yK24mP6Q==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/types": "^4.12.0", - "fast-xml-parser": "5.3.4", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws/lambda-invoke-store": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/@aws/lambda-invoke-store/-/lambda-invoke-store-0.2.3.tgz", - "integrity": "sha512-oLvsaPMTBejkkmHhjf09xTgk71mOqyr/409NKhRIL08If7AhVfUsJhVsx386uJaqNd42v9kWamQ9lFbkoC2dYw==", - "license": "Apache-2.0", - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@babel/code-frame": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz", - "integrity": "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==", - "license": "MIT", - "dependencies": { - "@babel/helper-validator-identifier": "^7.27.1", - "js-tokens": "^4.0.0", - "picocolors": "^1.1.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-validator-identifier": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.27.1.tgz", - "integrity": "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==", - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/runtime": { - "version": "7.27.6", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.27.6.tgz", - "integrity": "sha512-vbavdySgbTTrmFE+EsiqUTzlOr5bzlnJtUv9PynGCAKvfQqjIXbvFdumPM/GxMDfyuGMJaJAU6TO4zc1Jf1i8Q==", - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@csstools/color-helpers": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/@csstools/color-helpers/-/color-helpers-5.1.0.tgz", - "integrity": "sha512-S11EXWJyy0Mz5SYvRmY8nJYTFFd1LCNV+7cXyAgQtOOuzb4EsgfqDufL+9esx72/eLhsRdGZwaldu/h+E4t4BA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], - "license": "MIT-0", - "engines": { - "node": ">=18" - } - }, - "node_modules/@csstools/css-calc": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/@csstools/css-calc/-/css-calc-2.1.4.tgz", - "integrity": "sha512-3N8oaj+0juUw/1H3YwmDDJXCgTB1gKU6Hc/bB502u9zR0q2vd786XJH9QfrKIEgFlZmhZiq6epXl4rHqhzsIgQ==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], - "license": "MIT", - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "@csstools/css-parser-algorithms": "^3.0.5", - "@csstools/css-tokenizer": "^3.0.4" - } - }, - "node_modules/@csstools/css-color-parser": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@csstools/css-color-parser/-/css-color-parser-3.1.0.tgz", - "integrity": "sha512-nbtKwh3a6xNVIp/VRuXV64yTKnb1IjTAEEh3irzS+HkKjAOYLTGNb9pmVNntZ8iVBHcWDA2Dof0QtPgFI1BaTA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], - "license": "MIT", - "dependencies": { - "@csstools/color-helpers": "^5.1.0", - "@csstools/css-calc": "^2.1.4" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "@csstools/css-parser-algorithms": "^3.0.5", - "@csstools/css-tokenizer": "^3.0.4" - } - }, - "node_modules/@csstools/css-parser-algorithms": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/@csstools/css-parser-algorithms/-/css-parser-algorithms-3.0.5.tgz", - "integrity": "sha512-DaDeUkXZKjdGhgYaHNJTV9pV7Y9B3b644jCLs9Upc3VeNGg6LWARAT6O+Q+/COo+2gg/bM5rhpMAtf70WqfBdQ==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], - "license": "MIT", - "peer": true, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "@csstools/css-tokenizer": "^3.0.4" - } - }, - "node_modules/@csstools/css-tokenizer": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/@csstools/css-tokenizer/-/css-tokenizer-3.0.4.tgz", - "integrity": "sha512-Vd/9EVDiu6PPJt9yAh6roZP6El1xHrdvIVGjyBsHR0RYwNHgL7FJPyIIW4fANJNG6FtyZfvlRPpFI4ZM/lubvw==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], - "license": "MIT", - "peer": true, - "engines": { - "node": ">=18" - } - }, - "node_modules/@emnapi/runtime": { - "version": "1.4.3", - "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.4.3.tgz", - "integrity": "sha512-pBPWdu6MLKROBX05wSNKcNb++m5Er+KQ9QkB+WVM+pW2Kx9hoSrVTnu3BdkI5eBLZoKu/J6mW/B6i6bJB2ytXQ==", - "license": "MIT", - "optional": true, - "dependencies": { - "tslib": "^2.4.0" - } - }, - "node_modules/@esbuild/aix-ppc64": { - "version": "0.25.5", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.5.tgz", - "integrity": "sha512-9o3TMmpmftaCMepOdA5k/yDw8SfInyzWWTjYTFCX3kPSDJMROQTb8jg+h9Cnwnmm1vOzvxN7gIfB5V2ewpjtGA==", - "cpu": [ - "ppc64" - ], - "license": "MIT", - "optional": true, - "os": [ - "aix" - ], - "engines": { - "node": ">=18" + "node": ">=18" } }, "node_modules/@esbuild/android-arm": { @@ -1218,6 +503,7 @@ "cpu": [ "arm" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1234,6 +520,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1250,6 +537,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1266,6 +554,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1282,6 +571,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1298,6 +588,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1314,6 +605,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1330,6 +622,7 @@ "cpu": [ "arm" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1346,6 +639,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1362,6 +656,7 @@ "cpu": [ "ia32" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1378,6 +673,7 @@ "cpu": [ "loong64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1394,6 +690,7 @@ "cpu": [ "mips64el" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1410,6 +707,7 @@ "cpu": [ "ppc64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1426,6 +724,7 @@ "cpu": [ "riscv64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1442,6 +741,7 @@ "cpu": [ "s390x" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1458,6 +758,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1474,6 +775,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1490,6 +792,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1506,6 +809,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1522,6 +826,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1538,6 +843,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1554,6 +860,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1570,6 +877,7 @@ "cpu": [ "ia32" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1586,6 +894,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1965,13 +1274,6 @@ "url": "https://github.com/sponsors/antfu" } }, - "node_modules/@iconify/utils/node_modules/pathe": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", - "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", - "dev": true, - "license": "MIT" - }, "node_modules/@iconify/utils/node_modules/pkg-types": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-2.1.0.tgz", @@ -2458,6 +1760,16 @@ "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, + "node_modules/@istanbuljs/schema": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", + "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/@jridgewell/gen-mapping": { "version": "0.3.8", "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.8.tgz", @@ -2497,9 +1809,9 @@ "license": "MIT" }, "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.25", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", - "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", "license": "MIT", "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", @@ -2636,6 +1948,7 @@ "version": "1.0.0-next.29", "resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.29.tgz", "integrity": "sha512-wwQAWhWSuHaag8c4q/KN/vCoeOJYshAIvMQwD4GpSb3OiZklFfvAgmj0VCBBImRpuF/aFgIRzllXlVX93Jevww==", + "devOptional": true, "license": "MIT" }, "node_modules/@resvg/resvg-js": { @@ -2956,6 +2269,7 @@ "cpu": [ "arm" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2969,6 +2283,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2982,6 +2297,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2995,6 +2311,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -3008,6 +2325,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -3021,6 +2339,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -3034,6 +2353,7 @@ "cpu": [ "arm" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -3047,6 +2367,7 @@ "cpu": [ "arm" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -3060,6 +2381,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -3073,6 +2395,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -3086,6 +2409,7 @@ "cpu": [ "loong64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -3099,6 +2423,7 @@ "cpu": [ "ppc64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -3112,6 +2437,7 @@ "cpu": [ "riscv64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -3125,691 +2451,118 @@ "cpu": [ "riscv64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-s390x-gnu": { - "version": "4.41.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.41.1.tgz", - "integrity": "sha512-oIE6M8WC9ma6xYqjvPhzZYk6NbobIURvP/lEbh7FWplcMO6gn7MM2yHKA1eC/GvYwzNKK/1LYgqzdkZ8YFxR8g==", - "cpu": [ - "s390x" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.41.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.41.1.tgz", - "integrity": "sha512-cWBOvayNvA+SyeQMp79BHPK8ws6sHSsYnK5zDcsC3Hsxr1dgTABKjMnMslPq1DvZIp6uO7kIWhiGwaTdR4Og9A==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.41.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.41.1.tgz", - "integrity": "sha512-y5CbN44M+pUCdGDlZFzGGBSKCA4A/J2ZH4edTYSSxFg7ce1Xt3GtydbVKWLlzL+INfFIZAEg1ZV6hh9+QQf9YQ==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.41.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.41.1.tgz", - "integrity": "sha512-lZkCxIrjlJlMt1dLO/FbpZbzt6J/A8p4DnqzSa4PWqPEUUUnzXLeki/iyPLfV0BmHItlYgHUqJe+3KiyydmiNQ==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.41.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.41.1.tgz", - "integrity": "sha512-+psFT9+pIh2iuGsxFYYa/LhS5MFKmuivRsx9iPJWNSGbh2XVEjk90fmpUEjCnILPEPJnikAU6SFDiEUyOv90Pg==", - "cpu": [ - "ia32" - ], - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.41.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.41.1.tgz", - "integrity": "sha512-Wq2zpapRYLfi4aKxf2Xff0tN+7slj2d4R87WEzqw7ZLsVvO5zwYCIuEGSZYiK41+GlwUo1HiR+GdkLEJnCKTCw==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@shuding/opentype.js": { - "version": "1.4.0-beta.0", - "resolved": "https://registry.npmjs.org/@shuding/opentype.js/-/opentype.js-1.4.0-beta.0.tgz", - "integrity": "sha512-3NgmNyH3l/Hv6EvsWJbsvpcpUba6R8IREQ83nH83cyakCw7uM1arZKNfHwv1Wz6jgqrF/j4x5ELvR6PnK9nTcA==", - "license": "MIT", - "dependencies": { - "fflate": "^0.7.3", - "string.prototype.codepointat": "^0.2.1" - }, - "bin": { - "ot": "bin/ot" - }, - "engines": { - "node": ">= 8.0.0" - } - }, - "node_modules/@shuding/opentype.js/node_modules/fflate": { - "version": "0.7.4", - "resolved": "https://registry.npmjs.org/fflate/-/fflate-0.7.4.tgz", - "integrity": "sha512-5u2V/CDW15QM1XbbgS+0DfPxVB+jUKhWEKuuFuHncbk3tEEqzmoXL+2KyOFuKGqOnmdIy0/davWF1CkuwtibCw==", - "license": "MIT" - }, - "node_modules/@smithy/abort-controller": { - "version": "4.2.8", - "resolved": "https://registry.npmjs.org/@smithy/abort-controller/-/abort-controller-4.2.8.tgz", - "integrity": "sha512-peuVfkYHAmS5ybKxWcfraK7WBBP0J+rkfUcbHJJKQ4ir3UAUNQI+Y4Vt/PqSzGqgloJ5O1dk7+WzNL8wcCSXbw==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/types": "^4.12.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@smithy/config-resolver": { - "version": "4.4.6", - "resolved": "https://registry.npmjs.org/@smithy/config-resolver/-/config-resolver-4.4.6.tgz", - "integrity": "sha512-qJpzYC64kaj3S0fueiu3kXm8xPrR3PcXDPEgnaNMRn0EjNSZFoFjvbUp0YUDsRhN1CB90EnHJtbxWKevnH99UQ==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/node-config-provider": "^4.3.8", - "@smithy/types": "^4.12.0", - "@smithy/util-config-provider": "^4.2.0", - "@smithy/util-endpoints": "^3.2.8", - "@smithy/util-middleware": "^4.2.8", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@smithy/core": { - "version": "3.22.1", - "resolved": "https://registry.npmjs.org/@smithy/core/-/core-3.22.1.tgz", - "integrity": "sha512-x3ie6Crr58MWrm4viHqqy2Du2rHYZjwu8BekasrQx4ca+Y24dzVAwq3yErdqIbc2G3I0kLQA13PQ+/rde+u65g==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/middleware-serde": "^4.2.9", - "@smithy/protocol-http": "^5.3.8", - "@smithy/types": "^4.12.0", - "@smithy/util-base64": "^4.3.0", - "@smithy/util-body-length-browser": "^4.2.0", - "@smithy/util-middleware": "^4.2.8", - "@smithy/util-stream": "^4.5.11", - "@smithy/util-utf8": "^4.2.0", - "@smithy/uuid": "^1.1.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@smithy/credential-provider-imds": { - "version": "4.2.8", - "resolved": "https://registry.npmjs.org/@smithy/credential-provider-imds/-/credential-provider-imds-4.2.8.tgz", - "integrity": "sha512-FNT0xHS1c/CPN8upqbMFP83+ul5YgdisfCfkZ86Jh2NSmnqw/AJ6x5pEogVCTVvSm7j9MopRU89bmDelxuDMYw==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/node-config-provider": "^4.3.8", - "@smithy/property-provider": "^4.2.8", - "@smithy/types": "^4.12.0", - "@smithy/url-parser": "^4.2.8", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@smithy/fetch-http-handler": { - "version": "5.3.9", - "resolved": "https://registry.npmjs.org/@smithy/fetch-http-handler/-/fetch-http-handler-5.3.9.tgz", - "integrity": "sha512-I4UhmcTYXBrct03rwzQX1Y/iqQlzVQaPxWjCjula++5EmWq9YGBrx6bbGqluGc1f0XEfhSkiY4jhLgbsJUMKRA==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/protocol-http": "^5.3.8", - "@smithy/querystring-builder": "^4.2.8", - "@smithy/types": "^4.12.0", - "@smithy/util-base64": "^4.3.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@smithy/hash-node": { - "version": "4.2.8", - "resolved": "https://registry.npmjs.org/@smithy/hash-node/-/hash-node-4.2.8.tgz", - "integrity": "sha512-7ZIlPbmaDGxVoxErDZnuFG18WekhbA/g2/i97wGj+wUBeS6pcUeAym8u4BXh/75RXWhgIJhyC11hBzig6MljwA==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/types": "^4.12.0", - "@smithy/util-buffer-from": "^4.2.0", - "@smithy/util-utf8": "^4.2.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@smithy/invalid-dependency": { - "version": "4.2.8", - "resolved": "https://registry.npmjs.org/@smithy/invalid-dependency/-/invalid-dependency-4.2.8.tgz", - "integrity": "sha512-N9iozRybwAQ2dn9Fot9kI6/w9vos2oTXLhtK7ovGqwZjlOcxu6XhPlpLpC+INsxktqHinn5gS2DXDjDF2kG5sQ==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/types": "^4.12.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@smithy/is-array-buffer": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-4.2.0.tgz", - "integrity": "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ==", - "license": "Apache-2.0", - "dependencies": { - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@smithy/middleware-content-length": { - "version": "4.2.8", - "resolved": "https://registry.npmjs.org/@smithy/middleware-content-length/-/middleware-content-length-4.2.8.tgz", - "integrity": "sha512-RO0jeoaYAB1qBRhfVyq0pMgBoUK34YEJxVxyjOWYZiOKOq2yMZ4MnVXMZCUDenpozHue207+9P5ilTV1zeda0A==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/protocol-http": "^5.3.8", - "@smithy/types": "^4.12.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@smithy/middleware-endpoint": { - "version": "4.4.13", - "resolved": "https://registry.npmjs.org/@smithy/middleware-endpoint/-/middleware-endpoint-4.4.13.tgz", - "integrity": "sha512-x6vn0PjYmGdNuKh/juUJJewZh7MoQ46jYaJ2mvekF4EesMuFfrl4LaW/k97Zjf8PTCPQmPgMvwewg7eNoH9n5w==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/core": "^3.22.1", - "@smithy/middleware-serde": "^4.2.9", - "@smithy/node-config-provider": "^4.3.8", - "@smithy/shared-ini-file-loader": "^4.4.3", - "@smithy/types": "^4.12.0", - "@smithy/url-parser": "^4.2.8", - "@smithy/util-middleware": "^4.2.8", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@smithy/middleware-retry": { - "version": "4.4.30", - "resolved": "https://registry.npmjs.org/@smithy/middleware-retry/-/middleware-retry-4.4.30.tgz", - "integrity": "sha512-CBGyFvN0f8hlnqKH/jckRDz78Snrp345+PVk8Ux7pnkUCW97Iinse59lY78hBt04h1GZ6hjBN94BRwZy1xC8Bg==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/node-config-provider": "^4.3.8", - "@smithy/protocol-http": "^5.3.8", - "@smithy/service-error-classification": "^4.2.8", - "@smithy/smithy-client": "^4.11.2", - "@smithy/types": "^4.12.0", - "@smithy/util-middleware": "^4.2.8", - "@smithy/util-retry": "^4.2.8", - "@smithy/uuid": "^1.1.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@smithy/middleware-serde": { - "version": "4.2.9", - "resolved": "https://registry.npmjs.org/@smithy/middleware-serde/-/middleware-serde-4.2.9.tgz", - "integrity": "sha512-eMNiej0u/snzDvlqRGSN3Vl0ESn3838+nKyVfF2FKNXFbi4SERYT6PR392D39iczngbqqGG0Jl1DlCnp7tBbXQ==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/protocol-http": "^5.3.8", - "@smithy/types": "^4.12.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@smithy/middleware-stack": { - "version": "4.2.8", - "resolved": "https://registry.npmjs.org/@smithy/middleware-stack/-/middleware-stack-4.2.8.tgz", - "integrity": "sha512-w6LCfOviTYQjBctOKSwy6A8FIkQy7ICvglrZFl6Bw4FmcQ1Z420fUtIhxaUZZshRe0VCq4kvDiPiXrPZAe8oRA==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/types": "^4.12.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@smithy/node-config-provider": { - "version": "4.3.8", - "resolved": "https://registry.npmjs.org/@smithy/node-config-provider/-/node-config-provider-4.3.8.tgz", - "integrity": "sha512-aFP1ai4lrbVlWjfpAfRSL8KFcnJQYfTl5QxLJXY32vghJrDuFyPZ6LtUL+JEGYiFRG1PfPLHLoxj107ulncLIg==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/property-provider": "^4.2.8", - "@smithy/shared-ini-file-loader": "^4.4.3", - "@smithy/types": "^4.12.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@smithy/node-http-handler": { - "version": "4.4.9", - "resolved": "https://registry.npmjs.org/@smithy/node-http-handler/-/node-http-handler-4.4.9.tgz", - "integrity": "sha512-KX5Wml5mF+luxm1szW4QDz32e3NObgJ4Fyw+irhph4I/2geXwUy4jkIMUs5ZPGflRBeR6BUkC2wqIab4Llgm3w==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/abort-controller": "^4.2.8", - "@smithy/protocol-http": "^5.3.8", - "@smithy/querystring-builder": "^4.2.8", - "@smithy/types": "^4.12.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@smithy/property-provider": { - "version": "4.2.8", - "resolved": "https://registry.npmjs.org/@smithy/property-provider/-/property-provider-4.2.8.tgz", - "integrity": "sha512-EtCTbyIveCKeOXDSWSdze3k612yCPq1YbXsbqX3UHhkOSW8zKsM9NOJG5gTIya0vbY2DIaieG8pKo1rITHYL0w==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/types": "^4.12.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@smithy/protocol-http": { - "version": "5.3.8", - "resolved": "https://registry.npmjs.org/@smithy/protocol-http/-/protocol-http-5.3.8.tgz", - "integrity": "sha512-QNINVDhxpZ5QnP3aviNHQFlRogQZDfYlCkQT+7tJnErPQbDhysondEjhikuANxgMsZrkGeiAxXy4jguEGsDrWQ==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/types": "^4.12.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@smithy/querystring-builder": { - "version": "4.2.8", - "resolved": "https://registry.npmjs.org/@smithy/querystring-builder/-/querystring-builder-4.2.8.tgz", - "integrity": "sha512-Xr83r31+DrE8CP3MqPgMJl+pQlLLmOfiEUnoyAlGzzJIrEsbKsPy1hqH0qySaQm4oWrCBlUqRt+idEgunKB+iw==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/types": "^4.12.0", - "@smithy/util-uri-escape": "^4.2.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@smithy/querystring-parser": { - "version": "4.2.8", - "resolved": "https://registry.npmjs.org/@smithy/querystring-parser/-/querystring-parser-4.2.8.tgz", - "integrity": "sha512-vUurovluVy50CUlazOiXkPq40KGvGWSdmusa3130MwrR1UNnNgKAlj58wlOe61XSHRpUfIIh6cE0zZ8mzKaDPA==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/types": "^4.12.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@smithy/service-error-classification": { - "version": "4.2.8", - "resolved": "https://registry.npmjs.org/@smithy/service-error-classification/-/service-error-classification-4.2.8.tgz", - "integrity": "sha512-mZ5xddodpJhEt3RkCjbmUQuXUOaPNTkbMGR0bcS8FE0bJDLMZlhmpgrvPNCYglVw5rsYTpSnv19womw9WWXKQQ==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/types": "^4.12.0" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@smithy/shared-ini-file-loader": { - "version": "4.4.3", - "resolved": "https://registry.npmjs.org/@smithy/shared-ini-file-loader/-/shared-ini-file-loader-4.4.3.tgz", - "integrity": "sha512-DfQjxXQnzC5UbCUPeC3Ie8u+rIWZTvuDPAGU/BxzrOGhRvgUanaP68kDZA+jaT3ZI+djOf+4dERGlm9mWfFDrg==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/types": "^4.12.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@smithy/signature-v4": { - "version": "5.3.8", - "resolved": "https://registry.npmjs.org/@smithy/signature-v4/-/signature-v4-5.3.8.tgz", - "integrity": "sha512-6A4vdGj7qKNRF16UIcO8HhHjKW27thsxYci+5r/uVRkdcBEkOEiY8OMPuydLX4QHSrJqGHPJzPRwwVTqbLZJhg==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/is-array-buffer": "^4.2.0", - "@smithy/protocol-http": "^5.3.8", - "@smithy/types": "^4.12.0", - "@smithy/util-hex-encoding": "^4.2.0", - "@smithy/util-middleware": "^4.2.8", - "@smithy/util-uri-escape": "^4.2.0", - "@smithy/util-utf8": "^4.2.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@smithy/smithy-client": { - "version": "4.11.2", - "resolved": "https://registry.npmjs.org/@smithy/smithy-client/-/smithy-client-4.11.2.tgz", - "integrity": "sha512-SCkGmFak/xC1n7hKRsUr6wOnBTJ3L22Qd4e8H1fQIuKTAjntwgU8lrdMe7uHdiT2mJAOWA/60qaW9tiMu69n1A==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/core": "^3.22.1", - "@smithy/middleware-endpoint": "^4.4.13", - "@smithy/middleware-stack": "^4.2.8", - "@smithy/protocol-http": "^5.3.8", - "@smithy/types": "^4.12.0", - "@smithy/util-stream": "^4.5.11", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@smithy/types": { - "version": "4.12.0", - "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.12.0.tgz", - "integrity": "sha512-9YcuJVTOBDjg9LWo23Qp0lTQ3D7fQsQtwle0jVfpbUHy9qBwCEgKuVH4FqFB3VYu0nwdHKiEMA+oXz7oV8X1kw==", - "license": "Apache-2.0", - "dependencies": { - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@smithy/url-parser": { - "version": "4.2.8", - "resolved": "https://registry.npmjs.org/@smithy/url-parser/-/url-parser-4.2.8.tgz", - "integrity": "sha512-NQho9U68TGMEU639YkXnVMV3GEFFULmmaWdlu1E9qzyIePOHsoSnagTGSDv1Zi8DCNN6btxOSdgmy5E/hsZwhA==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/querystring-parser": "^4.2.8", - "@smithy/types": "^4.12.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@smithy/util-base64": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/@smithy/util-base64/-/util-base64-4.3.0.tgz", - "integrity": "sha512-GkXZ59JfyxsIwNTWFnjmFEI8kZpRNIBfxKjv09+nkAWPt/4aGaEWMM04m4sxgNVWkbt2MdSvE3KF/PfX4nFedQ==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/util-buffer-from": "^4.2.0", - "@smithy/util-utf8": "^4.2.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@smithy/util-body-length-browser": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/@smithy/util-body-length-browser/-/util-body-length-browser-4.2.0.tgz", - "integrity": "sha512-Fkoh/I76szMKJnBXWPdFkQJl2r9SjPt3cMzLdOB6eJ4Pnpas8hVoWPYemX/peO0yrrvldgCUVJqOAjUrOLjbxg==", - "license": "Apache-2.0", - "dependencies": { - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@smithy/util-body-length-node": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/@smithy/util-body-length-node/-/util-body-length-node-4.2.1.tgz", - "integrity": "sha512-h53dz/pISVrVrfxV1iqXlx5pRg3V2YWFcSQyPyXZRrZoZj4R4DeWRDo1a7dd3CPTcFi3kE+98tuNyD2axyZReA==", - "license": "Apache-2.0", - "dependencies": { - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@smithy/util-buffer-from": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-4.2.0.tgz", - "integrity": "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/is-array-buffer": "^4.2.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@smithy/util-config-provider": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/@smithy/util-config-provider/-/util-config-provider-4.2.0.tgz", - "integrity": "sha512-YEjpl6XJ36FTKmD+kRJJWYvrHeUvm5ykaUS5xK+6oXffQPHeEM4/nXlZPe+Wu0lsgRUcNZiliYNh/y7q9c2y6Q==", - "license": "Apache-2.0", - "dependencies": { - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@smithy/util-defaults-mode-browser": { - "version": "4.3.29", - "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-browser/-/util-defaults-mode-browser-4.3.29.tgz", - "integrity": "sha512-nIGy3DNRmOjaYaaKcQDzmWsro9uxlaqUOhZDHQed9MW/GmkBZPtnU70Pu1+GT9IBmUXwRdDuiyaeiy9Xtpn3+Q==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/property-provider": "^4.2.8", - "@smithy/smithy-client": "^4.11.2", - "@smithy/types": "^4.12.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } + "linux" + ] }, - "node_modules/@smithy/util-defaults-mode-node": { - "version": "4.2.32", - "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-node/-/util-defaults-mode-node-4.2.32.tgz", - "integrity": "sha512-7dtFff6pu5fsjqrVve0YMhrnzJtccCWDacNKOkiZjJ++fmjGExmmSu341x+WU6Oc1IccL7lDuaUj7SfrHpWc5Q==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/config-resolver": "^4.4.6", - "@smithy/credential-provider-imds": "^4.2.8", - "@smithy/node-config-provider": "^4.3.8", - "@smithy/property-provider": "^4.2.8", - "@smithy/smithy-client": "^4.11.2", - "@smithy/types": "^4.12.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.41.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.41.1.tgz", + "integrity": "sha512-oIE6M8WC9ma6xYqjvPhzZYk6NbobIURvP/lEbh7FWplcMO6gn7MM2yHKA1eC/GvYwzNKK/1LYgqzdkZ8YFxR8g==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] }, - "node_modules/@smithy/util-endpoints": { - "version": "3.2.8", - "resolved": "https://registry.npmjs.org/@smithy/util-endpoints/-/util-endpoints-3.2.8.tgz", - "integrity": "sha512-8JaVTn3pBDkhZgHQ8R0epwWt+BqPSLCjdjXXusK1onwJlRuN69fbvSK66aIKKO7SwVFM6x2J2ox5X8pOaWcUEw==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/node-config-provider": "^4.3.8", - "@smithy/types": "^4.12.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.41.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.41.1.tgz", + "integrity": "sha512-cWBOvayNvA+SyeQMp79BHPK8ws6sHSsYnK5zDcsC3Hsxr1dgTABKjMnMslPq1DvZIp6uO7kIWhiGwaTdR4Og9A==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] }, - "node_modules/@smithy/util-hex-encoding": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/@smithy/util-hex-encoding/-/util-hex-encoding-4.2.0.tgz", - "integrity": "sha512-CCQBwJIvXMLKxVbO88IukazJD9a4kQ9ZN7/UMGBjBcJYvatpWk+9g870El4cB8/EJxfe+k+y0GmR9CAzkF+Nbw==", - "license": "Apache-2.0", - "dependencies": { - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.41.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.41.1.tgz", + "integrity": "sha512-y5CbN44M+pUCdGDlZFzGGBSKCA4A/J2ZH4edTYSSxFg7ce1Xt3GtydbVKWLlzL+INfFIZAEg1ZV6hh9+QQf9YQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] }, - "node_modules/@smithy/util-middleware": { - "version": "4.2.8", - "resolved": "https://registry.npmjs.org/@smithy/util-middleware/-/util-middleware-4.2.8.tgz", - "integrity": "sha512-PMqfeJxLcNPMDgvPbbLl/2Vpin+luxqTGPpW3NAQVLbRrFRzTa4rNAASYeIGjRV9Ytuhzny39SpyU04EQreF+A==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/types": "^4.12.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.41.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.41.1.tgz", + "integrity": "sha512-lZkCxIrjlJlMt1dLO/FbpZbzt6J/A8p4DnqzSa4PWqPEUUUnzXLeki/iyPLfV0BmHItlYgHUqJe+3KiyydmiNQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] }, - "node_modules/@smithy/util-retry": { - "version": "4.2.8", - "resolved": "https://registry.npmjs.org/@smithy/util-retry/-/util-retry-4.2.8.tgz", - "integrity": "sha512-CfJqwvoRY0kTGe5AkQokpURNCT1u/MkRzMTASWMPPo2hNSnKtF1D45dQl3DE2LKLr4m+PW9mCeBMJr5mCAVThg==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/service-error-classification": "^4.2.8", - "@smithy/types": "^4.12.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.41.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.41.1.tgz", + "integrity": "sha512-+psFT9+pIh2iuGsxFYYa/LhS5MFKmuivRsx9iPJWNSGbh2XVEjk90fmpUEjCnILPEPJnikAU6SFDiEUyOv90Pg==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] }, - "node_modules/@smithy/util-stream": { - "version": "4.5.11", - "resolved": "https://registry.npmjs.org/@smithy/util-stream/-/util-stream-4.5.11.tgz", - "integrity": "sha512-lKmZ0S/3Qj2OF5H1+VzvDLb6kRxGzZHq6f3rAsoSu5cTLGsn3v3VQBA8czkNNXlLjoFEtVu3OQT2jEeOtOE2CA==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/fetch-http-handler": "^5.3.9", - "@smithy/node-http-handler": "^4.4.9", - "@smithy/types": "^4.12.0", - "@smithy/util-base64": "^4.3.0", - "@smithy/util-buffer-from": "^4.2.0", - "@smithy/util-hex-encoding": "^4.2.0", - "@smithy/util-utf8": "^4.2.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.41.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.41.1.tgz", + "integrity": "sha512-Wq2zpapRYLfi4aKxf2Xff0tN+7slj2d4R87WEzqw7ZLsVvO5zwYCIuEGSZYiK41+GlwUo1HiR+GdkLEJnCKTCw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] }, - "node_modules/@smithy/util-uri-escape": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/@smithy/util-uri-escape/-/util-uri-escape-4.2.0.tgz", - "integrity": "sha512-igZpCKV9+E/Mzrpq6YacdTQ0qTiLm85gD6N/IrmyDvQFA4UnU3d5g3m8tMT/6zG/vVkWSU+VxeUyGonL62DuxA==", - "license": "Apache-2.0", + "node_modules/@shuding/opentype.js": { + "version": "1.4.0-beta.0", + "resolved": "https://registry.npmjs.org/@shuding/opentype.js/-/opentype.js-1.4.0-beta.0.tgz", + "integrity": "sha512-3NgmNyH3l/Hv6EvsWJbsvpcpUba6R8IREQ83nH83cyakCw7uM1arZKNfHwv1Wz6jgqrF/j4x5ELvR6PnK9nTcA==", + "license": "MIT", "dependencies": { - "tslib": "^2.6.2" + "fflate": "^0.7.3", + "string.prototype.codepointat": "^0.2.1" }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@smithy/util-utf8": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-4.2.0.tgz", - "integrity": "sha512-zBPfuzoI8xyBtR2P6WQj63Rz8i3AmfAaJLuNG8dWsfvPe8lO4aCPYLn879mEgHndZH1zQ2oXmG8O1GGzzaoZiw==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/util-buffer-from": "^4.2.0", - "tslib": "^2.6.2" + "bin": { + "ot": "bin/ot" }, "engines": { - "node": ">=18.0.0" + "node": ">= 8.0.0" } }, - "node_modules/@smithy/uuid": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@smithy/uuid/-/uuid-1.1.0.tgz", - "integrity": "sha512-4aUIteuyxtBUhVdiQqcDhKFitwfd9hqoSDYY2KRXiWtgoWJ9Bmise+KfEPDiVHWeJepvF8xJO9/9+WDIciMFFw==", - "license": "Apache-2.0", - "dependencies": { - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } + "node_modules/@shuding/opentype.js/node_modules/fflate": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/fflate/-/fflate-0.7.4.tgz", + "integrity": "sha512-5u2V/CDW15QM1XbbgS+0DfPxVB+jUKhWEKuuFuHncbk3tEEqzmoXL+2KyOFuKGqOnmdIy0/davWF1CkuwtibCw==", + "license": "MIT" }, "node_modules/@standard-schema/spec": { "version": "1.1.0", @@ -3957,6 +2710,7 @@ "version": "10.4.0", "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-10.4.0.tgz", "integrity": "sha512-pemlzrSESWbdAloYml3bAJMEfNh1Z7EduzqPKprCH5S341frlpYnUEW0H72dLxa6IsYr+mPno20GiSm+h9dEdQ==", + "dev": true, "license": "MIT", "peer": true, "dependencies": { @@ -3977,6 +2731,7 @@ "version": "14.6.1", "resolved": "https://registry.npmjs.org/@testing-library/user-event/-/user-event-14.6.1.tgz", "integrity": "sha512-vq7fv0rnt+QTXgPxr5Hjc210p6YKq2kmdziLgnsZGgLJ9e6VAShx1pACLuRjd/AS/sr7phAR58OIIpf0LlmQNw==", + "dev": true, "license": "MIT", "engines": { "node": ">=12", @@ -4023,15 +2778,18 @@ "version": "5.0.4", "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.4.tgz", "integrity": "sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==", + "dev": true, "license": "MIT" }, "node_modules/@types/chai": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/@types/chai/-/chai-5.2.2.tgz", - "integrity": "sha512-8kB30R7Hwqf40JPiKhVzodJs2Qc1ZJ5zuT3uzw5Hq/dhNCl3G3l83jfpdI1e20BP348+fV7VIL/+FxaXkqBmWg==", + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-5.2.3.tgz", + "integrity": "sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==", + "dev": true, "license": "MIT", "dependencies": { - "@types/deep-eql": "*" + "@types/deep-eql": "*", + "assertion-error": "^2.0.1" } }, "node_modules/@types/cookie": { @@ -4045,6 +2803,7 @@ "version": "4.0.2", "resolved": "https://registry.npmjs.org/@types/deep-eql/-/deep-eql-4.0.2.tgz", "integrity": "sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==", + "dev": true, "license": "MIT" }, "node_modules/@types/dompurify": { @@ -4070,18 +2829,6 @@ "dev": true, "license": "MIT" }, - "node_modules/@types/jsdom": { - "version": "21.1.7", - "resolved": "https://registry.npmjs.org/@types/jsdom/-/jsdom-21.1.7.tgz", - "integrity": "sha512-yOriVnggzrnQ3a9OKOCxaVuSug3w3/SbOj5i7VwXWZEyUNl3bLF9V3MfxGbZKuwqJOQyRfqXyROBB1CoZLFWzA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/node": "*", - "@types/tough-cookie": "*", - "parse5": "^7.0.0" - } - }, "node_modules/@types/json-schema": { "version": "7.0.15", "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", @@ -4163,13 +2910,6 @@ "dev": true, "license": "MIT" }, - "node_modules/@types/tough-cookie": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-4.0.5.tgz", - "integrity": "sha512-/Ad8+nIOV7Rl++6f1BdKxFSMgmoqEoYbHRpPcx3JEfv8VRsQe9Z4mCXeJBzxs7mbHY/XOZZuXlRNfhpVPbs6ZA==", - "dev": true, - "license": "MIT" - }, "node_modules/@types/trusted-types": { "version": "2.0.7", "resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.7.tgz", @@ -4417,16 +3157,17 @@ "license": "ISC" }, "node_modules/@vitest/browser": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/@vitest/browser/-/browser-3.2.2.tgz", - "integrity": "sha512-LJk8ZhCGhgG6G6jFFJ9LX83ibRY8FszLuu9zPaYFDrcHbBwNXwt1v06HRs/vHVYxwjw3/BGzSIgn9Et2P6rCiA==", + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/@vitest/browser/-/browser-3.2.4.tgz", + "integrity": "sha512-tJxiPrWmzH8a+w9nLKlQMzAKX/7VjFs50MWgcAj7p9XQ7AQ9/35fByFYptgPELyLw+0aixTnC4pUWV+APcZ/kw==", + "dev": true, "license": "MIT", "peer": true, "dependencies": { "@testing-library/dom": "^10.4.0", "@testing-library/user-event": "^14.6.1", - "@vitest/mocker": "3.2.2", - "@vitest/utils": "3.2.2", + "@vitest/mocker": "3.2.4", + "@vitest/utils": "3.2.4", "magic-string": "^0.30.17", "sirv": "^3.0.1", "tinyrainbow": "^2.0.0", @@ -4437,7 +3178,7 @@ }, "peerDependencies": { "playwright": "*", - "vitest": "3.2.2", + "vitest": "3.2.4", "webdriverio": "^7.0.0 || ^8.0.0 || ^9.0.0" }, "peerDependenciesMeta": { @@ -4452,15 +3193,50 @@ } } }, + "node_modules/@vitest/coverage-v8": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/@vitest/coverage-v8/-/coverage-v8-3.2.4.tgz", + "integrity": "sha512-EyF9SXU6kS5Ku/U82E259WSnvg6c8KTjppUncuNdm5QHpe17mwREHnjDzozC8x9MZ0xfBUFSaLkRv4TMA75ALQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@ampproject/remapping": "^2.3.0", + "@bcoe/v8-coverage": "^1.0.2", + "ast-v8-to-istanbul": "^0.3.3", + "debug": "^4.4.1", + "istanbul-lib-coverage": "^3.2.2", + "istanbul-lib-report": "^3.0.1", + "istanbul-lib-source-maps": "^5.0.6", + "istanbul-reports": "^3.1.7", + "magic-string": "^0.30.17", + "magicast": "^0.3.5", + "std-env": "^3.9.0", + "test-exclude": "^7.0.1", + "tinyrainbow": "^2.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "@vitest/browser": "3.2.4", + "vitest": "3.2.4" + }, + "peerDependenciesMeta": { + "@vitest/browser": { + "optional": true + } + } + }, "node_modules/@vitest/expect": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-3.2.2.tgz", - "integrity": "sha512-ipHw0z669vEMjzz3xQE8nJX1s0rQIb7oEl4jjl35qWTwm/KIHERIg/p/zORrjAaZKXfsv7IybcNGHwhOOAPMwQ==", + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-3.2.4.tgz", + "integrity": "sha512-Io0yyORnB6sikFlt8QW5K7slY4OjqNX9jmJQ02QDda8lyM6B5oNgVWoSoKPac8/kgnCUzuHQKrSLtu/uOqqrig==", + "dev": true, "license": "MIT", "dependencies": { "@types/chai": "^5.2.2", - "@vitest/spy": "3.2.2", - "@vitest/utils": "3.2.2", + "@vitest/spy": "3.2.4", + "@vitest/utils": "3.2.4", "chai": "^5.2.0", "tinyrainbow": "^2.0.0" }, @@ -4469,12 +3245,13 @@ } }, "node_modules/@vitest/mocker": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-3.2.2.tgz", - "integrity": "sha512-jKojcaRyIYpDEf+s7/dD3LJt53c0dPfp5zCPXz9H/kcGrSlovU/t1yEaNzM9oFME3dcd4ULwRI/x0Po1Zf+LTw==", + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-3.2.4.tgz", + "integrity": "sha512-46ryTE9RZO/rfDd7pEqFl7etuyzekzEhUbTW3BvmeO/BcCMEgq59BKhek3dXDWgAj4oMK6OZi+vRr1wPW6qjEQ==", + "dev": true, "license": "MIT", "dependencies": { - "@vitest/spy": "3.2.2", + "@vitest/spy": "3.2.4", "estree-walker": "^3.0.3", "magic-string": "^0.30.17" }, @@ -4498,15 +3275,17 @@ "version": "3.0.3", "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", + "dev": true, "license": "MIT", "dependencies": { "@types/estree": "^1.0.0" } }, "node_modules/@vitest/pretty-format": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-3.2.2.tgz", - "integrity": "sha512-FY4o4U1UDhO9KMd2Wee5vumwcaHw7Vg4V7yR4Oq6uK34nhEJOmdRYrk3ClburPRUA09lXD/oXWZ8y/Sdma0aUQ==", + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-3.2.4.tgz", + "integrity": "sha512-IVNZik8IVRJRTr9fxlitMKeJeXFFFN0JaB9PHPGQ8NKQbGpfjlTx9zO4RefN8gp7eqjNy8nyK3NZmBzOPeIxtA==", + "dev": true, "license": "MIT", "dependencies": { "tinyrainbow": "^2.0.0" @@ -4516,31 +3295,28 @@ } }, "node_modules/@vitest/runner": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-3.2.2.tgz", - "integrity": "sha512-GYcHcaS3ejGRZYed2GAkvsjBeXIEerDKdX3orQrBJqLRiea4NSS9qvn9Nxmuy1IwIB+EjFOaxXnX79l8HFaBwg==", + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-3.2.4.tgz", + "integrity": "sha512-oukfKT9Mk41LreEW09vt45f8wx7DordoWUZMYdY/cyAk7w5TWkTRCNZYF7sX7n2wB7jyGAl74OxgwhPgKaqDMQ==", + "dev": true, "license": "MIT", "dependencies": { - "@vitest/utils": "3.2.2", - "pathe": "^2.0.3" + "@vitest/utils": "3.2.4", + "pathe": "^2.0.3", + "strip-literal": "^3.0.0" }, "funding": { "url": "https://opencollective.com/vitest" } }, - "node_modules/@vitest/runner/node_modules/pathe": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", - "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", - "license": "MIT" - }, "node_modules/@vitest/snapshot": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-3.2.2.tgz", - "integrity": "sha512-aMEI2XFlR1aNECbBs5C5IZopfi5Lb8QJZGGpzS8ZUHML5La5wCbrbhLOVSME68qwpT05ROEEOAZPRXFpxZV2wA==", + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-3.2.4.tgz", + "integrity": "sha512-dEYtS7qQP2CjU27QBC5oUOxLE/v5eLkGqPE0ZKEIDGMs4vKWe7IjgLOeauHsR0D5YuuycGRO5oSRXnwnmA78fQ==", + "dev": true, "license": "MIT", "dependencies": { - "@vitest/pretty-format": "3.2.2", + "@vitest/pretty-format": "3.2.4", "magic-string": "^0.30.17", "pathe": "^2.0.3" }, @@ -4548,16 +3324,11 @@ "url": "https://opencollective.com/vitest" } }, - "node_modules/@vitest/snapshot/node_modules/pathe": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", - "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", - "license": "MIT" - }, "node_modules/@vitest/spy": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-3.2.2.tgz", - "integrity": "sha512-6Utxlx3o7pcTxvp0u8kUiXtRFScMrUg28KjB3R2hon7w4YqOFAEA9QwzPVVS1QNL3smo4xRNOpNZClRVfpMcYg==", + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-3.2.4.tgz", + "integrity": "sha512-vAfasCOe6AIK70iP5UD11Ac4siNUNJ9i/9PZ3NKx07sG6sUxeag1LWdNrMWeKKYBLlzuK+Gn65Yd5nyL6ds+nw==", + "dev": true, "license": "MIT", "dependencies": { "tinyspy": "^4.0.3" @@ -4567,13 +3338,14 @@ } }, "node_modules/@vitest/utils": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-3.2.2.tgz", - "integrity": "sha512-qJYMllrWpF/OYfWHP32T31QCaLa3BAzT/n/8mNGhPdVcjY+JYazQFO1nsJvXU12Kp1xMpNY4AGuljPTNjQve6A==", + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-3.2.4.tgz", + "integrity": "sha512-fB2V0JFrQSMsCo9HiSq3Ezpdv4iYaXRG1Sx8edX3MwxfyNn83mKiGzOcH+Fkxt4MHxr3y42fQi1oeAInqgX2QA==", + "dev": true, "license": "MIT", "dependencies": { - "@vitest/pretty-format": "3.2.2", - "loupe": "^3.1.3", + "@vitest/pretty-format": "3.2.4", + "loupe": "^3.1.4", "tinyrainbow": "^2.0.0" }, "funding": { @@ -4742,6 +3514,7 @@ "version": "7.0.0", "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-7.0.0.tgz", "integrity": "sha512-GdYO7a61mR0fOlAsvC9/rIHf7L96sBc6dEWzeOu+KAea5bZyQRPIpojrVoI4AXGJS/ycu/fBTdLrUkA4ODrvjw==", + "dev": true, "license": "MIT", "dependencies": { "environment": "^1.0.0" @@ -4825,6 +3598,7 @@ "version": "5.3.0", "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.0.tgz", "integrity": "sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==", + "dev": true, "license": "Apache-2.0", "dependencies": { "dequal": "^2.0.3" @@ -4844,11 +3618,41 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz", "integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==", + "dev": true, "license": "MIT", "engines": { "node": ">=12" } }, + "node_modules/ast-v8-to-istanbul": { + "version": "0.3.11", + "resolved": "https://registry.npmjs.org/ast-v8-to-istanbul/-/ast-v8-to-istanbul-0.3.11.tgz", + "integrity": "sha512-Qya9fkoofMjCBNVdWINMjB5KZvkYfaO9/anwkWnjxibpWUxo5iHl2sOdP7/uAqaRuUYuoo8rDwnbaaKVFxoUvw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.31", + "estree-walker": "^3.0.3", + "js-tokens": "^10.0.0" + } + }, + "node_modules/ast-v8-to-istanbul/node_modules/estree-walker": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", + "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0" + } + }, + "node_modules/ast-v8-to-istanbul/node_modules/js-tokens": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-10.0.0.tgz", + "integrity": "sha512-lM/UBzQmfJRo9ABXbPWemivdCW8V2G8FHaHdypQaIy523snUjog0W71ayWXTjiR+ixeMyVHN2XcpnTd/liPg/Q==", + "dev": true, + "license": "MIT" + }, "node_modules/async-mutex": { "version": "0.5.0", "resolved": "https://registry.npmjs.org/async-mutex/-/async-mutex-0.5.0.tgz", @@ -4911,12 +3715,6 @@ "postcss": "^8.1.0" } }, - "node_modules/aws4": { - "version": "1.13.2", - "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.13.2.tgz", - "integrity": "sha512-lHe62zvbTB5eEABUVi/AwVh0ZKY9rMMDhmm+eeyuuUQbQ3+J+fONVQOZyj+DdrvD4BY33uYniyRJ4UJIaSKAfw==", - "license": "MIT" - }, "node_modules/axobject-query": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-4.1.0.tgz", @@ -5056,12 +3854,6 @@ "url": "https://opencollective.com/express" } }, - "node_modules/bowser": { - "version": "2.14.1", - "resolved": "https://registry.npmjs.org/bowser/-/bowser-2.14.1.tgz", - "integrity": "sha512-tzPjzCxygAKWFOJP011oxFHs57HzIhOEracIgAePE4pqB3LikALKnSzUyU4MGs9/iCEUuHlAJTjTc5M+u7YEGg==", - "license": "MIT" - }, "node_modules/brace-expansion": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", @@ -5188,6 +3980,7 @@ "version": "6.7.14", "resolved": "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz", "integrity": "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==", + "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -5284,9 +4077,10 @@ "license": "CC-BY-4.0" }, "node_modules/chai": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/chai/-/chai-5.2.0.tgz", - "integrity": "sha512-mCuXncKXk5iCLhfhwTc0izo0gtEmpz5CtG2y8GiOINBlMVS6v8TMRc5TaLWKS6692m9+dVVfzgeVxR5UxWHTYw==", + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/chai/-/chai-5.3.3.tgz", + "integrity": "sha512-4zNhdJD/iOjSH0A05ea+Ke6MU5mmpQcbQsSOkgdaUMJ9zTlDTD/GYlwohmIE2u0gaxHYiVHEn1Fw9mZ/ktJWgw==", + "dev": true, "license": "MIT", "dependencies": { "assertion-error": "^2.0.1", @@ -5296,13 +4090,14 @@ "pathval": "^2.0.0" }, "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", @@ -5316,9 +4111,10 @@ } }, "node_modules/check-error": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/check-error/-/check-error-2.1.1.tgz", - "integrity": "sha512-OAlb+T7V4Op9OwdkjmguYRqncdlx5JiofwOAUkmTF+jNdHwzTaTs4sRAGpzLF3oOz5xAyDGrPgeIDFQmDOTiJw==", + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/check-error/-/check-error-2.1.3.tgz", + "integrity": "sha512-PAJdDJusoxnwm1VwW07VWwUN1sl7smmC3OKggvndJFadxxDRyFJBX/ggnu/KE4kQAB7a3Dp8f/YXC1FlUprWmA==", + "dev": true, "license": "MIT", "engines": { "node": ">= 16" @@ -5344,6 +4140,7 @@ "version": "5.0.0", "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-5.0.0.tgz", "integrity": "sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw==", + "dev": true, "license": "MIT", "dependencies": { "restore-cursor": "^5.0.0" @@ -5359,6 +4156,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-4.0.0.tgz", "integrity": "sha512-nPdaFdQ0h/GEigbPClz11D0v/ZJEwxmeVZGeMo3Z5StPtUTkA9o1lD6QwoirYiSDzbcwn2XcjwmCp68W1IS4TA==", + "dev": true, "license": "MIT", "dependencies": { "slice-ansi": "^5.0.0", @@ -5675,6 +4473,7 @@ "version": "5.0.2", "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-5.0.2.tgz", "integrity": "sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==", + "dev": true, "license": "MIT", "engines": { "node": ">=6" @@ -5782,6 +4581,7 @@ "version": "0.5.16", "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.16.tgz", "integrity": "sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==", + "dev": true, "license": "MIT" }, "node_modules/dom-serializer": { @@ -5958,6 +4758,7 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/environment/-/environment-1.1.0.tgz", "integrity": "sha512-xUtoPkMggbz0MPyPiIWr1Kp4aeWJjDZ6SMvURhimjdZgsRuDplF5/s9hcgGhyXMhs+6vpnuoiZ2kFiu3FMnS8Q==", + "dev": true, "license": "MIT", "engines": { "node": ">=18" @@ -5988,6 +4789,7 @@ "version": "1.7.0", "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.7.0.tgz", "integrity": "sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==", + "dev": true, "license": "MIT" }, "node_modules/es-object-atoms": { @@ -6021,6 +4823,7 @@ "version": "0.25.5", "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.5.tgz", "integrity": "sha512-P8OtKZRv/5J5hhz0cUAdu/cLuPIKXpQl1R9pZtvmHWQvrAUVd0UNIPT4IB4W3rNOqVO0rlqHmCIbSwxh/c9yUQ==", + "devOptional": true, "hasInstallScript": true, "license": "MIT", "bin": { @@ -6383,6 +5186,7 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz", "integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==", + "dev": true, "license": "MIT" }, "node_modules/events": { @@ -6419,6 +5223,7 @@ "version": "8.0.1", "resolved": "https://registry.npmjs.org/execa/-/execa-8.0.1.tgz", "integrity": "sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==", + "dev": true, "license": "MIT", "dependencies": { "cross-spawn": "^7.0.3", @@ -6442,6 +5247,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz", "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==", + "dev": true, "license": "MIT", "engines": { "node": "^12.20.0 || ^14.13.1 || >=16.0.0" @@ -6454,6 +5260,7 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.2.1.tgz", "integrity": "sha512-/kP8CAwxzLVEeFrMm4kMmy4CCDlpipyA7MYLVrdJIkV0fYF0UaigQHRsxHiuY/GEea+bh4KSv3TIlgr+2UL6bw==", + "dev": true, "license": "Apache-2.0", "engines": { "node": ">=12.0.0" @@ -6662,24 +5469,6 @@ ], "license": "BSD-3-Clause" }, - "node_modules/fast-xml-parser": { - "version": "5.3.4", - "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-5.3.4.tgz", - "integrity": "sha512-EFd6afGmXlCx8H8WTZHhAoDaWaGyuIBoZJ2mknrNxug+aZKjkp0a0dlars9Izl+jF+7Gu1/5f/2h68cQpe0IiA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/NaturalIntelligence" - } - ], - "license": "MIT", - "dependencies": { - "strnum": "^2.1.0" - }, - "bin": { - "fxparser": "src/cli/cli.js" - } - }, "node_modules/fastq": { "version": "1.19.1", "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.19.1.tgz", @@ -6693,6 +5482,7 @@ "version": "6.4.5", "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.4.5.tgz", "integrity": "sha512-4BG7puHpVsIYxZUbiUE3RqGloLaSSwzYie5jvasC4LWuBWzZawynvYouhjbQKw2JuIGYdm0DzIxl8iVidKlUEw==", + "devOptional": true, "license": "MIT", "peerDependencies": { "picomatch": "^3 || ^4" @@ -6967,6 +5757,7 @@ "version": "1.3.0", "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.3.0.tgz", "integrity": "sha512-vpeMIQKxczTD/0s2CdEWHcb0eeJe6TFjxb+J5xgX7hScxqrGuyjmv4c1D4A/gelKfyox0gJJwIHF+fLjeaM8kQ==", + "dev": true, "license": "MIT", "engines": { "node": ">=18" @@ -7016,6 +5807,7 @@ "version": "8.0.1", "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-8.0.1.tgz", "integrity": "sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==", + "dev": true, "license": "MIT", "engines": { "node": ">=16" @@ -7163,6 +5955,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -7256,6 +6049,13 @@ "node": ">=12" } }, + "node_modules/html-escaper": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", + "dev": true, + "license": "MIT" + }, "node_modules/htmlparser2": { "version": "10.0.0", "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-10.0.0.tgz", @@ -7339,6 +6139,7 @@ "version": "5.0.0", "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-5.0.0.tgz", "integrity": "sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==", + "dev": true, "license": "Apache-2.0", "engines": { "node": ">=16.17.0" @@ -7357,6 +6158,7 @@ "version": "9.1.7", "resolved": "https://registry.npmjs.org/husky/-/husky-9.1.7.tgz", "integrity": "sha512-5gs5ytaNjBrh5Ow3zrvdUUY+0VxIuWVL4i9irt6friV+BqdCfmV11CQTWMiBYWHbXhco+J1kHfTOUkePhCDvMA==", + "dev": true, "license": "MIT", "bin": { "husky": "bin.js" @@ -7535,6 +6337,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-4.0.0.tgz", "integrity": "sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ==", + "dev": true, "license": "MIT", "engines": { "node": ">=12" @@ -7833,6 +6636,76 @@ "node": ">=18" } }, + "node_modules/istanbul-lib-coverage": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", + "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-report": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz", + "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^4.0.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-lib-report/node_modules/make-dir": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", + "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^7.5.3" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/istanbul-lib-source-maps": { + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-5.0.6.tgz", + "integrity": "sha512-yg2d+Em4KizZC5niWhQaIomgf5WlL4vOOjZ5xGCmF8SnPE/mDWWXgvRExdcpCgh9lLRRa1/fSYp2ymmbJ1pI+A==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.23", + "debug": "^4.1.1", + "istanbul-lib-coverage": "^3.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-reports": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.2.0.tgz", + "integrity": "sha512-HGYWWS/ehqTV3xN10i23tkPkpH46MLCIMFNCaaKNavAXTF1RkqxawEPtnjnGZ6XKSInBKkiOA5BKS+aZiY3AvA==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/jackspeak": { "version": "3.4.3", "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", @@ -7879,6 +6752,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true, "license": "MIT" }, "node_modules/js-yaml": { @@ -8111,6 +6985,7 @@ "version": "15.5.2", "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-15.5.2.tgz", "integrity": "sha512-YUSOLq9VeRNAo/CTaVmhGDKG+LBtA8KF1X4K5+ykMSwWST1vDxJRB2kv2COgLb1fvpCo+A/y9A0G0znNVmdx4w==", + "dev": true, "license": "MIT", "dependencies": { "chalk": "^5.4.1", @@ -8138,6 +7013,7 @@ "version": "5.4.1", "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.4.1.tgz", "integrity": "sha512-zgVZuo2WcZgfUEmsn6eO3kINexW8RAE4maiQ8QNs8CtpPCSyMiYsULR3HQYkm3w8FIA3SberyMJMSldGsW+U3w==", + "dev": true, "license": "MIT", "engines": { "node": "^12.17.0 || ^14.13 || >=16.0.0" @@ -8150,6 +7026,7 @@ "version": "13.1.0", "resolved": "https://registry.npmjs.org/commander/-/commander-13.1.0.tgz", "integrity": "sha512-/rFeCpNJQbhSZjGVwO9RFV3xPqbnERS8MmIQzCtD/zl6gpJuV/bMLuN92oG3F7d8oDEHHRrujSXNUr8fpjntKw==", + "dev": true, "license": "MIT", "engines": { "node": ">=18" @@ -8159,6 +7036,7 @@ "version": "8.3.3", "resolved": "https://registry.npmjs.org/listr2/-/listr2-8.3.3.tgz", "integrity": "sha512-LWzX2KsqcB1wqQ4AHgYb4RsDXauQiqhjLk+6hjbaeHG4zpjjVAB6wC/gz6X0l+Du1cN3pUB5ZlrvTbhGSNnUQQ==", + "dev": true, "license": "MIT", "dependencies": { "cli-truncate": "^4.0.0", @@ -8232,6 +7110,7 @@ "version": "6.1.0", "resolved": "https://registry.npmjs.org/log-update/-/log-update-6.1.0.tgz", "integrity": "sha512-9ie8ItPR6tjY5uYJh8K/Zrv/RMZ5VOlOWvtZdEHYSTFKZfIBPQa9tOAEeAWhd+AnIneLJ22w5fjOYtoutpWq5w==", + "dev": true, "license": "MIT", "dependencies": { "ansi-escapes": "^7.0.0", @@ -8251,6 +7130,7 @@ "version": "6.1.0", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", + "dev": true, "license": "MIT", "engines": { "node": ">=12" @@ -8263,6 +7143,7 @@ "version": "6.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "dev": true, "license": "MIT", "engines": { "node": ">=12" @@ -8275,6 +7156,7 @@ "version": "5.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-5.0.0.tgz", "integrity": "sha512-OVa3u9kkBbw7b8Xw5F9P+D/T9X+Z4+JruYVNapTjPYZYUznQ5YfWeFkOj606XYYW8yugTfC8Pj0hYqvi4ryAhA==", + "dev": true, "license": "MIT", "dependencies": { "get-east-asian-width": "^1.0.0" @@ -8290,6 +7172,7 @@ "version": "7.1.0", "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-7.1.0.tgz", "integrity": "sha512-bSiSngZ/jWeX93BqeIAbImyTbEihizcwNjFoRUIY/T1wWQsfsm2Vw1agPKylXvQTU7iASGdHhyqRlqQzfz+Htg==", + "dev": true, "license": "MIT", "dependencies": { "ansi-styles": "^6.2.1", @@ -8306,6 +7189,7 @@ "version": "7.1.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dev": true, "license": "MIT", "dependencies": { "ansi-regex": "^6.0.1" @@ -8318,9 +7202,10 @@ } }, "node_modules/loupe": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/loupe/-/loupe-3.1.3.tgz", - "integrity": "sha512-kkIp7XSkP78ZxJEsSxW3712C6teJVoeHHwgo9zJ380de7IYyJ2ISlxojcH2pC5OFLewESmnRi/+XCDIEEVyoug==", + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/loupe/-/loupe-3.2.1.tgz", + "integrity": "sha512-CdzqowRJCeLU72bHvWqwRBBlLcMEtIvGrlvef74kMnV2AolS9Y8xUv1I0U/MNAWMhBlKIoyuEgoJ0t/bbwHbLQ==", + "dev": true, "license": "MIT" }, "node_modules/lru-cache": { @@ -8364,6 +7249,18 @@ "@jridgewell/sourcemap-codec": "^1.5.0" } }, + "node_modules/magicast": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/magicast/-/magicast-0.3.5.tgz", + "integrity": "sha512-L0WhttDl+2BOsybvEOLK7fW3UA0OQ0IQ2d6Zl2x/a6vVRs3bAY0ECOSHHeL5jD+SbOpOCUEi0y1DgHEn9Qn1AQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.25.4", + "@babel/types": "^7.25.4", + "source-map-js": "^1.2.0" + } + }, "node_modules/make-dir": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", @@ -8443,6 +7340,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true, "license": "MIT" }, "node_modules/merge2": { @@ -8504,6 +7402,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz", "integrity": "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==", + "dev": true, "license": "MIT", "engines": { "node": ">=12" @@ -8516,6 +7415,7 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/mimic-function/-/mimic-function-5.0.1.tgz", "integrity": "sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==", + "dev": true, "license": "MIT", "engines": { "node": ">=18" @@ -8550,12 +7450,12 @@ } }, "node_modules/minipass": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", - "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", + "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", "license": "ISC", "engines": { - "node": ">=8" + "node": ">=16 || 14 >=14.17" } }, "node_modules/mlly": { @@ -8571,13 +7471,6 @@ "ufo": "^1.5.4" } }, - "node_modules/mlly/node_modules/pathe": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", - "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", - "dev": true, - "license": "MIT" - }, "node_modules/mongodb": { "version": "5.9.2", "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-5.9.2.tgz", @@ -8812,6 +7705,7 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-2.0.1.tgz", "integrity": "sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ==", + "devOptional": true, "license": "MIT", "engines": { "node": ">=10" @@ -8983,6 +7877,7 @@ "version": "5.3.0", "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.3.0.tgz", "integrity": "sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ==", + "dev": true, "license": "MIT", "dependencies": { "path-key": "^4.0.0" @@ -8998,6 +7893,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz", "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==", + "dev": true, "license": "MIT", "engines": { "node": ">=12" @@ -9093,6 +7989,7 @@ "version": "6.0.0", "resolved": "https://registry.npmjs.org/onetime/-/onetime-6.0.0.tgz", "integrity": "sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==", + "dev": true, "license": "MIT", "dependencies": { "mimic-fn": "^4.0.0" @@ -9403,10 +8300,18 @@ "node": ">=8" } }, + "node_modules/pathe": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", + "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", + "dev": true, + "license": "MIT" + }, "node_modules/pathval": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/pathval/-/pathval-2.0.0.tgz", - "integrity": "sha512-vE7JKRyES09KiunauX7nd2Q9/L7lhok4smP9RZTDeD4MVs72Dp2qNFVz39Nz5a0FVEW0BJR6C0DYrq6unoziZA==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pathval/-/pathval-2.0.1.tgz", + "integrity": "sha512-//nshmD55c46FuFw26xV/xFAaB5HF9Xdap7HJBBnrKdAd6/GxDBaNA1870O79+9ueg61cZLSVc+OaFlfmObYVQ==", + "dev": true, "license": "MIT", "engines": { "node": ">= 14.16" @@ -9442,6 +8347,7 @@ "version": "4.0.2", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz", "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==", + "devOptional": true, "license": "MIT", "engines": { "node": ">=12" @@ -9454,6 +8360,7 @@ "version": "0.6.0", "resolved": "https://registry.npmjs.org/pidtree/-/pidtree-0.6.0.tgz", "integrity": "sha512-eG2dWTVw5bzqGRztnHExczNxt5VGsE6OwTeCG3fdUf9KBsZzO3R5OIIIzWR+iZA0NtZ+RDVdaoE2dK1cn6jH4g==", + "dev": true, "license": "MIT", "bin": { "pidtree": "bin/pidtree.js" @@ -9632,18 +8539,11 @@ "pathe": "^2.0.1" } }, - "node_modules/pkg-types/node_modules/pathe": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", - "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", - "dev": true, - "license": "MIT" - }, "node_modules/playwright": { "version": "1.55.1", "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.55.1.tgz", "integrity": "sha512-cJW4Xd/G3v5ovXtJJ52MAOclqeac9S/aGGgRzLabuF8TnIb6xHvMzKIa6JmrRzUkeXJgfL1MhukP0NK6l39h3A==", - "devOptional": true, + "dev": true, "license": "Apache-2.0", "peer": true, "dependencies": { @@ -9663,7 +8563,7 @@ "version": "1.55.1", "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.55.1.tgz", "integrity": "sha512-Z6Mh9mkwX+zxSlHqdr5AOcJnfp+xUWLCt9uKV18fhzA8eyxUd8NUWzAjxUh55RZKSYwDGX0cfaySdhZJGMoJ+w==", - "devOptional": true, + "dev": true, "license": "Apache-2.0", "bin": { "playwright-core": "cli.js" @@ -10029,6 +8929,7 @@ "version": "27.5.1", "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz", "integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==", + "dev": true, "license": "MIT", "dependencies": { "ansi-regex": "^5.0.1", @@ -10043,6 +8944,7 @@ "version": "5.2.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, "license": "MIT", "engines": { "node": ">=10" @@ -10252,6 +9154,7 @@ "version": "17.0.2", "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", + "dev": true, "license": "MIT" }, "node_modules/read-cache": { @@ -10351,6 +9254,7 @@ "version": "5.1.0", "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-5.1.0.tgz", "integrity": "sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA==", + "dev": true, "license": "MIT", "dependencies": { "onetime": "^7.0.0", @@ -10367,6 +9271,7 @@ "version": "7.0.0", "resolved": "https://registry.npmjs.org/onetime/-/onetime-7.0.0.tgz", "integrity": "sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ==", + "dev": true, "license": "MIT", "dependencies": { "mimic-function": "^5.0.0" @@ -10392,6 +9297,7 @@ "version": "1.4.1", "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.4.1.tgz", "integrity": "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==", + "dev": true, "license": "MIT" }, "node_modules/rimraf": { @@ -10415,6 +9321,7 @@ "version": "4.41.1", "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.41.1.tgz", "integrity": "sha512-cPmwD3FnFv8rKMBc1MxWCwVQFxwf1JEmSX3iQXrRVVG15zerAIXRjMFVWnd5Q5QvgKF7Aj+5ykXFhUl+QGnyOw==", + "devOptional": true, "license": "MIT", "peer": true, "dependencies": { @@ -10455,6 +9362,7 @@ "version": "1.0.7", "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.7.tgz", "integrity": "sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ==", + "devOptional": true, "license": "MIT" }, "node_modules/router": { @@ -10853,6 +9761,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz", "integrity": "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==", + "dev": true, "license": "ISC" }, "node_modules/signal-exit": { @@ -10880,6 +9789,7 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/sirv/-/sirv-3.0.1.tgz", "integrity": "sha512-FoqMu0NCGBLCcAkS1qA+XJIQTR6/JHfQXl+uGteNCQ76T91DMUjPa9xfmeqMY3z80nLSg9yQmNjK0Px6RWsH/A==", + "devOptional": true, "license": "MIT", "dependencies": { "@polka/url": "^1.0.0-next.24", @@ -10904,6 +9814,7 @@ "version": "5.0.0", "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-5.0.0.tgz", "integrity": "sha512-FC+lgizVPfie0kkhqUScwRu1O/lF6NOgJmlCgK+/LYxDCTk8sGelYaHDhFcDN+Sn3Cv+3VSa4Byeo+IMCzpMgQ==", + "dev": true, "license": "MIT", "dependencies": { "ansi-styles": "^6.0.0", @@ -10920,6 +9831,7 @@ "version": "6.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "dev": true, "license": "MIT", "engines": { "node": ">=12" @@ -11014,6 +9926,7 @@ "version": "0.0.2", "resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz", "integrity": "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==", + "dev": true, "license": "MIT" }, "node_modules/statuses": { @@ -11029,6 +9942,7 @@ "version": "3.9.0", "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.9.0.tgz", "integrity": "sha512-UGvjygr6F6tpH7o2qyqR6QYpwraIjKSdtzyBdyytFOHmPZY917kwdwLG0RbOjWOnKmnm3PeHjaoLLMie7kPLQw==", + "dev": true, "license": "MIT" }, "node_modules/streamx": { @@ -11058,6 +9972,7 @@ "version": "0.3.2", "resolved": "https://registry.npmjs.org/string-argv/-/string-argv-0.3.2.tgz", "integrity": "sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==", + "dev": true, "license": "MIT", "engines": { "node": ">=0.6.19" @@ -11067,6 +9982,7 @@ "version": "7.2.0", "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", + "dev": true, "license": "MIT", "dependencies": { "emoji-regex": "^10.3.0", @@ -11114,6 +10030,7 @@ "version": "6.1.0", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", + "dev": true, "license": "MIT", "engines": { "node": ">=12" @@ -11126,6 +10043,7 @@ "version": "7.1.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dev": true, "license": "MIT", "dependencies": { "ansi-regex": "^6.0.1" @@ -11172,6 +10090,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-3.0.0.tgz", "integrity": "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==", + "dev": true, "license": "MIT", "engines": { "node": ">=12" @@ -11192,16 +10111,24 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/strnum": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/strnum/-/strnum-2.1.2.tgz", - "integrity": "sha512-l63NF9y/cLROq/yqKXSLtcMeeyOfnSQlfMSlzFt/K73oIaD8DGaQWd7Z34X9GPiKqP5rbSh84Hl4bOlLcjiSrQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/NaturalIntelligence" - } - ], + "node_modules/strip-literal": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/strip-literal/-/strip-literal-3.1.0.tgz", + "integrity": "sha512-8r3mkIM/2+PpjHoOtiAW8Rg3jJLHaV7xPwG+YRGrv6FP0wwk/toTpATxWYOW0BKdWwl82VT2tFYi5DlROa0Mxg==", + "dev": true, + "license": "MIT", + "dependencies": { + "js-tokens": "^9.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/strip-literal/node_modules/js-tokens": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-9.0.1.tgz", + "integrity": "sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ==", + "dev": true, "license": "MIT" }, "node_modules/strtok3": { @@ -11296,15 +10223,6 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/sucrase/node_modules/minipass": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", - "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", - "license": "ISC", - "engines": { - "node": ">=16 || 14 >=14.17" - } - }, "node_modules/superjson": { "version": "2.2.2", "resolved": "https://registry.npmjs.org/superjson/-/superjson-2.2.2.tgz", @@ -11322,6 +10240,7 @@ "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, "license": "MIT", "dependencies": { "has-flag": "^4.0.0" @@ -11658,6 +10577,59 @@ "bintrees": "1.0.2" } }, + "node_modules/test-exclude": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-7.0.1.tgz", + "integrity": "sha512-pFYqmTw68LXVjeWJMST4+borgQP2AyMNbg1BpZh9LbyhUeNkeaPF9gzfPGUAnSMV3qPYdWUwDIjjCLiSDOl7vg==", + "dev": true, + "license": "ISC", + "dependencies": { + "@istanbuljs/schema": "^0.1.2", + "glob": "^10.4.1", + "minimatch": "^9.0.4" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/test-exclude/node_modules/glob": { + "version": "10.5.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.5.0.tgz", + "integrity": "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==", + "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", + "dev": true, + "license": "ISC", + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^1.11.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/test-exclude/node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/text-decoder": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/text-decoder/-/text-decoder-1.2.3.tgz", @@ -11729,18 +10701,21 @@ "version": "2.9.0", "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.9.0.tgz", "integrity": "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==", + "dev": true, "license": "MIT" }, "node_modules/tinyexec": { "version": "0.3.2", "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-0.3.2.tgz", "integrity": "sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==", + "dev": true, "license": "MIT" }, "node_modules/tinyglobby": { "version": "0.2.14", "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.14.tgz", "integrity": "sha512-tX5e7OM1HnYr2+a2C/4V0htOcSQcoSTH9KgJnVvNm5zm/cyEWKJ7j7YutsH9CxMdtOkkLFy2AHrMci9IM8IPZQ==", + "devOptional": true, "license": "MIT", "dependencies": { "fdir": "^6.4.4", @@ -11754,9 +10729,10 @@ } }, "node_modules/tinypool": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/tinypool/-/tinypool-1.1.0.tgz", - "integrity": "sha512-7CotroY9a8DKsKprEy/a14aCCm8jYVmR7aFy4fpkZM8sdpNJbKkixuNjgM50yCmip2ezc8z4N7k3oe2+rfRJCQ==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/tinypool/-/tinypool-1.1.1.tgz", + "integrity": "sha512-Zba82s87IFq9A9XmjiX5uZA/ARWDrB03OHlq+Vw1fSdt0I+4/Kutwy8BP4Y/y/aORMo61FQ0vIb5j44vSo5Pkg==", + "dev": true, "license": "MIT", "engines": { "node": "^18.0.0 || >=20.0.0" @@ -11766,15 +10742,17 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-2.0.0.tgz", "integrity": "sha512-op4nsTR47R6p0vMUUoYl/a+ljLFVtlfaXkLQmqfLR1qHma1h/ysYk4hEXZ880bf2CYgTskvTa/e196Vd5dDQXw==", + "dev": true, "license": "MIT", "engines": { "node": ">=14.0.0" } }, "node_modules/tinyspy": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/tinyspy/-/tinyspy-4.0.3.tgz", - "integrity": "sha512-t2T/WLB2WRgZ9EpE4jgPJ9w+i66UZfDc8wHh0xrwiRNN+UwH98GIJkTeZqX9rg0i0ptwzqW+uYeIF0T4F8LR7A==", + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/tinyspy/-/tinyspy-4.0.4.tgz", + "integrity": "sha512-azl+t0z7pw/z958Gy9svOTuzqIk6xq+NSheJzn5MMWtWTFywIacg2wUlzKFGtt3cthx0r2SxMK0yzJOR0IES7Q==", + "dev": true, "license": "MIT", "engines": { "node": ">=14.0.0" @@ -11822,6 +10800,7 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/totalist/-/totalist-3.0.1.tgz", "integrity": "sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==", + "devOptional": true, "license": "MIT", "engines": { "node": ">=6" @@ -12184,6 +11163,7 @@ "version": "6.3.5", "resolved": "https://registry.npmjs.org/vite/-/vite-6.3.5.tgz", "integrity": "sha512-cZn6NDFE7wdTpINgs++ZJ4N49W2vRp8LCKrn3Ob1kYNtOo21vfDoaV5GzBfLU4MovSAB8uNRm4jgzVQZ+mBzPQ==", + "devOptional": true, "license": "MIT", "peer": true, "dependencies": { @@ -12256,9 +11236,10 @@ } }, "node_modules/vite-node": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-3.2.2.tgz", - "integrity": "sha512-Xj/jovjZvDXOq2FgLXu8NsY4uHUMWtzVmMC2LkCu9HWdr9Qu1Is5sanX3Z4jOFKdohfaWDnEJWp9pRP0vVpAcA==", + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-3.2.4.tgz", + "integrity": "sha512-EbKSKh+bh1E1IFxeO0pg1n4dvoOTt0UDiXMd/qn++r98+jPO1xtJilvXldeuQ8giIB5IkpjCgMleHMNEsGH6pg==", + "dev": true, "license": "MIT", "dependencies": { "cac": "^6.7.14", @@ -12277,16 +11258,11 @@ "url": "https://opencollective.com/vitest" } }, - "node_modules/vite-node/node_modules/pathe": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", - "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", - "license": "MIT" - }, "node_modules/vite/node_modules/fsevents": { "version": "2.3.3", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, "hasInstallScript": true, "license": "MIT", "optional": true, @@ -12317,20 +11293,21 @@ } }, "node_modules/vitest": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/vitest/-/vitest-3.2.2.tgz", - "integrity": "sha512-fyNn/Rp016Bt5qvY0OQvIUCwW2vnaEBLxP42PmKbNIoasSYjML+8xyeADOPvBe+Xfl/ubIw4og7Lt9jflRsCNw==", + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-3.2.4.tgz", + "integrity": "sha512-LUCP5ev3GURDysTWiP47wRRUpLKMOfPh+yKTx3kVIEiu5KOMeqzpnYNsKyOoVrULivR8tLcks4+lga33Whn90A==", + "dev": true, "license": "MIT", "peer": true, "dependencies": { "@types/chai": "^5.2.2", - "@vitest/expect": "3.2.2", - "@vitest/mocker": "3.2.2", - "@vitest/pretty-format": "^3.2.2", - "@vitest/runner": "3.2.2", - "@vitest/snapshot": "3.2.2", - "@vitest/spy": "3.2.2", - "@vitest/utils": "3.2.2", + "@vitest/expect": "3.2.4", + "@vitest/mocker": "3.2.4", + "@vitest/pretty-format": "^3.2.4", + "@vitest/runner": "3.2.4", + "@vitest/snapshot": "3.2.4", + "@vitest/spy": "3.2.4", + "@vitest/utils": "3.2.4", "chai": "^5.2.0", "debug": "^4.4.1", "expect-type": "^1.2.1", @@ -12341,10 +11318,10 @@ "tinybench": "^2.9.0", "tinyexec": "^0.3.2", "tinyglobby": "^0.2.14", - "tinypool": "^1.1.0", + "tinypool": "^1.1.1", "tinyrainbow": "^2.0.0", "vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0", - "vite-node": "3.2.2", + "vite-node": "3.2.4", "why-is-node-running": "^2.3.0" }, "bin": { @@ -12360,8 +11337,8 @@ "@edge-runtime/vm": "*", "@types/debug": "^4.1.12", "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", - "@vitest/browser": "3.2.2", - "@vitest/ui": "3.2.2", + "@vitest/browser": "3.2.4", + "@vitest/ui": "3.2.4", "happy-dom": "*", "jsdom": "*" }, @@ -12393,6 +11370,7 @@ "version": "0.1.0", "resolved": "https://registry.npmjs.org/vitest-browser-svelte/-/vitest-browser-svelte-0.1.0.tgz", "integrity": "sha512-YB6ZUZZQNqU1T9NzvTEDpwpPv35Ng1NZMPBh81zDrLEdOgROGE6nJb79NWb1Eu/a8VkHifqArpOZfJfALge6xQ==", + "dev": true, "license": "MIT", "engines": { "node": "^18.0.0 || >=20.0.0" @@ -12406,12 +11384,6 @@ "vitest": "^2.1.0 || ^3.0.0-0" } }, - "node_modules/vitest/node_modules/pathe": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", - "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", - "license": "MIT" - }, "node_modules/w3c-xmlserializer": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-4.0.0.tgz", @@ -12502,6 +11474,7 @@ "version": "2.3.0", "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.3.0.tgz", "integrity": "sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==", + "dev": true, "license": "MIT", "dependencies": { "siginfo": "^2.0.0", @@ -12534,6 +11507,7 @@ "version": "9.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.0.tgz", "integrity": "sha512-G8ura3S+3Z2G+mkgNRq8dqaFZAuxfsxpBB8OCTGRTCtp+l/v9nbFNmCUP1BZMts3G1142MsZfn6eeUKrr4PD1Q==", + "dev": true, "license": "MIT", "dependencies": { "ansi-styles": "^6.2.1", @@ -12598,6 +11572,7 @@ "version": "6.1.0", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", + "dev": true, "license": "MIT", "engines": { "node": ">=12" @@ -12610,6 +11585,7 @@ "version": "6.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "dev": true, "license": "MIT", "engines": { "node": ">=12" @@ -12622,6 +11598,7 @@ "version": "7.1.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dev": true, "license": "MIT", "dependencies": { "ansi-regex": "^6.0.1" diff --git a/package.json b/package.json index ed440de8814..4ae9a518263 100644 --- a/package.json +++ b/package.json @@ -12,6 +12,7 @@ "lint": "prettier --check . && eslint .", "format": "prettier --write .", "test": "vitest", + "test:conversation-flow:coverage": "vitest run --project server src/lib/conversation/generation/prepareTurn.spec.ts src/lib/conversation/generation/mergeFinalAnswer.spec.ts src/lib/conversation/generation/mergeRouterMetadata.spec.ts src/lib/conversation/generation/processClientUpdate.spec.ts src/lib/conversation/generation/parity.spec.ts src/lib/server/__tests__/conversation-id-post.spec.ts --coverage.enabled --coverage.provider=v8 --coverage.include=\"src/lib/conversation/generation/**/*.ts\" --coverage.thresholds.lines=100 --coverage.thresholds.functions=100 --coverage.thresholds.branches=100 --coverage.thresholds.statements=100", "updateLocalEnv": "vite-node --options.transformMode.ssr='/.*/' scripts/updateLocalEnv.ts", "populate": "vite-node --options.transformMode.ssr='/.*/' scripts/populate.ts", "config": "vite-node --options.transformMode.ssr='/.*/' scripts/config.ts", @@ -23,12 +24,11 @@ "@iconify-json/eos-icons": "^1.1.6", "@iconify-json/lucide": "^1.2.77", "@sveltejs/adapter-node": "^5.2.12", - "@sveltejs/kit": "^2.21.1", + "@sveltejs/kit": "^2.50.2", "@sveltejs/vite-plugin-svelte": "^5.0.3", "@tailwindcss/typography": "^0.5.9", "@types/dompurify": "^3.0.5", "@types/js-yaml": "^4.0.9", - "@types/jsdom": "^21.1.1", "@types/katex": "^0.16.7", "@types/mime-types": "^2.1.4", "@types/minimist": "^1.2.5", @@ -38,13 +38,16 @@ "@types/yazl": "^3.3.0", "@typescript-eslint/eslint-plugin": "^6.x", "@typescript-eslint/parser": "^6.x", + "@vitest/coverage-v8": "^3.2.4", "bson-objectid": "^2.0.4", "dompurify": "^3.2.4", "eslint": "^8.28.0", "eslint-config-prettier": "^8.5.0", "eslint-plugin-svelte": "^2.45.1", + "husky": "^9.0.11", "isomorphic-dompurify": "2.13.0", - "js-yaml": "^4.1.0", + "js-yaml": "^4.1.1", + "lint-staged": "^15.2.7", "minimist": "^1.2.8", "mongodb-memory-server": "^10.1.2", "playwright": "^1.55.1", @@ -61,18 +64,17 @@ "vite": "^6.3.5", "vite-node": "^3.0.9", "vitest": "^3.1.4", + "vitest-browser-svelte": "^0.1.0", "yazl": "^3.3.1" }, "type": "module", "dependencies": { - "@aws-sdk/credential-providers": "^3.925.0", "@huggingface/hub": "^2.2.0", "@huggingface/inference": "^4.11.3", "@iconify-json/bi": "^1.1.21", - "@modelcontextprotocol/sdk": "^1.25.2", + "@modelcontextprotocol/sdk": "^1.26.0", "@resvg/resvg-js": "^2.6.2", "autoprefixer": "^10.4.14", - "aws4": "^1.13.2", "bits-ui": "^2.14.2", "date-fns": "^2.29.3", "dotenv": "^16.5.0", @@ -80,12 +82,10 @@ "handlebars": "^4.7.8", "highlight.js": "^11.7.0", "htmlparser2": "^10.0.0", - "husky": "^9.0.11", "ip-address": "^9.0.5", "jsdom": "^22.0.0", "json5": "^2.2.3", "katex": "^0.16.21", - "lint-staged": "^15.2.7", "marked": "^12.0.1", "mime-types": "^2.1.35", "mongodb": "^5.8.0", @@ -104,7 +104,6 @@ "tailwindcss": "^3.4.0", "undici": "^7.18.2", "uuid": "^10.0.0", - "vitest-browser-svelte": "^0.1.0", "zod": "^3.22.3" }, "overrides": { diff --git a/src/lib/conversation/generation/index.ts b/src/lib/conversation/generation/index.ts new file mode 100644 index 00000000000..410c494cb1c --- /dev/null +++ b/src/lib/conversation/generation/index.ts @@ -0,0 +1,17 @@ +export { prepareTurn, type PreparedTurn } from "./prepareTurn"; +export { + mergeFinalAnswer, + mergeFinalAnswerWithPrefix, + type MergeFinalAnswerInput, + type MergeFinalAnswerWithPrefixInput, +} from "./mergeFinalAnswer"; +export { + mergeRouterMetadata, + type RouterMetadata, + type RouterMetadataIncoming, +} from "./mergeRouterMetadata"; +export { + processClientUpdate, + type ProcessClientUpdateInput, + type ProcessClientUpdateResult, +} from "./processClientUpdate"; diff --git a/src/lib/conversation/generation/mergeFinalAnswer.spec.ts b/src/lib/conversation/generation/mergeFinalAnswer.spec.ts new file mode 100644 index 00000000000..8cd19710e50 --- /dev/null +++ b/src/lib/conversation/generation/mergeFinalAnswer.spec.ts @@ -0,0 +1,151 @@ +import { describe, expect, it } from "vitest"; +import { mergeFinalAnswer, mergeFinalAnswerWithPrefix } from "./mergeFinalAnswer"; + +describe("mergeFinalAnswer", () => { + it("uses final text when interrupted and no content was streamed", () => { + expect( + mergeFinalAnswer({ + currentContent: "", + finalText: "partial", + interrupted: true, + hadTools: false, + }) + ).toBe("partial"); + }); + + it("preserves streamed content when interrupted", () => { + expect( + mergeFinalAnswer({ + currentContent: "already streamed", + finalText: "provider final", + interrupted: true, + hadTools: false, + }) + ).toBe("already streamed"); + }); + + it("replaces content when tools were not used", () => { + expect( + mergeFinalAnswer({ + currentContent: "streamed", + finalText: "authoritative final", + hadTools: false, + }) + ).toBe("authoritative final"); + }); + + it("uses final text directly when tools were used but nothing was streamed", () => { + expect( + mergeFinalAnswer({ + currentContent: "", + finalText: "tool final", + hadTools: true, + }) + ).toBe("tool final"); + }); + + it("keeps existing content when tool run already streamed the final text", () => { + expect( + mergeFinalAnswer({ + currentContent: "hello world ", + finalText: "world", + hadTools: true, + }) + ).toBe("hello world "); + + expect( + mergeFinalAnswer({ + currentContent: "hello world", + finalText: "world", + hadTools: true, + }) + ).toBe("hello world"); + }); + + it("uses final text when it already includes the streamed prefix", () => { + expect( + mergeFinalAnswer({ + currentContent: "hello world ", + finalText: "hello world and more", + hadTools: true, + }) + ).toBe("hello world and more"); + + expect( + mergeFinalAnswer({ + currentContent: "hello", + finalText: "hello world", + hadTools: true, + }) + ).toBe("hello world"); + }); + + it("merges streamed and final text with a paragraph gap when needed", () => { + expect( + mergeFinalAnswer({ + currentContent: "draft", + finalText: "follow-up", + hadTools: true, + }) + ).toBe("draft\n\nfollow-up"); + + expect( + mergeFinalAnswer({ + currentContent: "draft\n\n", + finalText: "follow-up", + hadTools: true, + }) + ).toBe("draft\n\nfollow-up"); + + expect( + mergeFinalAnswer({ + currentContent: "draft", + finalText: "\nfollow-up", + hadTools: true, + }) + ).toBe("draft\nfollow-up"); + }); + + it("handles empty final text in tool mode", () => { + expect( + mergeFinalAnswer({ + currentContent: "draft", + finalText: "", + hadTools: true, + }) + ).toBe("draft\n\n"); + }); + + it("defaults undefined final text to empty string", () => { + expect( + mergeFinalAnswer({ + currentContent: "draft", + hadTools: false, + }) + ).toBe(""); + }); +}); + +describe("mergeFinalAnswerWithPrefix", () => { + it("merges only the generated suffix and keeps prefix untouched", () => { + expect( + mergeFinalAnswerWithPrefix({ + prefixContent: "[prefix]", + currentContent: "[prefix]draft", + finalText: "final", + hadTools: true, + }) + ).toBe("[prefix]draft\n\nfinal"); + }); + + it("falls back when current content does not start with prefix", () => { + expect( + mergeFinalAnswerWithPrefix({ + prefixContent: "[prefix]", + currentContent: "draft", + finalText: "final", + hadTools: false, + }) + ).toBe("[prefix]final"); + }); +}); diff --git a/src/lib/conversation/generation/mergeFinalAnswer.ts b/src/lib/conversation/generation/mergeFinalAnswer.ts new file mode 100644 index 00000000000..25e4379b53e --- /dev/null +++ b/src/lib/conversation/generation/mergeFinalAnswer.ts @@ -0,0 +1,81 @@ +export type MergeFinalAnswerInput = { + currentContent: string; + finalText?: string | null; + interrupted?: boolean; + hadTools: boolean; +}; + +export function mergeFinalAnswer({ + currentContent, + finalText, + interrupted = false, + hadTools, +}: MergeFinalAnswerInput): string { + const existing = currentContent; + const normalizedFinalText = finalText ?? ""; + + if (interrupted) { + if (existing) { + return existing; + } + + return normalizedFinalText; + } + + if (!hadTools) { + return normalizedFinalText; + } + + if (!existing) { + return normalizedFinalText; + } + + const trimmedExistingSuffix = existing.replace(/\s+$/, ""); + const trimmedFinalPrefix = normalizedFinalText.replace(/^\s+/, ""); + const alreadyStreamed = + normalizedFinalText.length > 0 && + (existing.endsWith(normalizedFinalText) || + (trimmedFinalPrefix.length > 0 && trimmedExistingSuffix.endsWith(trimmedFinalPrefix))); + + if (alreadyStreamed) { + return existing; + } + + const finalIncludesExisting = + normalizedFinalText.length > 0 && + (normalizedFinalText.startsWith(existing) || + (trimmedExistingSuffix.length > 0 && trimmedFinalPrefix.startsWith(trimmedExistingSuffix))); + + if (finalIncludesExisting) { + return normalizedFinalText; + } + + const needsGap = !/\n\n$/.test(existing) && !/^\n/.test(normalizedFinalText); + return `${existing}${needsGap ? "\n\n" : ""}${normalizedFinalText}`; +} + +export type MergeFinalAnswerWithPrefixInput = MergeFinalAnswerInput & { + prefixContent: string; +}; + +export function mergeFinalAnswerWithPrefix({ + prefixContent, + currentContent, + finalText, + interrupted, + hadTools, +}: MergeFinalAnswerWithPrefixInput): string { + const normalizedPrefix = prefixContent; + const relativeCurrent = currentContent.startsWith(normalizedPrefix) + ? currentContent.slice(normalizedPrefix.length) + : currentContent; + + const nextRelative = mergeFinalAnswer({ + currentContent: relativeCurrent, + finalText, + interrupted, + hadTools, + }); + + return `${normalizedPrefix}${nextRelative}`; +} diff --git a/src/lib/conversation/generation/mergeRouterMetadata.spec.ts b/src/lib/conversation/generation/mergeRouterMetadata.spec.ts new file mode 100644 index 00000000000..7a22ec9ca98 --- /dev/null +++ b/src/lib/conversation/generation/mergeRouterMetadata.spec.ts @@ -0,0 +1,60 @@ +import { describe, expect, it } from "vitest"; +import { mergeRouterMetadata } from "./mergeRouterMetadata"; + +describe("mergeRouterMetadata", () => { + it("applies route/model updates and keeps previous provider when omitted", () => { + const merged = mergeRouterMetadata( + { + route: "old-route", + model: "old-model", + provider: "hf-inference" as never, + }, + { route: "new-route", model: "new-model" } + ); + + expect(merged).toEqual({ + route: "new-route", + model: "new-model", + provider: "hf-inference", + }); + }); + + it("keeps existing route/model on provider-only updates", () => { + const merged = mergeRouterMetadata( + { route: "router-a", model: "model-a" }, + { route: "", model: "", provider: "cerebras" as never } + ); + + expect(merged).toEqual({ route: "router-a", model: "model-a", provider: "cerebras" }); + }); + + it("does not erase existing values when incoming fields are empty", () => { + const merged = mergeRouterMetadata( + { route: "router-a", model: "model-a", provider: "hf-inference" as never }, + { route: " ", model: "", provider: undefined } + ); + + expect(merged).toEqual({ + route: "router-a", + model: "model-a", + provider: "hf-inference", + }); + }); + + it("supports undefined incoming metadata and empty existing state", () => { + expect(mergeRouterMetadata(undefined, undefined)).toEqual({ route: "", model: "" }); + expect( + mergeRouterMetadata( + { route: "router-a", model: "model-a", provider: "hf-inference" as never }, + undefined + ) + ).toEqual({ + route: "router-a", + model: "model-a", + provider: "hf-inference", + }); + expect( + mergeRouterMetadata(undefined, { route: "", model: "", provider: "novita" as never }) + ).toEqual({ route: "", model: "", provider: "novita" }); + }); +}); diff --git a/src/lib/conversation/generation/mergeRouterMetadata.ts b/src/lib/conversation/generation/mergeRouterMetadata.ts new file mode 100644 index 00000000000..632dda4f8ee --- /dev/null +++ b/src/lib/conversation/generation/mergeRouterMetadata.ts @@ -0,0 +1,29 @@ +import type { Message } from "$lib/types/Message"; + +export type RouterMetadata = NonNullable; +export type RouterMetadataIncoming = Partial | undefined | null; + +function hasValue(value: string | undefined): value is string { + return Boolean(value && value.trim().length > 0); +} + +export function mergeRouterMetadata( + existing: Message["routerMetadata"], + incoming: RouterMetadataIncoming +): RouterMetadata { + const currentRoute = existing?.route ?? ""; + const currentModel = existing?.model ?? ""; + const currentProvider = existing?.provider; + + if (!incoming) { + return currentProvider + ? { route: currentRoute, model: currentModel, provider: currentProvider } + : { route: currentRoute, model: currentModel }; + } + + const route = hasValue(incoming.route) ? incoming.route : currentRoute; + const model = hasValue(incoming.model) ? incoming.model : currentModel; + const provider = incoming.provider ?? currentProvider; + + return provider ? { route, model, provider } : { route, model }; +} diff --git a/src/lib/conversation/generation/parity.spec.ts b/src/lib/conversation/generation/parity.spec.ts new file mode 100644 index 00000000000..a229e72ade0 --- /dev/null +++ b/src/lib/conversation/generation/parity.spec.ts @@ -0,0 +1,75 @@ +import { describe, expect, it } from "vitest"; +import { mergeFinalAnswer, mergeFinalAnswerWithPrefix } from "./mergeFinalAnswer"; +import { mergeRouterMetadata } from "./mergeRouterMetadata"; + +describe("conversation generation parity contracts", () => { + it("keeps client/server final-answer merge behavior aligned", () => { + const vectors = [ + { + prefix: "", + current: "draft", + finalText: "final", + interrupted: false, + hadTools: false, + }, + { + prefix: "preface\n", + current: "draft", + finalText: "final", + interrupted: false, + hadTools: true, + }, + { + prefix: "preface\n", + current: "already streamed", + finalText: "already streamed", + interrupted: false, + hadTools: true, + }, + { + prefix: "preface\n", + current: "partial", + finalText: "provider", + interrupted: true, + hadTools: false, + }, + ]; + + for (const vector of vectors) { + const serverResult = mergeFinalAnswerWithPrefix({ + prefixContent: vector.prefix, + currentContent: `${vector.prefix}${vector.current}`, + finalText: vector.finalText, + interrupted: vector.interrupted, + hadTools: vector.hadTools, + }); + + const clientResult = `${vector.prefix}${mergeFinalAnswer({ + currentContent: vector.current, + finalText: vector.finalText, + interrupted: vector.interrupted, + hadTools: vector.hadTools, + })}`; + + expect(serverResult).toBe(clientResult); + } + }); + + it("keeps router metadata merge behavior aligned across sequential updates", () => { + const updates = [ + { route: "router-a", model: "model-a" }, + { route: "", model: "", provider: "hf-inference" as never }, + { route: "router-b", model: "model-b" }, + { route: "", model: "", provider: "cerebras" as never }, + ]; + + let serverMetadata = undefined; + let clientMetadata = undefined; + + for (const update of updates) { + serverMetadata = mergeRouterMetadata(serverMetadata, update); + clientMetadata = mergeRouterMetadata(clientMetadata, update); + expect(serverMetadata).toEqual(clientMetadata); + } + }); +}); diff --git a/src/lib/conversation/generation/prepareTurn.spec.ts b/src/lib/conversation/generation/prepareTurn.spec.ts new file mode 100644 index 00000000000..c1094e222e2 --- /dev/null +++ b/src/lib/conversation/generation/prepareTurn.spec.ts @@ -0,0 +1,257 @@ +import { describe, expect, it } from "vitest"; +import type { Message } from "$lib/types/Message"; +import { prepareTurn } from "./prepareTurn"; + +function createUserMessage(params: { prompt: string; files?: Message["files"] }) { + return { + from: "user" as const, + content: params.prompt, + files: params.files, + }; +} + +function createAssistantMessage() { + return { + from: "assistant" as const, + content: "", + }; +} + +describe("prepareTurn", () => { + it("creates a normal user+assistant turn", () => { + const tree = { + messages: [] as Message[], + rootMessageId: undefined as Message["id"] | undefined, + }; + + const preparedTurn = prepareTurn({ + tree, + prompt: "Hello", + createUserMessage, + createAssistantMessage, + }); + + expect(tree.messages).toHaveLength(2); + expect(tree.rootMessageId).toBe(preparedTurn.promptAnchorId); + expect(tree.messages[0].from).toBe("user"); + expect(tree.messages[0].content).toBe("Hello"); + expect(tree.messages[1].from).toBe("assistant"); + expect(tree.messages[1].ancestors).toEqual([preparedTurn.promptAnchorId]); + expect(preparedTurn.excludeAnchorFromPrompt).toBe(false); + }); + + it("defaults to an empty prompt for normal sends", () => { + const tree = { + messages: [] as Message[], + rootMessageId: undefined as Message["id"] | undefined, + }; + + prepareTurn({ + tree, + createUserMessage, + createAssistantMessage, + }); + + expect(tree.messages[0].content).toBe(""); + }); + + it("creates an edited user retry branch and a new assistant child", () => { + const tree = { + rootMessageId: "root", + messages: [ + { + id: "root", + from: "system", + content: "sys", + ancestors: [], + children: ["user-1"], + }, + { + id: "user-1", + from: "user", + content: "old", + files: [{ type: "hash", name: "old.txt", value: "sha-old", mime: "text/plain" }], + ancestors: ["root"], + children: ["assistant-1"], + }, + { + id: "assistant-1", + from: "assistant", + content: "old answer", + ancestors: ["root", "user-1"], + children: [], + }, + ] satisfies Message[], + }; + + const preparedTurn = prepareTurn({ + tree, + isRetry: true, + messageId: "user-1", + prompt: "edited", + files: [{ type: "hash", name: "new.txt", value: "sha-new", mime: "text/plain" }], + createUserMessage, + createAssistantMessage, + }); + + const newUserMessage = tree.messages.find( + (message) => message.id === preparedTurn.promptAnchorId + ); + const newAssistantMessage = tree.messages.find( + (message) => message.id === preparedTurn.assistantMessageId + ); + + expect(preparedTurn.excludeAnchorFromPrompt).toBe(false); + expect(newUserMessage?.from).toBe("user"); + expect(newUserMessage?.content).toBe("edited"); + expect(newUserMessage?.files?.[0]?.name).toBe("new.txt"); + expect(newUserMessage?.ancestors).toEqual(["root"]); + expect(newAssistantMessage?.from).toBe("assistant"); + expect(newAssistantMessage?.ancestors).toEqual(["root", preparedTurn.promptAnchorId]); + }); + + it("creates a sibling assistant for assistant retry and excludes anchor from prompt", () => { + const tree = { + rootMessageId: "root", + messages: [ + { id: "root", from: "system", content: "sys", ancestors: [], children: ["user-1"] }, + { + id: "user-1", + from: "user", + content: "question", + ancestors: ["root"], + children: ["assistant-1"], + }, + { + id: "assistant-1", + from: "assistant", + content: "answer", + ancestors: ["root", "user-1"], + children: [], + }, + ] satisfies Message[], + }; + + const preparedTurn = prepareTurn({ + tree, + isRetry: true, + messageId: "assistant-1", + createUserMessage, + createAssistantMessage, + }); + + const newAssistant = tree.messages.find( + (message) => message.id === preparedTurn.assistantMessageId + ); + + expect(preparedTurn.promptAnchorId).toBe("assistant-1"); + expect(preparedTurn.excludeAnchorFromPrompt).toBe(true); + expect(newAssistant?.from).toBe("assistant"); + expect(newAssistant?.ancestors).toEqual(["root", "user-1"]); + }); + + it("throws when retry target does not exist", () => { + const tree = { + rootMessageId: "root", + messages: [ + { id: "root", from: "system", content: "sys", ancestors: [], children: [] }, + ] satisfies Message[], + }; + + expect(() => + prepareTurn({ + tree, + isRetry: true, + messageId: "missing", + prompt: "retry", + createUserMessage, + createAssistantMessage, + }) + ).toThrowError("Message not found"); + }); + + it("throws when retrying a user message without a replacement prompt", () => { + const tree = { + rootMessageId: "root", + messages: [ + { id: "root", from: "system", content: "sys", ancestors: [], children: ["user-1"] }, + { + id: "user-1", + from: "user", + content: "old", + ancestors: ["root"], + children: [], + }, + ] satisfies Message[], + }; + + expect(() => + prepareTurn({ + tree, + isRetry: true, + messageId: "user-1", + createUserMessage, + createAssistantMessage, + }) + ).toThrowError("Retrying a user message requires a new prompt"); + }); + + it("throws for retry on legacy conversation and root message", () => { + const legacyTree = { + messages: [{ id: "user-1", from: "user", content: "legacy" }] satisfies Message[], + rootMessageId: undefined as Message["id"] | undefined, + }; + + expect(() => + prepareTurn({ + tree: legacyTree, + isRetry: true, + messageId: "user-1", + prompt: "edited", + createUserMessage, + createAssistantMessage, + }) + ).toThrowError("Cannot add a sibling to a legacy conversation"); + + const rootedTree = { + rootMessageId: "root", + messages: [ + { id: "root", from: "user", content: "root", ancestors: [], children: [] }, + ] satisfies Message[], + }; + + expect(() => + prepareTurn({ + tree: rootedTree, + isRetry: true, + messageId: "root", + prompt: "edited", + createUserMessage, + createAssistantMessage, + }) + ).toThrowError("The sibling message is the root message"); + }); + + it("falls back to normal turn creation when retry target is not user/assistant", () => { + const tree = { + rootMessageId: "root", + messages: [ + { id: "root", from: "system", content: "sys", ancestors: [], children: [] }, + ] satisfies Message[], + }; + + const preparedTurn = prepareTurn({ + tree, + isRetry: true, + messageId: "root", + prompt: "new user turn", + createUserMessage, + createAssistantMessage, + }); + + expect(tree.messages).toHaveLength(3); + expect(preparedTurn.excludeAnchorFromPrompt).toBe(false); + expect(tree.messages.at(-2)?.from).toBe("user"); + expect(tree.messages.at(-1)?.from).toBe("assistant"); + }); +}); diff --git a/src/lib/conversation/generation/prepareTurn.ts b/src/lib/conversation/generation/prepareTurn.ts new file mode 100644 index 00000000000..9581b5a5c0f --- /dev/null +++ b/src/lib/conversation/generation/prepareTurn.ts @@ -0,0 +1,95 @@ +import { addChildren } from "$lib/utils/tree/addChildren"; +import { addSibling } from "$lib/utils/tree/addSibling"; +import type { Tree, TreeId } from "$lib/utils/tree/tree"; +import type { Message } from "$lib/types/Message"; + +export type PreparedTurn = { + assistantMessageId: Message["id"]; + promptAnchorId: Message["id"]; + excludeAnchorFromPrompt: boolean; +}; + +type NewConversationMessage = Omit; + +type PrepareTurnInput = { + tree: Tree; + messageId?: TreeId; + prompt?: string; + isRetry?: boolean; + files?: Message["files"]; + createUserMessage: (params: { + prompt: string; + files?: Message["files"]; + retryTarget?: Message; + }) => NewConversationMessage; + createAssistantMessage: (params?: { retryTarget?: Message }) => NewConversationMessage; +}; + +export function prepareTurn({ + tree, + messageId, + prompt, + isRetry = false, + files, + createUserMessage, + createAssistantMessage, +}: PrepareTurnInput): PreparedTurn { + if (isRetry && messageId) { + const messageToRetry = tree.messages.find((message) => message.id === messageId); + if (!messageToRetry) { + throw new Error("Message not found"); + } + + if (messageToRetry.from === "user") { + if (!prompt) { + throw new Error("Retrying a user message requires a new prompt"); + } + + const newUserMessageId = addSibling( + tree, + createUserMessage({ prompt, files, retryTarget: messageToRetry }), + messageId + ); + + const assistantMessageId = addChildren( + tree, + createAssistantMessage({ retryTarget: messageToRetry }), + newUserMessageId + ); + + return { + assistantMessageId, + promptAnchorId: newUserMessageId, + excludeAnchorFromPrompt: false, + }; + } + + if (messageToRetry.from === "assistant") { + const assistantMessageId = addSibling( + tree, + createAssistantMessage({ retryTarget: messageToRetry }), + messageId + ); + + return { + assistantMessageId, + promptAnchorId: messageId, + excludeAnchorFromPrompt: true, + }; + } + } + + const newUserMessageId = addChildren( + tree, + createUserMessage({ prompt: prompt ?? "", files }), + messageId + ); + + const assistantMessageId = addChildren(tree, createAssistantMessage(), newUserMessageId); + + return { + assistantMessageId, + promptAnchorId: newUserMessageId, + excludeAnchorFromPrompt: false, + }; +} diff --git a/src/lib/conversation/generation/processClientUpdate.spec.ts b/src/lib/conversation/generation/processClientUpdate.spec.ts new file mode 100644 index 00000000000..e57e2a18496 --- /dev/null +++ b/src/lib/conversation/generation/processClientUpdate.spec.ts @@ -0,0 +1,318 @@ +import { describe, expect, it } from "vitest"; +import type { Message } from "$lib/types/Message"; +import { + MessageToolUpdateType, + MessageUpdateStatus, + MessageUpdateType, +} from "$lib/types/MessageUpdate"; +import { mergeFinalAnswer } from "./mergeFinalAnswer"; +import { processClientUpdate } from "./processClientUpdate"; + +function createMessage(overrides?: Partial): Message { + return { + id: "assistant-1", + from: "assistant", + content: "", + updates: [], + ...overrides, + }; +} + +describe("processClientUpdate", () => { + it("buffers stream updates and flushes them on non-stream updates", () => { + const initial = createMessage(); + + const firstStream = processClientUpdate({ + message: initial, + update: { type: MessageUpdateType.Stream, token: "Hel\0" }, + disableStream: false, + buffer: "", + lastUpdateTime: new Date("2026-01-01T00:00:00.000Z"), + maxUpdateTimeMs: 100, + now: new Date("2026-01-01T00:00:00.010Z"), + }); + + expect(firstStream.message.updates?.at(-1)).toEqual({ + type: MessageUpdateType.Stream, + token: "Hel", + }); + expect(firstStream.buffer).toBe("Hel"); + expect(firstStream.message.content).toBe(""); + expect(firstStream.effects.setPendingFalse).toBe(true); + + const secondStream = processClientUpdate({ + message: firstStream.message, + update: { type: MessageUpdateType.Stream, token: "lo" }, + disableStream: false, + buffer: firstStream.buffer, + lastUpdateTime: firstStream.lastUpdateTime, + maxUpdateTimeMs: 100, + now: new Date("2026-01-01T00:00:00.020Z"), + }); + + expect(secondStream.message.updates).toHaveLength(1); + expect(secondStream.message.updates?.[0]).toEqual({ + type: MessageUpdateType.Stream, + token: "Hello", + }); + expect(secondStream.buffer).toBe("Hello"); + + const flushWithTool = processClientUpdate({ + message: secondStream.message, + update: { + type: MessageUpdateType.Tool, + subtype: MessageToolUpdateType.Call, + uuid: "tool-1", + call: { name: "search", parameters: { q: "hello" } }, + }, + disableStream: false, + buffer: secondStream.buffer, + lastUpdateTime: secondStream.lastUpdateTime, + maxUpdateTimeMs: 100, + now: new Date("2026-01-01T00:00:00.030Z"), + }); + + expect(flushWithTool.message.content).toBe("Hello"); + expect(flushWithTool.buffer).toBe(""); + expect(flushWithTool.message.updates).toHaveLength(2); + expect(flushWithTool.lastUpdateTime.toISOString()).toBe("2026-01-01T00:00:00.030Z"); + }); + + it("flushes buffered content when debounce threshold is exceeded", () => { + const result = processClientUpdate({ + message: createMessage(), + update: { type: MessageUpdateType.Stream, token: "chunk" }, + disableStream: false, + buffer: "", + lastUpdateTime: new Date("2026-01-01T00:00:00.000Z"), + maxUpdateTimeMs: 5, + now: new Date("2026-01-01T00:00:00.010Z"), + }); + + expect(result.buffer).toBe(""); + expect(result.message.content).toBe("chunk"); + }); + + it("keeps streamed updates buffered when stream display is disabled", () => { + const result = processClientUpdate({ + message: createMessage(), + update: { type: MessageUpdateType.Stream, token: "hidden" }, + disableStream: true, + buffer: "", + lastUpdateTime: new Date("2026-01-01T00:00:00.000Z"), + maxUpdateTimeMs: 100, + }); + + expect(result.message.content).toBe(""); + expect(result.buffer).toBe(""); + expect(result.effects.setPendingFalse).toBe(false); + expect(result.message.updates).toHaveLength(1); + }); + + it("applies final answer merging with tool awareness", () => { + const message = createMessage({ + content: "Draft", + updates: [ + { + type: MessageUpdateType.Tool, + subtype: MessageToolUpdateType.Call, + uuid: "tool-1", + call: { name: "tool", parameters: {} }, + }, + ], + }); + + const result = processClientUpdate({ + message, + update: { type: MessageUpdateType.FinalAnswer, text: "Final", interrupted: false }, + disableStream: false, + buffer: "", + lastUpdateTime: new Date("2026-01-01T00:00:00.000Z"), + maxUpdateTimeMs: 100, + }); + + expect(result.message.content).toBe( + mergeFinalAnswer({ + currentContent: "Draft", + finalText: "Final", + interrupted: false, + hadTools: true, + }) + ); + }); + + it("replaces streamed content with final answer when no tools were used", () => { + const result = processClientUpdate({ + message: createMessage({ content: "Draft", updates: [] }), + update: { type: MessageUpdateType.FinalAnswer, text: "Final", interrupted: false }, + disableStream: false, + buffer: "", + lastUpdateTime: new Date(), + maxUpdateTimeMs: 100, + }); + + expect(result.message.content).toBe("Final"); + }); + + it("handles status errors including subscription-required status", () => { + const subscriptionError = processClientUpdate({ + message: createMessage(), + update: { + type: MessageUpdateType.Status, + status: MessageUpdateStatus.Error, + message: "Payment required", + statusCode: 402, + }, + disableStream: false, + buffer: "", + lastUpdateTime: new Date(), + maxUpdateTimeMs: 100, + }); + + expect(subscriptionError.effects.showSubscribeModal).toBe(true); + expect(subscriptionError.effects.errorMessage).toBeUndefined(); + + const genericError = processClientUpdate({ + message: createMessage(), + update: { + type: MessageUpdateType.Status, + status: MessageUpdateStatus.Error, + message: "Something went wrong", + }, + disableStream: false, + buffer: "", + lastUpdateTime: new Date(), + maxUpdateTimeMs: 100, + }); + + expect(genericError.effects.showSubscribeModal).toBe(false); + expect(genericError.effects.errorMessage).toBe("Something went wrong"); + + const defaultMessageError = processClientUpdate({ + message: createMessage(), + update: { + type: MessageUpdateType.Status, + status: MessageUpdateStatus.Error, + }, + disableStream: false, + buffer: "", + lastUpdateTime: new Date(), + maxUpdateTimeMs: 100, + }); + + expect(defaultMessageError.effects.errorMessage).toBe("An error has occurred"); + }); + + it("emits title effects and merges file/router updates", () => { + const withTitle = processClientUpdate({ + message: createMessage(), + update: { type: MessageUpdateType.Title, title: "New title" }, + disableStream: false, + buffer: "", + lastUpdateTime: new Date(), + maxUpdateTimeMs: 100, + }); + expect(withTitle.effects.title).toBe("New title"); + + const withFile = processClientUpdate({ + message: withTitle.message, + update: { + type: MessageUpdateType.File, + name: "image.png", + sha: "sha256", + mime: "image/png", + }, + disableStream: false, + buffer: withTitle.buffer, + lastUpdateTime: withTitle.lastUpdateTime, + maxUpdateTimeMs: 100, + }); + expect(withFile.message.files).toEqual([ + { type: "hash", value: "sha256", mime: "image/png", name: "image.png" }, + ]); + + const withRouterMetadata = processClientUpdate({ + message: { + ...withFile.message, + routerMetadata: { route: "route-a", model: "model-a" }, + }, + update: { + type: MessageUpdateType.RouterMetadata, + route: "", + model: "", + provider: "hf-inference" as never, + }, + disableStream: false, + buffer: withFile.buffer, + lastUpdateTime: withFile.lastUpdateTime, + maxUpdateTimeMs: 100, + }); + + expect(withRouterMetadata.message.routerMetadata).toEqual({ + route: "route-a", + model: "model-a", + provider: "hf-inference", + }); + }); + + it("ignores keepalive updates while still flushing buffered content", () => { + const result = processClientUpdate({ + message: createMessage(), + update: { + type: MessageUpdateType.Status, + status: MessageUpdateStatus.KeepAlive, + }, + disableStream: false, + buffer: "buffered", + lastUpdateTime: new Date("2026-01-01T00:00:00.000Z"), + maxUpdateTimeMs: 100, + now: new Date("2026-01-01T00:00:01.000Z"), + }); + + expect(result.message.updates).toEqual([]); + expect(result.message.content).toBe("buffered"); + expect(result.buffer).toBe(""); + }); + + it("stores non-error status updates without extra effects", () => { + const result = processClientUpdate({ + message: createMessage(), + update: { + type: MessageUpdateType.Status, + status: MessageUpdateStatus.Finished, + }, + disableStream: false, + buffer: "", + lastUpdateTime: new Date(), + maxUpdateTimeMs: 100, + }); + + expect(result.message.updates).toContainEqual({ + type: MessageUpdateType.Status, + status: MessageUpdateStatus.Finished, + }); + expect(result.effects.errorMessage).toBeUndefined(); + expect(result.effects.showSubscribeModal).toBe(false); + }); + + it("handles messages with undefined updates", () => { + const result = processClientUpdate({ + message: createMessage({ updates: undefined }), + update: { + type: MessageUpdateType.Status, + status: MessageUpdateStatus.Finished, + }, + disableStream: false, + buffer: "", + lastUpdateTime: new Date(), + maxUpdateTimeMs: 100, + }); + + expect(result.message.updates).toEqual([ + { + type: MessageUpdateType.Status, + status: MessageUpdateStatus.Finished, + }, + ]); + }); +}); diff --git a/src/lib/conversation/generation/processClientUpdate.ts b/src/lib/conversation/generation/processClientUpdate.ts new file mode 100644 index 00000000000..8d523cbee01 --- /dev/null +++ b/src/lib/conversation/generation/processClientUpdate.ts @@ -0,0 +1,155 @@ +import type { Message } from "$lib/types/Message"; +import { + MessageUpdateStatus, + MessageUpdateType, + type MessageUpdate, +} from "$lib/types/MessageUpdate"; +import { mergeFinalAnswer } from "./mergeFinalAnswer"; +import { mergeRouterMetadata } from "./mergeRouterMetadata"; + +export type ProcessClientUpdateInput = { + message: Message; + update: MessageUpdate; + disableStream: boolean; + buffer: string; + lastUpdateTime: Date; + maxUpdateTimeMs: number; + now?: Date; +}; + +export type ProcessClientUpdateResult = { + message: Message; + buffer: string; + lastUpdateTime: Date; + effects: { + setPendingFalse: boolean; + errorMessage?: string; + showSubscribeModal: boolean; + title?: string; + }; +}; + +function sanitizeUpdate(update: MessageUpdate): MessageUpdate { + if (update.type !== MessageUpdateType.Stream) { + return update; + } + + return { + ...update, + token: update.token.replaceAll("\0", ""), + }; +} + +export function processClientUpdate({ + message, + update, + disableStream, + buffer, + lastUpdateTime, + maxUpdateTimeMs, + now = new Date(), +}: ProcessClientUpdateInput): ProcessClientUpdateResult { + const normalizedUpdate = sanitizeUpdate(update); + let nextUpdates = [...(message.updates ?? [])]; + const nextMessage: Message = { + ...message, + content: message.content, + updates: nextUpdates, + files: message.files ? [...message.files] : undefined, + }; + + let nextBuffer = buffer; + let nextLastUpdateTime = lastUpdateTime; + + const effects: ProcessClientUpdateResult["effects"] = { + setPendingFalse: false, + showSubscribeModal: false, + }; + + const isKeepAlive = + normalizedUpdate.type === MessageUpdateType.Status && + normalizedUpdate.status === MessageUpdateStatus.KeepAlive; + + if (!isKeepAlive) { + if (normalizedUpdate.type === MessageUpdateType.Stream) { + const lastUpdate = nextUpdates.at(-1); + + if (lastUpdate?.type === MessageUpdateType.Stream) { + const mergedStreamUpdate = { + ...lastUpdate, + token: lastUpdate.token + normalizedUpdate.token, + }; + + nextUpdates = [...nextUpdates.slice(0, -1), mergedStreamUpdate]; + } else { + nextUpdates = [...nextUpdates, normalizedUpdate]; + } + } else { + nextUpdates = [...nextUpdates, normalizedUpdate]; + } + nextMessage.updates = nextUpdates; + } + + if ( + normalizedUpdate.type !== MessageUpdateType.Stream && + !disableStream && + nextBuffer.length > 0 + ) { + nextMessage.content += nextBuffer; + nextBuffer = ""; + nextLastUpdateTime = now; + } + + if (normalizedUpdate.type === MessageUpdateType.Stream && !disableStream) { + nextBuffer += normalizedUpdate.token; + + if (now.getTime() - nextLastUpdateTime.getTime() > maxUpdateTimeMs) { + nextMessage.content += nextBuffer; + nextBuffer = ""; + nextLastUpdateTime = now; + } + + effects.setPendingFalse = true; + } else if (normalizedUpdate.type === MessageUpdateType.FinalAnswer) { + const hadTools = nextUpdates.some( + (messageUpdate) => messageUpdate.type === MessageUpdateType.Tool + ); + + nextMessage.content = mergeFinalAnswer({ + currentContent: nextMessage.content, + finalText: normalizedUpdate.text, + interrupted: normalizedUpdate.interrupted, + hadTools, + }); + } else if ( + normalizedUpdate.type === MessageUpdateType.Status && + normalizedUpdate.status === MessageUpdateStatus.Error + ) { + if (normalizedUpdate.statusCode === 402) { + effects.showSubscribeModal = true; + } else { + effects.errorMessage = normalizedUpdate.message ?? "An error has occurred"; + } + } else if (normalizedUpdate.type === MessageUpdateType.Title) { + effects.title = normalizedUpdate.title; + } else if (normalizedUpdate.type === MessageUpdateType.File) { + nextMessage.files = [ + ...(nextMessage.files ?? []), + { + type: "hash", + value: normalizedUpdate.sha, + mime: normalizedUpdate.mime, + name: normalizedUpdate.name, + }, + ]; + } else if (normalizedUpdate.type === MessageUpdateType.RouterMetadata) { + nextMessage.routerMetadata = mergeRouterMetadata(nextMessage.routerMetadata, normalizedUpdate); + } + + return { + message: nextMessage, + buffer: nextBuffer, + lastUpdateTime: nextLastUpdateTime, + effects, + }; +} diff --git a/src/lib/server/__tests__/conversation-id-post.spec.ts b/src/lib/server/__tests__/conversation-id-post.spec.ts new file mode 100644 index 00000000000..416e5f52bfb --- /dev/null +++ b/src/lib/server/__tests__/conversation-id-post.spec.ts @@ -0,0 +1,349 @@ +import { afterEach, describe, expect, it, vi } from "vitest"; +import { ObjectId } from "mongodb"; +import { v4 } from "uuid"; +import type { Message } from "$lib/types/Message"; +import { + MessageToolUpdateType, + MessageUpdateStatus, + MessageUpdateType, + type MessageUpdate, +} from "$lib/types/MessageUpdate"; +import { collections } from "$lib/server/database"; +import { + cleanupTestData, + createTestConversation, + createTestLocals, + createTestUser, +} from "$lib/server/api/__tests__/testHelpers"; + +const { generationScenarios, observedGenerationMessages, abortScenarioStep, mockGetEndpoint } = + vi.hoisted(() => ({ + generationScenarios: [] as Array>, + observedGenerationMessages: [] as Message[][], + abortScenarioStep: Symbol("abort"), + mockGetEndpoint: vi.fn(async () => ({ type: "mock-endpoint" })), + })); + +vi.mock("$lib/server/models", async () => { + const { z } = await import("zod"); + + return { + models: [ + { + id: "test-model", + name: "Test Model", + isRouter: true, + getEndpoint: mockGetEndpoint, + }, + ], + validModelIdSchema: z.string(), + }; +}); + +vi.mock("$lib/server/textGeneration", () => ({ + async *textGeneration ({ messages }: { messages: Message[] }) { + observedGenerationMessages.push(messages.map((message) => ({ ...message }))); + const scenario = generationScenarios.shift() ?? []; + for (const step of scenario) { + if (step === abortScenarioStep) { + const abortError = new Error("Request was aborted."); + abortError.name = "AbortError"; + throw abortError; + } + yield step as MessageUpdate; + } + }, +})); + +vi.mock("$lib/server/metrics", () => ({ + MetricsServer: { + isEnabled: () => false, + getMetrics: () => undefined, + }, +})); + +import { POST } from "../../../routes/conversation/[id]/+server"; + +function buildRequest(payload: Record): Request { + const form = new FormData(); + form.append("data", JSON.stringify(payload)); + + return new Request("http://localhost/conversation", { + method: "POST", + body: form, + }); +} + +async function parseJsonlResponse(response: Response): Promise { + const reader = response.body?.getReader(); + if (!reader) return []; + + const decoder = new TextDecoder(); + let text = ""; + let done = false; + while (!done) { + const { done: streamDone, value } = await reader.read(); + if (streamDone) { + done = true; + continue; + } + if (typeof value === "string") { + text += value; + } else if (value instanceof Uint8Array) { + text += decoder.decode(value, { stream: true }); + } + } + + text += decoder.decode(); + + return text + .split("\n") + .map((line) => line.trim()) + .filter((line) => line.startsWith("{")) + .map((line) => JSON.parse(line) as MessageUpdate); +} + +async function invokePost(params: { + conversationId: string; + locals: App.Locals; + payload: Record; +}) { + return POST({ + request: buildRequest(params.payload), + locals: params.locals, + params: { id: params.conversationId }, + getClientAddress: () => "127.0.0.1", + } as never); +} + +describe.sequential("POST /conversation/[id]", () => { + afterEach(async () => { + generationScenarios.length = 0; + observedGenerationMessages.length = 0; + vi.clearAllMocks(); + await cleanupTestData(); + await collections.messageEvents.deleteMany({}); + }); + + it("throws 401 for unauthenticated requests", async () => { + const locals = createTestLocals({ user: undefined, sessionId: undefined }); + + try { + await invokePost({ + conversationId: new ObjectId().toString(), + locals, + payload: { inputs: "hello" }, + }); + expect.fail("Expected 401 error"); + } catch (error) { + expect((error as { status: number }).status).toBe(401); + } + }); + + it("throws 404 when the conversation does not exist", async () => { + const { locals } = await createTestUser(); + + try { + await invokePost({ + conversationId: new ObjectId().toString(), + locals, + payload: { inputs: "hello" }, + }); + expect.fail("Expected 404 error"); + } catch (error) { + expect((error as { status: number }).status).toBe(404); + } + }); + + it("creates user and assistant turns on normal send and streams updates", async () => { + const { locals } = await createTestUser(); + const conversation = await createTestConversation(locals, { messages: [] }); + + generationScenarios.push([ + { type: MessageUpdateType.Stream, token: "Hello " }, + { type: MessageUpdateType.Stream, token: "world" }, + { type: MessageUpdateType.FinalAnswer, text: "Hello world", interrupted: false }, + { type: MessageUpdateType.Status, status: MessageUpdateStatus.Finished }, + ]); + + const response = await invokePost({ + conversationId: conversation._id.toString(), + locals, + payload: { inputs: "Say hello" }, + }); + + expect(response.status).toBe(200); + expect(response.headers.get("Content-Type")).toBe("application/jsonl"); + const updates = await parseJsonlResponse(response); + expect(updates.some((update) => update.type === MessageUpdateType.Stream)).toBe(true); + expect( + updates.some( + (update) => + update.type === MessageUpdateType.FinalAnswer && + update.text === "Hello world" && + update.interrupted === false + ) + ).toBe(true); + + const updatedConversation = await collections.conversations.findOne({ _id: conversation._id }); + expect(updatedConversation?.messages).toHaveLength(2); + expect(updatedConversation?.messages[0]).toMatchObject({ from: "user", content: "Say hello" }); + expect(updatedConversation?.messages[1]).toMatchObject({ + from: "assistant", + content: "Hello world", + }); + expect(observedGenerationMessages[0].map((message) => message.from)).toEqual(["user"]); + expect(observedGenerationMessages[0][0].content).toBe("Say hello"); + expect(mockGetEndpoint).toHaveBeenCalled(); + }); + + it("uses retry-assistant subtree without including the retried assistant in prompt", async () => { + const { locals } = await createTestUser(); + const rootId = v4(); + const userId = v4(); + const assistantId = v4(); + + const conversation = await createTestConversation(locals, { + rootMessageId: rootId, + messages: [ + { + id: rootId, + from: "system", + content: "sys", + ancestors: [], + children: [userId], + }, + { + id: userId, + from: "user", + content: "question", + ancestors: [rootId], + children: [assistantId], + }, + { + id: assistantId, + from: "assistant", + content: "old answer", + ancestors: [rootId, userId], + children: [], + }, + ], + }); + + generationScenarios.push([ + { type: MessageUpdateType.FinalAnswer, text: "new answer", interrupted: false }, + { type: MessageUpdateType.Status, status: MessageUpdateStatus.Finished }, + ]); + + const response = await invokePost({ + conversationId: conversation._id.toString(), + locals, + payload: { id: assistantId, is_retry: true }, + }); + await parseJsonlResponse(response); + + expect(observedGenerationMessages[0].map((message) => message.id)).toEqual([rootId, userId]); + + const updatedConversation = await collections.conversations.findOne({ _id: conversation._id }); + const assistants = (updatedConversation?.messages ?? []).filter( + (message) => message.from === "assistant" + ); + expect(assistants).toHaveLength(2); + const newAssistant = assistants.find((message) => message.id !== assistantId); + expect(newAssistant?.content).toBe("new answer"); + expect(newAssistant?.ancestors).toEqual([rootId, userId]); + }); + + it("merges final answers with streamed pre-tool content", async () => { + const { locals } = await createTestUser(); + const conversation = await createTestConversation(locals, { messages: [] }); + + generationScenarios.push([ + { type: MessageUpdateType.Stream, token: "Draft story." }, + { + type: MessageUpdateType.Tool, + subtype: MessageToolUpdateType.Call, + uuid: "tool-1", + call: { name: "image", parameters: { prompt: "cat" } }, + }, + { type: MessageUpdateType.FinalAnswer, text: "Image caption.", interrupted: false }, + { type: MessageUpdateType.Status, status: MessageUpdateStatus.Finished }, + ]); + + const response = await invokePost({ + conversationId: conversation._id.toString(), + locals, + payload: { inputs: "Tell a story" }, + }); + await parseJsonlResponse(response); + + const updatedConversation = await collections.conversations.findOne({ _id: conversation._id }); + const assistant = updatedConversation?.messages.find((message) => message.from === "assistant"); + expect(assistant?.content).toBe("Draft story.\n\nImage caption."); + }); + + it("preserves route/model on provider-only router metadata updates", async () => { + const { locals } = await createTestUser(); + const conversation = await createTestConversation(locals, { messages: [] }); + + generationScenarios.push([ + { + type: MessageUpdateType.RouterMetadata, + route: "router-a", + model: "model-a", + }, + { + type: MessageUpdateType.RouterMetadata, + route: "", + model: "", + provider: "hf-inference" as never, + }, + { type: MessageUpdateType.FinalAnswer, text: "done", interrupted: false }, + { type: MessageUpdateType.Status, status: MessageUpdateStatus.Finished }, + ]); + + const response = await invokePost({ + conversationId: conversation._id.toString(), + locals, + payload: { inputs: "metadata" }, + }); + await parseJsonlResponse(response); + + const updatedConversation = await collections.conversations.findOne({ _id: conversation._id }); + const assistant = updatedConversation?.messages.find((message) => message.from === "assistant"); + expect(assistant?.routerMetadata).toEqual({ + route: "router-a", + model: "model-a", + provider: "hf-inference", + }); + }); + + it("emits interrupted final answer on abort", async () => { + const { locals } = await createTestUser(); + const conversation = await createTestConversation(locals, { messages: [] }); + + generationScenarios.push([ + { type: MessageUpdateType.Stream, token: "partial answer" }, + abortScenarioStep, + ]); + + const response = await invokePost({ + conversationId: conversation._id.toString(), + locals, + payload: { inputs: "abort" }, + }); + const updates = await parseJsonlResponse(response); + + const interruptedFinal = updates.find( + (update) => update.type === MessageUpdateType.FinalAnswer && update.interrupted === true + ); + expect(interruptedFinal).toBeDefined(); + expect(interruptedFinal?.type).toBe(MessageUpdateType.FinalAnswer); + expect((interruptedFinal as { text: string }).text).toBe("partial answer"); + + const updatedConversation = await collections.conversations.findOne({ _id: conversation._id }); + const assistant = updatedConversation?.messages.find((message) => message.from === "assistant"); + expect(assistant?.content).toBe("partial answer"); + expect(assistant?.interrupted).toBe(true); + }); +}); diff --git a/src/routes/conversation/[id]/+page.svelte b/src/routes/conversation/[id]/+page.svelte index a910588db78..e15d281d1d3 100644 --- a/src/routes/conversation/[id]/+page.svelte +++ b/src/routes/conversation/[id]/+page.svelte @@ -9,11 +9,8 @@ import { ERROR_MESSAGES, error } from "$lib/stores/errors"; import { findCurrentModel } from "$lib/utils/models"; import type { Message } from "$lib/types/Message"; - import { MessageUpdateStatus, MessageUpdateType } from "$lib/types/MessageUpdate"; import titleUpdate from "$lib/stores/titleUpdate"; import file2base64 from "$lib/utils/file2base64"; - import { addChildren } from "$lib/utils/tree/addChildren"; - import { addSibling } from "$lib/utils/tree/addSibling"; import { fetchMessageUpdates } from "$lib/utils/messageUpdates"; import type { v4 } from "uuid"; import { useSettingsStore } from "$lib/stores/settings.js"; @@ -30,6 +27,7 @@ import { loading } from "$lib/stores/loading.js"; import { requireAuthUser } from "$lib/utils/auth.js"; import { isConversationGenerationActive } from "$lib/utils/generationState"; + import { prepareTurn, processClientUpdate } from "$lib/conversation/generation"; let { data = $bindable() } = $props(); @@ -125,89 +123,40 @@ ) ); - let messageToWriteToId: Message["id"] | undefined = undefined; - // used for building the prompt, subtree of the conversation that goes from the latest message to the root + let messageToWriteToId: Message["id"] | undefined = undefined; + const tree = { messages, rootMessageId: data.rootMessageId }; - if (isRetry && messageId) { - // two cases, if we're retrying a user message with a newPrompt set, - // it means we're editing a user message - // if we're retrying on an assistant message, newPrompt cannot be set - // it means we're retrying the last assistant message for a new answer - - const messageToRetry = messages.find((message) => message.id === messageId); - - if (!messageToRetry) { - $error = "Message not found"; - } - - if (messageToRetry?.from === "user" && prompt) { - // add a sibling to this message from the user, with the alternative prompt - // add a children to that sibling, where we can write to - const newUserMessageId = addSibling( - { - messages, - rootMessageId: data.rootMessageId, - }, - { + try { + const preparedTurn = prepareTurn({ + tree, + messageId, + prompt, + isRetry, + files: base64Files, + createUserMessage: ({ prompt, files, retryTarget }) => ({ from: "user", content: prompt, - files: messageToRetry.files, - }, - messageId - ); - messageToWriteToId = addChildren( - { - messages, - rootMessageId: data.rootMessageId, - }, - { from: "assistant", content: "" }, - newUserMessageId - ); - } else if (messageToRetry?.from === "assistant") { - // we're retrying an assistant message, to generate a new answer - // just add a sibling to the assistant answer where we can write to - messageToWriteToId = addSibling( - { - messages, - rootMessageId: data.rootMessageId, - }, - { from: "assistant", content: "" }, - messageId - ); - } - } else { - // just a normal linear conversation, so we add the user message - // and the blank assistant message back to back - const newUserMessageId = addChildren( - { - messages, - rootMessageId: data.rootMessageId, - }, - { - from: "user", - content: prompt ?? "", - files: base64Files, - }, - messageId - ); + files: retryTarget?.files ?? files, + }), + createAssistantMessage: () => ({ + from: "assistant", + content: "", + }), + }); + + messageToWriteToId = preparedTurn.assistantMessageId; + if (!data.rootMessageId && tree.rootMessageId) { + data.rootMessageId = tree.rootMessageId; + } + } catch (prepareError) { + if (prepareError instanceof Error && prepareError.message === "Message not found") { + $error = "Message not found"; + return; + } - if (!data.rootMessageId) { - data.rootMessageId = newUserMessageId; + throw prepareError; } - messageToWriteToId = addChildren( - { - messages, - rootMessageId: data.rootMessageId, - }, - { - from: "assistant", - content: "", - }, - newUserMessageId - ); - } - const userMessage = messages.find((message) => message.id === messageId); const messageToWriteTo = messages.find((message) => message.id === messageToWriteToId); if (!messageToWriteTo) { @@ -242,146 +191,45 @@ // Initialize lastUpdateTime outside the loop to persist between updates let lastUpdateTime = new Date(); - for await (const update of messageUpdatesIterator) { - if ($isAborted) { - messageUpdatesAbortController.abort(); - return; - } - - // Remove null characters added due to remote keylogging prevention - // See server code for more details - if (update.type === MessageUpdateType.Stream) { - update.token = update.token.replaceAll("\0", ""); - } - - const isKeepAlive = - update.type === MessageUpdateType.Status && - update.status === MessageUpdateStatus.KeepAlive; - - if (!isKeepAlive) { - if (update.type === MessageUpdateType.Stream) { - const existingUpdates = messageToWriteTo.updates ?? []; - const lastUpdate = existingUpdates.at(-1); - if (lastUpdate?.type === MessageUpdateType.Stream) { - // Create fresh objects/arrays so the UI reacts to merged tokens - const merged = { - ...lastUpdate, - token: (lastUpdate.token ?? "") + (update.token ?? ""), - }; - messageToWriteTo.updates = [...existingUpdates.slice(0, -1), merged]; - } else { - messageToWriteTo.updates = [...existingUpdates, update]; - } - } else { - messageToWriteTo.updates = [...(messageToWriteTo.updates ?? []), update]; + for await (const update of messageUpdatesIterator) { + if ($isAborted) { + messageUpdatesAbortController.abort(); + return; } - } - const currentTime = new Date(); - - // If we receive a non-stream update (e.g. tool/status/final answer), - // flush any buffered stream tokens so the UI doesn't appear to cut - // mid-sentence while tools are running or the final answer arrives. - if ( - update.type !== MessageUpdateType.Stream && - !$settings.disableStream && - buffer.length > 0 - ) { - messageToWriteTo.content += buffer; - buffer = ""; - lastUpdateTime = currentTime; - } - if (update.type === MessageUpdateType.Stream && !$settings.disableStream) { - buffer += update.token; - // Check if this is the first update or if enough time has passed - if (currentTime.getTime() - lastUpdateTime.getTime() > updateDebouncer.maxUpdateTime) { - messageToWriteTo.content += buffer; - buffer = ""; - lastUpdateTime = currentTime; + const processedUpdate = processClientUpdate({ + message: messageToWriteTo, + update, + disableStream: $settings.disableStream, + buffer, + lastUpdateTime, + maxUpdateTimeMs: updateDebouncer.maxUpdateTime, + }); + + Object.assign(messageToWriteTo, processedUpdate.message); + buffer = processedUpdate.buffer; + lastUpdateTime = processedUpdate.lastUpdateTime; + + if (processedUpdate.effects.setPendingFalse) { + pending = false; } - pending = false; - } else if (update.type === MessageUpdateType.FinalAnswer) { - // Mirror server-side merge behavior so the UI reflects the - // final text once tools complete, while preserving any - // pre‑tool streamed content when appropriate. - const finalText = update.text ?? ""; - const isInterrupted = update.interrupted === true; - const hadTools = - messageToWriteTo.updates?.some((u) => u.type === MessageUpdateType.Tool) ?? false; - - if (isInterrupted) { - // Preserve streamed content on abort. If we never streamed, fall back to finalText. - if (!messageToWriteTo.content) { - messageToWriteTo.content = finalText; - } - } else if (hadTools) { - const existing = messageToWriteTo.content; - const trimmedExistingSuffix = existing.replace(/\s+$/, ""); - const trimmedFinalPrefix = finalText.replace(/^\s+/, ""); - const alreadyStreamed = - finalText && - (existing.endsWith(finalText) || - (trimmedFinalPrefix.length > 0 && - trimmedExistingSuffix.endsWith(trimmedFinalPrefix))); - - if (existing && existing.length > 0) { - if (alreadyStreamed) { - // A. Already streamed the same final text; keep as-is. - messageToWriteTo.content = existing; - } else if ( - finalText && - (finalText.startsWith(existing) || - (trimmedExistingSuffix.length > 0 && - trimmedFinalPrefix.startsWith(trimmedExistingSuffix))) - ) { - // B. Final text already includes streamed prefix; use it verbatim. - messageToWriteTo.content = finalText; - } else { - // C. Merge with a paragraph break for readability. - const needsGap = !/\n\n$/.test(existing) && !/^\n/.test(finalText ?? ""); - messageToWriteTo.content = existing + (needsGap ? "\n\n" : "") + finalText; - } - } else { - messageToWriteTo.content = finalText; - } - } else { - // No tools: final answer replaces streamed content so - // the provider's final text is authoritative. - messageToWriteTo.content = finalText; - } - } else if ( - update.type === MessageUpdateType.Status && - update.status === MessageUpdateStatus.Error - ) { - // Check if this is a 402 payment required error - if (update.statusCode === 402) { + if (processedUpdate.effects.showSubscribeModal) { showSubscribeModal = true; - } else { - $error = update.message ?? "An error has occurred"; } - } else if (update.type === MessageUpdateType.Title) { - const convInData = conversations.find(({ id }) => id === page.params.id); - if (convInData) { - convInData.title = update.title; - - $titleUpdate = { - title: update.title, - convId, - }; + if (processedUpdate.effects.errorMessage) { + $error = processedUpdate.effects.errorMessage; + } + if (processedUpdate.effects.title) { + const convInData = conversations.find(({ id }) => id === page.params.id); + if (convInData) { + convInData.title = processedUpdate.effects.title; + $titleUpdate = { + title: processedUpdate.effects.title, + convId, + }; + } } - } else if (update.type === MessageUpdateType.File) { - messageToWriteTo.files = [ - ...(messageToWriteTo.files ?? []), - { type: "hash", value: update.sha, mime: update.mime, name: update.name }, - ]; - } else if (update.type === MessageUpdateType.RouterMetadata) { - // Update router metadata immediately when received - messageToWriteTo.routerMetadata = { - route: update.route, - model: update.model, - }; } - } } catch (err) { if (err instanceof Error && err.message.includes("overloaded")) { $error = "Too much traffic, please try again."; diff --git a/src/routes/conversation/[id]/+server.ts b/src/routes/conversation/[id]/+server.ts index fdb057e0ae4..7139cb8a044 100644 --- a/src/routes/conversation/[id]/+server.ts +++ b/src/routes/conversation/[id]/+server.ts @@ -18,14 +18,17 @@ import { uploadFile } from "$lib/server/files/uploadFile"; import { convertLegacyConversation } from "$lib/utils/tree/convertLegacyConversation"; import { isMessageId } from "$lib/utils/tree/isMessageId"; import { buildSubtree } from "$lib/utils/tree/buildSubtree.js"; -import { addChildren } from "$lib/utils/tree/addChildren.js"; -import { addSibling } from "$lib/utils/tree/addSibling.js"; import { usageLimits } from "$lib/server/usageLimits"; import { textGeneration } from "$lib/server/textGeneration"; import type { TextGenerationContext } from "$lib/server/textGeneration/types"; import { logger } from "$lib/server/logger.js"; import { AbortRegistry } from "$lib/server/abortRegistry"; import { MetricsServer } from "$lib/server/metrics"; +import { + mergeFinalAnswerWithPrefix, + mergeRouterMetadata, + prepareTurn, +} from "$lib/conversation/generation"; export async function POST({ request, locals, params, getClientAddress }) { const id = z.string().parse(params.id); @@ -230,81 +233,39 @@ export async function POST({ request, locals, params, getClientAddress }) { // used for building the prompt, subtree of the conversation that goes from the latest message to the root let messagesForPrompt: Message[] = []; - if (isRetry && messageId) { - // two cases, if we're retrying a user message with a newPrompt set, - // it means we're editing a user message - // if we're retrying on an assistant message, newPrompt cannot be set - // it means we're retrying the last assistant message for a new answer - - const messageToRetry = conv.messages.find((message) => message.id === messageId); - - if (!messageToRetry) { - error(404, "Message not found"); - } - - if (messageToRetry.from === "user" && newPrompt) { - // add a sibling to this message from the user, with the alternative prompt - // add a children to that sibling, where we can write to - const newUserMessageId = addSibling( - conv, - { - from: "user", - content: newPrompt, - files: uploadedFiles, - createdAt: new Date(), - updatedAt: new Date(), - }, - messageId - ); - messageToWriteToId = addChildren( - conv, - { - from: "assistant", - content: "", - createdAt: new Date(), - updatedAt: new Date(), - }, - newUserMessageId - ); - messagesForPrompt = buildSubtree(conv, newUserMessageId); - } else if (messageToRetry.from === "assistant") { - // we're retrying an assistant message, to generate a new answer - // just add a sibling to the assistant answer where we can write to - messageToWriteToId = addSibling( - conv, - { from: "assistant", content: "", createdAt: new Date(), updatedAt: new Date() }, - messageId - ); - messagesForPrompt = buildSubtree(conv, messageId); - messagesForPrompt.pop(); // don't need the latest assistant message in the prompt since we're retrying it - } - } else { - // just a normal linear conversation, so we add the user message - // and the blank assistant message back to back - const newUserMessageId = addChildren( - conv, - { + try { + const preparedTurn = prepareTurn({ + tree: conv, + messageId, + prompt: newPrompt, + isRetry, + files: uploadedFiles, + createUserMessage: ({ prompt, files }) => ({ from: "user", - content: newPrompt ?? "", - files: uploadedFiles, + content: prompt, + files, createdAt: new Date(), updatedAt: new Date(), - }, - messageId - ); - - messageToWriteToId = addChildren( - conv, - { + }), + createAssistantMessage: () => ({ from: "assistant", content: "", createdAt: new Date(), updatedAt: new Date(), - }, - newUserMessageId - ); - // build the prompt from the user message - messagesForPrompt = buildSubtree(conv, newUserMessageId); + }), + }); + + messageToWriteToId = preparedTurn.assistantMessageId; + messagesForPrompt = buildSubtree(conv, preparedTurn.promptAnchorId); + if (preparedTurn.excludeAnchorFromPrompt) { + messagesForPrompt.pop(); + } + } catch (e) { + if (e instanceof Error && e.message === "Message not found") { + error(404, "Message not found"); + } + + throw e; } const messageToWriteTo = conv.messages.find((message) => message.id === messageToWriteToId); @@ -429,40 +390,16 @@ export async function POST({ request, locals, params, getClientAddress }) { // Set the final text and the interrupted flag else if (event.type === MessageUpdateType.FinalAnswer) { messageToWriteTo.interrupted = event.interrupted; - // Default behavior: replace the streamed text with the provider's final text. - // However, when tools (MCP/function calls) were used, providers often stream - // some content (e.g., a story) before triggering tools, then return a - // different follow‑up message afterwards (e.g., an image caption). Our - // previous logic overwrote the pre‑tool content. Preserve it by merging in - // the pre‑tool stream when tool updates occurred and the final text does - // not already include the streamed prefix. const hadTools = (messageToWriteTo.updates ?? []).some( (u) => u.type === MessageUpdateType.Tool ); - - if (hadTools) { - const existing = messageToWriteTo.content.slice(initialMessageContent.length); - if (existing && existing.length > 0) { - // A. If we already streamed the same final text, keep as-is. - if (event.text && existing.endsWith(event.text)) { - messageToWriteTo.content = initialMessageContent + existing; - } - // B. If the final text already includes the streamed prefix, use it verbatim. - else if (event.text && event.text.startsWith(existing)) { - messageToWriteTo.content = initialMessageContent + event.text; - } - // C. Otherwise, merge with a paragraph break for readability. - else { - const needsGap = !/\n\n$/.test(existing) && !/^\n/.test(event.text ?? ""); - messageToWriteTo.content = - initialMessageContent + existing + (needsGap ? "\n\n" : "") + (event.text ?? ""); - } - } else { - messageToWriteTo.content = initialMessageContent + (event.text ?? ""); - } - } else { - messageToWriteTo.content = initialMessageContent + event.text; - } + messageToWriteTo.content = mergeFinalAnswerWithPrefix({ + prefixContent: initialMessageContent, + currentContent: messageToWriteTo.content, + finalText: event.text, + interrupted: event.interrupted, + hadTools, + }); finalAnswerReceived = true; if (metricsEnabled && metrics) { @@ -480,21 +417,11 @@ export async function POST({ request, locals, params, getClientAddress }) { // Store router metadata (for router models) or provider info (for all models) else if (event.type === MessageUpdateType.RouterMetadata) { - // Merge metadata updates to preserve existing fields (router may send route/model first, then provider comes later) - if (model?.isRouter) { - messageToWriteTo.routerMetadata = { - route: event.route || messageToWriteTo.routerMetadata?.route || "", - model: event.model || messageToWriteTo.routerMetadata?.model || "", - provider: event.provider || messageToWriteTo.routerMetadata?.provider, - }; - } - // Store provider-only metadata for non-router models if available - else if (event.provider) { - messageToWriteTo.routerMetadata = { - route: messageToWriteTo.routerMetadata?.route || "", - model: messageToWriteTo.routerMetadata?.model || "", - provider: event.provider, - }; + if (model?.isRouter || event.provider) { + messageToWriteTo.routerMetadata = mergeRouterMetadata( + messageToWriteTo.routerMetadata, + event + ); } }