From fb2b131eee995229e72b17d0233166c6340c82f9 Mon Sep 17 00:00:00 2001 From: pranav-kural Date: Fri, 5 Jul 2024 19:04:46 -0400 Subject: [PATCH] completed integration tests and updated multiple functionalities --- jest.config.ts | 198 ++ package.json | 26 +- pnpm-lock.yaml | 2762 ++++++++++++++++- scripts/copy-build-files.mjs | 21 + src/agents/chat-agent.ts | 155 +- src/auth/api-key-store.ts | 21 +- src/auth/firestore-api-key-store.ts | 88 +- src/auth/in-memory-api-key-store.ts | 9 - src/cache/cache-store.ts | 7 + src/cache/firestore-cache-store.ts | 22 +- src/cache/in-memory-cache-store.ts | 26 +- src/flows/flow.ts | 161 +- src/history/chat-history-store.ts | 47 +- src/history/firestore-chat-history-store.ts | 29 +- src/history/in-memory-chat-history-store.ts | 7 +- src/models/model.ts | 2 + .../inventory-data.csv | 0 .../return-policy.md | 0 src/tests/api-keys.tests.ts | 113 + src/tests/cache.tests.ts | 87 + src/tests/chat-history.tests.ts | 122 + src/tests/flow-rag.tests.ts | 74 + src/tests/flow.tests.ts | 66 + src/tests/test-data/inventory-data.csv | 36 + test-flows.ts | 62 +- 25 files changed, 3878 insertions(+), 263 deletions(-) create mode 100644 jest.config.ts create mode 100644 scripts/copy-build-files.mjs rename src/rag/knowledge-bases/{test-retail-store-kb => test-data}/inventory-data.csv (100%) rename src/rag/knowledge-bases/{test-retail-store-kb => test-data}/return-policy.md (100%) create mode 100644 src/tests/api-keys.tests.ts create mode 100644 src/tests/cache.tests.ts create mode 100644 src/tests/chat-history.tests.ts create mode 100644 src/tests/flow-rag.tests.ts create mode 100644 src/tests/flow.tests.ts create mode 100644 src/tests/test-data/inventory-data.csv diff --git a/jest.config.ts b/jest.config.ts new file mode 100644 index 0000000..d38524e --- /dev/null +++ b/jest.config.ts @@ -0,0 +1,198 @@ +/** + * For a detailed explanation regarding each configuration property, visit: + * https://jestjs.io/docs/configuration + */ + +import type { Config } from "jest"; + +const config: Config = { + // All imported modules in your tests should be mocked automatically + // automock: false, + + // Stop running tests after `n` failures + // bail: 0, + + // The directory where Jest should store its cached dependency information + // cacheDirectory: "/private/var/folders/qk/v_fq_2v94r984skwk0b1glyr0000gn/T/jest_dx", + + // Automatically clear mock calls, instances, contexts and results before every test + clearMocks: true, + + // Indicates whether the coverage information should be collected while executing the test + // collectCoverage: false, + + // An array of glob patterns indicating a set of files for which coverage information should be collected + // collectCoverageFrom: undefined, + + // The directory where Jest should output its coverage files + // coverageDirectory: undefined, + + // An array of regexp pattern strings used to skip coverage collection + // coveragePathIgnorePatterns: [ + // "/node_modules/" + // ], + + // Indicates which provider should be used to instrument code for coverage + coverageProvider: "v8", + + // A list of reporter names that Jest uses when writing coverage reports + // coverageReporters: [ + // "json", + // "text", + // "lcov", + // "clover" + // ], + + // An object that configures minimum threshold enforcement for coverage results + // coverageThreshold: undefined, + + // A path to a custom dependency extractor + // dependencyExtractor: undefined, + + // Make calling deprecated APIs throw helpful error messages + // errorOnDeprecated: false, + + // The default configuration for fake timers + // fakeTimers: { + // "enableGlobally": false + // }, + + // Force coverage collection from ignored files using an array of glob patterns + // forceCoverageMatch: [], + + // A path to a module which exports an async function that is triggered once before all test suites + // globalSetup: undefined, + + // A path to a module which exports an async function that is triggered once after all test suites + // globalTeardown: undefined, + + // A set of global variables that need to be available in all test environments + // globals: {}, + + // The maximum amount of workers used to run your tests. Can be specified as % or a number. E.g. maxWorkers: 10% will use 10% of your CPU amount + 1 as the maximum worker number. maxWorkers: 2 will use a maximum of 2 workers. + // maxWorkers: "50%", + + // An array of directory names to be searched recursively up from the requiring module's location + // moduleDirectories: [ + // "node_modules" + // ], + + // An array of file extensions your modules use + // moduleFileExtensions: [ + // "js", + // "mjs", + // "cjs", + // "jsx", + // "ts", + // "tsx", + // "json", + // "node" + // ], + + // A map from regular expressions to module names or to arrays of module names that allow to stub out resources with a single module + // moduleNameMapper: {}, + + // An array of regexp pattern strings, matched against all module paths before considered 'visible' to the module loader + // modulePathIgnorePatterns: [], + + // Activates notifications for test results + // notify: false, + + // An enum that specifies notification mode. Requires { notify: true } + // notifyMode: "failure-change", + + // A preset that is used as a base for Jest's configuration + // preset: undefined, + + // Run tests from one or more projects + // projects: undefined, + + // Use this configuration option to add custom reporters to Jest + // reporters: undefined, + + // Automatically reset mock state before every test + // resetMocks: false, + + // Reset the module registry before running each individual test + // resetModules: false, + + // A path to a custom resolver + // resolver: undefined, + + // Automatically restore mock state and implementation before every test + // restoreMocks: false, + + // The root directory that Jest should scan for tests and modules within + // rootDir: "src/tests/", + + // A list of paths to directories that Jest should use to search for files in + // roots: [ + // "" + // ], + + // Allows you to use a custom runner instead of Jest's default test runner + // runner: "jest-runner", + + // The paths to modules that run some code to configure or set up the testing environment before each test + // setupFiles: [], + + // A list of paths to modules that run some code to configure or set up the testing framework before each test + // setupFilesAfterEnv: [], + + // The number of seconds after which a test is considered as slow and reported as such in the results. + // slowTestThreshold: 5, + + // A list of paths to snapshot serializer modules Jest should use for snapshot testing + // snapshotSerializers: [], + + // The test environment that will be used for testing + // testEnvironment: "jest-environment-node", + + // Options that will be passed to the testEnvironment + // testEnvironmentOptions: {}, + + // Adds a location field to test results + // testLocationInResults: false, + + // The glob patterns Jest uses to detect test files + testMatch: ["**/lib/tests/**/*.[jt]s?(x)"], + + // An array of regexp pattern strings that are matched against all test paths, matched tests are skipped + // testPathIgnorePatterns: [ + // "/node_modules/" + // ], + + // The regexp pattern or array of patterns that Jest uses to detect test files + // testRegex: [], + + // This option allows the use of a custom results processor + // testResultsProcessor: undefined, + + // This option allows use of a custom test runner + // testRunner: "jest-circus/runner", + + // A map from regular expressions to paths to transformers + transform: { + "^.+\\.ts?$": "ts-jest", + }, + + // An array of regexp pattern strings that are matched against all source file paths, matched files will skip transformation + // transformIgnorePatterns: [ + // "/node_modules/", + // "\\.pnp\\.[^\\/]+$" + // ], + + // An array of regexp pattern strings that are matched against all modules before the module loader will automatically return a mock for them + // unmockedModulePathPatterns: undefined, + + // Indicates whether each individual test should be reported during the run + // verbose: undefined, + + // An array of regexp patterns that are matched against all source file paths before re-running tests in watch mode + // watchPathIgnorePatterns: [], + + // Whether to use watchman for file crawling + // watchman: true, +}; + +export default config; diff --git a/package.json b/package.json index bb200a4..990a3d5 100644 --- a/package.json +++ b/package.json @@ -3,26 +3,40 @@ "scripts": { "start": "nodemon -x tsx src/index.js", "dev": "npm run build && npm run start", - "build": "swc --strip-leading-paths --delete-dir-on-start -d lib src && cp -r src/prompts lib/ && cp -r src/rag/knowledge-bases lib/rag/", + "build": "swc --strip-leading-paths --delete-dir-on-start -d lib src && node scripts/copy-build-files.mjs", "lint": "pnpm eslint .", "format": "pnpm prettier . --write", - "test": "echo \"Error: no test specified\" && exit 1" + "test": "NODE_OPTIONS=\"$NODE_OPTIONS --experimental-vm-modules\" jest --no-watchman", + "buildandtest": "pnpm build && pnpm test", + "predeploy": "pnpm lint && pnpm format && pnpm build && pnpm test" }, - "name": "intento-genkit", + "name": "qvikchat", "version": "1.0.0", - "keywords": [], - "author": "", + "keywords": [ + "conversational ai", + "chat", + "chatbot", + "chat agent", + "langchain", + "genkit" + ], + "author": "Oconva (https://github.com/oconva)", "license": "ISC", - "description": "", + "description": "Framework to build secure, performant and reliable chat apps and services quickly and efficiently.", "devDependencies": { "@eslint/js": "^9.6.0", "@swc/cli": "^0.4.0", "@types/cors": "^2.8.17", "@types/eslint__js": "^8.42.3", + "@types/jest": "^29.5.12", "eslint": "^8.56.0", "eslint-config-prettier": "^9.1.0", + "fs-extra": "^11.2.0", + "jest": "^29.7.0", "nodemon": "^3.1.4", "prettier": "^3.3.2", + "ts-jest": "^29.1.5", + "ts-node": "^10.9.2", "tsx": "^4.16.2", "typescript": "^5.5.3", "typescript-eslint": "^7.15.0" diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 8b14530..a08929b 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -80,18 +80,33 @@ importers: "@types/eslint__js": specifier: ^8.42.3 version: 8.42.3 + "@types/jest": + specifier: ^29.5.12 + version: 29.5.12 eslint: specifier: ^8.56.0 version: 8.57.0 eslint-config-prettier: specifier: ^9.1.0 version: 9.1.0(eslint@8.57.0) + fs-extra: + specifier: ^11.2.0 + version: 11.2.0 + jest: + specifier: ^29.7.0 + version: 29.7.0(@types/node@20.14.9)(ts-node@10.9.2(@swc/core@1.6.7)(@types/node@20.14.9)(typescript@5.5.3)) nodemon: specifier: ^3.1.4 version: 3.1.4 prettier: specifier: ^3.3.2 version: 3.3.2 + ts-jest: + specifier: ^29.1.5 + version: 29.1.5(@babel/core@7.24.7)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.24.7))(jest@29.7.0(@types/node@20.14.9)(ts-node@10.9.2(@swc/core@1.6.7)(@types/node@20.14.9)(typescript@5.5.3)))(typescript@5.5.3) + ts-node: + specifier: ^10.9.2 + version: 10.9.2(@swc/core@1.6.7)(@types/node@20.14.9)(typescript@5.5.3) tsx: specifier: ^4.16.2 version: 4.16.2 @@ -103,12 +118,297 @@ importers: version: 7.15.0(eslint@8.57.0)(typescript@5.5.3) packages: + "@ampproject/remapping@2.3.0": + resolution: + { + integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==, + } + engines: { node: ">=6.0.0" } + "@anthropic-ai/sdk@0.9.1": resolution: { integrity: sha512-wa1meQ2WSfoY8Uor3EdrJq0jTiZJoKoSii2ZVWRY1oN4Tlr5s59pADg9T79FTbPe1/se5c3pBeZgJL63wmuoBA==, } + "@babel/code-frame@7.24.7": + resolution: + { + integrity: sha512-BcYH1CVJBO9tvyIZ2jVeXgSIMvGZ2FDRvDdOIVQyuklNKSsx+eppDEBq/g47Ayw+RqNFE+URvOShmf+f/qwAlA==, + } + engines: { node: ">=6.9.0" } + + "@babel/compat-data@7.24.7": + resolution: + { + integrity: sha512-qJzAIcv03PyaWqxRgO4mSU3lihncDT296vnyuE2O8uA4w3UHWI4S3hgeZd1L8W1Bft40w9JxJ2b412iDUFFRhw==, + } + engines: { node: ">=6.9.0" } + + "@babel/core@7.24.7": + resolution: + { + integrity: sha512-nykK+LEK86ahTkX/3TgauT0ikKoNCfKHEaZYTUVupJdTLzGNvrblu4u6fa7DhZONAltdf8e662t/abY8idrd/g==, + } + engines: { node: ">=6.9.0" } + + "@babel/generator@7.24.7": + resolution: + { + integrity: sha512-oipXieGC3i45Y1A41t4tAqpnEZWgB/lC6Ehh6+rOviR5XWpTtMmLN+fGjz9vOiNRt0p6RtO6DtD0pdU3vpqdSA==, + } + engines: { node: ">=6.9.0" } + + "@babel/helper-compilation-targets@7.24.7": + resolution: + { + integrity: sha512-ctSdRHBi20qWOfy27RUb4Fhp07KSJ3sXcuSvTrXrc4aG8NSYDo1ici3Vhg9bg69y5bj0Mr1lh0aeEgTvc12rMg==, + } + engines: { node: ">=6.9.0" } + + "@babel/helper-environment-visitor@7.24.7": + resolution: + { + integrity: sha512-DoiN84+4Gnd0ncbBOM9AZENV4a5ZiL39HYMyZJGZ/AZEykHYdJw0wW3kdcsh9/Kn+BRXHLkkklZ51ecPKmI1CQ==, + } + engines: { node: ">=6.9.0" } + + "@babel/helper-function-name@7.24.7": + resolution: + { + integrity: sha512-FyoJTsj/PEUWu1/TYRiXTIHc8lbw+TDYkZuoE43opPS5TrI7MyONBE1oNvfguEXAD9yhQRrVBnXdXzSLQl9XnA==, + } + engines: { node: ">=6.9.0" } + + "@babel/helper-hoist-variables@7.24.7": + resolution: + { + integrity: sha512-MJJwhkoGy5c4ehfoRyrJ/owKeMl19U54h27YYftT0o2teQ3FJ3nQUf/I3LlJsX4l3qlw7WRXUmiyajvHXoTubQ==, + } + engines: { node: ">=6.9.0" } + + "@babel/helper-module-imports@7.24.7": + resolution: + { + integrity: sha512-8AyH3C+74cgCVVXow/myrynrAGv+nTVg5vKu2nZph9x7RcRwzmh0VFallJuFTZ9mx6u4eSdXZfcOzSqTUm0HCA==, + } + engines: { node: ">=6.9.0" } + + "@babel/helper-module-transforms@7.24.7": + resolution: + { + integrity: sha512-1fuJEwIrp+97rM4RWdO+qrRsZlAeL1lQJoPqtCYWv0NL115XM93hIH4CSRln2w52SqvmY5hqdtauB6QFCDiZNQ==, + } + engines: { node: ">=6.9.0" } + peerDependencies: + "@babel/core": ^7.0.0 + + "@babel/helper-plugin-utils@7.24.7": + resolution: + { + integrity: sha512-Rq76wjt7yz9AAc1KnlRKNAi/dMSVWgDRx43FHoJEbcYU6xOWaE2dVPwcdTukJrjxS65GITyfbvEYHvkirZ6uEg==, + } + engines: { node: ">=6.9.0" } + + "@babel/helper-simple-access@7.24.7": + resolution: + { + integrity: sha512-zBAIvbCMh5Ts+b86r/CjU+4XGYIs+R1j951gxI3KmmxBMhCg4oQMsv6ZXQ64XOm/cvzfU1FmoCyt6+owc5QMYg==, + } + engines: { node: ">=6.9.0" } + + "@babel/helper-split-export-declaration@7.24.7": + resolution: + { + integrity: sha512-oy5V7pD+UvfkEATUKvIjvIAH/xCzfsFVw7ygW2SI6NClZzquT+mwdTfgfdbUiceh6iQO0CHtCPsyze/MZ2YbAA==, + } + engines: { node: ">=6.9.0" } + + "@babel/helper-string-parser@7.24.7": + resolution: + { + integrity: sha512-7MbVt6xrwFQbunH2DNQsAP5sTGxfqQtErvBIvIMi6EQnbgUOuVYanvREcmFrOPhoXBrTtjhhP+lW+o5UfK+tDg==, + } + engines: { node: ">=6.9.0" } + + "@babel/helper-validator-identifier@7.24.7": + resolution: + { + integrity: sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w==, + } + engines: { node: ">=6.9.0" } + + "@babel/helper-validator-option@7.24.7": + resolution: + { + integrity: sha512-yy1/KvjhV/ZCL+SM7hBrvnZJ3ZuT9OuZgIJAGpPEToANvc3iM6iDvBnRjtElWibHU6n8/LPR/EjX9EtIEYO3pw==, + } + engines: { node: ">=6.9.0" } + + "@babel/helpers@7.24.7": + resolution: + { + integrity: sha512-NlmJJtvcw72yRJRcnCmGvSi+3jDEg8qFu3z0AFoymmzLx5ERVWyzd9kVXr7Th9/8yIJi2Zc6av4Tqz3wFs8QWg==, + } + engines: { node: ">=6.9.0" } + + "@babel/highlight@7.24.7": + resolution: + { + integrity: sha512-EStJpq4OuY8xYfhGVXngigBJRWxftKX9ksiGDnmlY3o7B/V7KIAc9X4oiK87uPJSc/vs5L869bem5fhZa8caZw==, + } + engines: { node: ">=6.9.0" } + + "@babel/parser@7.24.7": + resolution: + { + integrity: sha512-9uUYRm6OqQrCqQdG1iCBwBPZgN8ciDBro2nIOFaiRz1/BCxaI7CNvQbDHvsArAC7Tw9Hda/B3U+6ui9u4HWXPw==, + } + engines: { node: ">=6.0.0" } + hasBin: true + + "@babel/plugin-syntax-async-generators@7.8.4": + resolution: + { + integrity: sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==, + } + peerDependencies: + "@babel/core": ^7.0.0-0 + + "@babel/plugin-syntax-bigint@7.8.3": + resolution: + { + integrity: sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==, + } + peerDependencies: + "@babel/core": ^7.0.0-0 + + "@babel/plugin-syntax-class-properties@7.12.13": + resolution: + { + integrity: sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==, + } + peerDependencies: + "@babel/core": ^7.0.0-0 + + "@babel/plugin-syntax-import-meta@7.10.4": + resolution: + { + integrity: sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==, + } + peerDependencies: + "@babel/core": ^7.0.0-0 + + "@babel/plugin-syntax-json-strings@7.8.3": + resolution: + { + integrity: sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==, + } + peerDependencies: + "@babel/core": ^7.0.0-0 + + "@babel/plugin-syntax-jsx@7.24.7": + resolution: + { + integrity: sha512-6ddciUPe/mpMnOKv/U+RSd2vvVy+Yw/JfBB0ZHYjEZt9NLHmCUylNYlsbqCCS1Bffjlb0fCwC9Vqz+sBz6PsiQ==, + } + engines: { node: ">=6.9.0" } + peerDependencies: + "@babel/core": ^7.0.0-0 + + "@babel/plugin-syntax-logical-assignment-operators@7.10.4": + resolution: + { + integrity: sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==, + } + peerDependencies: + "@babel/core": ^7.0.0-0 + + "@babel/plugin-syntax-nullish-coalescing-operator@7.8.3": + resolution: + { + integrity: sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==, + } + peerDependencies: + "@babel/core": ^7.0.0-0 + + "@babel/plugin-syntax-numeric-separator@7.10.4": + resolution: + { + integrity: sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==, + } + peerDependencies: + "@babel/core": ^7.0.0-0 + + "@babel/plugin-syntax-object-rest-spread@7.8.3": + resolution: + { + integrity: sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==, + } + peerDependencies: + "@babel/core": ^7.0.0-0 + + "@babel/plugin-syntax-optional-catch-binding@7.8.3": + resolution: + { + integrity: sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==, + } + peerDependencies: + "@babel/core": ^7.0.0-0 + + "@babel/plugin-syntax-optional-chaining@7.8.3": + resolution: + { + integrity: sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==, + } + peerDependencies: + "@babel/core": ^7.0.0-0 + + "@babel/plugin-syntax-top-level-await@7.14.5": + resolution: + { + integrity: sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==, + } + engines: { node: ">=6.9.0" } + peerDependencies: + "@babel/core": ^7.0.0-0 + + "@babel/plugin-syntax-typescript@7.24.7": + resolution: + { + integrity: sha512-c/+fVeJBB0FeKsFvwytYiUD+LBvhHjGSI0g446PRGdSVGZLRNArBUno2PETbAly3tpiNAQR5XaZ+JslxkotsbA==, + } + engines: { node: ">=6.9.0" } + peerDependencies: + "@babel/core": ^7.0.0-0 + + "@babel/template@7.24.7": + resolution: + { + integrity: sha512-jYqfPrU9JTF0PmPy1tLYHW4Mp4KlgxJD9l2nP9fD6yT/ICi554DmrWBAEYpIelzjHf1msDP3PxJIRt/nFNfBig==, + } + engines: { node: ">=6.9.0" } + + "@babel/traverse@7.24.7": + resolution: + { + integrity: sha512-yb65Ed5S/QAcewNPh0nZczy9JdYXkkAbIsEo+P7BE7yO3txAY30Y/oPa3QkQ5It3xVG2kpKMg9MsdxZaO31uKA==, + } + engines: { node: ">=6.9.0" } + + "@babel/types@7.24.7": + resolution: + { + integrity: sha512-XEFXSlxiG5td2EJRe8vOmRbaXVgfcBlszKujvVmWIK/UpywWljQCfzAv3RQCGujWQ1RD4YYWEAqDXfuJiy8f5Q==, + } + engines: { node: ">=6.9.0" } + + "@bcoe/v8-coverage@0.2.3": + resolution: + { + integrity: sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==, + } + "@colors/colors@1.6.0": resolution: { @@ -116,6 +416,13 @@ packages: } engines: { node: ">=0.1.90" } + "@cspotcode/source-map-support@0.8.1": + resolution: + { + integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==, + } + engines: { node: ">=12" } + "@dabh/diagnostics@2.0.3": resolution: { @@ -684,6 +991,167 @@ packages: } deprecated: Use @eslint/object-schema instead + "@istanbuljs/load-nyc-config@1.1.0": + resolution: + { + integrity: sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==, + } + engines: { node: ">=8" } + + "@istanbuljs/schema@0.1.3": + resolution: + { + integrity: sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==, + } + engines: { node: ">=8" } + + "@jest/console@29.7.0": + resolution: + { + integrity: sha512-5Ni4CU7XHQi32IJ398EEP4RrB8eV09sXP2ROqD4bksHrnTree52PsxvX8tpL8LvTZ3pFzXyPbNQReSN41CAhOg==, + } + engines: { node: ^14.15.0 || ^16.10.0 || >=18.0.0 } + + "@jest/core@29.7.0": + resolution: + { + integrity: sha512-n7aeXWKMnGtDA48y8TLWJPJmLmmZ642Ceo78cYWEpiD7FzDgmNDV/GCVRorPABdXLJZ/9wzzgZAlHjXjxDHGsg==, + } + engines: { node: ^14.15.0 || ^16.10.0 || >=18.0.0 } + peerDependencies: + node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 + peerDependenciesMeta: + node-notifier: + optional: true + + "@jest/environment@29.7.0": + resolution: + { + integrity: sha512-aQIfHDq33ExsN4jP1NWGXhxgQ/wixs60gDiKO+XVMd8Mn0NWPWgc34ZQDTb2jKaUWQ7MuwoitXAsN2XVXNMpAw==, + } + engines: { node: ^14.15.0 || ^16.10.0 || >=18.0.0 } + + "@jest/expect-utils@29.7.0": + resolution: + { + integrity: sha512-GlsNBWiFQFCVi9QVSx7f5AgMeLxe9YCCs5PuP2O2LdjDAA8Jh9eX7lA1Jq/xdXw3Wb3hyvlFNfZIfcRetSzYcA==, + } + engines: { node: ^14.15.0 || ^16.10.0 || >=18.0.0 } + + "@jest/expect@29.7.0": + resolution: + { + integrity: sha512-8uMeAMycttpva3P1lBHB8VciS9V0XAr3GymPpipdyQXbBcuhkLQOSe8E/p92RyAdToS6ZD1tFkX+CkhoECE0dQ==, + } + engines: { node: ^14.15.0 || ^16.10.0 || >=18.0.0 } + + "@jest/fake-timers@29.7.0": + resolution: + { + integrity: sha512-q4DH1Ha4TTFPdxLsqDXK1d3+ioSL7yL5oCMJZgDYm6i+6CygW5E5xVr/D1HdsGxjt1ZWSfUAs9OxSB/BNelWrQ==, + } + engines: { node: ^14.15.0 || ^16.10.0 || >=18.0.0 } + + "@jest/globals@29.7.0": + resolution: + { + integrity: sha512-mpiz3dutLbkW2MNFubUGUEVLkTGiqW6yLVTA+JbP6fI6J5iL9Y0Nlg8k95pcF8ctKwCS7WVxteBs29hhfAotzQ==, + } + engines: { node: ^14.15.0 || ^16.10.0 || >=18.0.0 } + + "@jest/reporters@29.7.0": + resolution: + { + integrity: sha512-DApq0KJbJOEzAFYjHADNNxAE3KbhxQB1y5Kplb5Waqw6zVbuWatSnMjE5gs8FUgEPmNsnZA3NCWl9NG0ia04Pg==, + } + engines: { node: ^14.15.0 || ^16.10.0 || >=18.0.0 } + peerDependencies: + node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 + peerDependenciesMeta: + node-notifier: + optional: true + + "@jest/schemas@29.6.3": + resolution: + { + integrity: sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==, + } + engines: { node: ^14.15.0 || ^16.10.0 || >=18.0.0 } + + "@jest/source-map@29.6.3": + resolution: + { + integrity: sha512-MHjT95QuipcPrpLM+8JMSzFx6eHp5Bm+4XeFDJlwsvVBjmKNiIAvasGK2fxz2WbGRlnvqehFbh07MMa7n3YJnw==, + } + engines: { node: ^14.15.0 || ^16.10.0 || >=18.0.0 } + + "@jest/test-result@29.7.0": + resolution: + { + integrity: sha512-Fdx+tv6x1zlkJPcWXmMDAG2HBnaR9XPSd5aDWQVsfrZmLVT3lU1cwyxLgRmXR9yrq4NBoEm9BMsfgFzTQAbJYA==, + } + engines: { node: ^14.15.0 || ^16.10.0 || >=18.0.0 } + + "@jest/test-sequencer@29.7.0": + resolution: + { + integrity: sha512-GQwJ5WZVrKnOJuiYiAF52UNUJXgTZx1NHjFSEB0qEMmSZKAkdMoIzw/Cj6x6NF4AvV23AUqDpFzQkN/eYCYTxw==, + } + engines: { node: ^14.15.0 || ^16.10.0 || >=18.0.0 } + + "@jest/transform@29.7.0": + resolution: + { + integrity: sha512-ok/BTPFzFKVMwO5eOHRrvnBVHdRy9IrsrW1GpMaQ9MCnilNLXQKmAX8s1YXDFaai9xJpac2ySzV0YeRRECr2Vw==, + } + engines: { node: ^14.15.0 || ^16.10.0 || >=18.0.0 } + + "@jest/types@29.6.3": + resolution: + { + integrity: sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==, + } + engines: { node: ^14.15.0 || ^16.10.0 || >=18.0.0 } + + "@jridgewell/gen-mapping@0.3.5": + resolution: + { + integrity: sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==, + } + engines: { node: ">=6.0.0" } + + "@jridgewell/resolve-uri@3.1.2": + resolution: + { + integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==, + } + engines: { node: ">=6.0.0" } + + "@jridgewell/set-array@1.2.1": + resolution: + { + integrity: sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==, + } + engines: { node: ">=6.0.0" } + + "@jridgewell/sourcemap-codec@1.4.15": + resolution: + { + integrity: sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==, + } + + "@jridgewell/trace-mapping@0.3.25": + resolution: + { + integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==, + } + + "@jridgewell/trace-mapping@0.3.9": + resolution: + { + integrity: sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==, + } + "@js-sdsl/ordered-map@4.4.2": resolution: { @@ -2156,6 +2624,12 @@ packages: integrity: sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ==, } + "@sinclair/typebox@0.27.8": + resolution: + { + integrity: sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==, + } + "@sindresorhus/is@4.6.0": resolution: { @@ -2163,6 +2637,18 @@ packages: } engines: { node: ">=10" } + "@sinonjs/commons@3.0.1": + resolution: + { + integrity: sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==, + } + + "@sinonjs/fake-timers@10.3.0": + resolution: + { + integrity: sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==, + } + "@swc/cli@0.4.0": resolution: { @@ -2311,6 +2797,30 @@ packages: } engines: { node: ">= 10" } + "@tsconfig/node10@1.0.11": + resolution: + { + integrity: sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==, + } + + "@tsconfig/node12@1.0.11": + resolution: + { + integrity: sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==, + } + + "@tsconfig/node14@1.0.3": + resolution: + { + integrity: sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==, + } + + "@tsconfig/node16@1.0.4": + resolution: + { + integrity: sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==, + } + "@types/accepts@1.3.7": resolution: { @@ -2323,6 +2833,30 @@ packages: integrity: sha512-vBkIh9AY22kVOCEKo5CJlyCgmSWvasC+SWUxL/x/vOwRobMpI/HG1xp/Ae3AqmSiZeLUbOhW0FCD3ZjqqUxmXw==, } + "@types/babel__core@7.20.5": + resolution: + { + integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==, + } + + "@types/babel__generator@7.6.8": + resolution: + { + integrity: sha512-ASsj+tpEDsEiFr1arWrlN6V3mdfjRMZt6LtK/Vp/kreFLnr5QH5+DhvD5nINYZXzwJvXeGq+05iUXcAzVrqWtw==, + } + + "@types/babel__template@7.4.4": + resolution: + { + integrity: sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==, + } + + "@types/babel__traverse@7.20.6": + resolution: + { + integrity: sha512-r1bzfrm0tomOI8g1SzvCaQHo6Lcv6zu0EA+W2kHrt8dyrHQxGzBBL4kdkzIS+jBMV+EYcMAEAqXqYaLJq5rOZg==, + } + "@types/body-parser@1.19.5": resolution: { @@ -2413,6 +2947,12 @@ packages: integrity: sha512-I8cGRJj3pyOLs/HndoP+25vOqhqWkAZsWMEmq1qXy/b/M3ppufecUwaK2/TVDVxcV61/iSdhykUjQQ2DLSrTdg==, } + "@types/graceful-fs@4.1.9": + resolution: + { + integrity: sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ==, + } + "@types/hapi__catbox@10.2.6": resolution: { @@ -2461,6 +3001,30 @@ packages: integrity: sha512-69LyhUgrXdgcNDv7ogs1qXZomnfOEnSmrmMFqKgt1XMJxmoOSG/u3wYy13yACIfKuMJ8IhKgHafDO3sx19zVQQ==, } + "@types/istanbul-lib-coverage@2.0.6": + resolution: + { + integrity: sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==, + } + + "@types/istanbul-lib-report@3.0.3": + resolution: + { + integrity: sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==, + } + + "@types/istanbul-reports@3.0.4": + resolution: + { + integrity: sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==, + } + + "@types/jest@29.5.12": + resolution: + { + integrity: sha512-eDC8bTvT/QhYdxJAulQikueigY5AsdBRH2yDKW3yveW7svY3+DzN84/2NUgkw10RTiJbWqZrTtoGVdYlvFJdLw==, + } + "@types/json-schema@7.0.15": resolution: { @@ -2611,6 +3175,12 @@ packages: integrity: sha512-9Hp0ObzwwO57DpLFF0InUjUm/II8GmKAvzbefxQTihCb7KI6yc9yzf0nLc4mVdby5N4DRCgQM2wCup9KTieeww==, } + "@types/stack-utils@2.0.3": + resolution: + { + integrity: sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==, + } + "@types/tedious@4.0.14": resolution: { @@ -2635,6 +3205,18 @@ packages: integrity: sha512-jg+97EGIcY9AGHJJRaaPVgetKDsrTgbRjQ5Msgjh/DQKEFl0DtyRr/VCOyD1T2R1MNeWPK/u7JoGhlDZnKBAfA==, } + "@types/yargs-parser@21.0.3": + resolution: + { + integrity: sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==, + } + + "@types/yargs@17.0.32": + resolution: + { + integrity: sha512-xQ67Yc/laOG5uMfX/093MRlGGCIBzZMarVa+gfNKJxWAIgykYpVGkBdbqEzGDDfCrVUj6Hiff4mTZ5BA6TmAog==, + } + "@typescript-eslint/eslint-plugin@7.15.0": resolution: { @@ -2753,6 +3335,13 @@ packages: peerDependencies: acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 + acorn-walk@8.3.3: + resolution: + { + integrity: sha512-MxXdReSRhGO7VlFe1bRG/oI7/mdLV9B9JJT0N8vZOhF7gFRR5l3M8W9G8JxmKV+JC5mGqJ0QvqfSOLsCPa4nUw==, + } + engines: { node: ">=0.4.0" } + acorn@8.12.1: resolution: { @@ -2805,6 +3394,13 @@ packages: integrity: sha512-F0twR8U1ZU67JIEtekUcLkXkoO5mMMmgGD8sK/xUFzJ805jxHQl92hImFAqqXMyMYjSPOyUPAwHYhB72g5sTXw==, } + ansi-escapes@4.3.2: + resolution: + { + integrity: sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==, + } + engines: { node: ">=8" } + ansi-regex@5.0.1: resolution: { @@ -2812,6 +3408,13 @@ packages: } engines: { node: ">=8" } + ansi-styles@3.2.1: + resolution: + { + integrity: sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==, + } + engines: { node: ">=4" } + ansi-styles@4.3.0: resolution: { @@ -2839,6 +3442,12 @@ packages: integrity: sha512-Of/R0wqp83cgHozfIYLbBMnej79U/SVGOOyuB3VVFv1NRM/PSFMK12x9KVtiYzJqmnU5WR2qp0Z5rHb7sWGnFQ==, } + arg@4.1.3: + resolution: + { + integrity: sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==, + } + argparse@1.0.10: resolution: { @@ -2895,6 +3504,46 @@ packages: integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==, } + babel-jest@29.7.0: + resolution: + { + integrity: sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg==, + } + engines: { node: ^14.15.0 || ^16.10.0 || >=18.0.0 } + peerDependencies: + "@babel/core": ^7.8.0 + + babel-plugin-istanbul@6.1.1: + resolution: + { + integrity: sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==, + } + engines: { node: ">=8" } + + babel-plugin-jest-hoist@29.6.3: + resolution: + { + integrity: sha512-ESAc/RJvGTFEzRwOTT4+lNDk/GNHMkKbNzsvT0qKRfDyyYTskxB5rnU2njIDYVxXCBHHEI1c0YwHob3WaYujOg==, + } + engines: { node: ^14.15.0 || ^16.10.0 || >=18.0.0 } + + babel-preset-current-node-syntax@1.0.1: + resolution: + { + integrity: sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ==, + } + peerDependencies: + "@babel/core": ^7.0.0 + + babel-preset-jest@29.6.3: + resolution: + { + integrity: sha512-0B3bhxR6snWXJZtR/RliHTDPRgn1sNHOR0yVtq/IiQFyuOVjFS+wuio/R4gSNkyYmKmJB4wGZv2NZanmKmTnNA==, + } + engines: { node: ^14.15.0 || ^16.10.0 || >=18.0.0 } + peerDependencies: + "@babel/core": ^7.0.0 + balanced-match@1.0.2: resolution: { @@ -2979,12 +3628,39 @@ packages: } engines: { node: ">=8" } + browserslist@4.23.1: + resolution: + { + integrity: sha512-TUfofFo/KsK/bWZ9TWQ5O26tsWW4Uhmt8IYklbnUa70udB6P2wA7w7o4PY4muaEPBQaAX+CEnmmIA41NVHtPVw==, + } + engines: { node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7 } + hasBin: true + + bs-logger@0.2.6: + resolution: + { + integrity: sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==, + } + engines: { node: ">= 6" } + + bser@2.1.1: + resolution: + { + integrity: sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==, + } + buffer-equal-constant-time@1.0.1: resolution: { integrity: sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==, } + buffer-from@1.1.2: + resolution: + { + integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==, + } + bytes@3.1.2: resolution: { @@ -3020,6 +3696,13 @@ packages: } engines: { node: ">=6" } + camelcase@5.3.1: + resolution: + { + integrity: sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==, + } + engines: { node: ">=6" } + camelcase@6.3.0: resolution: { @@ -3027,6 +3710,19 @@ packages: } engines: { node: ">=10" } + caniuse-lite@1.0.30001640: + resolution: + { + integrity: sha512-lA4VMpW0PSUrFnkmVuEKBUovSWKhj7puyCg8StBChgu298N1AtuF1sKWEvfDuimSEDbhlb/KqPKC3fs1HbuQUA==, + } + + chalk@2.4.2: + resolution: + { + integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==, + } + engines: { node: ">=4" } + chalk@4.1.2: resolution: { @@ -3034,6 +3730,13 @@ packages: } engines: { node: ">=10" } + char-regex@1.0.2: + resolution: + { + integrity: sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==, + } + engines: { node: ">=10" } + charenc@0.0.2: resolution: { @@ -3065,6 +3768,13 @@ packages: openai: optional: true + ci-info@3.9.0: + resolution: + { + integrity: sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==, + } + engines: { node: ">=8" } + cjs-module-lexer@1.3.1: resolution: { @@ -3084,6 +3794,19 @@ packages: integrity: sha512-ROoL94jJH2dUVML2Y/5PEDNaSHgeOdSDicUyS7izcF63G6sTc/FTjLub4b8Il9S8S0beOfYt0TaA5qvFK+w0wA==, } + co@4.6.0: + resolution: + { + integrity: sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==, + } + engines: { iojs: ">= 1.0.0", node: ">= 0.12.0" } + + collect-v8-coverage@1.0.2: + resolution: + { + integrity: sha512-lHl4d5/ONEbLlJvaJNtsF/Lz+WvB07u2ycqTYbdrq7UypDXailES4valYb2eWiJFxZlVmpGekfqoxQhzyFdT4Q==, + } + color-convert@1.9.3: resolution: { @@ -3174,6 +3897,12 @@ packages: } engines: { node: ">= 0.6" } + convert-source-map@2.0.0: + resolution: + { + integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==, + } + cookie-signature@1.0.6: resolution: { @@ -3194,6 +3923,20 @@ packages: } engines: { node: ">= 0.10" } + create-jest@29.7.0: + resolution: + { + integrity: sha512-Adz2bdH0Vq3F53KEMJOoftQFutWCukm6J24wbPWRO4k1kMY7gS7ds/uoJkNuV8wDCtWWnuwGcJwpWcih+zEW1Q==, + } + engines: { node: ^14.15.0 || ^16.10.0 || >=18.0.0 } + hasBin: true + + create-require@1.1.1: + resolution: + { + integrity: sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==, + } + cross-spawn@5.1.0: resolution: { @@ -3264,12 +4007,30 @@ packages: } engines: { node: ">=10" } + dedent@1.5.3: + resolution: + { + integrity: sha512-NHQtfOOW68WD8lgypbLA5oT+Bt0xXJhiYvoR6SmmNXZfpzOGXwdKWmcwG8N7PwVVWV3eF/68nmD9BaJSsTBhyQ==, + } + peerDependencies: + babel-plugin-macros: ^3.1.0 + peerDependenciesMeta: + babel-plugin-macros: + optional: true + deep-is@0.1.4: resolution: { integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==, } + deepmerge@4.3.1: + resolution: + { + integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==, + } + engines: { node: ">=0.10.0" } + defer-to-connect@2.0.1: resolution: { @@ -3305,6 +4066,27 @@ packages: } engines: { node: ">= 0.8", npm: 1.2.8000 || >= 1.4.16 } + detect-newline@3.1.0: + resolution: + { + integrity: sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==, + } + engines: { node: ">=8" } + + diff-sequences@29.6.3: + resolution: + { + integrity: sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==, + } + engines: { node: ^14.15.0 || ^16.10.0 || >=18.0.0 } + + diff@4.0.2: + resolution: + { + integrity: sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==, + } + engines: { node: ">=0.3.1" } + digest-fetch@1.3.0: resolution: { @@ -3357,6 +4139,19 @@ packages: integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==, } + electron-to-chromium@1.4.816: + resolution: + { + integrity: sha512-EKH5X5oqC6hLmiS7/vYtZHZFTNdhsYG5NVPRN6Yn0kQHNBlT59+xSM8HBy66P5fxWpKgZbPqb+diC64ng295Jw==, + } + + emittery@0.13.1: + resolution: + { + integrity: sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==, + } + engines: { node: ">=12" } + emoji-regex@8.0.0: resolution: { @@ -3382,6 +4177,12 @@ packages: integrity: sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==, } + error-ex@1.3.2: + resolution: + { + integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==, + } + es-define-property@1.0.0: resolution: { @@ -3417,6 +4218,20 @@ packages: integrity: sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==, } + escape-string-regexp@1.0.5: + resolution: + { + integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==, + } + engines: { node: ">=0.8.0" } + + escape-string-regexp@2.0.0: + resolution: + { + integrity: sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==, + } + engines: { node: ">=8" } + escape-string-regexp@4.0.0: resolution: { @@ -3553,6 +4368,20 @@ packages: } engines: { node: ">=4" } + exit@0.1.2: + resolution: + { + integrity: sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==, + } + engines: { node: ">= 0.8.0" } + + expect@29.7.0: + resolution: + { + integrity: sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw==, + } + engines: { node: ^14.15.0 || ^16.10.0 || >=18.0.0 } + expr-eval@2.0.2: resolution: { @@ -3644,6 +4473,12 @@ packages: } engines: { node: ">=0.8.0" } + fb-watchman@2.0.2: + resolution: + { + integrity: sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==, + } + fecha@4.2.3: resolution: { @@ -3699,6 +4534,13 @@ packages: } engines: { node: ">= 0.8" } + find-up@4.1.0: + resolution: + { + integrity: sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==, + } + engines: { node: ">=8" } + find-up@5.0.0: resolution: { @@ -3810,6 +4652,13 @@ packages: integrity: sha512-I8ZuJ/qG92NWX8i5x1Y8qyj3vizhXS31OxjKDu3LKP+7/qBgfIKValiZIEwoVoJKUHlhWtYrktkxV1XsX+pPlg==, } + fs-extra@11.2.0: + resolution: + { + integrity: sha512-PmDi3uwK5nFuXh7XDTlVnS17xJS7vW36is2+w3xcv8SVxiB4NyATf4ctkVY5bkSjX0Y4nbvZCq1/EjtEyr9ktw==, + } + engines: { node: ">=14.14" } + fs.realpath@1.0.0: resolution: { @@ -3885,6 +4734,13 @@ packages: "@genkit-ai/ai": ^0.5.0 "@genkit-ai/core": ^0.5.0 + gensync@1.0.0-beta.2: + resolution: + { + integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==, + } + engines: { node: ">=6.9.0" } + get-caller-file@2.0.5: resolution: { @@ -3899,6 +4755,13 @@ packages: } engines: { node: ">= 0.4" } + get-package-type@0.1.0: + resolution: + { + integrity: sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==, + } + engines: { node: ">=8.0.0" } + get-stream@3.0.0: resolution: { @@ -3947,6 +4810,13 @@ packages: } deprecated: Glob versions prior to v9 are no longer supported + globals@11.12.0: + resolution: + { + integrity: sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==, + } + engines: { node: ">=4" } + globals@13.24.0: resolution: { @@ -4024,6 +4894,12 @@ packages: } engines: { node: ">=10.19.0" } + graceful-fs@4.2.11: + resolution: + { + integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==, + } + graphemer@1.4.0: resolution: { @@ -4099,6 +4975,12 @@ packages: integrity: sha512-K//PSRMQk4FZ78Kyau+mZurHn3FH0Vwr+H36eE0rPbeYkRRi9YxceYPhuN60UwWorxyKHhqoAJl2OFKa4BVtaA==, } + html-escaper@2.0.2: + resolution: + { + integrity: sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==, + } + http-cache-semantics@4.1.1: resolution: { @@ -4198,6 +5080,14 @@ packages: integrity: sha512-1LrZPDtW+atAxH42S6288qyDFNQ2YCty+2mxEPRtfazH6Z5QwkaBSTS2ods7hnVJioF6rkRfNoA6A/MstpFXLg==, } + import-local@3.1.0: + resolution: + { + integrity: sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==, + } + engines: { node: ">=8" } + hasBin: true + imurmurhash@0.1.4: resolution: { @@ -4231,6 +5121,12 @@ packages: integrity: sha512-UtilS7hLRu++wb/WBAw9bNuP1Eg04Ivn1vERJck8zJthEvXCBEBpGR/33u/xLKWEQf95803oalHrVDptcAvFdQ==, } + is-arrayish@0.2.1: + resolution: + { + integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==, + } + is-arrayish@0.3.2: resolution: { @@ -4271,6 +5167,13 @@ packages: } engines: { node: ">=8" } + is-generator-fn@2.1.0: + resolution: + { + integrity: sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==, + } + engines: { node: ">=6" } + is-glob@4.0.3: resolution: { @@ -4295,42 +5198,291 @@ packages: is-path-inside@3.0.3: resolution: { - integrity: sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==, + integrity: sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==, + } + engines: { node: ">=8" } + + is-plain-obj@1.1.0: + resolution: + { + integrity: sha512-yvkRyxmFKEOQ4pNXCmJG5AEQNlXJS5LaONXo5/cLdTZdWvsZ1ioJEonLGAosKlMWE8lwUy/bJzMjcw8az73+Fg==, + } + engines: { node: ">=0.10.0" } + + is-stream@1.1.0: + resolution: + { + integrity: sha512-uQPm8kcs47jx38atAcWTVxyltQYoPT68y9aWYdV6yWXSyW8mzSat0TL6CiWdZeCdF3KrAvpVtnHbTv4RN+rqdQ==, + } + engines: { node: ">=0.10.0" } + + is-stream@2.0.1: + resolution: + { + integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==, + } + engines: { node: ">=8" } + + isexe@2.0.0: + resolution: + { + integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==, + } + + isomorphic-fetch@3.0.0: + resolution: + { + integrity: sha512-qvUtwJ3j6qwsF3jLxkZ72qCgjMysPzDfeV240JHiGZsANBYd+EEuu35v7dfrJ9Up0Ak07D7GGSkGhCHTqg/5wA==, + } + + istanbul-lib-coverage@3.2.2: + resolution: + { + integrity: sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==, + } + engines: { node: ">=8" } + + istanbul-lib-instrument@5.2.1: + resolution: + { + integrity: sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==, + } + engines: { node: ">=8" } + + istanbul-lib-instrument@6.0.3: + resolution: + { + integrity: sha512-Vtgk7L/R2JHyyGW07spoFlB8/lpjiOLTjMdms6AFMraYt3BaJauod/NGrfnVG/y4Ix1JEuMRPDPEj2ua+zz1/Q==, + } + engines: { node: ">=10" } + + istanbul-lib-report@3.0.1: + resolution: + { + integrity: sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==, + } + engines: { node: ">=10" } + + istanbul-lib-source-maps@4.0.1: + resolution: + { + integrity: sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==, + } + engines: { node: ">=10" } + + istanbul-reports@3.1.7: + resolution: + { + integrity: sha512-BewmUXImeuRk2YY0PVbxgKAysvhRPUQE0h5QRM++nVWyubKGV0l8qQ5op8+B2DOmwSe63Jivj0BjkPQVf8fP5g==, + } + engines: { node: ">=8" } + + jest-changed-files@29.7.0: + resolution: + { + integrity: sha512-fEArFiwf1BpQ+4bXSprcDc3/x4HSzL4al2tozwVpDFpsxALjLYdyiIK4e5Vz66GQJIbXJ82+35PtysofptNX2w==, + } + engines: { node: ^14.15.0 || ^16.10.0 || >=18.0.0 } + + jest-circus@29.7.0: + resolution: + { + integrity: sha512-3E1nCMgipcTkCocFwM90XXQab9bS+GMsjdpmPrlelaxwD93Ad8iVEjX/vvHPdLPnFf+L40u+5+iutRdA1N9myw==, + } + engines: { node: ^14.15.0 || ^16.10.0 || >=18.0.0 } + + jest-cli@29.7.0: + resolution: + { + integrity: sha512-OVVobw2IubN/GSYsxETi+gOe7Ka59EFMR/twOU3Jb2GnKKeMGJB5SGUUrEz3SFVmJASUdZUzy83sLNNQ2gZslg==, + } + engines: { node: ^14.15.0 || ^16.10.0 || >=18.0.0 } + hasBin: true + peerDependencies: + node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 + peerDependenciesMeta: + node-notifier: + optional: true + + jest-config@29.7.0: + resolution: + { + integrity: sha512-uXbpfeQ7R6TZBqI3/TxCU4q4ttk3u0PJeC+E0zbfSoSjq6bJ7buBPxzQPL0ifrkY4DNu4JUdk0ImlBUYi840eQ==, + } + engines: { node: ^14.15.0 || ^16.10.0 || >=18.0.0 } + peerDependencies: + "@types/node": "*" + ts-node: ">=9.0.0" + peerDependenciesMeta: + "@types/node": + optional: true + ts-node: + optional: true + + jest-diff@29.7.0: + resolution: + { + integrity: sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==, + } + engines: { node: ^14.15.0 || ^16.10.0 || >=18.0.0 } + + jest-docblock@29.7.0: + resolution: + { + integrity: sha512-q617Auw3A612guyaFgsbFeYpNP5t2aoUNLwBUbc/0kD1R4t9ixDbyFTHd1nok4epoVFpr7PmeWHrhvuV3XaJ4g==, + } + engines: { node: ^14.15.0 || ^16.10.0 || >=18.0.0 } + + jest-each@29.7.0: + resolution: + { + integrity: sha512-gns+Er14+ZrEoC5fhOfYCY1LOHHr0TI+rQUHZS8Ttw2l7gl+80eHc/gFf2Ktkw0+SIACDTeWvpFcv3B04VembQ==, + } + engines: { node: ^14.15.0 || ^16.10.0 || >=18.0.0 } + + jest-environment-node@29.7.0: + resolution: + { + integrity: sha512-DOSwCRqXirTOyheM+4d5YZOrWcdu0LNZ87ewUoywbcb2XR4wKgqiG8vNeYwhjFMbEkfju7wx2GYH0P2gevGvFw==, + } + engines: { node: ^14.15.0 || ^16.10.0 || >=18.0.0 } + + jest-get-type@29.6.3: + resolution: + { + integrity: sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==, + } + engines: { node: ^14.15.0 || ^16.10.0 || >=18.0.0 } + + jest-haste-map@29.7.0: + resolution: + { + integrity: sha512-fP8u2pyfqx0K1rGn1R9pyE0/KTn+G7PxktWidOBTqFPLYX0b9ksaMFkhK5vrS3DVun09pckLdlx90QthlW7AmA==, + } + engines: { node: ^14.15.0 || ^16.10.0 || >=18.0.0 } + + jest-leak-detector@29.7.0: + resolution: + { + integrity: sha512-kYA8IJcSYtST2BY9I+SMC32nDpBT3J2NvWJx8+JCuCdl/CR1I4EKUJROiP8XtCcxqgTTBGJNdbB1A8XRKbTetw==, + } + engines: { node: ^14.15.0 || ^16.10.0 || >=18.0.0 } + + jest-matcher-utils@29.7.0: + resolution: + { + integrity: sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g==, + } + engines: { node: ^14.15.0 || ^16.10.0 || >=18.0.0 } + + jest-message-util@29.7.0: + resolution: + { + integrity: sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w==, + } + engines: { node: ^14.15.0 || ^16.10.0 || >=18.0.0 } + + jest-mock@29.7.0: + resolution: + { + integrity: sha512-ITOMZn+UkYS4ZFh83xYAOzWStloNzJFO2s8DWrE4lhtGD+AorgnbkiKERe4wQVBydIGPx059g6riW5Btp6Llnw==, + } + engines: { node: ^14.15.0 || ^16.10.0 || >=18.0.0 } + + jest-pnp-resolver@1.2.3: + resolution: + { + integrity: sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==, + } + engines: { node: ">=6" } + peerDependencies: + jest-resolve: "*" + peerDependenciesMeta: + jest-resolve: + optional: true + + jest-regex-util@29.6.3: + resolution: + { + integrity: sha512-KJJBsRCyyLNWCNBOvZyRDnAIfUiRJ8v+hOBQYGn8gDyF3UegwiP4gwRR3/SDa42g1YbVycTidUF3rKjyLFDWbg==, + } + engines: { node: ^14.15.0 || ^16.10.0 || >=18.0.0 } + + jest-resolve-dependencies@29.7.0: + resolution: + { + integrity: sha512-un0zD/6qxJ+S0et7WxeI3H5XSe9lTBBR7bOHCHXkKR6luG5mwDDlIzVQ0V5cZCuoTgEdcdwzTghYkTWfubi+nA==, + } + engines: { node: ^14.15.0 || ^16.10.0 || >=18.0.0 } + + jest-resolve@29.7.0: + resolution: + { + integrity: sha512-IOVhZSrg+UvVAshDSDtHyFCCBUl/Q3AAJv8iZ6ZjnZ74xzvwuzLXid9IIIPgTnY62SJjfuupMKZsZQRsCvxEgA==, + } + engines: { node: ^14.15.0 || ^16.10.0 || >=18.0.0 } + + jest-runner@29.7.0: + resolution: + { + integrity: sha512-fsc4N6cPCAahybGBfTRcq5wFR6fpLznMg47sY5aDpsoejOcVYFb07AHuSnR0liMcPTgBsA3ZJL6kFOjPdoNipQ==, + } + engines: { node: ^14.15.0 || ^16.10.0 || >=18.0.0 } + + jest-runtime@29.7.0: + resolution: + { + integrity: sha512-gUnLjgwdGqW7B4LvOIkbKs9WGbn+QLqRQQ9juC6HndeDiezIwhDP+mhMwHWCEcfQ5RUXa6OPnFF8BJh5xegwwQ==, + } + engines: { node: ^14.15.0 || ^16.10.0 || >=18.0.0 } + + jest-snapshot@29.7.0: + resolution: + { + integrity: sha512-Rm0BMWtxBcioHr1/OX5YCP8Uov4riHvKPknOGs804Zg9JGZgmIBkbtlxJC/7Z4msKYVbIJtfU+tKb8xlYNfdkw==, } - engines: { node: ">=8" } + engines: { node: ^14.15.0 || ^16.10.0 || >=18.0.0 } - is-plain-obj@1.1.0: + jest-util@29.7.0: resolution: { - integrity: sha512-yvkRyxmFKEOQ4pNXCmJG5AEQNlXJS5LaONXo5/cLdTZdWvsZ1ioJEonLGAosKlMWE8lwUy/bJzMjcw8az73+Fg==, + integrity: sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==, } - engines: { node: ">=0.10.0" } + engines: { node: ^14.15.0 || ^16.10.0 || >=18.0.0 } - is-stream@1.1.0: + jest-validate@29.7.0: resolution: { - integrity: sha512-uQPm8kcs47jx38atAcWTVxyltQYoPT68y9aWYdV6yWXSyW8mzSat0TL6CiWdZeCdF3KrAvpVtnHbTv4RN+rqdQ==, + integrity: sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw==, } - engines: { node: ">=0.10.0" } + engines: { node: ^14.15.0 || ^16.10.0 || >=18.0.0 } - is-stream@2.0.1: + jest-watcher@29.7.0: resolution: { - integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==, + integrity: sha512-49Fg7WXkU3Vl2h6LbLtMQ/HyB6rXSIX7SqvBLQmssRBGN9I0PNvPmAmCWSOY6SOvrjhI/F7/bGAv9RtnsPA03g==, } - engines: { node: ">=8" } + engines: { node: ^14.15.0 || ^16.10.0 || >=18.0.0 } - isexe@2.0.0: + jest-worker@29.7.0: resolution: { - integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==, + integrity: sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==, } + engines: { node: ^14.15.0 || ^16.10.0 || >=18.0.0 } - isomorphic-fetch@3.0.0: + jest@29.7.0: resolution: { - integrity: sha512-qvUtwJ3j6qwsF3jLxkZ72qCgjMysPzDfeV240JHiGZsANBYd+EEuu35v7dfrJ9Up0Ak07D7GGSkGhCHTqg/5wA==, + integrity: sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw==, } + engines: { node: ^14.15.0 || ^16.10.0 || >=18.0.0 } + hasBin: true + peerDependencies: + node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 + peerDependenciesMeta: + node-notifier: + optional: true joi@17.13.3: resolution: @@ -4350,6 +5502,12 @@ packages: integrity: sha512-L7wURW1fH9Qaext0VzaUDpFGVQgjkdE3Dgsy9/+yXyGEpBKnylTd0mU0bfbNkKDlXRb6TEsZkwuflu1B8uQbJQ==, } + js-tokens@4.0.0: + resolution: + { + integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==, + } + js-yaml@3.14.1: resolution: { @@ -4364,6 +5522,14 @@ packages: } hasBin: true + jsesc@2.5.2: + resolution: + { + integrity: sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==, + } + engines: { node: ">=4" } + hasBin: true + json-bigint@1.0.0: resolution: { @@ -4376,6 +5542,12 @@ packages: integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==, } + json-parse-even-better-errors@2.3.1: + resolution: + { + integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==, + } + json-schema-traverse@0.4.1: resolution: { @@ -4408,6 +5580,12 @@ packages: engines: { node: ">=6" } hasBin: true + jsonfile@6.1.0: + resolution: + { + integrity: sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==, + } + jsonpointer@5.0.1: resolution: { @@ -4459,6 +5637,13 @@ packages: integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==, } + kleur@3.0.3: + resolution: + { + integrity: sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==, + } + engines: { node: ">=6" } + kuler@2.0.0: resolution: { @@ -4974,6 +6159,13 @@ packages: openai: optional: true + leven@3.1.0: + resolution: + { + integrity: sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==, + } + engines: { node: ">=6" } + levn@0.4.1: resolution: { @@ -4987,6 +6179,19 @@ packages: integrity: sha512-FWWMIEOxz3GwUI4Ts/IvgVy6LPvoMPgjMdQ185nN6psJyBJ4yOpzqm695/h5umdLJg2vW3GR5iG11MAkR2AzJA==, } + lines-and-columns@1.2.4: + resolution: + { + integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==, + } + + locate-path@5.0.0: + resolution: + { + integrity: sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==, + } + engines: { node: ">=8" } + locate-path@6.0.0: resolution: { @@ -5048,6 +6253,12 @@ packages: integrity: sha512-JPFqXFeZQ7BfS00H58kClY7SPVeHertPE0lNuCyZ26/XlN8TvakYD7b9bGyNmXbT/D3BbtPAAmq90gPWqLkxlQ==, } + lodash.memoize@4.1.2: + resolution: + { + integrity: sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==, + } + lodash.merge@4.6.2: resolution: { @@ -5086,6 +6297,12 @@ packages: integrity: sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==, } + lru-cache@5.1.1: + resolution: + { + integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==, + } + lru-cache@6.0.0: resolution: { @@ -5099,6 +6316,25 @@ packages: integrity: sha512-GXn7gyHAMhO13WSKrIiNfztwxodVsP8IoZ3XfrJV4yH2x0/OeTO/FIaAHTY5YekdGgW94njfuKmyyt1E0mR6Ug==, } + make-dir@4.0.0: + resolution: + { + integrity: sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==, + } + engines: { node: ">=10" } + + make-error@1.3.6: + resolution: + { + integrity: sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==, + } + + makeerror@1.0.12: + resolution: + { + integrity: sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==, + } + md5@2.3.0: resolution: { @@ -5348,6 +6584,18 @@ packages: } hasBin: true + node-int64@0.4.0: + resolution: + { + integrity: sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==, + } + + node-releases@2.0.14: + resolution: + { + integrity: sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==, + } + nodemon@3.1.4: resolution: { @@ -5479,6 +6727,13 @@ packages: } engines: { node: ">=4" } + p-limit@2.3.0: + resolution: + { + integrity: sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==, + } + engines: { node: ">=6" } + p-limit@3.1.0: resolution: { @@ -5486,6 +6741,13 @@ packages: } engines: { node: ">=10" } + p-locate@4.1.0: + resolution: + { + integrity: sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==, + } + engines: { node: ">=8" } + p-locate@5.0.0: resolution: { @@ -5514,6 +6776,13 @@ packages: } engines: { node: ">=8" } + p-try@2.2.0: + resolution: + { + integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==, + } + engines: { node: ">=6" } + parent-module@1.0.1: resolution: { @@ -5521,6 +6790,13 @@ packages: } engines: { node: ">=6" } + parse-json@5.2.0: + resolution: + { + integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==, + } + engines: { node: ">=8" } + parseurl@1.3.3: resolution: { @@ -5602,6 +6878,12 @@ packages: } engines: { node: ">=4" } + picocolors@1.0.1: + resolution: + { + integrity: sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==, + } + picomatch@2.3.1: resolution: { @@ -5616,12 +6898,26 @@ packages: } engines: { node: ">=0.10.0" } + pirates@4.0.6: + resolution: + { + integrity: sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==, + } + engines: { node: ">= 6" } + piscina@4.6.1: resolution: { integrity: sha512-z30AwWGtQE+Apr+2WBZensP2lIvwoaMcOPkQlIEmSGMJNUvaYACylPYrQM6wSdUNJlnDVMSpLv7xTMJqlVshOA==, } + pkg-dir@4.2.0: + resolution: + { + integrity: sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==, + } + engines: { node: ">=8" } + postgres-array@2.0.0: resolution: { @@ -5681,6 +6977,20 @@ packages: engines: { node: ">=14" } hasBin: true + pretty-format@29.7.0: + resolution: + { + integrity: sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==, + } + engines: { node: ^14.15.0 || ^16.10.0 || >=18.0.0 } + + prompts@2.4.2: + resolution: + { + integrity: sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==, + } + engines: { node: ">= 6" } + proto3-json-serializer@2.0.2: resolution: { @@ -5733,6 +7043,12 @@ packages: } engines: { node: ">=6" } + pure-rand@6.1.0: + resolution: + { + integrity: sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA==, + } + qs@6.11.0: resolution: { @@ -5774,6 +7090,12 @@ packages: } engines: { node: ">= 0.8" } + react-is@18.3.1: + resolution: + { + integrity: sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==, + } + readable-stream@3.6.2: resolution: { @@ -5822,6 +7144,13 @@ packages: integrity: sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==, } + resolve-cwd@3.0.0: + resolution: + { + integrity: sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==, + } + engines: { node: ">=8" } + resolve-from@4.0.0: resolution: { @@ -5829,12 +7158,26 @@ packages: } engines: { node: ">=4" } + resolve-from@5.0.0: + resolution: + { + integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==, + } + engines: { node: ">=8" } + resolve-pkg-maps@1.0.0: resolution: { integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==, } + resolve.exports@2.0.2: + resolution: + { + integrity: sha512-X2UW6Nw3n/aMgDVy+0rSqgHlv39WZAlZrXCdnbyEiKm17DSqHX4MmQMaST3FbeWR5FTuRcUwYAziZajji0Y7mg==, + } + engines: { node: ">=10" } + resolve@1.22.8: resolution: { @@ -5922,6 +7265,13 @@ packages: } engines: { node: ">=12" } + semver@6.3.1: + resolution: + { + integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==, + } + hasBin: true + semver@7.6.2: resolution: { @@ -6017,6 +7367,12 @@ packages: } engines: { node: ">=10" } + sisteransi@1.0.5: + resolution: + { + integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==, + } + slash@3.0.0: resolution: { @@ -6038,6 +7394,12 @@ packages: } engines: { node: ">=0.10.0" } + source-map-support@0.5.13: + resolution: + { + integrity: sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==, + } + source-map@0.6.1: resolution: { @@ -6064,6 +7426,13 @@ packages: integrity: sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg==, } + stack-utils@2.0.6: + resolution: + { + integrity: sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==, + } + engines: { node: ">=10" } + statuses@2.0.1: resolution: { @@ -6083,6 +7452,13 @@ packages: integrity: sha512-76ORR0DO1o1hlKwTbi/DM3EXWGf3ZJYO8cXX5RJwnul2DEg2oyoZyjLNoQM8WsvZiFKCRfC1O0J7iCvie3RZmQ==, } + string-length@4.0.2: + resolution: + { + integrity: sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==, + } + engines: { node: ">=10" } + string-width@4.2.3: resolution: { @@ -6103,6 +7479,13 @@ packages: } engines: { node: ">=8" } + strip-bom@4.0.0: + resolution: + { + integrity: sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==, + } + engines: { node: ">=8" } + strip-eof@1.0.0: resolution: { @@ -6164,6 +7547,13 @@ packages: } engines: { node: ">=8" } + supports-color@8.1.1: + resolution: + { + integrity: sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==, + } + engines: { node: ">=10" } + supports-preserve-symlinks-flag@1.0.0: resolution: { @@ -6178,6 +7568,13 @@ packages: } engines: { node: ">=14" } + test-exclude@6.0.0: + resolution: + { + integrity: sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==, + } + engines: { node: ">=8" } + text-hex@1.0.0: resolution: { @@ -6190,6 +7587,19 @@ packages: integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==, } + tmpl@1.0.5: + resolution: + { + integrity: sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==, + } + + to-fast-properties@2.0.0: + resolution: + { + integrity: sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==, + } + engines: { node: ">=4" } + to-regex-range@5.0.1: resolution: { @@ -6247,6 +7657,33 @@ packages: peerDependencies: typescript: ">=4.2.0" + ts-jest@29.1.5: + resolution: + { + integrity: sha512-UuClSYxM7byvvYfyWdFI+/2UxMmwNyJb0NPkZPQE2hew3RurV7l7zURgOHAd/1I1ZdPpe3GUsXNXAcN8TFKSIg==, + } + engines: { node: ^14.15.0 || ^16.10.0 || ^18.0.0 || >=20.0.0 } + hasBin: true + peerDependencies: + "@babel/core": ">=7.0.0-beta.0 <8" + "@jest/transform": ^29.0.0 + "@jest/types": ^29.0.0 + babel-jest: ^29.0.0 + esbuild: "*" + jest: ^29.0.0 + typescript: ">=4.3 <6" + peerDependenciesMeta: + "@babel/core": + optional: true + "@jest/transform": + optional: true + "@jest/types": + optional: true + babel-jest: + optional: true + esbuild: + optional: true + ts-md5@1.3.1: resolution: { @@ -6254,6 +7691,23 @@ packages: } engines: { node: ">=12" } + ts-node@10.9.2: + resolution: + { + integrity: sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==, + } + hasBin: true + peerDependencies: + "@swc/core": ">=1.2.50" + "@swc/wasm": ">=1.2.50" + "@types/node": "*" + typescript: ">=2.7" + peerDependenciesMeta: + "@swc/core": + optional: true + "@swc/wasm": + optional: true + tslib@2.6.3: resolution: { @@ -6275,6 +7729,13 @@ packages: } engines: { node: ">= 0.8.0" } + type-detect@4.0.8: + resolution: + { + integrity: sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==, + } + engines: { node: ">=4" } + type-fest@0.20.2: resolution: { @@ -6282,6 +7743,13 @@ packages: } engines: { node: ">=10" } + type-fest@0.21.3: + resolution: + { + integrity: sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==, + } + engines: { node: ">=10" } + type-is@1.6.18: resolution: { @@ -6330,6 +7798,13 @@ packages: integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==, } + universalify@2.0.1: + resolution: + { + integrity: sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==, + } + engines: { node: ">= 10.0.0" } + unpipe@1.0.0: resolution: { @@ -6337,6 +7812,15 @@ packages: } engines: { node: ">= 0.8" } + update-browserslist-db@1.1.0: + resolution: + { + integrity: sha512-EdRAaAyk2cUE1wOf2DkEhzxqOQvFOoRJFNS6NeyJ01Gp2beMRpBAINjM2iDXE3KCuKhwnvHIQCJm6ThL2Z+HzQ==, + } + hasBin: true + peerDependencies: + browserslist: ">= 4.21.0" + uri-js@4.4.1: resolution: { @@ -6383,6 +7867,19 @@ packages: } hasBin: true + v8-compile-cache-lib@3.0.1: + resolution: + { + integrity: sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==, + } + + v8-to-istanbul@9.3.0: + resolution: + { + integrity: sha512-kiGUalWN+rgBJ/1OHZsBtU4rXZOfj/7rKQxULKlIzwzQSvMJUUNgPwJEEh7gU6xEVxC0ahoOBvN2YI8GH6FNgA==, + } + engines: { node: ">=10.12.0" } + vary@1.1.2: resolution: { @@ -6397,6 +7894,12 @@ packages: } engines: { node: ">=6.0.0" } + walker@1.0.8: + resolution: + { + integrity: sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==, + } + web-streams-polyfill@3.3.3: resolution: { @@ -6495,8 +7998,15 @@ packages: wrappy@1.0.2: resolution: { - integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==, + integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==, + } + + write-file-atomic@4.0.2: + resolution: + { + integrity: sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==, } + engines: { node: ^12.13.0 || ^14.15.0 || >=16.0.0 } xtend@4.0.2: resolution: @@ -6518,6 +8028,12 @@ packages: integrity: sha512-ncTzHV7NvsQZkYe1DW7cbDLm0YpzHmZF5r/iyP3ZnQtMiJ+pjzisCiMNI+Sj+xQF5pXhSHxSB3uDbsBTzY/c2A==, } + yallist@3.1.1: + resolution: + { + integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==, + } + yallist@4.0.0: resolution: { @@ -6546,6 +8062,13 @@ packages: } engines: { node: ">=12" } + yn@3.1.1: + resolution: + { + integrity: sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==, + } + engines: { node: ">=6" } + yocto-queue@0.1.0: resolution: { @@ -6568,6 +8091,11 @@ packages: } snapshots: + "@ampproject/remapping@2.3.0": + dependencies: + "@jridgewell/gen-mapping": 0.3.5 + "@jridgewell/trace-mapping": 0.3.25 + "@anthropic-ai/sdk@0.9.1": dependencies: "@types/node": 18.19.39 @@ -6582,8 +8110,219 @@ snapshots: transitivePeerDependencies: - encoding + "@babel/code-frame@7.24.7": + dependencies: + "@babel/highlight": 7.24.7 + picocolors: 1.0.1 + + "@babel/compat-data@7.24.7": {} + + "@babel/core@7.24.7": + dependencies: + "@ampproject/remapping": 2.3.0 + "@babel/code-frame": 7.24.7 + "@babel/generator": 7.24.7 + "@babel/helper-compilation-targets": 7.24.7 + "@babel/helper-module-transforms": 7.24.7(@babel/core@7.24.7) + "@babel/helpers": 7.24.7 + "@babel/parser": 7.24.7 + "@babel/template": 7.24.7 + "@babel/traverse": 7.24.7 + "@babel/types": 7.24.7 + convert-source-map: 2.0.0 + debug: 4.3.5(supports-color@5.5.0) + gensync: 1.0.0-beta.2 + json5: 2.2.3 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + + "@babel/generator@7.24.7": + dependencies: + "@babel/types": 7.24.7 + "@jridgewell/gen-mapping": 0.3.5 + "@jridgewell/trace-mapping": 0.3.25 + jsesc: 2.5.2 + + "@babel/helper-compilation-targets@7.24.7": + dependencies: + "@babel/compat-data": 7.24.7 + "@babel/helper-validator-option": 7.24.7 + browserslist: 4.23.1 + lru-cache: 5.1.1 + semver: 6.3.1 + + "@babel/helper-environment-visitor@7.24.7": + dependencies: + "@babel/types": 7.24.7 + + "@babel/helper-function-name@7.24.7": + dependencies: + "@babel/template": 7.24.7 + "@babel/types": 7.24.7 + + "@babel/helper-hoist-variables@7.24.7": + dependencies: + "@babel/types": 7.24.7 + + "@babel/helper-module-imports@7.24.7": + dependencies: + "@babel/traverse": 7.24.7 + "@babel/types": 7.24.7 + transitivePeerDependencies: + - supports-color + + "@babel/helper-module-transforms@7.24.7(@babel/core@7.24.7)": + dependencies: + "@babel/core": 7.24.7 + "@babel/helper-environment-visitor": 7.24.7 + "@babel/helper-module-imports": 7.24.7 + "@babel/helper-simple-access": 7.24.7 + "@babel/helper-split-export-declaration": 7.24.7 + "@babel/helper-validator-identifier": 7.24.7 + transitivePeerDependencies: + - supports-color + + "@babel/helper-plugin-utils@7.24.7": {} + + "@babel/helper-simple-access@7.24.7": + dependencies: + "@babel/traverse": 7.24.7 + "@babel/types": 7.24.7 + transitivePeerDependencies: + - supports-color + + "@babel/helper-split-export-declaration@7.24.7": + dependencies: + "@babel/types": 7.24.7 + + "@babel/helper-string-parser@7.24.7": {} + + "@babel/helper-validator-identifier@7.24.7": {} + + "@babel/helper-validator-option@7.24.7": {} + + "@babel/helpers@7.24.7": + dependencies: + "@babel/template": 7.24.7 + "@babel/types": 7.24.7 + + "@babel/highlight@7.24.7": + dependencies: + "@babel/helper-validator-identifier": 7.24.7 + chalk: 2.4.2 + js-tokens: 4.0.0 + picocolors: 1.0.1 + + "@babel/parser@7.24.7": + dependencies: + "@babel/types": 7.24.7 + + "@babel/plugin-syntax-async-generators@7.8.4(@babel/core@7.24.7)": + dependencies: + "@babel/core": 7.24.7 + "@babel/helper-plugin-utils": 7.24.7 + + "@babel/plugin-syntax-bigint@7.8.3(@babel/core@7.24.7)": + dependencies: + "@babel/core": 7.24.7 + "@babel/helper-plugin-utils": 7.24.7 + + "@babel/plugin-syntax-class-properties@7.12.13(@babel/core@7.24.7)": + dependencies: + "@babel/core": 7.24.7 + "@babel/helper-plugin-utils": 7.24.7 + + "@babel/plugin-syntax-import-meta@7.10.4(@babel/core@7.24.7)": + dependencies: + "@babel/core": 7.24.7 + "@babel/helper-plugin-utils": 7.24.7 + + "@babel/plugin-syntax-json-strings@7.8.3(@babel/core@7.24.7)": + dependencies: + "@babel/core": 7.24.7 + "@babel/helper-plugin-utils": 7.24.7 + + "@babel/plugin-syntax-jsx@7.24.7(@babel/core@7.24.7)": + dependencies: + "@babel/core": 7.24.7 + "@babel/helper-plugin-utils": 7.24.7 + + "@babel/plugin-syntax-logical-assignment-operators@7.10.4(@babel/core@7.24.7)": + dependencies: + "@babel/core": 7.24.7 + "@babel/helper-plugin-utils": 7.24.7 + + "@babel/plugin-syntax-nullish-coalescing-operator@7.8.3(@babel/core@7.24.7)": + dependencies: + "@babel/core": 7.24.7 + "@babel/helper-plugin-utils": 7.24.7 + + "@babel/plugin-syntax-numeric-separator@7.10.4(@babel/core@7.24.7)": + dependencies: + "@babel/core": 7.24.7 + "@babel/helper-plugin-utils": 7.24.7 + + "@babel/plugin-syntax-object-rest-spread@7.8.3(@babel/core@7.24.7)": + dependencies: + "@babel/core": 7.24.7 + "@babel/helper-plugin-utils": 7.24.7 + + "@babel/plugin-syntax-optional-catch-binding@7.8.3(@babel/core@7.24.7)": + dependencies: + "@babel/core": 7.24.7 + "@babel/helper-plugin-utils": 7.24.7 + + "@babel/plugin-syntax-optional-chaining@7.8.3(@babel/core@7.24.7)": + dependencies: + "@babel/core": 7.24.7 + "@babel/helper-plugin-utils": 7.24.7 + + "@babel/plugin-syntax-top-level-await@7.14.5(@babel/core@7.24.7)": + dependencies: + "@babel/core": 7.24.7 + "@babel/helper-plugin-utils": 7.24.7 + + "@babel/plugin-syntax-typescript@7.24.7(@babel/core@7.24.7)": + dependencies: + "@babel/core": 7.24.7 + "@babel/helper-plugin-utils": 7.24.7 + + "@babel/template@7.24.7": + dependencies: + "@babel/code-frame": 7.24.7 + "@babel/parser": 7.24.7 + "@babel/types": 7.24.7 + + "@babel/traverse@7.24.7": + dependencies: + "@babel/code-frame": 7.24.7 + "@babel/generator": 7.24.7 + "@babel/helper-environment-visitor": 7.24.7 + "@babel/helper-function-name": 7.24.7 + "@babel/helper-hoist-variables": 7.24.7 + "@babel/helper-split-export-declaration": 7.24.7 + "@babel/parser": 7.24.7 + "@babel/types": 7.24.7 + debug: 4.3.5(supports-color@5.5.0) + globals: 11.12.0 + transitivePeerDependencies: + - supports-color + + "@babel/types@7.24.7": + dependencies: + "@babel/helper-string-parser": 7.24.7 + "@babel/helper-validator-identifier": 7.24.7 + to-fast-properties: 2.0.0 + + "@bcoe/v8-coverage@0.2.3": {} + "@colors/colors@1.6.0": {} + "@cspotcode/source-map-support@0.8.1": + dependencies: + "@jridgewell/trace-mapping": 0.3.9 + "@dabh/diagnostics@2.0.3": dependencies: colorspace: 1.1.4 @@ -7046,6 +8785,200 @@ snapshots: "@humanwhocodes/object-schema@2.0.3": {} + "@istanbuljs/load-nyc-config@1.1.0": + dependencies: + camelcase: 5.3.1 + find-up: 4.1.0 + get-package-type: 0.1.0 + js-yaml: 3.14.1 + resolve-from: 5.0.0 + + "@istanbuljs/schema@0.1.3": {} + + "@jest/console@29.7.0": + dependencies: + "@jest/types": 29.6.3 + "@types/node": 20.14.9 + chalk: 4.1.2 + jest-message-util: 29.7.0 + jest-util: 29.7.0 + slash: 3.0.0 + + "@jest/core@29.7.0(ts-node@10.9.2(@swc/core@1.6.7)(@types/node@20.14.9)(typescript@5.5.3))": + dependencies: + "@jest/console": 29.7.0 + "@jest/reporters": 29.7.0 + "@jest/test-result": 29.7.0 + "@jest/transform": 29.7.0 + "@jest/types": 29.6.3 + "@types/node": 20.14.9 + ansi-escapes: 4.3.2 + chalk: 4.1.2 + ci-info: 3.9.0 + exit: 0.1.2 + graceful-fs: 4.2.11 + jest-changed-files: 29.7.0 + jest-config: 29.7.0(@types/node@20.14.9)(ts-node@10.9.2(@swc/core@1.6.7)(@types/node@20.14.9)(typescript@5.5.3)) + jest-haste-map: 29.7.0 + jest-message-util: 29.7.0 + jest-regex-util: 29.6.3 + jest-resolve: 29.7.0 + jest-resolve-dependencies: 29.7.0 + jest-runner: 29.7.0 + jest-runtime: 29.7.0 + jest-snapshot: 29.7.0 + jest-util: 29.7.0 + jest-validate: 29.7.0 + jest-watcher: 29.7.0 + micromatch: 4.0.7 + pretty-format: 29.7.0 + slash: 3.0.0 + strip-ansi: 6.0.1 + transitivePeerDependencies: + - babel-plugin-macros + - supports-color + - ts-node + + "@jest/environment@29.7.0": + dependencies: + "@jest/fake-timers": 29.7.0 + "@jest/types": 29.6.3 + "@types/node": 20.14.9 + jest-mock: 29.7.0 + + "@jest/expect-utils@29.7.0": + dependencies: + jest-get-type: 29.6.3 + + "@jest/expect@29.7.0": + dependencies: + expect: 29.7.0 + jest-snapshot: 29.7.0 + transitivePeerDependencies: + - supports-color + + "@jest/fake-timers@29.7.0": + dependencies: + "@jest/types": 29.6.3 + "@sinonjs/fake-timers": 10.3.0 + "@types/node": 20.14.9 + jest-message-util: 29.7.0 + jest-mock: 29.7.0 + jest-util: 29.7.0 + + "@jest/globals@29.7.0": + dependencies: + "@jest/environment": 29.7.0 + "@jest/expect": 29.7.0 + "@jest/types": 29.6.3 + jest-mock: 29.7.0 + transitivePeerDependencies: + - supports-color + + "@jest/reporters@29.7.0": + dependencies: + "@bcoe/v8-coverage": 0.2.3 + "@jest/console": 29.7.0 + "@jest/test-result": 29.7.0 + "@jest/transform": 29.7.0 + "@jest/types": 29.6.3 + "@jridgewell/trace-mapping": 0.3.25 + "@types/node": 20.14.9 + chalk: 4.1.2 + collect-v8-coverage: 1.0.2 + exit: 0.1.2 + glob: 7.2.3 + graceful-fs: 4.2.11 + istanbul-lib-coverage: 3.2.2 + istanbul-lib-instrument: 6.0.3 + istanbul-lib-report: 3.0.1 + istanbul-lib-source-maps: 4.0.1 + istanbul-reports: 3.1.7 + jest-message-util: 29.7.0 + jest-util: 29.7.0 + jest-worker: 29.7.0 + slash: 3.0.0 + string-length: 4.0.2 + strip-ansi: 6.0.1 + v8-to-istanbul: 9.3.0 + transitivePeerDependencies: + - supports-color + + "@jest/schemas@29.6.3": + dependencies: + "@sinclair/typebox": 0.27.8 + + "@jest/source-map@29.6.3": + dependencies: + "@jridgewell/trace-mapping": 0.3.25 + callsites: 3.1.0 + graceful-fs: 4.2.11 + + "@jest/test-result@29.7.0": + dependencies: + "@jest/console": 29.7.0 + "@jest/types": 29.6.3 + "@types/istanbul-lib-coverage": 2.0.6 + collect-v8-coverage: 1.0.2 + + "@jest/test-sequencer@29.7.0": + dependencies: + "@jest/test-result": 29.7.0 + graceful-fs: 4.2.11 + jest-haste-map: 29.7.0 + slash: 3.0.0 + + "@jest/transform@29.7.0": + dependencies: + "@babel/core": 7.24.7 + "@jest/types": 29.6.3 + "@jridgewell/trace-mapping": 0.3.25 + babel-plugin-istanbul: 6.1.1 + chalk: 4.1.2 + convert-source-map: 2.0.0 + fast-json-stable-stringify: 2.1.0 + graceful-fs: 4.2.11 + jest-haste-map: 29.7.0 + jest-regex-util: 29.6.3 + jest-util: 29.7.0 + micromatch: 4.0.7 + pirates: 4.0.6 + slash: 3.0.0 + write-file-atomic: 4.0.2 + transitivePeerDependencies: + - supports-color + + "@jest/types@29.6.3": + dependencies: + "@jest/schemas": 29.6.3 + "@types/istanbul-lib-coverage": 2.0.6 + "@types/istanbul-reports": 3.0.4 + "@types/node": 20.14.9 + "@types/yargs": 17.0.32 + chalk: 4.1.2 + + "@jridgewell/gen-mapping@0.3.5": + dependencies: + "@jridgewell/set-array": 1.2.1 + "@jridgewell/sourcemap-codec": 1.4.15 + "@jridgewell/trace-mapping": 0.3.25 + + "@jridgewell/resolve-uri@3.1.2": {} + + "@jridgewell/set-array@1.2.1": {} + + "@jridgewell/sourcemap-codec@1.4.15": {} + + "@jridgewell/trace-mapping@0.3.25": + dependencies: + "@jridgewell/resolve-uri": 3.1.2 + "@jridgewell/sourcemap-codec": 1.4.15 + + "@jridgewell/trace-mapping@0.3.9": + dependencies: + "@jridgewell/resolve-uri": 3.1.2 + "@jridgewell/sourcemap-codec": 1.4.15 + "@js-sdsl/ordered-map@4.4.2": {} "@langchain/community@0.0.53(chromadb@1.8.1(openai@4.52.3))(firebase-admin@12.2.0)(jsonwebtoken@9.0.2)(langchain@0.1.37(@google-cloud/storage@7.11.2)(chromadb@1.8.1(openai@4.52.3))(d3-dsv@2.0.0)(fast-xml-parser@4.4.0)(firebase-admin@12.2.0)(handlebars@4.7.8)(ignore@5.3.1)(jsonwebtoken@9.0.2)(openai@4.52.3))(openai@4.52.3)": @@ -7916,8 +9849,18 @@ snapshots: "@sideway/pinpoint@2.0.0": {} + "@sinclair/typebox@0.27.8": {} + "@sindresorhus/is@4.6.0": {} + "@sinonjs/commons@3.0.1": + dependencies: + type-detect: 4.0.8 + + "@sinonjs/fake-timers@10.3.0": + dependencies: + "@sinonjs/commons": 3.0.1 + "@swc/cli@0.4.0(@swc/core@1.6.7)(chokidar@3.6.0)": dependencies: "@mole-inc/bin-wrapper": 8.0.1 @@ -7993,12 +9936,41 @@ snapshots: "@tootallnate/once@2.0.0": {} + "@tsconfig/node10@1.0.11": {} + + "@tsconfig/node12@1.0.11": {} + + "@tsconfig/node14@1.0.3": {} + + "@tsconfig/node16@1.0.4": {} + "@types/accepts@1.3.7": dependencies: "@types/node": 20.14.9 "@types/aws-lambda@8.10.122": {} + "@types/babel__core@7.20.5": + dependencies: + "@babel/parser": 7.24.7 + "@babel/types": 7.24.7 + "@types/babel__generator": 7.6.8 + "@types/babel__template": 7.4.4 + "@types/babel__traverse": 7.20.6 + + "@types/babel__generator@7.6.8": + dependencies: + "@babel/types": 7.24.7 + + "@types/babel__template@7.4.4": + dependencies: + "@babel/parser": 7.24.7 + "@babel/types": 7.24.7 + + "@types/babel__traverse@7.20.6": + dependencies: + "@babel/types": 7.24.7 + "@types/body-parser@1.19.5": dependencies: "@types/connect": 3.4.38 @@ -8069,6 +10041,10 @@ snapshots: "@types/express-serve-static-core": 4.19.5 "@types/serve-static": 1.15.7 + "@types/graceful-fs@4.1.9": + dependencies: + "@types/node": 20.14.9 + "@types/hapi__catbox@10.2.6": {} "@types/hapi__hapi@20.0.13": @@ -8100,6 +10076,21 @@ snapshots: dependencies: "@types/node": 20.14.9 + "@types/istanbul-lib-coverage@2.0.6": {} + + "@types/istanbul-lib-report@3.0.3": + dependencies: + "@types/istanbul-lib-coverage": 2.0.6 + + "@types/istanbul-reports@3.0.4": + dependencies: + "@types/istanbul-lib-report": 3.0.3 + + "@types/jest@29.5.12": + dependencies: + expect: 29.7.0 + pretty-format: 29.7.0 + "@types/json-schema@7.0.15": {} "@types/jsonwebtoken@9.0.6": @@ -8198,6 +10189,8 @@ snapshots: "@types/shimmer@1.0.5": {} + "@types/stack-utils@2.0.3": {} + "@types/tedious@4.0.14": dependencies: "@types/node": 20.14.9 @@ -8208,6 +10201,12 @@ snapshots: "@types/uuid@9.0.8": {} + "@types/yargs-parser@21.0.3": {} + + "@types/yargs@17.0.32": + dependencies: + "@types/yargs-parser": 21.0.3 + "@typescript-eslint/eslint-plugin@7.15.0(@typescript-eslint/parser@7.15.0(eslint@8.57.0)(typescript@5.5.3))(eslint@8.57.0)(typescript@5.5.3)": dependencies: "@eslint-community/regexpp": 4.11.0 @@ -8308,6 +10307,10 @@ snapshots: dependencies: acorn: 8.12.1 + acorn-walk@8.3.3: + dependencies: + acorn: 8.12.1 + acorn@8.12.1: {} agent-base@6.0.2: @@ -8344,8 +10347,16 @@ snapshots: require-from-string: 2.0.2 uri-js: 4.4.1 + ansi-escapes@4.3.2: + dependencies: + type-fest: 0.21.3 + ansi-regex@5.0.1: {} + ansi-styles@3.2.1: + dependencies: + color-convert: 1.9.3 + ansi-styles@4.3.0: dependencies: color-convert: 2.0.1 @@ -8359,6 +10370,8 @@ snapshots: arch@2.2.0: {} + arg@4.1.3: {} + argparse@1.0.10: dependencies: sprintf-js: 1.0.3 @@ -8384,6 +10397,58 @@ snapshots: asynckit@0.4.0: {} + babel-jest@29.7.0(@babel/core@7.24.7): + dependencies: + "@babel/core": 7.24.7 + "@jest/transform": 29.7.0 + "@types/babel__core": 7.20.5 + babel-plugin-istanbul: 6.1.1 + babel-preset-jest: 29.6.3(@babel/core@7.24.7) + chalk: 4.1.2 + graceful-fs: 4.2.11 + slash: 3.0.0 + transitivePeerDependencies: + - supports-color + + babel-plugin-istanbul@6.1.1: + dependencies: + "@babel/helper-plugin-utils": 7.24.7 + "@istanbuljs/load-nyc-config": 1.1.0 + "@istanbuljs/schema": 0.1.3 + istanbul-lib-instrument: 5.2.1 + test-exclude: 6.0.0 + transitivePeerDependencies: + - supports-color + + babel-plugin-jest-hoist@29.6.3: + dependencies: + "@babel/template": 7.24.7 + "@babel/types": 7.24.7 + "@types/babel__core": 7.20.5 + "@types/babel__traverse": 7.20.6 + + babel-preset-current-node-syntax@1.0.1(@babel/core@7.24.7): + dependencies: + "@babel/core": 7.24.7 + "@babel/plugin-syntax-async-generators": 7.8.4(@babel/core@7.24.7) + "@babel/plugin-syntax-bigint": 7.8.3(@babel/core@7.24.7) + "@babel/plugin-syntax-class-properties": 7.12.13(@babel/core@7.24.7) + "@babel/plugin-syntax-import-meta": 7.10.4(@babel/core@7.24.7) + "@babel/plugin-syntax-json-strings": 7.8.3(@babel/core@7.24.7) + "@babel/plugin-syntax-logical-assignment-operators": 7.10.4(@babel/core@7.24.7) + "@babel/plugin-syntax-nullish-coalescing-operator": 7.8.3(@babel/core@7.24.7) + "@babel/plugin-syntax-numeric-separator": 7.10.4(@babel/core@7.24.7) + "@babel/plugin-syntax-object-rest-spread": 7.8.3(@babel/core@7.24.7) + "@babel/plugin-syntax-optional-catch-binding": 7.8.3(@babel/core@7.24.7) + "@babel/plugin-syntax-optional-chaining": 7.8.3(@babel/core@7.24.7) + "@babel/plugin-syntax-top-level-await": 7.14.5(@babel/core@7.24.7) + + babel-preset-jest@29.6.3(@babel/core@7.24.7): + dependencies: + "@babel/core": 7.24.7 + babel-plugin-jest-hoist: 29.6.3 + babel-preset-current-node-syntax: 1.0.1(@babel/core@7.24.7) + balanced-match@1.0.2: {} base-64@0.1.0: {} @@ -8442,8 +10507,25 @@ snapshots: dependencies: fill-range: 7.1.1 + browserslist@4.23.1: + dependencies: + caniuse-lite: 1.0.30001640 + electron-to-chromium: 1.4.816 + node-releases: 2.0.14 + update-browserslist-db: 1.1.0(browserslist@4.23.1) + + bs-logger@0.2.6: + dependencies: + fast-json-stable-stringify: 2.1.0 + + bser@2.1.1: + dependencies: + node-int64: 0.4.0 + buffer-equal-constant-time@1.0.1: {} + buffer-from@1.1.2: {} + bytes@3.1.2: {} cacheable-lookup@5.0.4: {} @@ -8468,13 +10550,25 @@ snapshots: callsites@3.1.0: {} + camelcase@5.3.1: {} + camelcase@6.3.0: {} + caniuse-lite@1.0.30001640: {} + + chalk@2.4.2: + dependencies: + ansi-styles: 3.2.1 + escape-string-regexp: 1.0.5 + supports-color: 5.5.0 + chalk@4.1.2: dependencies: ansi-styles: 4.3.0 supports-color: 7.2.0 + char-regex@1.0.2: {} + charenc@0.0.2: {} chokidar@3.6.0: @@ -8498,6 +10592,8 @@ snapshots: transitivePeerDependencies: - encoding + ci-info@3.9.0: {} + cjs-module-lexer@1.3.1: {} cliui@8.0.1: @@ -8510,6 +10606,10 @@ snapshots: dependencies: mimic-response: 1.0.1 + co@4.6.0: {} + + collect-v8-coverage@1.0.2: {} + color-convert@1.9.3: dependencies: color-name: 1.1.3 @@ -8555,6 +10655,8 @@ snapshots: content-type@1.0.5: {} + convert-source-map@2.0.0: {} + cookie-signature@1.0.6: {} cookie@0.6.0: {} @@ -8564,6 +10666,23 @@ snapshots: object-assign: 4.1.1 vary: 1.1.2 + create-jest@29.7.0(@types/node@20.14.9)(ts-node@10.9.2(@swc/core@1.6.7)(@types/node@20.14.9)(typescript@5.5.3)): + dependencies: + "@jest/types": 29.6.3 + chalk: 4.1.2 + exit: 0.1.2 + graceful-fs: 4.2.11 + jest-config: 29.7.0(@types/node@20.14.9)(ts-node@10.9.2(@swc/core@1.6.7)(@types/node@20.14.9)(typescript@5.5.3)) + jest-util: 29.7.0 + prompts: 2.4.2 + transitivePeerDependencies: + - "@types/node" + - babel-plugin-macros + - supports-color + - ts-node + + create-require@1.1.1: {} + cross-spawn@5.1.0: dependencies: lru-cache: 4.1.5 @@ -8602,8 +10721,12 @@ snapshots: dependencies: mimic-response: 3.1.0 + dedent@1.5.3: {} + deep-is@0.1.4: {} + deepmerge@4.3.1: {} + defer-to-connect@2.0.1: {} define-data-property@1.1.4: @@ -8618,6 +10741,12 @@ snapshots: destroy@1.2.0: {} + detect-newline@3.1.0: {} + + diff-sequences@29.6.3: {} + + diff@4.0.2: {} + digest-fetch@1.3.0: dependencies: base-64: 0.1.0 @@ -8650,6 +10779,10 @@ snapshots: ee-first@1.1.1: {} + electron-to-chromium@1.4.816: {} + + emittery@0.13.1: {} + emoji-regex@8.0.0: {} enabled@2.0.0: {} @@ -8660,6 +10793,10 @@ snapshots: dependencies: once: 1.4.0 + error-ex@1.3.2: + dependencies: + is-arrayish: 0.2.1 + es-define-property@1.0.0: dependencies: get-intrinsic: 1.2.4 @@ -8696,6 +10833,10 @@ snapshots: escape-html@1.0.3: {} + escape-string-regexp@1.0.5: {} + + escape-string-regexp@2.0.0: {} + escape-string-regexp@4.0.0: {} escape-string-regexp@5.0.0: {} @@ -8810,6 +10951,16 @@ snapshots: dependencies: pify: 2.3.0 + exit@0.1.2: {} + + expect@29.7.0: + dependencies: + "@jest/expect-utils": 29.7.0 + jest-get-type: 29.6.3 + jest-matcher-utils: 29.7.0 + jest-message-util: 29.7.0 + jest-util: 29.7.0 + expr-eval@2.0.2: {} express@4.19.2: @@ -8890,6 +11041,10 @@ snapshots: dependencies: websocket-driver: 0.7.4 + fb-watchman@2.0.2: + dependencies: + bser: 2.1.1 + fecha@4.2.3: {} fetch-blob@3.2.0: @@ -8931,6 +11086,11 @@ snapshots: transitivePeerDependencies: - supports-color + find-up@4.1.0: + dependencies: + locate-path: 5.0.0 + path-exists: 4.0.0 + find-up@5.0.0: dependencies: locate-path: 6.0.0 @@ -9013,6 +11173,12 @@ snapshots: dependencies: js-yaml: 3.14.1 + fs-extra@11.2.0: + dependencies: + graceful-fs: 4.2.11 + jsonfile: 6.1.0 + universalify: 2.0.1 + fs.realpath@1.0.0: {} fsevents@2.3.3: @@ -9218,6 +11384,8 @@ snapshots: transitivePeerDependencies: - encoding + gensync@1.0.0-beta.2: {} + get-caller-file@2.0.5: {} get-intrinsic@1.2.4: @@ -9228,6 +11396,8 @@ snapshots: has-symbols: 1.0.3 hasown: 2.0.2 + get-package-type@0.1.0: {} + get-stream@3.0.0: {} get-stream@5.2.0: @@ -9257,6 +11427,8 @@ snapshots: once: 1.4.0 path-is-absolute: 1.0.1 + globals@11.12.0: {} + globals@13.24.0: dependencies: type-fest: 0.20.2 @@ -9362,6 +11534,8 @@ snapshots: p-cancelable: 2.1.1 responselike: 2.0.1 + graceful-fs@4.2.11: {} + graphemer@1.4.0: {} gtoken@5.3.2: @@ -9408,6 +11582,8 @@ snapshots: html-entities@2.5.2: {} + html-escaper@2.0.2: {} + http-cache-semantics@4.1.1: {} http-errors@2.0.0: @@ -9475,6 +11651,11 @@ snapshots: cjs-module-lexer: 1.3.1 module-details-from-path: 1.0.3 + import-local@3.1.0: + dependencies: + pkg-dir: 4.2.0 + resolve-cwd: 3.0.0 + imurmurhash@0.1.4: {} inflight@1.0.6: @@ -9488,6 +11669,8 @@ snapshots: is-any-array@2.0.1: {} + is-arrayish@0.2.1: {} + is-arrayish@0.3.2: {} is-binary-path@2.1.0: @@ -9504,6 +11687,8 @@ snapshots: is-fullwidth-code-point@3.0.0: {} + is-generator-fn@2.1.0: {} + is-glob@4.0.3: dependencies: is-extglob: 2.1.1 @@ -9529,6 +11714,356 @@ snapshots: transitivePeerDependencies: - encoding + istanbul-lib-coverage@3.2.2: {} + + istanbul-lib-instrument@5.2.1: + dependencies: + "@babel/core": 7.24.7 + "@babel/parser": 7.24.7 + "@istanbuljs/schema": 0.1.3 + istanbul-lib-coverage: 3.2.2 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + + istanbul-lib-instrument@6.0.3: + dependencies: + "@babel/core": 7.24.7 + "@babel/parser": 7.24.7 + "@istanbuljs/schema": 0.1.3 + istanbul-lib-coverage: 3.2.2 + semver: 7.6.2 + transitivePeerDependencies: + - supports-color + + istanbul-lib-report@3.0.1: + dependencies: + istanbul-lib-coverage: 3.2.2 + make-dir: 4.0.0 + supports-color: 7.2.0 + + istanbul-lib-source-maps@4.0.1: + dependencies: + debug: 4.3.5(supports-color@5.5.0) + istanbul-lib-coverage: 3.2.2 + source-map: 0.6.1 + transitivePeerDependencies: + - supports-color + + istanbul-reports@3.1.7: + dependencies: + html-escaper: 2.0.2 + istanbul-lib-report: 3.0.1 + + jest-changed-files@29.7.0: + dependencies: + execa: 5.1.1 + jest-util: 29.7.0 + p-limit: 3.1.0 + + jest-circus@29.7.0: + dependencies: + "@jest/environment": 29.7.0 + "@jest/expect": 29.7.0 + "@jest/test-result": 29.7.0 + "@jest/types": 29.6.3 + "@types/node": 20.14.9 + chalk: 4.1.2 + co: 4.6.0 + dedent: 1.5.3 + is-generator-fn: 2.1.0 + jest-each: 29.7.0 + jest-matcher-utils: 29.7.0 + jest-message-util: 29.7.0 + jest-runtime: 29.7.0 + jest-snapshot: 29.7.0 + jest-util: 29.7.0 + p-limit: 3.1.0 + pretty-format: 29.7.0 + pure-rand: 6.1.0 + slash: 3.0.0 + stack-utils: 2.0.6 + transitivePeerDependencies: + - babel-plugin-macros + - supports-color + + jest-cli@29.7.0(@types/node@20.14.9)(ts-node@10.9.2(@swc/core@1.6.7)(@types/node@20.14.9)(typescript@5.5.3)): + dependencies: + "@jest/core": 29.7.0(ts-node@10.9.2(@swc/core@1.6.7)(@types/node@20.14.9)(typescript@5.5.3)) + "@jest/test-result": 29.7.0 + "@jest/types": 29.6.3 + chalk: 4.1.2 + create-jest: 29.7.0(@types/node@20.14.9)(ts-node@10.9.2(@swc/core@1.6.7)(@types/node@20.14.9)(typescript@5.5.3)) + exit: 0.1.2 + import-local: 3.1.0 + jest-config: 29.7.0(@types/node@20.14.9)(ts-node@10.9.2(@swc/core@1.6.7)(@types/node@20.14.9)(typescript@5.5.3)) + jest-util: 29.7.0 + jest-validate: 29.7.0 + yargs: 17.7.2 + transitivePeerDependencies: + - "@types/node" + - babel-plugin-macros + - supports-color + - ts-node + + jest-config@29.7.0(@types/node@20.14.9)(ts-node@10.9.2(@swc/core@1.6.7)(@types/node@20.14.9)(typescript@5.5.3)): + dependencies: + "@babel/core": 7.24.7 + "@jest/test-sequencer": 29.7.0 + "@jest/types": 29.6.3 + babel-jest: 29.7.0(@babel/core@7.24.7) + chalk: 4.1.2 + ci-info: 3.9.0 + deepmerge: 4.3.1 + glob: 7.2.3 + graceful-fs: 4.2.11 + jest-circus: 29.7.0 + jest-environment-node: 29.7.0 + jest-get-type: 29.6.3 + jest-regex-util: 29.6.3 + jest-resolve: 29.7.0 + jest-runner: 29.7.0 + jest-util: 29.7.0 + jest-validate: 29.7.0 + micromatch: 4.0.7 + parse-json: 5.2.0 + pretty-format: 29.7.0 + slash: 3.0.0 + strip-json-comments: 3.1.1 + optionalDependencies: + "@types/node": 20.14.9 + ts-node: 10.9.2(@swc/core@1.6.7)(@types/node@20.14.9)(typescript@5.5.3) + transitivePeerDependencies: + - babel-plugin-macros + - supports-color + + jest-diff@29.7.0: + dependencies: + chalk: 4.1.2 + diff-sequences: 29.6.3 + jest-get-type: 29.6.3 + pretty-format: 29.7.0 + + jest-docblock@29.7.0: + dependencies: + detect-newline: 3.1.0 + + jest-each@29.7.0: + dependencies: + "@jest/types": 29.6.3 + chalk: 4.1.2 + jest-get-type: 29.6.3 + jest-util: 29.7.0 + pretty-format: 29.7.0 + + jest-environment-node@29.7.0: + dependencies: + "@jest/environment": 29.7.0 + "@jest/fake-timers": 29.7.0 + "@jest/types": 29.6.3 + "@types/node": 20.14.9 + jest-mock: 29.7.0 + jest-util: 29.7.0 + + jest-get-type@29.6.3: {} + + jest-haste-map@29.7.0: + dependencies: + "@jest/types": 29.6.3 + "@types/graceful-fs": 4.1.9 + "@types/node": 20.14.9 + anymatch: 3.1.3 + fb-watchman: 2.0.2 + graceful-fs: 4.2.11 + jest-regex-util: 29.6.3 + jest-util: 29.7.0 + jest-worker: 29.7.0 + micromatch: 4.0.7 + walker: 1.0.8 + optionalDependencies: + fsevents: 2.3.3 + + jest-leak-detector@29.7.0: + dependencies: + jest-get-type: 29.6.3 + pretty-format: 29.7.0 + + jest-matcher-utils@29.7.0: + dependencies: + chalk: 4.1.2 + jest-diff: 29.7.0 + jest-get-type: 29.6.3 + pretty-format: 29.7.0 + + jest-message-util@29.7.0: + dependencies: + "@babel/code-frame": 7.24.7 + "@jest/types": 29.6.3 + "@types/stack-utils": 2.0.3 + chalk: 4.1.2 + graceful-fs: 4.2.11 + micromatch: 4.0.7 + pretty-format: 29.7.0 + slash: 3.0.0 + stack-utils: 2.0.6 + + jest-mock@29.7.0: + dependencies: + "@jest/types": 29.6.3 + "@types/node": 20.14.9 + jest-util: 29.7.0 + + jest-pnp-resolver@1.2.3(jest-resolve@29.7.0): + optionalDependencies: + jest-resolve: 29.7.0 + + jest-regex-util@29.6.3: {} + + jest-resolve-dependencies@29.7.0: + dependencies: + jest-regex-util: 29.6.3 + jest-snapshot: 29.7.0 + transitivePeerDependencies: + - supports-color + + jest-resolve@29.7.0: + dependencies: + chalk: 4.1.2 + graceful-fs: 4.2.11 + jest-haste-map: 29.7.0 + jest-pnp-resolver: 1.2.3(jest-resolve@29.7.0) + jest-util: 29.7.0 + jest-validate: 29.7.0 + resolve: 1.22.8 + resolve.exports: 2.0.2 + slash: 3.0.0 + + jest-runner@29.7.0: + dependencies: + "@jest/console": 29.7.0 + "@jest/environment": 29.7.0 + "@jest/test-result": 29.7.0 + "@jest/transform": 29.7.0 + "@jest/types": 29.6.3 + "@types/node": 20.14.9 + chalk: 4.1.2 + emittery: 0.13.1 + graceful-fs: 4.2.11 + jest-docblock: 29.7.0 + jest-environment-node: 29.7.0 + jest-haste-map: 29.7.0 + jest-leak-detector: 29.7.0 + jest-message-util: 29.7.0 + jest-resolve: 29.7.0 + jest-runtime: 29.7.0 + jest-util: 29.7.0 + jest-watcher: 29.7.0 + jest-worker: 29.7.0 + p-limit: 3.1.0 + source-map-support: 0.5.13 + transitivePeerDependencies: + - supports-color + + jest-runtime@29.7.0: + dependencies: + "@jest/environment": 29.7.0 + "@jest/fake-timers": 29.7.0 + "@jest/globals": 29.7.0 + "@jest/source-map": 29.6.3 + "@jest/test-result": 29.7.0 + "@jest/transform": 29.7.0 + "@jest/types": 29.6.3 + "@types/node": 20.14.9 + chalk: 4.1.2 + cjs-module-lexer: 1.3.1 + collect-v8-coverage: 1.0.2 + glob: 7.2.3 + graceful-fs: 4.2.11 + jest-haste-map: 29.7.0 + jest-message-util: 29.7.0 + jest-mock: 29.7.0 + jest-regex-util: 29.6.3 + jest-resolve: 29.7.0 + jest-snapshot: 29.7.0 + jest-util: 29.7.0 + slash: 3.0.0 + strip-bom: 4.0.0 + transitivePeerDependencies: + - supports-color + + jest-snapshot@29.7.0: + dependencies: + "@babel/core": 7.24.7 + "@babel/generator": 7.24.7 + "@babel/plugin-syntax-jsx": 7.24.7(@babel/core@7.24.7) + "@babel/plugin-syntax-typescript": 7.24.7(@babel/core@7.24.7) + "@babel/types": 7.24.7 + "@jest/expect-utils": 29.7.0 + "@jest/transform": 29.7.0 + "@jest/types": 29.6.3 + babel-preset-current-node-syntax: 1.0.1(@babel/core@7.24.7) + chalk: 4.1.2 + expect: 29.7.0 + graceful-fs: 4.2.11 + jest-diff: 29.7.0 + jest-get-type: 29.6.3 + jest-matcher-utils: 29.7.0 + jest-message-util: 29.7.0 + jest-util: 29.7.0 + natural-compare: 1.4.0 + pretty-format: 29.7.0 + semver: 7.6.2 + transitivePeerDependencies: + - supports-color + + jest-util@29.7.0: + dependencies: + "@jest/types": 29.6.3 + "@types/node": 20.14.9 + chalk: 4.1.2 + ci-info: 3.9.0 + graceful-fs: 4.2.11 + picomatch: 2.3.1 + + jest-validate@29.7.0: + dependencies: + "@jest/types": 29.6.3 + camelcase: 6.3.0 + chalk: 4.1.2 + jest-get-type: 29.6.3 + leven: 3.1.0 + pretty-format: 29.7.0 + + jest-watcher@29.7.0: + dependencies: + "@jest/test-result": 29.7.0 + "@jest/types": 29.6.3 + "@types/node": 20.14.9 + ansi-escapes: 4.3.2 + chalk: 4.1.2 + emittery: 0.13.1 + jest-util: 29.7.0 + string-length: 4.0.2 + + jest-worker@29.7.0: + dependencies: + "@types/node": 20.14.9 + jest-util: 29.7.0 + merge-stream: 2.0.0 + supports-color: 8.1.1 + + jest@29.7.0(@types/node@20.14.9)(ts-node@10.9.2(@swc/core@1.6.7)(@types/node@20.14.9)(typescript@5.5.3)): + dependencies: + "@jest/core": 29.7.0(ts-node@10.9.2(@swc/core@1.6.7)(@types/node@20.14.9)(typescript@5.5.3)) + "@jest/types": 29.6.3 + import-local: 3.1.0 + jest-cli: 29.7.0(@types/node@20.14.9)(ts-node@10.9.2(@swc/core@1.6.7)(@types/node@20.14.9)(typescript@5.5.3)) + transitivePeerDependencies: + - "@types/node" + - babel-plugin-macros + - supports-color + - ts-node + joi@17.13.3: dependencies: "@hapi/hoek": 9.3.0 @@ -9543,6 +12078,8 @@ snapshots: dependencies: base64-js: 1.5.1 + js-tokens@4.0.0: {} + js-yaml@3.14.1: dependencies: argparse: 1.0.10 @@ -9552,12 +12089,16 @@ snapshots: dependencies: argparse: 2.0.1 + jsesc@2.5.2: {} + json-bigint@1.0.0: dependencies: bignumber.js: 9.1.2 json-buffer@3.0.1: {} + json-parse-even-better-errors@2.3.1: {} + json-schema-traverse@0.4.1: {} json-schema-traverse@1.0.0: {} @@ -9568,6 +12109,12 @@ snapshots: json5@2.2.3: {} + jsonfile@6.1.0: + dependencies: + universalify: 2.0.1 + optionalDependencies: + graceful-fs: 4.2.11 + jsonpointer@5.0.1: {} jsonwebtoken@9.0.2: @@ -9620,6 +12167,8 @@ snapshots: dependencies: json-buffer: 3.0.1 + kleur@3.0.3: {} + kuler@2.0.0: {} langchain@0.1.37(@google-cloud/storage@7.11.2)(chromadb@1.8.1(openai@4.52.3))(d3-dsv@2.0.0)(fast-xml-parser@4.4.0)(firebase-admin@12.2.0)(handlebars@4.7.8)(ignore@5.3.1)(jsonwebtoken@9.0.2)(openai@4.52.3): @@ -9826,6 +12375,8 @@ snapshots: langchain: 0.2.8(chromadb@1.8.1(openai@4.52.3))(d3-dsv@2.0.0)(fast-xml-parser@4.4.0)(handlebars@4.7.8)(ignore@5.3.1)(openai@4.52.3) openai: 4.52.3 + leven@3.1.0: {} + levn@0.4.1: dependencies: prelude-ls: 1.2.1 @@ -9833,6 +12384,12 @@ snapshots: limiter@1.1.5: {} + lines-and-columns@1.2.4: {} + + locate-path@5.0.0: + dependencies: + p-locate: 4.1.0 + locate-path@6.0.0: dependencies: p-locate: 5.0.0 @@ -9855,6 +12412,8 @@ snapshots: lodash.mapvalues@4.6.0: {} + lodash.memoize@4.1.2: {} + lodash.merge@4.6.2: {} lodash.once@4.1.1: {} @@ -9877,6 +12436,10 @@ snapshots: pseudomap: 1.0.2 yallist: 2.1.2 + lru-cache@5.1.1: + dependencies: + yallist: 3.1.1 + lru-cache@6.0.0: dependencies: yallist: 4.0.0 @@ -9886,6 +12449,16 @@ snapshots: lodash.clonedeep: 4.5.0 lru-cache: 6.0.0 + make-dir@4.0.0: + dependencies: + semver: 7.6.2 + + make-error@1.3.6: {} + + makeerror@1.0.12: + dependencies: + tmpl: 1.0.5 + md5@2.3.0: dependencies: charenc: 0.0.2 @@ -9997,6 +12570,10 @@ snapshots: node-gyp-build@4.8.1: optional: true + node-int64@0.4.0: {} + + node-releases@2.0.14: {} + nodemon@3.1.4: dependencies: chokidar: 3.6.0 @@ -10078,10 +12655,18 @@ snapshots: p-finally@1.0.0: {} + p-limit@2.3.0: + dependencies: + p-try: 2.2.0 + p-limit@3.1.0: dependencies: yocto-queue: 0.1.0 + p-locate@4.1.0: + dependencies: + p-limit: 2.3.0 + p-locate@5.0.0: dependencies: p-limit: 3.1.0 @@ -10100,10 +12685,19 @@ snapshots: dependencies: p-finally: 1.0.0 + p-try@2.2.0: {} + parent-module@1.0.1: dependencies: callsites: 3.1.0 + parse-json@5.2.0: + dependencies: + "@babel/code-frame": 7.24.7 + error-ex: 1.3.2 + json-parse-even-better-errors: 2.3.1 + lines-and-columns: 1.2.4 + parseurl@1.3.3: {} path-exists@4.0.0: {} @@ -10134,14 +12728,22 @@ snapshots: postgres-date: 1.0.7 postgres-interval: 1.2.0 + picocolors@1.0.1: {} + picomatch@2.3.1: {} pify@2.3.0: {} + pirates@4.0.6: {} + piscina@4.6.1: optionalDependencies: nice-napi: 1.0.2 + pkg-dir@4.2.0: + dependencies: + find-up: 4.1.0 + postgres-array@2.0.0: {} postgres-bytea@1.0.0: {} @@ -10161,6 +12763,17 @@ snapshots: prettier@3.3.2: {} + pretty-format@29.7.0: + dependencies: + "@jest/schemas": 29.6.3 + ansi-styles: 5.2.0 + react-is: 18.3.1 + + prompts@2.4.2: + dependencies: + kleur: 3.0.3 + sisteransi: 1.0.5 + proto3-json-serializer@2.0.2: dependencies: protobufjs: 7.3.2 @@ -10202,6 +12815,8 @@ snapshots: punycode@2.3.1: {} + pure-rand@6.1.0: {} + qs@6.11.0: dependencies: side-channel: 1.0.6 @@ -10223,6 +12838,8 @@ snapshots: iconv-lite: 0.4.24 unpipe: 1.0.0 + react-is@18.3.1: {} + readable-stream@3.6.2: dependencies: inherits: 2.0.4 @@ -10251,10 +12868,18 @@ snapshots: resolve-alpn@1.2.1: {} + resolve-cwd@3.0.0: + dependencies: + resolve-from: 5.0.0 + resolve-from@4.0.0: {} + resolve-from@5.0.0: {} + resolve-pkg-maps@1.0.0: {} + resolve.exports@2.0.2: {} + resolve@1.22.8: dependencies: is-core-module: 2.14.0 @@ -10300,6 +12925,8 @@ snapshots: dependencies: semver: 7.6.2 + semver@6.3.1: {} + semver@7.6.2: {} send@0.18.0: @@ -10371,6 +12998,8 @@ snapshots: dependencies: semver: 7.6.2 + sisteransi@1.0.5: {} + slash@3.0.0: {} sort-keys-length@1.0.1: @@ -10381,6 +13010,11 @@ snapshots: dependencies: is-plain-obj: 1.1.0 + source-map-support@0.5.13: + dependencies: + buffer-from: 1.1.2 + source-map: 0.6.1 + source-map@0.6.1: {} source-map@0.7.4: {} @@ -10389,6 +13023,10 @@ snapshots: stack-trace@0.0.10: {} + stack-utils@2.0.6: + dependencies: + escape-string-regexp: 2.0.0 + statuses@2.0.1: {} stream-events@1.0.5: @@ -10397,6 +13035,11 @@ snapshots: stream-shift@1.0.3: {} + string-length@4.0.2: + dependencies: + char-regex: 1.0.2 + strip-ansi: 6.0.1 + string-width@4.2.3: dependencies: emoji-regex: 8.0.0 @@ -10411,6 +13054,8 @@ snapshots: dependencies: ansi-regex: 5.0.1 + strip-bom@4.0.0: {} + strip-eof@1.0.0: {} strip-final-newline@2.0.0: {} @@ -10437,6 +13082,10 @@ snapshots: dependencies: has-flag: 4.0.0 + supports-color@8.1.1: + dependencies: + has-flag: 4.0.0 + supports-preserve-symlinks-flag@1.0.0: {} teeny-request@9.0.0: @@ -10450,10 +13099,20 @@ snapshots: - encoding - supports-color + test-exclude@6.0.0: + dependencies: + "@istanbuljs/schema": 0.1.3 + glob: 7.2.3 + minimatch: 3.1.2 + text-hex@1.0.0: {} text-table@0.2.0: {} + tmpl@1.0.5: {} + + to-fast-properties@2.0.0: {} + to-regex-range@5.0.1: dependencies: is-number: 7.0.0 @@ -10479,8 +13138,46 @@ snapshots: dependencies: typescript: 5.5.3 + ts-jest@29.1.5(@babel/core@7.24.7)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.24.7))(jest@29.7.0(@types/node@20.14.9)(ts-node@10.9.2(@swc/core@1.6.7)(@types/node@20.14.9)(typescript@5.5.3)))(typescript@5.5.3): + dependencies: + bs-logger: 0.2.6 + fast-json-stable-stringify: 2.1.0 + jest: 29.7.0(@types/node@20.14.9)(ts-node@10.9.2(@swc/core@1.6.7)(@types/node@20.14.9)(typescript@5.5.3)) + jest-util: 29.7.0 + json5: 2.2.3 + lodash.memoize: 4.1.2 + make-error: 1.3.6 + semver: 7.6.2 + typescript: 5.5.3 + yargs-parser: 21.1.1 + optionalDependencies: + "@babel/core": 7.24.7 + "@jest/transform": 29.7.0 + "@jest/types": 29.6.3 + babel-jest: 29.7.0(@babel/core@7.24.7) + ts-md5@1.3.1: {} + ts-node@10.9.2(@swc/core@1.6.7)(@types/node@20.14.9)(typescript@5.5.3): + dependencies: + "@cspotcode/source-map-support": 0.8.1 + "@tsconfig/node10": 1.0.11 + "@tsconfig/node12": 1.0.11 + "@tsconfig/node14": 1.0.3 + "@tsconfig/node16": 1.0.4 + "@types/node": 20.14.9 + acorn: 8.12.1 + acorn-walk: 8.3.3 + arg: 4.1.3 + create-require: 1.1.1 + diff: 4.0.2 + make-error: 1.3.6 + typescript: 5.5.3 + v8-compile-cache-lib: 3.0.1 + yn: 3.1.1 + optionalDependencies: + "@swc/core": 1.6.7 + tslib@2.6.3: {} tsx@4.16.2: @@ -10494,8 +13191,12 @@ snapshots: dependencies: prelude-ls: 1.2.1 + type-detect@4.0.8: {} + type-fest@0.20.2: {} + type-fest@0.21.3: {} + type-is@1.6.18: dependencies: media-typer: 0.3.0 @@ -10521,8 +13222,16 @@ snapshots: undici-types@5.26.5: {} + universalify@2.0.1: {} + unpipe@1.0.0: {} + update-browserslist-db@1.1.0(browserslist@4.23.1): + dependencies: + browserslist: 4.23.1 + escalade: 3.1.2 + picocolors: 1.0.1 + uri-js@4.4.1: dependencies: punycode: 2.3.1 @@ -10539,10 +13248,22 @@ snapshots: uuid@9.0.1: {} + v8-compile-cache-lib@3.0.1: {} + + v8-to-istanbul@9.3.0: + dependencies: + "@jridgewell/trace-mapping": 0.3.25 + "@types/istanbul-lib-coverage": 2.0.6 + convert-source-map: 2.0.0 + vary@1.1.2: {} walkdir@0.4.1: {} + walker@1.0.8: + dependencies: + makeerror: 1.0.12 + web-streams-polyfill@3.3.3: {} web-streams-polyfill@4.0.0-beta.3: {} @@ -10604,12 +13325,19 @@ snapshots: wrappy@1.0.2: {} + write-file-atomic@4.0.2: + dependencies: + imurmurhash: 0.1.4 + signal-exit: 3.0.7 + xtend@4.0.2: {} y18n@5.0.8: {} yallist@2.1.2: {} + yallist@3.1.1: {} + yallist@4.0.0: {} yaml@2.4.5: {} @@ -10626,6 +13354,8 @@ snapshots: y18n: 5.0.8 yargs-parser: 21.1.1 + yn@3.1.1: {} + yocto-queue@0.1.0: {} zod-to-json-schema@3.23.1(zod@3.23.8): diff --git a/scripts/copy-build-files.mjs b/scripts/copy-build-files.mjs new file mode 100644 index 0000000..1eff08a --- /dev/null +++ b/scripts/copy-build-files.mjs @@ -0,0 +1,21 @@ +import fs from "fs-extra"; + +// source directory +const sourceDir = "src"; +// build directory +const destinationDir = "lib"; + +// Copy the 'prompts' directory +fs.copySync(sourceDir + "/prompts", destinationDir + "/prompts"); + +// Copy the 'knowledge-bases' directory inside 'rag' directory +fs.copySync( + sourceDir + "/rag/knowledge-bases", + destinationDir + "/rag/knowledge-bases" +); + +// Copy the 'tests/test-data' directory +fs.copySync( + sourceDir + "/tests/test-data", + destinationDir + "/tests/test-data" +); diff --git a/src/agents/chat-agent.ts b/src/agents/chat-agent.ts index 1571252..eaf09d6 100644 --- a/src/agents/chat-agent.ts +++ b/src/agents/chat-agent.ts @@ -1,8 +1,11 @@ import { generate } from "@genkit-ai/ai"; import type { GenerateResponse } from "@genkit-ai/ai"; import { ChatHistoryStore } from "../history/chat-history-store"; -import { InMemoryChatHistoryStore } from "../history/in-memory-chat-history-store"; -import { ModelConfig, SupportedModels } from "../models/model"; +import { + ModelConfig, + SupportedModelNames, + SupportedModels, +} from "../models/model"; import { closeEndedSystemPrompt, openEndedSystemPrompt, @@ -38,8 +41,6 @@ export type AgentTypeConfig = * @property topic - The topic for the chat agent. * @property systemPrompt - The system prompt for the chat agent. * @property chatPrompt - The chat prompt for the chat agent. - * @property enableChatHistory - Indicates whether to use chat history. - * @property chatHistoryStore - The chat history store. * @property tools - Tools for the chat agent. * @property model - The supported model to use for chat completion. * @property modelConfig - The model configuration. @@ -47,19 +48,21 @@ export type AgentTypeConfig = export type ChatAgentConfig = { systemPrompt?: Dotprompt; chatPrompt?: Dotprompt; - enableChatHistory?: boolean; - chatHistoryStore?: ChatHistoryStore; tools?: ToolArgument[]; model?: SupportedModels; modelConfig?: ModelConfig; } & AgentTypeConfig; +type DefaultChatAgentConfigType = { + agentType: ChatAgentType; + model: SupportedModels; +}; + /** * Represents the default chat agent configuration. */ -export const defaultChatAgentConfig: ChatAgentConfig = { +export const defaultChatAgentConfig: DefaultChatAgentConfigType = { agentType: "open-ended", - enableChatHistory: false, model: "gemini15Flash", }; @@ -72,12 +75,24 @@ export interface ChatAgentAttributes { topic?: string; systemPrompt?: Dotprompt; chatPrompt?: Dotprompt; - enableChatHistory: boolean; - chatHistoryStore: ChatHistoryStore; - model?: SupportedModels; + tools?: ToolArgument[]; modelConfig?: ModelConfig; } +/** + * Represents the properties for generating a response with chat history. + */ +export type GenerateResponseHistoryProps = + | { + enableChatHistory: true; + chatId?: string; + history?: MessageData[]; + chatHistoryStore: ChatHistoryStore; + } + | { + enableChatHistory?: false; + }; + /** * Represents the properties for generating a response. * @@ -85,6 +100,8 @@ export interface ChatAgentAttributes { * @property context - The context object. * @property chatId - The ID of the chat history. * @property history - The chat history. + * @property enableChatHistory - Indicates whether to use chat history. + * @property chatHistoryStore - The chat history store. * @property tools - The tool arguments. * @property model - The supported model. * @property modelConfig - The model configuration. @@ -95,13 +112,12 @@ export type GenerateResponseProps = { query: string; context?: string; chatId?: string; - history?: MessageData[]; tools?: ToolArgument[]; model?: SupportedModels; modelConfig?: ModelConfig; systemPrompt?: Dotprompt; chatPrompt?: Dotprompt; -}; +} & GenerateResponseHistoryProps; /** * Represents the return object for generating a response. @@ -129,11 +145,9 @@ export interface ChatAgentMethods { ) => Promise; /** - * Retrieves the chat history for a given chat ID.iven chat ID. - * @param chatId - The ID of the chat history to retrieve. - * @returns Returns a promise that resolves to the chat history for the given chat ID if available, otherwise returns undefined. + * Method to get model name that the chat agent is using. */ - getChatHistory: (chatId: string) => Promise; + getModelName(): string; } /** @@ -146,7 +160,7 @@ export interface ChatAgentInterface type GenerateSystemPromptResponseParams = { agentType?: ChatAgentType; prompt: Dotprompt; - model?: SupportedModels; + model?: string; modelConfig?: ModelConfig; query?: string; context?: string; @@ -162,10 +176,8 @@ export class ChatAgent implements ChatAgentInterface { topic?: string; systemPrompt?: Dotprompt; chatPrompt?: Dotprompt; - enableChatHistory: boolean; - chatHistoryStore: ChatHistoryStore; tools?: ToolArgument[]; - model?: SupportedModels; + private modelName: string; modelConfig?: ModelConfig; /** @@ -180,16 +192,18 @@ export class ChatAgent implements ChatAgentInterface { * @param model - The supported model. If not provided, will use the default model (e.g. Gemini 1.5 Flash). * @param modelConfig - The model configuration. */ - constructor(config: ChatAgentConfig = defaultChatAgentConfig) { + constructor(config: ChatAgentConfig = {}) { this.agentType = config.agentType ?? defaultChatAgentConfig.agentType; this.systemPrompt = config.systemPrompt; this.chatPrompt = config.chatPrompt; - this.enableChatHistory = config.enableChatHistory ?? false; - this.chatHistoryStore = - config.chatHistoryStore ?? new InMemoryChatHistoryStore(); this.tools = config.tools; - this.model = config.model; + this.modelName = config.model + ? SupportedModelNames[config.model] + : SupportedModelNames[defaultChatAgentConfig.model]; this.modelConfig = config.modelConfig; + if ("topic" in config) { + this.topic = config.topic; + } } /** @@ -251,7 +265,7 @@ export class ChatAgent implements ChatAgentInterface { /** * Generates a response using the system prompt. * @param agentType - The type of agent. - * @param model - The supported model. + * @param model - The supported model name. * @param modelConfig - The model configuration. * @param query - The query string. * @param context - The context string. @@ -271,7 +285,8 @@ export class ChatAgent implements ChatAgentInterface { }: GenerateSystemPromptResponseParams) { // generate the response const res = prompt.generate({ - model: model, // if undefined, will use model defined in the dotprompt + // if undefined, will use model defined in the dotprompt + model: model, config: modelConfig, input: ChatAgent.getFormattedInput(agentType, query, context, topic), tools: tools, @@ -292,90 +307,94 @@ export class ChatAgent implements ChatAgentInterface { * @returns Returns a promise that resolves to the generated response. * @throws Throws an error if chat history enabled but the chat history store is not initialized or if no data is found for the chat ID. */ - async generateResponse({ - query, - context, - chatId, - history, - tools, - model, - modelConfig, - systemPrompt, - }: GenerateResponseProps): Promise { + async generateResponse( + params: GenerateResponseProps + ): Promise { // System prompt to use // In order of priority: systemPrompt provided as argument to generateResponse, this.systemPrompt, default system prompt const prompt = - systemPrompt ?? + params.systemPrompt ?? this.systemPrompt ?? ChatAgent.getSystemPrompt(this.agentType); // if not using chat history - if (!this.enableChatHistory) { + if (!params.enableChatHistory) { // return response in specified format return { res: await ChatAgent.generateSystemPromptResponse({ agentType: this.agentType, prompt, - model: model ?? this.model, - modelConfig: modelConfig ?? this.modelConfig, - query, - context, + model: params.model + ? SupportedModelNames[params.model] + : this.modelName, + modelConfig: params.modelConfig ?? this.modelConfig, + query: params.query, + context: params.context, topic: this.topic, - tools: tools ?? this.tools, + tools: params.tools ?? this.tools, }), }; } // if using chat history, confirm chat history store is initialized - if (!this.chatHistoryStore) + if (!params.chatHistoryStore) throw new Error("Chat history store not initialized"); // if no chatID provided - if (!chatId) { + if (!params.chatId) { // generate response for given query (will use system prompt) const res = await ChatAgent.generateSystemPromptResponse({ agentType: this.agentType, prompt, - model: model ?? this.model, - modelConfig: modelConfig ?? this.modelConfig, - query, - context, + model: params.model + ? SupportedModelNames[params.model] + : this.modelName, + modelConfig: params.modelConfig ?? this.modelConfig, + query: params.query, + context: params.context, topic: this.topic, - tools: tools ?? this.tools, + tools: params.tools ?? this.tools, }); // add chat history and obtain new chat ID - chatId = await this.chatHistoryStore.addChatHistory(res.toHistory()); + params.chatId = await params.chatHistoryStore.addChatHistory( + res.toHistory() + ); // return response in specified format return { - chatId, + chatId: params.chatId, res, }; } // retrieve chat history if not provided already const chatHistory = - history ?? (await this.chatHistoryStore.getChatHistory(chatId)); + params.history ?? + (await params.chatHistoryStore.getChatHistory(params.chatId)); // if no chat history provided and no chat history found for the given chat ID - if (!chatHistory) throw new Error(`No data found for chat ID ${chatId}.`); - // generate response for given query (will use chat prompt and chat history) + if (!chatHistory) + throw new Error(`No data found for chat ID ${params.chatId}.`); + // generate response for given query (will use chat prompt and any provided chat history, context and tools) const res = await generate({ - model: model ?? this.model, - prompt: query, + model: params.model ?? this.modelName, + prompt: params.query, history: chatHistory, - tools, + context: params.context + ? [{ content: [{ text: params.context }] }] + : undefined, + tools: params.tools, }); // update chat history with new messages (user query and model response) - await this.chatHistoryStore.addMessages(chatId, res.toHistory().slice(-2)); + await params.chatHistoryStore.addMessages( + params.chatId, + res.toHistory().slice(-2) + ); // return response in specified format return { - chatId, + chatId: params.chatId, res, }; } /** - * Retrieves the chat history for a given chat ID. - * @param chatId - The ID of the chat history to retrieve. - * @returns Returns a promise that resolves to the chat history for the given chat ID if available, otherwise returns undefined. + * Method to get model name that the chat agent is using. */ - async getChatHistory(chatId: string): Promise { - if (!this.enableChatHistory || !this.chatHistoryStore) return undefined; - return await this.chatHistoryStore.getChatHistory(chatId); + getModelName() { + return this.modelName; } } diff --git a/src/auth/api-key-store.ts b/src/auth/api-key-store.ts index 2f35fb9..1e46ff7 100644 --- a/src/auth/api-key-store.ts +++ b/src/auth/api-key-store.ts @@ -1,3 +1,5 @@ +import { CollectionReference, WriteResult } from "firebase-admin/firestore"; + /** * Represents an API key. */ @@ -77,14 +79,12 @@ export interface APIKeyStore { /** * Map containing all API keys. */ - keys: APIKeyCollection; + keys: APIKeyCollection | CollectionReference; /** - * Verifies if the given API key exists and its status is active. - * @param key - The API key to verify. - * @returns A promise that resolves to a boolean indicating whether the API key is valid. + * Collection reference to the Firestore collection containing API keys. */ - verifyAPIKey: (key: APIKey) => Promise; + // collectionRef: CollectionReference; /** * Adds a new API key record. @@ -92,7 +92,10 @@ export interface APIKeyStore { * @param config - The configuration for the new API key record. * @returns A promise that resolves to a boolean indicating whether the API key was successfully added. */ - addKey: (key: APIKey, config: NewAPIKeyRecord) => Promise; + addKey: ( + key: APIKey, + config: NewAPIKeyRecord + ) => Promise | Promise; /** * Updates an existing API key record. @@ -112,7 +115,7 @@ export interface APIKeyStore { status?: APIKeyStatus; endpoints?: string[] | "all"; requests?: number; - }) => Promise; + }) => Promise | Promise; /** * Gets a specific API key record. @@ -126,12 +129,12 @@ export interface APIKeyStore { * @param key - The API key to delete. * @returns A promise that resolves to a boolean indicating whether the API key was successfully deleted. */ - deleteKey: (key: APIKey) => Promise; + deleteKey: (key: APIKey) => Promise | Promise; /** * Increments the requests count for an API key. * @param key - The API key to increment the requests count for. * @returns A promise that resolves to a boolean indicating whether the requests count was successfully incremented. */ - incrementRequests: (key: APIKey) => Promise; + incrementRequests: (key: APIKey) => Promise | Promise; } diff --git a/src/auth/firestore-api-key-store.ts b/src/auth/firestore-api-key-store.ts index b7a90de..d744234 100644 --- a/src/auth/firestore-api-key-store.ts +++ b/src/auth/firestore-api-key-store.ts @@ -1,48 +1,41 @@ import { - APIKeyCollection, + CollectionReference, + FieldValue, + WriteResult, +} from "firebase-admin/firestore"; +import { APIKeyStore, - APIKey, APIKeyRecord, APIKeyStatus, NewAPIKeyRecord, } from "./api-key-store"; +import { app } from "firebase-admin"; /** * Configurations for the FirestoreAPIKeyStore. * @property collectionName - The name of the Firestore collection to store API keys. */ type FirestoreAPIKeyStoreConfig = { + firebaseApp: app.App; collectionName: string; }; /** - * Represents an in-memory implementation of the APIKeyStore interface. + * Represents an Firestore implementation of the APIKeyStore interface. */ export class FirestoreAPIKeyStore implements APIKeyStore { /** - * Name of the collection in Firestore where API keys are stored. - */ - collectionName: string; - /** - * The collection of API keys. + * The collection of API keys or a reference to the Firestore collection. */ - keys: APIKeyCollection; + keys: CollectionReference; /** - * Creates an instance of InMemoryAPIKeyStore. + * Creates an instance of FirestoreAPIKeyStore. */ constructor(config: FirestoreAPIKeyStoreConfig) { - this.keys = new Map(); - this.collectionName = config.collectionName; - } - - /** - * Verifies if an API key is valid and active. - * @param key - The API key to verify. - * @returns A boolean indicating whether the API key is valid and active. - */ - async verifyAPIKey(key: string): Promise { - return this.keys.has(key) && this.keys.get(key)?.status === "active"; + this.keys = config.firebaseApp + .firestore() + .collection(config.collectionName); } /** @@ -51,23 +44,21 @@ export class FirestoreAPIKeyStore implements APIKeyStore { * @param key - The API key to add. * @param record - The record associated with the API key. * @returns A boolean indicating whether the API key was added successfully. - * @throws Throws an error if the UID is not provided. + * @throws Throws an error if unable to add the API key. */ async addKey( key: string, { status = "disabled", endpoints = [], uid }: NewAPIKeyRecord - ): Promise { + ): Promise { if (uid === "") throw new Error("UID is required to create an API key"); - - this.keys.set(key, { + // Add the new API key to the Firestore collection + return await this.keys.doc(key).set({ requests: 0, lastUsed: new Date(), status, endpoints, uid, }); - - return true; } /** @@ -86,21 +77,15 @@ export class FirestoreAPIKeyStore implements APIKeyStore { status?: APIKeyStatus; flows?: string[] | "all"; requests?: number; - }): Promise { - const apiKey = this.keys.get(key); - if (!apiKey) throw new Error("API key not found"); - - if (status) { - apiKey.status = status; - } - if (flows) { - apiKey.endpoints = flows; - } - if (requests) { - apiKey.requests = requests; - } - // if successful, return true - return true; + }): Promise { + // values to update + const valuesToUpdate = { + ...(status && { status }), + ...(flows && { endpoints: flows }), + ...(requests && { requests }), + }; + // Update the API key in the Firestore collection + return await this.keys.doc(key).update(valuesToUpdate); } /** @@ -109,7 +94,8 @@ export class FirestoreAPIKeyStore implements APIKeyStore { * @returns The record associated with the API key. */ async getKey(key: string): Promise { - return this.keys.get(key); + const keyRef = await this.keys.doc(key).get(); + return keyRef.data() as APIKeyRecord; } /** @@ -117,8 +103,8 @@ export class FirestoreAPIKeyStore implements APIKeyStore { * @param key - The API key to delete. * @returns A boolean indicating whether the API key was deleted successfully. */ - async deleteKey(key: string): Promise { - return this.keys.delete(key); + async deleteKey(key: string): Promise { + return await this.keys.doc(key).delete(); } /** @@ -127,13 +113,11 @@ export class FirestoreAPIKeyStore implements APIKeyStore { * @returns A boolean indicating whether the requests were incremented successfully. * @throws Throws an error if the API key is not found. */ - async incrementRequests(key: string): Promise { - const apiKey = this.keys.get(key); - if (!apiKey) throw new Error("API key not found"); - - return this.updateKey({ - key, - requests: apiKey.requests + 1, + async incrementRequests(key: string): Promise { + // Increment the requests count for the API key + return await this.keys.doc(key).update({ + requests: FieldValue.increment(1), + lastUsed: new Date(), }); } } diff --git a/src/auth/in-memory-api-key-store.ts b/src/auth/in-memory-api-key-store.ts index f10399f..66aa0ae 100644 --- a/src/auth/in-memory-api-key-store.ts +++ b/src/auth/in-memory-api-key-store.ts @@ -20,15 +20,6 @@ export class InMemoryAPIKeyStore implements APIKeyStore { this.keys = new Map(); } - /** - * Verifies if an API key is valid and active. - * @param key - The API key to verify. - * @returns A boolean indicating whether the API key is valid and active. - */ - async verifyAPIKey(key: string): Promise { - return this.keys.has(key) && this.keys.get(key)?.status === "active"; - } - /** * Adds a new API key to the store. * By default, API key is disabled and has access to no endpoints. diff --git a/src/cache/cache-store.ts b/src/cache/cache-store.ts index f4d6416..0eefad3 100644 --- a/src/cache/cache-store.ts +++ b/src/cache/cache-store.ts @@ -25,6 +25,8 @@ export type CacheRecord = { expiry?: ExpiryDate; /** cache threshold. Query data is cached after this threshold reaches zero. Avoids the need to cache all data for every query. */ cacheThreshold: number; + /** record number of cache hits */ + cacheHits: number; }; /** Cache collection is a map containing all cache records. */ @@ -102,4 +104,9 @@ export interface CacheStore { decrementCacheThreshold( hash: QueryHash ): Promise | Promise; + + /** + * Increment the cache hits every time a cached response is used. + */ + incrementCacheHits(hash: QueryHash): Promise | Promise; } diff --git a/src/cache/firestore-cache-store.ts b/src/cache/firestore-cache-store.ts index efd2710..52c2fa4 100644 --- a/src/cache/firestore-cache-store.ts +++ b/src/cache/firestore-cache-store.ts @@ -1,4 +1,8 @@ -import { CollectionReference, WriteResult } from "firebase-admin/firestore"; +import { + CollectionReference, + FieldValue, + WriteResult, +} from "firebase-admin/firestore"; import { generateHash } from "../utils/utils"; import { CacheRecord, CacheStore } from "./cache-store"; import { app } from "firebase-admin"; @@ -56,6 +60,7 @@ export class FirestoreCacheStore implements CacheStore { const record: CacheRecord = { query, // complete query (may include chat history) cacheThreshold: this.cacheQueryAfterThreshold, // set cache threshold to the configured value + cacheHits: 0, }; // Add the record to the cache @@ -95,6 +100,7 @@ export class FirestoreCacheStore implements CacheStore { response, expiry: new Date(Date.now() + this.recordExpiryDuration), // set expiry date based on cache store configurations cacheThreshold: 0, // set cache threshold to 0 since query response is being cached now + cacheHits: 0, // set cache hits to 0 }; // Add the record to the cache @@ -154,4 +160,18 @@ export class FirestoreCacheStore implements CacheStore { cacheThreshold: data.cacheThreshold - 1, }); } + + /** + * Increments the cache hits for a specific query. + * Use this every time a cached response is used. + * @param hash - The hash of the query. + * @returns A promise with write operation result. + * @throws Error if the record is not found in the cache. + */ + async incrementCacheHits(hash: string): Promise { + // Increment the cache hits + return await this.cache.doc(hash).update({ + cacheHits: FieldValue.increment(1), + }); + } } diff --git a/src/cache/in-memory-cache-store.ts b/src/cache/in-memory-cache-store.ts index 02533a1..583bafa 100644 --- a/src/cache/in-memory-cache-store.ts +++ b/src/cache/in-memory-cache-store.ts @@ -13,9 +13,9 @@ import { */ export type InMemoryCacheStoreConfig = { /** duration after which each record expires */ - recordExpiryDuration: number; + recordExpiryDuration?: number; /** threshold after which a query is cached */ - cacheQueryAfterThreshold: number; + cacheQueryAfterThreshold?: number; }; /** @@ -31,8 +31,8 @@ export class InMemoryCacheStore implements CacheStore { constructor( { - recordExpiryDuration, - cacheQueryAfterThreshold, + recordExpiryDuration = 1000 * 60 * 60 * 24, + cacheQueryAfterThreshold = 3, }: InMemoryCacheStoreConfig = { recordExpiryDuration: 1000 * 60 * 60 * 24, // 24 hours cacheQueryAfterThreshold: 3, @@ -59,6 +59,7 @@ export class InMemoryCacheStore implements CacheStore { const record: CacheRecord = { query, // complete query (may include chat history) cacheThreshold: this.cacheQueryAfterThreshold, // set cache threshold to the configured value + cacheHits: 0, // set cache hits to 0 }; // Add the record to the cache @@ -101,6 +102,7 @@ export class InMemoryCacheStore implements CacheStore { response, expiry: new Date(Date.now() + this.recordExpiryDuration), // set expiry date based on cache store configurations cacheThreshold: 0, // set cache threshold to 0 since query response is being cached now + cacheHits: 0, // set cache hits to 0 }; // Add the record to the cache @@ -161,4 +163,20 @@ export class InMemoryCacheStore implements CacheStore { } return -1; } + + /** + * Increments the cache hits for a specific query. + * Use this every time a cached response is used. + * @param hash - The hash of the query. + * @returns The updated cache hits if the query exists in the cache. + * @throws Error if the record is not found in the cache. + */ + async incrementCacheHits(hash: string): Promise { + // Increment the cache hits + const record = this.cache.get(hash); + // if no record, throw an error + if (!record) throw new Error("Record not found in cache"); + // else, increment cache hits + record.cacheHits = record.cacheHits + 1; + } } diff --git a/src/flows/flow.ts b/src/flows/flow.ts index 56cee0d..8522db3 100644 --- a/src/flows/flow.ts +++ b/src/flows/flow.ts @@ -1,5 +1,9 @@ import { z } from "zod"; -import { ChatAgent } from "../agents/chat-agent"; +import { + ChatAgent, + GenerateResponseHistoryProps, + GenerateResponseProps, +} from "../agents/chat-agent"; import { defineFlow } from "@genkit-ai/flow"; import { APIKeyStore } from "../auth/api-key-store"; import { CacheStore } from "../cache/cache-store"; @@ -11,6 +15,16 @@ import { TextDataRetriever, } from "../rag/retrievers/retriever"; import { getDataRetriever } from "../rag/retrievers/data-retriever"; +import { ChatHistoryStore } from "../history/chat-history-store"; + +type ChatHistoryParams = + | { + enableChatHistory: true; + chatHistoryStore: ChatHistoryStore; + } + | { + enableChatHistory?: false; + }; type AuthParams = | { @@ -33,21 +47,36 @@ type CacheParams = type RAGParams = | { enableRAG: true; + contextTopic?: string; retrieverConfig: RetrieverConfig; } | { enableRAG: true; + contextTopic?: string; retriever: TextDataRetriever; } | { enableRAG?: false; }; -type DefineChatFlowConfig = { - chatAgent: ChatAgent; +type ChatAgentTypeParams = + | { + agentType?: "open-ended"; + } + | { + agentType: "close-ended"; + topic: string; + } + | { + chatAgent: ChatAgent; + }; + +export type DefineChatFlowConfig = { endpoint: string; enableChatHistory?: boolean; -} & AuthParams & +} & ChatAgentTypeParams & + ChatHistoryParams & + AuthParams & CacheParams & RAGParams; @@ -56,6 +85,7 @@ type DefineChatFlowConfig = { * @param chatAgent Chat Agent instance to use for this flow. * @param endpoint Flow endpoint value that will be used to send requests to this flow. * @param enableChatHistory Enable chat history for this flow. If chat ID is provided, chat history will be fetched and used to generate response. If no chat ID is provided, a new chat ID will be generated to store chat history, and will be returned in the response. + * @param chatHistoryStore Chat History Store instance to use for this flow. * @param enableAuth Enable authentication for this flow. Must provide an API Key Store instance if set to true. * @param apiKeyStore API Key Store instance to use for this flow. * @param enableCache Enable caching for this flow. Must provide a Cache Store instance if set to true. @@ -101,9 +131,6 @@ export const defineChatFlow = (config: DefineChatFlowConfig) => }, ], authPolicy: async (auth, input) => { - console.log("Auth policy called"); - console.log("Auth:", auth); - console.log("Input:", input); if (config.enableAuth) { // check if auth object is valid if (!auth || !auth.key) throw new Error("Error: Invalid API key"); @@ -124,6 +151,40 @@ export const defineChatFlow = (config: DefineChatFlowConfig) => async ({ query, chatId }) => { if (query === "") return { response: "How can I help you today?" }; + // store chat agent + let chatAgent: ChatAgent; + + // Initialize chat agent if not provided + if (!("chatAgent" in config)) { + // Initialize chat agent based on the provided type + // If agent type if close-ended, and RAG is not enabled (i.e., no context needed in queries) + if (config.agentType === "close-ended" && !config.enableRAG) { + // check if topic is provided + if (!config.topic) { + throw new Error( + "Error: Topic not provided for close-ended chat agent." + ); + } + // Initialize close-ended chat agent with the provided topic + chatAgent = new ChatAgent({ + agentType: "close-ended", + topic: config.topic, + }); + } else if (config.enableRAG) { + // Initialize chat agent with RAG + chatAgent = new ChatAgent({ + agentType: "rag", + topic: ("contextTopic" in config && config.contextTopic) || "", + }); + } else { + // Initialize open-ended chat + chatAgent = new ChatAgent(); + } + } else { + // use the provided chat agent + chatAgent = config.chatAgent; + } + // store query with context (includes the previous chat history if any, since that provides essential context) // will be used in caching and RAG, if enabled let queryWithContext = query; @@ -139,18 +200,32 @@ export const defineChatFlow = (config: DefineChatFlowConfig) => // used only if cache is enabled let cacheThresholdReached = false; + // if chatId is provided, get chat history and add it to the query context + if (config.enableChatHistory && chatId) { + try { + // try getting chat history for the given chat ID + const chatHistory = + await config.chatHistoryStore.getChatHistory(chatId); + + // add chat history to the query context + queryWithContext += getChatHistoryAsString(chatHistory); + // store chat history for use in generating response later + history = chatHistory; + } catch (error) { + return { + error: + error instanceof Error + ? error.message + : `Error fetching chat history for chat ID: ${chatId}`, + }; + } + } + + // if code here, chat history is disabled OR chat history is enabled but chat ID is not provided + // Don't generate new chat ID here, handled by the chat agent after response generation + // If using cache and cache store is provided if (config.enableCache && config.cacheStore) { - // if chatId is provided, get chat history and add it to the query context - if (config.enableChatHistory && chatId) { - const chatHistory = await config.chatAgent.getChatHistory(chatId); - if (chatHistory) { - // add chat history to the query context - queryWithContext += getChatHistoryAsString(chatHistory); - // store chat history for use in generating response later - history = chatHistory; - } - } // Generate hash of the complete query to use as a key for the cache queryHash = generateHash(queryWithContext); @@ -160,15 +235,19 @@ export const defineChatFlow = (config: DefineChatFlowConfig) => error: "Error: Invalid query. Could not generate hash.", }; - // Check cache for the query - const cachedQuery = await config.cacheStore.getRecord(queryHash); - // If the query is cached, return the cached response - if (cachedQuery) { + try { + // Check cache for the query + const cachedQuery = await config.cacheStore.getRecord(queryHash); + // check if cached response is available if (cachedQuery.response) { - console.log("Chat flow with history: returning cached response"); - return { response: cachedQuery.response, chatId }; + // increment cache hits + config.cacheStore.incrementCacheHits(queryHash); + // return the cached response with the chat ID + return config.enableChatHistory + ? { response: cachedQuery.response, chatId } + : cachedQuery.response; } // if response is not available, but query is in cache @@ -182,7 +261,7 @@ export const defineChatFlow = (config: DefineChatFlowConfig) => // if cacheThreshold reaches 0, cache the response cacheThresholdReached = true; } - } else { + } catch (error) { // if query is not in cache, add it to cache to track the number of times this query is received // sending hash is optional. Sending so hash doesn't have to be recalculated // remeber to add the query with context @@ -215,13 +294,27 @@ export const defineChatFlow = (config: DefineChatFlowConfig) => } } - // Generate a response using the chat agent - const response = await config.chatAgent.generateResponse({ + // Prepare query for generating response + let queryWithParams: GenerateResponseProps = { query, - chatId, - history, context, - }); + }; + + // If chat history is enabled + if (config.enableChatHistory) { + // Prepare history props for generating response + const historyProps: GenerateResponseHistoryProps = { + enableChatHistory: config.enableChatHistory, + chatId: chatId, + history: history, + chatHistoryStore: config.chatHistoryStore, + }; + // Add history props to the query + queryWithParams = { ...queryWithParams, ...historyProps }; + } + + // Generate a response using the chat agent + const response = await chatAgent.generateResponse(queryWithParams); // If using cache and cache store is provided, and // if cacheThreshold reaches 0 for this query, cache the response @@ -229,10 +322,12 @@ export const defineChatFlow = (config: DefineChatFlowConfig) => config.cacheStore.cacheResponse(queryHash, response.res.text()); } - return { - response: response.res.text(), - chatId: response.chatId, - }; + return config.enableChatHistory + ? { + response: response.res.text(), + chatId: response.chatId, + } + : response.res.text(); } catch (error) { return { error: `Error: ${error}`, diff --git a/src/history/chat-history-store.ts b/src/history/chat-history-store.ts index 27ed12c..c6830fc 100644 --- a/src/history/chat-history-store.ts +++ b/src/history/chat-history-store.ts @@ -1,4 +1,5 @@ import { MessageData } from "@genkit-ai/ai/model"; +import { CollectionReference } from "firebase-admin/firestore"; /** * Represents a record of chat history. @@ -18,24 +19,56 @@ export type ChatHistoryCollection = Map; * * @interface ChatHistoryStore * - * @property {ChatHistoryCollection} history - The collection of chat history records. + * @property {ChatHistoryCollection | CollectionReference} history - The collection of chat history records. * @property {(messages?: MessageData[]) => Promise} addChatHistory - Adds a new chat history to the store. - * @property {(chatId: string, messages: MessageData[]) => Promise} updateChatHistory - Updates an existing chat history in the store. - * @property {(chatId: string, messages: MessageData[]) => Promise} addMessages - Adds messages to an existing chat history in the store. - * @property {(chatId: string) => Promise} getChatHistory - Retrieves the chat history for a given chat ID. - * @property {(chatId: string) => Promise} deleteChatHistory - Deletes the chat history for a given chat ID. + * @property {(chatId: string, messages: MessageData[]) => Promise | Promise} updateChatHistory - Updates an existing chat history in the store. + * @property {(chatId: string, messages: MessageData[]) => Promise | Promise} addMessages - Adds messages to an existing chat history in the store. + * @property {(chatId: string) => Promise} getChatHistory - Retrieves chat history from the store. + * @property {(chatId: string) => Promise | Promise} deleteChatHistory - Deletes chat history from the store. */ export interface ChatHistoryStore { - history: ChatHistoryCollection; + /** + * The collection of chat history records. + */ + history: ChatHistoryCollection | CollectionReference; + /** + * Add new chat history to the store. Returns chat ID of the new chat history. + * @param messages add new chat history to the store + * @returns chat ID of the new chat history + */ addChatHistory: (messages?: MessageData[]) => Promise; + /** + * Update existing chat history in the store. Overwrites existing messages with new messages. + * @param chatId ID of the chat history to update + * @param messages messages to add to the chat history + * @throws Error if unable to update chat history + */ updateChatHistory: ( chatId: string, messages: MessageData[] ) => Promise | Promise; + /** + * Add messages to an existing chat history in the store. + * @param chatId ID of the chat history to update + * @param messages messages to add to the chat history + * @throws Error if unable to add messages to chat history + */ addMessages: ( chatId: string, messages: MessageData[] ) => Promise | Promise; - getChatHistory: (chatId: string) => Promise; + /** + * Get chat history from the store for the specified chat ID. + * @param chatId Chat ID for the chat history to retrieve + * @returns Array of messages pretaining to the chat history + * @throws Error if unable to retrieve chat history + */ + getChatHistory: (chatId: string) => Promise; + /** + * Delete chat history from the store for the specified chat ID. + * @param chatId Chat ID for the chat history to delete + * @throws Error if unable to delete chat history + * @returns Promise that resolves when chat history is deleted + */ deleteChatHistory: (chatId: string) => Promise | Promise; } diff --git a/src/history/firestore-chat-history-store.ts b/src/history/firestore-chat-history-store.ts index 6b0be5e..0672957 100644 --- a/src/history/firestore-chat-history-store.ts +++ b/src/history/firestore-chat-history-store.ts @@ -1,7 +1,7 @@ import { MessageData } from "@genkit-ai/ai/model"; import { app } from "firebase-admin"; -import { FieldValue } from "firebase-admin/firestore"; -import { ChatHistoryCollection, ChatHistoryStore } from "./chat-history-store"; +import { CollectionReference, FieldValue } from "firebase-admin/firestore"; +import { ChatHistoryStore } from "./chat-history-store"; /** * Configuration for the Firebase chat history store. @@ -18,12 +18,7 @@ export class FirestoreChatHistoryStore implements ChatHistoryStore { /** * Reference to the collection in Firestore where chat history is stored. */ - collectionRef: FirebaseFirestore.CollectionReference; - - /** - * The collection of chat history records. - */ - history: ChatHistoryCollection = new Map(); + history: CollectionReference; /** * Initializes a new instance of the FirebaseChatHistoryStore class. @@ -31,7 +26,7 @@ export class FirestoreChatHistoryStore implements ChatHistoryStore { */ constructor(config: FirestoreChatHistoryStoreConfig) { // initialize Firestore collection reference - this.collectionRef = config.firebaseApp + this.history = config.firebaseApp .firestore() .collection(config.collectionName); } @@ -43,7 +38,7 @@ export class FirestoreChatHistoryStore implements ChatHistoryStore { */ async addChatHistory(messages?: MessageData[]): Promise { // add chat history to Firestore - const newChatHistory = await this.collectionRef.add({ + const newChatHistory = await this.history.add({ messages: messages || [], lastUpdated: new Date(), }); @@ -63,7 +58,7 @@ export class FirestoreChatHistoryStore implements ChatHistoryStore { messages: MessageData[] ): Promise { // update firestore chat history - await this.collectionRef.doc(chatId).update({ + await this.history.doc(chatId).update({ messages: messages, lastUpdated: new Date(), }); @@ -77,7 +72,7 @@ export class FirestoreChatHistoryStore implements ChatHistoryStore { */ async addMessages(chatId: string, messages: MessageData[]): Promise { // add message to chat history - await this.collectionRef.doc(chatId).update({ + await this.history.doc(chatId).update({ messages: FieldValue.arrayUnion(...messages), lastUpdated: new Date(), }); @@ -89,15 +84,15 @@ export class FirestoreChatHistoryStore implements ChatHistoryStore { * @returns Returns the chat history as an array of MessageData objects. Returns undefined if the chat history is not found. * @throws Throws an error if the conversation with the specified ID is not found. */ - async getChatHistory(chatId: string): Promise { + async getChatHistory(chatId: string): Promise { // get chat history from Firestore - const chatHistory = await this.collectionRef.doc(chatId).get(); + const chatHistory = await this.history.doc(chatId).get(); if (!chatHistory.exists) { throw new Error(`Chat history with ID ${chatId} not found.`); } // return messages const data = chatHistory.data(); - return data ? (data.messages as MessageData[]) : undefined; + return data ? (data.messages as MessageData[]) : []; } /** @@ -107,10 +102,10 @@ export class FirestoreChatHistoryStore implements ChatHistoryStore { */ async deleteChatHistory(chatId: string): Promise { // delete chat history from Firestore - const chatHistory = await this.collectionRef.doc(chatId).get(); + const chatHistory = await this.history.doc(chatId).get(); if (!chatHistory.exists) { throw new Error(`Chat history with ID ${chatId} not found.`); } - await this.collectionRef.doc(chatId).delete(); + await this.history.doc(chatId).delete(); } } diff --git a/src/history/in-memory-chat-history-store.ts b/src/history/in-memory-chat-history-store.ts index 0a67c97..b37c189 100644 --- a/src/history/in-memory-chat-history-store.ts +++ b/src/history/in-memory-chat-history-store.ts @@ -76,11 +76,14 @@ export class InMemoryChatHistoryStore implements ChatHistoryStore { * @returns Returns the chat history as an array of MessageData objects. * @throws Throws an error if the conversation with the specified ID is not found. */ - async getChatHistory(chatId: string): Promise { + async getChatHistory(chatId: string): Promise { // get chat history record const chatHistoryRecord = this.history.get(chatId); + // if chat history record not found for the given chat ID, throw an error + if (!chatHistoryRecord) + throw new Error(`Chat history with ID ${chatId} not found.`); // if chat history record is valid, return chat history - return chatHistoryRecord ? chatHistoryRecord.messages : undefined; + return chatHistoryRecord.messages; } /** diff --git a/src/models/model.ts b/src/models/model.ts index 1ee58b3..688a2f9 100644 --- a/src/models/model.ts +++ b/src/models/model.ts @@ -21,6 +21,8 @@ export const SupportedModelNames = { gpt4: gpt4.name, } as const; +export const getSupportedModelNames = () => Object.values(SupportedModelNames); + /** * List of supported models. */ diff --git a/src/rag/knowledge-bases/test-retail-store-kb/inventory-data.csv b/src/rag/knowledge-bases/test-data/inventory-data.csv similarity index 100% rename from src/rag/knowledge-bases/test-retail-store-kb/inventory-data.csv rename to src/rag/knowledge-bases/test-data/inventory-data.csv diff --git a/src/rag/knowledge-bases/test-retail-store-kb/return-policy.md b/src/rag/knowledge-bases/test-data/return-policy.md similarity index 100% rename from src/rag/knowledge-bases/test-retail-store-kb/return-policy.md rename to src/rag/knowledge-bases/test-data/return-policy.md diff --git a/src/tests/api-keys.tests.ts b/src/tests/api-keys.tests.ts new file mode 100644 index 0000000..610ff1f --- /dev/null +++ b/src/tests/api-keys.tests.ts @@ -0,0 +1,113 @@ +import { runFlow } from "@genkit-ai/flow"; +import { defineChatFlow } from "../flows/flow"; +import { InMemoryAPIKeyStore } from "../auth/in-memory-api-key-store"; +import { generateAlphaNumericString } from "../utils/utils"; +import { setupGenkit } from "../genkit"; + +/** + * Test suite for Chat Flow Core Functionality. + * + * Some tests include the use of LLM model, defining a chat agent, defining API key store, defining chat history store, and defining cache store. + */ +describe("Test - Flow API Keys Tests", () => { + beforeAll(() => { + setupGenkit(); + }); + + // Tests to be performed + // Set to true to run the test + const Tests = { + test_api_key_is_required: true, + test_api_key_auth_working: true, + }; + + // default test timeout + const defaultTimeout = 10000; // 10 secondss + + if (Tests.test_api_key_is_required) + test( + "Test API Key is required", + async () => { + // Initialize API key store + const apiKeyStore = new InMemoryAPIKeyStore(); + // add a test API key + const key = generateAlphaNumericString(); + apiKeyStore.addKey(key, { + uid: "test-user", + status: "active", + endpoints: "all", // allow access to all endpoints + }); + // define chat flow + const flow = defineChatFlow({ + endpoint: "test-chat-open-api-key-required", + enableAuth: true, + apiKeyStore, + }); + + let response; + + try { + // send test query without API key + response = await runFlow(flow, { + query: "How can you help? In one sentence.", + uid: "test-user", + }); + + throw new Error( + `Expected an error to be thrown. Instead received response: ${JSON.stringify(response)}` + ); + } catch (error) { + // check response is undefined + expect(response).not.toBeDefined(); + // check error message is valid + expect(error).toBeDefined(); + } + }, + defaultTimeout + ); + + if (Tests.test_api_key_auth_working) + test( + "Test API Key auth working", + async () => { + // Initialize API key store + const apiKeyStore = new InMemoryAPIKeyStore(); + // Test user ID and key + const testUID = "test-user"; + // add a test API key + const testKey = generateAlphaNumericString(); + apiKeyStore.addKey(testKey, { + uid: testUID, + status: "active", + endpoints: "all", // allow access to all endpoints + }); + // define chat flow + const flow = defineChatFlow({ + endpoint: "test-chat-open-api-key-auth-working", + enableAuth: true, + apiKeyStore, + }); + try { + // send test query with API key + const response = await runFlow( + flow, + { + query: "How can you help? In one sentence.", + uid: testUID, + }, + { + withLocalAuthContext: { + key: testKey, + }, + } + ); + // check response is valid and does not contain error + expect(response).toBeDefined(); + expect(response).not.toHaveProperty("error"); + } catch (error) { + throw new Error(`Error in test. Error: ${error}`); + } + }, + defaultTimeout + ); +}); diff --git a/src/tests/cache.tests.ts b/src/tests/cache.tests.ts new file mode 100644 index 0000000..32c4944 --- /dev/null +++ b/src/tests/cache.tests.ts @@ -0,0 +1,87 @@ +import { runFlow } from "@genkit-ai/flow"; +import { defineChatFlow } from "../flows/flow"; +import { InMemoryCacheStore } from "../cache/in-memory-cache-store"; +import { setupGenkit } from "../genkit"; +import { CacheCollection } from "../cache/cache-store"; + +/** + * Test suite for Chat Flow Core Functionality. + * + * Some tests include the use of LLM model, defining a chat agent, defining API key store, defining chat history store, and defining cache store. + */ +describe("Test - Flow Cache Tests", () => { + beforeAll(() => { + setupGenkit(); + }); + + // Tests to be performed + // Set to true to run the test + const Tests = { + test_cache_works: true, + }; + + // default test timeout + const defaultTimeout = 10000; // 10 secondss + + if (Tests.test_cache_works) + test( + "Test cache works", + async () => { + // use in-memory cache store + const cacheStore = new InMemoryCacheStore({ + cacheQueryAfterThreshold: 2, // cache response after same query is received twice + }); + // define chat flow + const flow = defineChatFlow({ + endpoint: "test-chat-open-cache", + enableCache: true, + cacheStore: cacheStore, + }); + + try { + // send query the first time + await runFlow(flow, { + query: "Answer in one sentence: what is Firebase?", + }); + + // send query the second time + await runFlow(flow, { + query: "Answer in one sentence: what is Firebase?", + }); + + // send query the third time + const response = await runFlow(flow, { + query: "Answer in one sentence: what is Firebase?", + }); + + // check response is valid + expect(response).toBeDefined(); + + // confirm response type + if (typeof response === "string") { + // should not be empty + expect(response.length).toBeGreaterThan(0); + // check cache was used + const atLeastOneCacheHit = (cache: CacheCollection) => { + let flag = false; + cache.forEach((val) => { + if (val.cacheHits > 0) { + flag = true; + } + }); + return flag; + }; + // confirm cache was used + expect(atLeastOneCacheHit(cacheStore.cache)).toBeTruthy(); + } else { + throw new Error( + `Invalid response object. Response: ${JSON.stringify(response)}` + ); + } + } catch (error) { + throw new Error(`Error in test. Error: ${error}`); + } + }, + defaultTimeout + ); +}); diff --git a/src/tests/chat-history.tests.ts b/src/tests/chat-history.tests.ts new file mode 100644 index 0000000..c8f6451 --- /dev/null +++ b/src/tests/chat-history.tests.ts @@ -0,0 +1,122 @@ +import { runFlow } from "@genkit-ai/flow"; +import { defineChatFlow } from "../flows/flow"; +import { setupGenkit } from "../genkit"; +import { InMemoryChatHistoryStore } from "../history/in-memory-chat-history-store"; + +/** + * Test suite for Chat Flow Core Functionality. + * + * Some tests include the use of LLM model, defining a chat agent, defining API key store, defining chat history store, and defining cache store. + */ +describe("Test - Flow Chat History Tests", () => { + beforeAll(() => { + setupGenkit(); + }); + + // Tests to be performed + // Set to true to run the test + const Tests = { + sending_invalid_chat_id_when_chat_history_is_disabled: true, + sending_invalid_chat_id_when_chat_history_is_enabled: true, + test_chat_history_works: true, + }; + + // default test timeout + const defaultTimeout = 10000; // 10 secondss + + if (Tests.sending_invalid_chat_id_when_chat_history_is_disabled) + test( + "Sending invalid Chat ID when chat history is disabled", + async () => { + const flow = defineChatFlow({ + endpoint: "test-chat-open-chat-id-history-disabled", + enableChatHistory: false, + }); + const response = await runFlow(flow, { + query: "How can you help? In one sentence.", + chatId: "test-chat-id", + }); + expect(response).toBeDefined(); + // expected return type string + if (typeof response === "string") { + // should not be empty + expect(response.length).toBeGreaterThan(0); + } else { + throw new Error( + `Invalid response type. Expected string. Response: ${JSON.stringify(response)}` + ); + } + }, + defaultTimeout + ); + + if (Tests.sending_invalid_chat_id_when_chat_history_is_enabled) + test( + "Sending invalid Chat ID when chat history is enabled", + async () => { + const flow = defineChatFlow({ + endpoint: "test-chat-open-chat-id-history-enabled", + enableChatHistory: true, + chatHistoryStore: new InMemoryChatHistoryStore(), + }); + const response = await runFlow(flow, { + query: "How can you help? In one sentence.", + chatId: "test-chat-id", + }); + expect(response).toBeDefined(); + expect(response).toHaveProperty("error"); + }, + defaultTimeout + ); + + if (Tests.test_chat_history_works) + test( + "Test chat history works", + async () => { + const flow = defineChatFlow({ + endpoint: "test-chat-open-chat-history", + enableChatHistory: true, + chatHistoryStore: new InMemoryChatHistoryStore(), + }); + const response = await runFlow(flow, { + query: "What is Firebase? In one sentence.", + }); + expect(response).toBeDefined(); + expect(response).toHaveProperty("chatId"); + + if (typeof response !== "string" && "chatId" in response) { + const chatId = response.chatId; + + // response should not be empty + expect(response.response.length).toBeGreaterThan(0); + + const secondResponse = await runFlow(flow, { + query: "Can I use it for authentication? In one sentence.", + chatId, + }); + + expect(secondResponse).toBeDefined(); + expect(secondResponse).toHaveProperty("chatId"); + + if ( + typeof secondResponse !== "string" && + "chatId" in secondResponse + ) { + // response should not be empty + expect(response.response.length).toBeGreaterThan(0); + // chat ID should be the same + expect(secondResponse.chatId).toEqual(chatId); + } else { + throw new Error( + `error in second response. Invalid response object. Response: ${JSON.stringify(response)}` + ); + } + } else { + throw new Error( + `error in response. Invalid response object. Response: ${JSON.stringify(response)}` + ); + } + }, + defaultTimeout + ); +}); diff --git a/src/tests/flow-rag.tests.ts b/src/tests/flow-rag.tests.ts new file mode 100644 index 0000000..deb5a1e --- /dev/null +++ b/src/tests/flow-rag.tests.ts @@ -0,0 +1,74 @@ +import { runFlow } from "@genkit-ai/flow"; +import { defineChatFlow } from "../flows/flow"; +import { setupGenkit } from "../genkit"; +import { getDataRetriever } from "../rag/retrievers/data-retriever"; + +/** + * Test suite for Chat Flow Core Functionality. + * + * Some tests include the use of LLM model, defining a chat agent, defining API key store, defining chat history store, and defining cache store. + */ +describe("Test - Flow RAG Tests", () => { + beforeAll(() => { + setupGenkit(); + }); + + // Tests to be performed + // Set to true to run the test + const Tests = { + test_rag_works: true, + }; + + // default test timeout + const defaultTimeout = 10000; // 10 secondss + + if (Tests.test_rag_works) + test( + "Test RAG works (w/ Data Retriever, Embedding Generation, RAG-enabled Flow)", + async () => { + // define chat flow + const flow = defineChatFlow({ + endpoint: "test-chat-open-rag", + enableRAG: true, + retriever: await getDataRetriever({ + dataType: "csv", + filePath: "lib/tests/test-data/inventory-data.csv", + generateEmbeddings: true, + }), + }); + try { + // send test query + const response = await runFlow(flow, { + query: "What is the price of Seagate ST1000DX002?", + }); + + // check response is valid and does not contain error + expect(response).toBeDefined(); + expect(response).not.toHaveProperty("error"); + + // confirm response type + if (typeof response === "string") { + // should not be empty + expect(response.length).toBeGreaterThan(0); + // should contain 68.06 + expect(response).toContain("68.06"); + } else { + expect(response).toHaveProperty("response"); + if ("response" in response) { + // should not be empty + expect(response.response.length).toBeGreaterThan(0); + // should contain 68.06 + expect(response.response).toContain("68.06"); + } else { + throw new Error( + `Response field invalid. Response: ${JSON.stringify(response)}` + ); + } + } + } catch (error) { + throw new Error(`Error in test. Error: ${error}`); + } + }, + defaultTimeout + ); +}); diff --git a/src/tests/flow.tests.ts b/src/tests/flow.tests.ts new file mode 100644 index 0000000..72f18eb --- /dev/null +++ b/src/tests/flow.tests.ts @@ -0,0 +1,66 @@ +import { runFlow } from "@genkit-ai/flow"; +import { defineChatFlow } from "../flows/flow"; +import { setupGenkit } from "../genkit"; + +/** + * Test suite for Chat Flow Core Functionality. + * + * Some tests include the use of LLM model, defining a chat agent, defining API key store, defining chat history store, and defining cache store. + */ +describe("Test - Chat Flow Core Funtionality Tests", () => { + beforeAll(() => { + setupGenkit(); + }); + + // Tests to be performed + // Set to true to run the test + const Tests = { + define_chat_flow: true, + confirm_response_generation: true, + sending_invalid_chat_id_when_chat_history_is_disabled: true, + sending_invalid_chat_id_when_chat_history_is_enabled: true, + test_chat_history_works: true, + test_cache_works: true, + test_api_key_is_required: true, + test_api_key_auth_working: true, + test_rag_works: true, + }; + + // default test timeout + const defaultTimeout = 10000; // 10 secondss + + if (Tests.define_chat_flow) + test("Define chat flow", () => { + const flow = defineChatFlow({ endpoint: "test-chat" }); + expect(flow).toBeDefined(); + }); + + if (Tests.confirm_response_generation) + test( + "Confirm response generation", + async () => { + const flow = defineChatFlow({ + endpoint: "test-chat-open-response", + }); + const response = await runFlow(flow, { + query: "How can you help? In one sentence.", + }); + expect(response).toBeDefined(); + if (typeof response === "string") { + // should not be empty + expect(response.length).toBeGreaterThan(0); + } else { + expect(response).toHaveProperty("response"); + if ("response" in response) { + // should not be empty + expect(response.response.length).toBeGreaterThan(0); + } else { + throw new Error( + `error in response generation. Response: ${JSON.stringify(response)}` + ); + } + } + }, + defaultTimeout + ); +}); diff --git a/src/tests/test-data/inventory-data.csv b/src/tests/test-data/inventory-data.csv new file mode 100644 index 0000000..1bde451 --- /dev/null +++ b/src/tests/test-data/inventory-data.csv @@ -0,0 +1,36 @@ +CATEGORY_ID,CATEGORY_NAME,PRODUCT_ID,PRODUCT_NAME,DESCRIPTION,DESCRIPTION - Detail 1,DESCRIPTION - Detail 2,DESCRIPTION - Detail 3,DESCRIPTION - Detail 4,STANDARD_COST,LIST_PRICE,COUNTRY_ID,REGION_ID,LOCATION_ID,WAREHOUSE_ID,QUANTITY,WAREHOUSE_NAME,ADDRESS,POSTAL_CODE,CITY,STATE,COUNTRY_NAME +5,Storage,22,Seagate ST3000DM008,"Series:Barracuda,Type:7200RPM,Capacity:3TB,Cache:64MB",Series:Barracuda,Type:7200RPM,Capacity:3TB,Cache:64MB,61.63,83.61,MX,2,23,7,50,Mexico City,Mariano Escobedo 9991,11932,Monterrey,Nuevo León,Mexico +5,Storage,23,Western Digital WDS250G1B0A,"Series:Blue,Type:SSD,Capacity:250GB,Cache:N/A",Series:Blue,Type:SSD,Capacity:250GB,Cache:N/A,72.54,89.89,AU,3,13,6,62,Sydney,12-98 Victoria Street,2901,Sydney,New South Wales,Australia +5,Storage,24,Seagate ST2000DM006,"Series:Barracuda,Type:7200RPM,Capacity:2TB,Cache:64MB",Series:Barracuda,Type:7200RPM,Capacity:2TB,Cache:64MB,47.93,66.89,MX,2,23,7,50,Mexico City,Mariano Escobedo 9991,11932,Monterrey,Nuevo León,Mexico +5,Storage,25,Samsung MZ-75E250B/AM,"Series:850 EVO-Series,Type:SSD,Capacity:250GB,Cache:N/A",Series:850 EVO-Series,Type:SSD,Capacity:250GB,Cache:N/A,87.98,104.88,MX,2,23,7,51,Mexico City,Mariano Escobedo 9991,11932,Monterrey,Nuevo León,Mexico +5,Storage,26,Samsung MZ-75E500B/AM,"Series:850 EVO-Series,Type:SSD,Capacity:500GB,Cache:N/A",Series:850 EVO-Series,Type:SSD,Capacity:500GB,Cache:N/A,157.81,178.09,MX,2,23,7,51,Mexico City,Mariano Escobedo 9991,11932,Monterrey,Nuevo León,Mexico +5,Storage,33,ADATA ASU800SS-128GT-C,"Series:Ultimate SU800,Type:SSD,Capacity:128GB,Cache:N/A",Series:Ultimate SU800,Type:SSD,Capacity:128GB,Cache:N/A,37.78,52.65,CN,3,11,8,42,Beijing,40-5-12 Laogianggen,190518,Beijing,Shenzhen,China +5,Storage,44,Seagate ST1000DM010,"Series:BarraCuda,Type:7200RPM,Capacity:1TB,Cache:64MB",Series:BarraCuda,Type:7200RPM,Capacity:1TB,Cache:64MB,42.18,49.37,US,2,6,2,122,San Francisco,2011 Interiors Blvd,99236,South San Francisco,California,United States of America +5,Storage,56,Western Digital WD2500AAJS,"Series:Caviar Blue,Type:7200RPM,Capacity:250GB,Cache:8MB",Series:Caviar Blue,Type:7200RPM,Capacity:250GB,Cache:8MB,15.23,16.99,AU,3,13,6,58,Sydney,12-98 Victoria Street,2901,Sydney,New South Wales,Australia +5,Storage,57,Western Digital WD20EZRZ,"Series:Blue,Type:5400RPM,Capacity:2TB,Cache:64MB",Series:Blue,Type:5400RPM,Capacity:2TB,Cache:64MB,58.01,67.34,AU,3,13,6,66,Sydney,12-98 Victoria Street,2901,Sydney,New South Wales,Australia +5,Storage,94,Western Digital WD2500AVVS,"Series:AV-GP,Type:5400RPM,Capacity:250GB,Cache:8MB",Series:AV-GP,Type:5400RPM,Capacity:250GB,Cache:8MB,12.63,15.55,MX,2,23,7,57,Mexico City,Mariano Escobedo 9991,11932,Monterrey,Nuevo León,Mexico +5,Storage,95,Western Digital WDS256G1X0C,"Series:Black PCIe,Type:SSD,Capacity:256GB,Cache:N/A",Series:Black PCIe,Type:SSD,Capacity:256GB,Cache:N/A,85.87,109.99,AU,3,13,6,60,Sydney,12-98 Victoria Street,2901,Sydney,New South Wales,Australia +5,Storage,96,SanDisk SDSSDHII-480G-G25,"Series:Ultra II,Type:SSD,Capacity:480GB,Cache:N/A",Series:Ultra II,Type:SSD,Capacity:480GB,Cache:N/A,102.62,141.56,AU,3,13,6,60,Sydney,12-98 Victoria Street,2901,Sydney,New South Wales,Australia +5,Storage,99,Seagate ST1000DX002,"Series:FireCuda,Type:Hybrid,Capacity:1TB,Cache:64MB",Series:FireCuda,Type:Hybrid,Capacity:1TB,Cache:64MB,55.41,68.06,CA,2,9,5,88,Toronto,147 Spadina Ave,M5V 2L7,Toronto,Ontario,Canada +5,Storage,100,Crucial CT275MX300SSD1,"Series:MX300,Type:SSD,Capacity:275GB,Cache:N/A",Series:MX300,Type:SSD,Capacity:275GB,Cache:N/A,79.21,97.88,CA,2,9,5,88,Toronto,147 Spadina Ave,M5V 2L7,Toronto,Ontario,Canada +5,Storage,104,SanDisk SDSSDA-240G-G26,"Series:SSD PLUS,Type:SSD,Capacity:240GB,Cache:N/A",Series:SSD PLUS,Type:SSD,Capacity:240GB,Cache:N/A,61.1,83.88,CN,3,11,8,46,Beijing,40-5-12 Laogianggen,190518,Beijing,Shenzhen,China +5,Storage,130,Western Digital WD2003FZEX,"Series:BLACK SERIES,Type:7200RPM,Capacity:2TB,Cache:64MB",Series:BLACK SERIES,Type:7200RPM,Capacity:2TB,Cache:64MB,91.76,117.45,MX,2,23,7,66,Mexico City,Mariano Escobedo 9991,11932,Monterrey,Nuevo León,Mexico +5,Storage,135,Samsung MZ-V6E250,"Series:960 EVO,Type:SSD,Capacity:250GB,Cache:512MB",Series:960 EVO,Type:SSD,Capacity:250GB,Cache:512MB,92.98,127.88,US,2,6,2,89,San Francisco,2011 Interiors Blvd,99236,South San Francisco,California,United States of America +5,Storage,139,Hitachi HUS724030ALE641,"Series:Ultrastar 7K4000,Type:7200RPM,Capacity:3TB,Cache:64MB",Series:Ultrastar 7K4000,Type:7200RPM,Capacity:3TB,Cache:64MB,54.03,65.92,US,2,6,2,93,San Francisco,2011 Interiors Blvd,99236,South San Francisco,California,United States of America +5,Storage,168,Seagate ST31000340NS - FFP,"Series:Barracuda ES,Type:7200RPM,Capacity:1TB,Cache:32MB",Series:Barracuda ES,Type:7200RPM,Capacity:1TB,Cache:32MB,34.4,43.99,MX,2,23,7,68,Mexico City,Mariano Escobedo 9991,11932,Monterrey,Nuevo León,Mexico +5,Storage,230,ADATA ASU800SS-512GT-C,"Series:Ultimate SU800,Type:SSD,Capacity:512GB,Cache:N/A",Series:Ultimate SU800,Type:SSD,Capacity:512GB,Cache:N/A,113.29,136.69,MX,2,23,7,136,Mexico City,Mariano Escobedo 9991,11932,Monterrey,Nuevo León,Mexico +5,Storage,232,Western Digital WD1003FZEX,"Series:BLACK SERIES,Type:7200RPM,Capacity:1TB,Cache:64MB",Series:BLACK SERIES,Type:7200RPM,Capacity:1TB,Cache:64MB,61.76,70.89,CN,3,11,8,124,Beijing,40-5-12 Laogianggen,190518,Beijing,Shenzhen,China +5,Storage,233,SanDisk SDSSDA-120G-G26,"Series:SSD PLUS,Type:SSD,Capacity:120GB,Cache:N/A",Series:SSD PLUS,Type:SSD,Capacity:120GB,Cache:N/A,52.7,59.99,CN,3,11,8,124,Beijing,40-5-12 Laogianggen,190518,Beijing,Shenzhen,China +5,Storage,234,Crucial CT525MX300SSD1,"Series:MX300,Type:SSD,Capacity:525GB,Cache:N/A",Series:MX300,Type:SSD,Capacity:525GB,Cache:N/A,135.59,150.99,CA,2,9,5,164,Toronto,147 Spadina Ave,M5V 2L7,Toronto,Ontario,Canada +5,Storage,235,Hitachi A7K1000-1000,"Series:Ultrastar,Type:7200RPM,Capacity:1TB,Cache:32MB",Series:Ultrastar,Type:7200RPM,Capacity:1TB,Cache:32MB,29.94,41.99,CA,2,9,5,164,Toronto,147 Spadina Ave,M5V 2L7,Toronto,Ontario,Canada +5,Storage,254,Samsung MZ-7KE256BW,"Series:850 Pro Series,Type:SSD,Capacity:256GB,Cache:N/A",Series:850 Pro Series,Type:SSD,Capacity:256GB,Cache:N/A,97.19,119.99,CN,3,11,8,136,Beijing,40-5-12 Laogianggen,190518,Beijing,Shenzhen,China +5,Storage,255,Seagate ST2000DX002,"Series:FireCuda,Type:Hybrid,Capacity:2TB,Cache:64MB",Series:FireCuda,Type:Hybrid,Capacity:2TB,Cache:64MB,64.48,90.99,AU,3,13,6,162,Sydney,12-98 Victoria Street,2901,Sydney,New South Wales,Australia +5,Storage,256,Western Digital WD5000AACS,"Series:Caviar Green,Type:5400RPM,Capacity:500GB,Cache:16MB",Series:Caviar Green,Type:5400RPM,Capacity:500GB,Cache:16MB,20.14,26.99,AU,3,13,6,162,Sydney,12-98 Victoria Street,2901,Sydney,New South Wales,Australia +5,Storage,257,SanDisk SDSSDHII-240G-G25,"Series:Ultra II,Type:SSD,Capacity:240GB,Cache:N/A",Series:Ultra II,Type:SSD,Capacity:240GB,Cache:N/A,73.39,84.95,US,2,6,2,226,San Francisco,2011 Interiors Blvd,99236,South San Francisco,California,United States of America +5,Storage,258,PNY SSD7CS1311-120-RB,"Series:CS1311,Type:SSD,Capacity:120GB,Cache:N/A",Series:CS1311,Type:SSD,Capacity:120GB,Cache:N/A,50.59,57.98,CA,2,9,5,176,Toronto,147 Spadina Ave,M5V 2L7,Toronto,Ontario,Canada +5,Storage,259,PNY SSD9SC240GMDA-RB,"Series:XLR8,Type:SSD,Capacity:240GB,Cache:N/A",Series:XLR8,Type:SSD,Capacity:240GB,Cache:N/A,58.4,80.72,US,2,6,2,226,San Francisco,2011 Interiors Blvd,99236,South San Francisco,California,United States of America +5,Storage,260,Crucial CT1050MX300SSD1,"Series:MX300,Type:SSD,Capacity:1.1TB,Cache:N/A",Series:MX300,Type:SSD,Capacity:1.1TB,Cache:N/A,192.52,267.99,MX,2,23,7,149,Mexico City,Mariano Escobedo 9991,11932,Monterrey,Nuevo León,Mexico +5,Storage,263,Western Digital WDS250G1B0B,"Series:Blue,Type:SSD,Capacity:250GB,Cache:N/A",Series:Blue,Type:SSD,Capacity:250GB,Cache:N/A,70.71,89.99,US,2,6,2,227,San Francisco,2011 Interiors Blvd,99236,South San Francisco,California,United States of America +5,Storage,264,Samsung MZ-75E120B/AM,"Series:850 EVO-Series,Type:SSD,Capacity:120GB,Cache:N/A",Series:850 EVO-Series,Type:SSD,Capacity:120GB,Cache:N/A,74.41,88.99,US,2,6,2,227,San Francisco,2011 Interiors Blvd,99236,South San Francisco,California,United States of America +5,Storage,280,Western Digital WDS500G1B0B,"Series:Blue,Type:SSD,Capacity:500GB,Cache:N/A",Series:Blue,Type:SSD,Capacity:500GB,Cache:N/A,106.89,149.88,AU,3,13,6,180,Sydney,12-98 Victoria Street,2901,Sydney,New South Wales,Australia +5,Storage,284,Kingston SA400S37/120G,"Series:A400,Type:SSD,Capacity:120GB,Cache:N/A",Series:A400,Type:SSD,Capacity:120GB,Cache:N/A,40.63,54.99,AU,3,13,6,320,Sydney,12-98 Victoria Street,2901,Sydney,New South Wales,Australia diff --git a/test-flows.ts b/test-flows.ts index 6090cbb..566e7c9 100644 --- a/test-flows.ts +++ b/test-flows.ts @@ -1,8 +1,9 @@ import { ChatAgent } from "./src/agents/chat-agent"; import { InMemoryAPIKeyStore } from "./src/auth/in-memory-api-key-store"; import { InMemoryCacheStore } from "./src/cache/in-memory-cache-store"; -import { ENDPOINTS, GLOBAL_CONFIG } from "./src/config"; +import { ENDPOINTS } from "./src/config"; import { defineChatFlow } from "./src/flows/flow"; +import { InMemoryChatHistoryStore } from "./src/history/in-memory-chat-history-store"; import { getDataRetriever } from "./src/rag/retrievers/data-retriever"; import { generateAlphaNumericString } from "./src/utils/utils"; @@ -15,10 +16,9 @@ export const defineTestFlows = async () => { }); // Open-ended chat flow with support for chat history defineChatFlow({ - chatAgent: new ChatAgent({ - enableChatHistory: true, - }), endpoint: ENDPOINTS.CHAT.OPEN_ENDED_WITH_HISTORY, + enableChatHistory: true, + chatHistoryStore: new InMemoryChatHistoryStore(), }); // Close-ended chat flow (will only answer queries related to specified topic, in this case, 'Firebase') @@ -31,83 +31,67 @@ export const defineTestFlows = async () => { }); // Close-ended chat flow with support for chat history defineChatFlow({ - chatAgent: new ChatAgent({ - agentType: "close-ended", - topic: "Firebase", - enableChatHistory: true, - }), endpoint: ENDPOINTS.CHAT.CLOSE_ENDED_WITH_HISTORY, + agentType: "close-ended", + topic: "Firebase", + enableChatHistory: true, + chatHistoryStore: new InMemoryChatHistoryStore(), }); // Below are examples of flows that support authentication using API keys and support response caching // Initialize API key store - const apiKeyStore = new InMemoryAPIKeyStore(); + const testAPIKeyStore = new InMemoryAPIKeyStore(); // add a test API key const key = generateAlphaNumericString(); - apiKeyStore.addKey(key, { + testAPIKeyStore.addKey(key, { uid: "test-user", status: "active", endpoints: "all", // allow access to all endpoints }); console.log("\nTest API Key"); - console.dir(apiKeyStore); - - // Define a cache store - const cacheStore = new InMemoryCacheStore(GLOBAL_CONFIG.cacheStoreConfig); + console.dir(testAPIKeyStore); // Open-ended chat flow with support for chat history, authentication, and caching defineChatFlow({ - chatAgent: new ChatAgent({ - enableChatHistory: true, - }), endpoint: ENDPOINTS.CHAT.OPEN_ENDED_HISTORY_AUTH_CACHED, enableChatHistory: true, + chatHistoryStore: new InMemoryChatHistoryStore(), enableAuth: true, - apiKeyStore, + apiKeyStore: testAPIKeyStore, enableCache: true, - cacheStore, + cacheStore: new InMemoryCacheStore(), }); // Close-ended chat flow with support for chat history, authentication, and caching defineChatFlow({ - chatAgent: new ChatAgent({ - agentType: "close-ended", - topic: "Firebase", - enableChatHistory: true, - }), + agentType: "close-ended", + topic: "Firebase", endpoint: ENDPOINTS.CHAT.CLOSE_ENDED_HISTORY_AUTH_CACHED, enableChatHistory: true, + chatHistoryStore: new InMemoryChatHistoryStore(), enableAuth: true, - apiKeyStore, + apiKeyStore: testAPIKeyStore, enableCache: true, - cacheStore, + cacheStore: new InMemoryCacheStore(), }); // Index inventory data and get retriever const inventoryDataRetriever = await getDataRetriever({ dataType: "csv", - filePath: "lib/rag/knowledge-bases/test-retail-store-kb/inventory-data.csv", + filePath: "lib/rag/knowledge-base/test-data/inventory-data.csv", generateEmbeddings: true, - retrievalOptions: { - k: 10, // return top 10 matching documents - searchType: "mmr", // use Maximal Marginal Relevance (MMR) for search - }, }); // Inventory Data chat flow with support for chat history, authentication, caching and RAG defineChatFlow({ - chatAgent: new ChatAgent({ - agentType: "rag", - topic: "Store Inventory Data", - enableChatHistory: true, - }), endpoint: ENDPOINTS.CHAT.RAG_HISTORY_AUTH_CACHED + "-inventory", enableChatHistory: true, + chatHistoryStore: new InMemoryChatHistoryStore(), enableAuth: true, - apiKeyStore, + apiKeyStore: testAPIKeyStore, enableCache: true, - cacheStore, + cacheStore: new InMemoryCacheStore(), enableRAG: true, retriever: inventoryDataRetriever, });