diff --git a/llm-recs/appengine-server/package-lock.json b/llm-recs/appengine-server/package-lock.json index 13ad481c..ab1ceb34 100644 --- a/llm-recs/appengine-server/package-lock.json +++ b/llm-recs/appengine-server/package-lock.json @@ -11,6 +11,7 @@ "dependencies": { "express": "^4.18.2", "google-auth-library": "^9.2.0", + "ts-llmt": "^1.0.1", "ts-node": "^10.9.1", "underscore": "^1.13.6" }, @@ -29,25 +30,18 @@ "typescript": "~5.1.3" } }, - "node_modules/@aashutoshrathi/word-wrap": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz", - "integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/@bcoe/v8-coverage": { "version": "0.2.3", "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@cspotcode/source-map-support": { "version": "0.8.1", "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", + "license": "MIT", "dependencies": { "@jridgewell/trace-mapping": "0.3.9" }, @@ -56,34 +50,40 @@ } }, "node_modules/@eslint-community/eslint-utils": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", - "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.1.tgz", + "integrity": "sha512-s3O3waFUrMV8P/XaF/+ZTp1X9XBZW1a4B97ZnjQF2KYWaFD2A8KyFBsrsfSjEmjn3RGWAIuvlneuZm3CUK3jbA==", "dev": true, + "license": "MIT", "dependencies": { - "eslint-visitor-keys": "^3.3.0" + "eslint-visitor-keys": "^3.4.3" }, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, + "funding": { + "url": "https://opencollective.com/eslint" + }, "peerDependencies": { "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" } }, "node_modules/@eslint-community/regexpp": { - "version": "4.10.0", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.10.0.tgz", - "integrity": "sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA==", + "version": "4.11.2", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.11.2.tgz", + "integrity": "sha512-2WwyTYNVaMNUWPZTOJdkax9iqTdirrApgTbk+Qoq5EPX6myqZvG8QGFRgdKmkjKVG6/G/a565vpPauHk0+hpBA==", "dev": true, + "license": "MIT", "engines": { "node": "^12.0.0 || ^14.0.0 || >=16.0.0" } }, "node_modules/@eslint/eslintrc": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.3.tgz", - "integrity": "sha512-yZzuIG+jnVu6hNSzFEN07e8BxF3uAzYtQb6uDkaYZLo6oYZDCq454c5kB8zxnzfCYyP4MIuyBn10L0DqwujTmA==", + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", + "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", "dev": true, + "license": "MIT", "dependencies": { "ajv": "^6.12.4", "debug": "^4.3.2", @@ -102,124 +102,38 @@ "url": "https://opencollective.com/eslint" } }, - "node_modules/@eslint/eslintrc/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/@eslint/eslintrc/node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/@eslint/eslintrc/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/@eslint/eslintrc/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, "node_modules/@eslint/js": { - "version": "8.53.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.53.0.tgz", - "integrity": "sha512-Kn7K8dx/5U6+cT1yEhpX1w4PCSg0M+XyRILPgvwcEBjerFWCwQj5sbr3/VmxqV0JGHCBCzyd6LxypEuehypY1w==", + "version": "8.57.1", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.1.tgz", + "integrity": "sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q==", "dev": true, + "license": "MIT", "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, "node_modules/@humanwhocodes/config-array": { - "version": "0.11.13", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.13.tgz", - "integrity": "sha512-JSBDMiDKSzQVngfRjOdFXgFfklaXI4K9nLF49Auh21lmBWRLIK3+xTErTWD4KU54pb6coM6ESE7Awz/FNU3zgQ==", + "version": "0.13.0", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.13.0.tgz", + "integrity": "sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw==", + "deprecated": "Use @eslint/config-array instead", "dev": true, + "license": "Apache-2.0", "dependencies": { - "@humanwhocodes/object-schema": "^2.0.1", - "debug": "^4.1.1", + "@humanwhocodes/object-schema": "^2.0.3", + "debug": "^4.3.1", "minimatch": "^3.0.5" }, "engines": { "node": ">=10.10.0" } }, - "node_modules/@humanwhocodes/config-array/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/@humanwhocodes/config-array/node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/@humanwhocodes/config-array/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/@humanwhocodes/config-array/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, "node_modules/@humanwhocodes/module-importer": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", "dev": true, + "license": "Apache-2.0", "engines": { "node": ">=12.22" }, @@ -229,37 +143,43 @@ } }, "node_modules/@humanwhocodes/object-schema": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.1.tgz", - "integrity": "sha512-dvuCeX5fC9dXgJn9t+X5atfmgQAzUOWqS1254Gh0m6i8wKd10ebXkfNKiRK+1GWi/yTvvLDHpoxLr0xxxeslWw==", - "dev": true + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz", + "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==", + "deprecated": "Use @eslint/object-schema instead", + "dev": true, + "license": "BSD-3-Clause" }, "node_modules/@istanbuljs/schema": { "version": "0.1.3", "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz", - "integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "license": "MIT", "engines": { "node": ">=6.0.0" } }, "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.4.15", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", - "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==" + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", + "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==", + "license": "MIT" }, "node_modules/@jridgewell/trace-mapping": { "version": "0.3.9", "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", + "license": "MIT", "dependencies": { "@jridgewell/resolve-uri": "^3.0.3", "@jridgewell/sourcemap-codec": "^1.4.10" @@ -270,6 +190,7 @@ "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", "dev": true, + "license": "MIT", "dependencies": { "@nodelib/fs.stat": "2.0.5", "run-parallel": "^1.1.9" @@ -283,6 +204,7 @@ "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", "dev": true, + "license": "MIT", "engines": { "node": ">= 8" } @@ -292,6 +214,7 @@ "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", "dev": true, + "license": "MIT", "dependencies": { "@nodelib/fs.scandir": "2.1.5", "fastq": "^1.6.0" @@ -301,67 +224,77 @@ } }, "node_modules/@tsconfig/node10": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz", - "integrity": "sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==" + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.11.tgz", + "integrity": "sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==", + "license": "MIT" }, "node_modules/@tsconfig/node12": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", - "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==" + "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", + "license": "MIT" }, "node_modules/@tsconfig/node14": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", - "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==" + "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", + "license": "MIT" }, "node_modules/@tsconfig/node16": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", - "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==" + "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", + "license": "MIT" }, "node_modules/@tsconfig/node18": { - "version": "18.2.2", - "resolved": "https://registry.npmjs.org/@tsconfig/node18/-/node18-18.2.2.tgz", - "integrity": "sha512-d6McJeGsuoRlwWZmVIeE8CUA27lu6jLjvv1JzqmpsytOYYbVi1tHZEnwCNVOXnj4pyLvneZlFlpXUK+X9wBWyw==", - "dev": true + "version": "18.2.4", + "resolved": "https://registry.npmjs.org/@tsconfig/node18/-/node18-18.2.4.tgz", + "integrity": "sha512-5xxU8vVs9/FNcvm3gE07fPbn9tl6tqGGWA9tSlwsUEkBxtRnTsNmwrV8gasZ9F/EobaSv9+nu8AxUKccw77JpQ==", + "dev": true, + "license": "MIT" }, "node_modules/@types/body-parser": { - "version": "1.19.4", - "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.4.tgz", - "integrity": "sha512-N7UDG0/xiPQa2D/XrVJXjkWbpqHCd2sBaB32ggRF2l83RhPfamgKGF8gwwqyksS95qUS5ZYF9aF+lLPRlwI2UA==", + "version": "1.19.5", + "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.5.tgz", + "integrity": "sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg==", "dev": true, + "license": "MIT", "dependencies": { "@types/connect": "*", "@types/node": "*" } }, "node_modules/@types/chai": { - "version": "4.3.11", - "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.3.11.tgz", - "integrity": "sha512-qQR1dr2rGIHYlJulmr8Ioq3De0Le9E4MJ5AiaeAETJJpndT1uUNHsGFK3L/UIu+rbkQSdj8J/w2bCsBZc/Y5fQ==", - "dev": true + "version": "4.3.20", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.3.20.tgz", + "integrity": "sha512-/pC9HAB5I/xMlc5FP77qjCnI16ChlJfW0tGa0IUcFn38VJrTV6DeZ60NU5KZBtaOZqjdpwTWohz5HU1RrhiYxQ==", + "dev": true, + "license": "MIT" }, "node_modules/@types/connect": { - "version": "3.4.37", - "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.37.tgz", - "integrity": "sha512-zBUSRqkfZ59OcwXon4HVxhx5oWCJmc0OtBTK05M+p0dYjgN6iTwIL2T/WbsQZrEsdnwaF9cWQ+azOnpPvIqY3Q==", + "version": "3.4.38", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz", + "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==", "dev": true, + "license": "MIT", "dependencies": { "@types/node": "*" } }, "node_modules/@types/cookiejar": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/@types/cookiejar/-/cookiejar-2.1.3.tgz", - "integrity": "sha512-LZ8SD3LpNmLMDLkG2oCBjZg+ETnx6XdCjydUE0HwojDmnDfDUnhMKKbtth1TZh+hzcqb03azrYWoXLS8sMXdqg==", - "dev": true + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@types/cookiejar/-/cookiejar-2.1.5.tgz", + "integrity": "sha512-he+DHOWReW0nghN24E1WUqM0efK4kI9oTqDm6XmK8ZPe2djZ90BSNdGnIyCLzCPw7/pogPlGbzI2wHGGmi4O/Q==", + "dev": true, + "license": "MIT" }, "node_modules/@types/express": { - "version": "4.17.20", - "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.20.tgz", - "integrity": "sha512-rOaqlkgEvOW495xErXMsmyX3WKBInbhG5eqojXYi3cGUaLoRDlXa5d52fkfWZT963AZ3v2eZ4MbKE6WpDAGVsw==", + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.21.tgz", + "integrity": "sha512-ejlPM315qwLpaQlQDTjPdsUFSc6ZsP4AN6AlWnogPjQ7CVi7PYF3YVz+CY3jE2pwYf7E/7HlDAN0rV2GxTG0HQ==", "dev": true, + "license": "MIT", "dependencies": { "@types/body-parser": "*", "@types/express-serve-static-core": "^4.17.33", @@ -370,10 +303,11 @@ } }, "node_modules/@types/express-serve-static-core": { - "version": "4.17.39", - "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.39.tgz", - "integrity": "sha512-BiEUfAiGCOllomsRAZOiMFP7LAnrifHpt56pc4Z7l9K6ACyN06Ns1JLMBxwkfLOjJRlSf06NwWsT7yzfpaVpyQ==", + "version": "4.19.6", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.19.6.tgz", + "integrity": "sha512-N4LZ2xG7DatVqhCZzOGb1Yi5lMbXSZcmdLDe9EzSndPV2HpWYWzRbaerl2n27irrm94EPpprqa8KpskPT085+A==", "dev": true, + "license": "MIT", "dependencies": { "@types/node": "*", "@types/qs": "*", @@ -382,94 +316,115 @@ } }, "node_modules/@types/http-errors": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.3.tgz", - "integrity": "sha512-pP0P/9BnCj1OVvQR2lF41EkDG/lWWnDyA203b/4Fmi2eTyORnBtcDoKDwjWQthELrBvWkMOrvSOnZ8OVlW6tXA==", - "dev": true + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.4.tgz", + "integrity": "sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA==", + "dev": true, + "license": "MIT" }, "node_modules/@types/istanbul-lib-coverage": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.5.tgz", - "integrity": "sha512-zONci81DZYCZjiLe0r6equvZut0b+dBRPBN5kBDjsONnutYNtJMoWQ9uR2RkL1gLG9NMTzvf+29e5RFfPbeKhQ==", - "dev": true + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz", + "integrity": "sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/methods": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/@types/methods/-/methods-1.1.4.tgz", + "integrity": "sha512-ymXWVrDiCxTBE3+RIrrP533E70eA+9qu7zdWoHuOmGujkYtzf4HQF96b8nwHLqhuf4ykX61IGRIB38CC6/sImQ==", + "dev": true, + "license": "MIT" }, "node_modules/@types/mime": { - "version": "1.3.4", - "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.4.tgz", - "integrity": "sha512-1Gjee59G25MrQGk8bsNvC6fxNiRgUlGn2wlhGf95a59DrprnnHk80FIMMFG9XHMdrfsuA119ht06QPDXA1Z7tw==", - "dev": true + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz", + "integrity": "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==", + "dev": true, + "license": "MIT" }, "node_modules/@types/mocha": { - "version": "10.0.3", - "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-10.0.3.tgz", - "integrity": "sha512-RsOPImTriV/OE4A9qKjMtk2MnXiuLLbcO3nCXK+kvq4nr0iMfFgpjaX3MPLb6f7+EL1FGSelYvuJMV6REH+ZPQ==", - "dev": true + "version": "10.0.9", + "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-10.0.9.tgz", + "integrity": "sha512-sicdRoWtYevwxjOHNMPTl3vSfJM6oyW8o1wXeI7uww6b6xHg8eBznQDNSGBCDJmsE8UMxP05JgZRtsKbTqt//Q==", + "dev": true, + "license": "MIT" }, "node_modules/@types/node": { - "version": "20.8.7", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.8.7.tgz", - "integrity": "sha512-21TKHHh3eUHIi2MloeptJWALuCu5H7HQTdTrWIFReA8ad+aggoX+lRes3ex7/FtpC+sVUpFMQ+QTfYr74mruiQ==", + "version": "22.8.1", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.8.1.tgz", + "integrity": "sha512-k6Gi8Yyo8EtrNtkHXutUu2corfDf9su95VYVP10aGYMMROM6SAItZi0w1XszA6RtWTHSVp5OeFof37w0IEqCQg==", + "license": "MIT", "dependencies": { - "undici-types": "~5.25.1" + "undici-types": "~6.19.8" } }, "node_modules/@types/qs": { - "version": "6.9.9", - "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.9.tgz", - "integrity": "sha512-wYLxw35euwqGvTDx6zfY1vokBFnsK0HNrzc6xNHchxfO2hpuRg74GbkEW7e3sSmPvj0TjCDT1VCa6OtHXnubsg==", - "dev": true + "version": "6.9.16", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.16.tgz", + "integrity": "sha512-7i+zxXdPD0T4cKDuxCUXJ4wHcsJLwENa6Z3dCu8cfCK743OGy5Nu1RmAGqDPsoTDINVEcdXKRvR/zre+P2Ku1A==", + "dev": true, + "license": "MIT" }, "node_modules/@types/range-parser": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.6.tgz", - "integrity": "sha512-+0autS93xyXizIYiyL02FCY8N+KkKPhILhcUSA276HxzreZ16kl+cmwvV2qAM/PuCCwPXzOXOWhiPcw20uSFcA==", - "dev": true + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz", + "integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==", + "dev": true, + "license": "MIT" }, "node_modules/@types/send": { - "version": "0.17.3", - "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.3.tgz", - "integrity": "sha512-/7fKxvKUoETxjFUsuFlPB9YndePpxxRAOfGC/yJdc9kTjTeP5kRCTzfnE8kPUKCeyiyIZu0YQ76s50hCedI1ug==", + "version": "0.17.4", + "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.4.tgz", + "integrity": "sha512-x2EM6TJOybec7c52BX0ZspPodMsQUd5L6PRwOunVyVUhXiBSKf3AezDL8Dgvgt5o0UfKNfuA0eMLr2wLT4AiBA==", "dev": true, + "license": "MIT", "dependencies": { "@types/mime": "^1", "@types/node": "*" } }, "node_modules/@types/serve-static": { - "version": "1.15.4", - "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.4.tgz", - "integrity": "sha512-aqqNfs1XTF0HDrFdlY//+SGUxmdSUbjeRXb5iaZc3x0/vMbYmdw9qvOgHWOyyLFxSSRnUuP5+724zBgfw8/WAw==", + "version": "1.15.7", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.7.tgz", + "integrity": "sha512-W8Ym+h8nhuRwaKPaDw34QUkwsGi6Rc4yYqvKFo5rm2FUEhCFbzVWrxXUxuKK8TASjWsysJY0nsmNCGhCOIsrOw==", "dev": true, + "license": "MIT", "dependencies": { "@types/http-errors": "*", - "@types/mime": "*", - "@types/node": "*" + "@types/node": "*", + "@types/send": "*" } }, "node_modules/@types/superagent": { - "version": "4.1.20", - "resolved": "https://registry.npmjs.org/@types/superagent/-/superagent-4.1.20.tgz", - "integrity": "sha512-GfpwJgYSr3yO+nArFkmyqv3i0vZavyEG5xPd/o95RwpKYpsOKJYI5XLdxLpdRbZI3YiGKKdIOFIf/jlP7A0Jxg==", + "version": "8.1.9", + "resolved": "https://registry.npmjs.org/@types/superagent/-/superagent-8.1.9.tgz", + "integrity": "sha512-pTVjI73witn+9ILmoJdajHGW2jkSaOzhiFYF1Rd3EQ94kymLqB9PjD9ISg7WaALC7+dCHT0FGe9T2LktLq/3GQ==", "dev": true, + "license": "MIT", "dependencies": { - "@types/cookiejar": "*", - "@types/node": "*" + "@types/cookiejar": "^2.1.5", + "@types/methods": "^1.1.4", + "@types/node": "*", + "form-data": "^4.0.0" } }, "node_modules/@types/supertest": { - "version": "2.0.15", - "resolved": "https://registry.npmjs.org/@types/supertest/-/supertest-2.0.15.tgz", - "integrity": "sha512-jUCZZ/TMcpGzoSaed9Gjr8HCf3HehExdibyw3OHHEL1als1KmyzcOZZH4MjbObI8TkWsEr7bc7gsW0WTDni+qQ==", + "version": "2.0.16", + "resolved": "https://registry.npmjs.org/@types/supertest/-/supertest-2.0.16.tgz", + "integrity": "sha512-6c2ogktZ06tr2ENoZivgm7YnprnhYE4ZoXGMY+oA7IuAf17M8FWvujXZGmxLv8y0PTyts4x5A+erSwVUFA8XSg==", "dev": true, + "license": "MIT", "dependencies": { "@types/superagent": "*" } }, "node_modules/@types/yargs": { - "version": "17.0.32", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.32.tgz", - "integrity": "sha512-xQ67Yc/laOG5uMfX/093MRlGGCIBzZMarVa+gfNKJxWAIgykYpVGkBdbqEzGDDfCrVUj6Hiff4mTZ5BA6TmAog==", + "version": "17.0.33", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.33.tgz", + "integrity": "sha512-WpxBCKWPLr4xSsHgz511rFJAM+wS28w2zEO1QDNY5zM/S8ok70NNfztH0xwhqKyaK0OHCbN98LDAZuy1ctxDkA==", "dev": true, + "license": "MIT", "dependencies": { "@types/yargs-parser": "*" } @@ -478,18 +433,21 @@ "version": "21.0.3", "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.3.tgz", "integrity": "sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@ungap/structured-clone": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/accepts": { "version": "1.3.8", "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "license": "MIT", "dependencies": { "mime-types": "~2.1.34", "negotiator": "0.6.3" @@ -499,9 +457,10 @@ } }, "node_modules/acorn": { - "version": "8.10.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.10.0.tgz", - "integrity": "sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==", + "version": "8.13.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.13.0.tgz", + "integrity": "sha512-8zSiw54Oxrdym50NlZ9sUusyO1Z1ZchgRLWRaK6c86XJFClyCgFKetdowBg5bKxyp/u+CDBJG4Mpp0m3HLZl9w==", + "license": "MIT", "bin": { "acorn": "bin/acorn" }, @@ -514,22 +473,28 @@ "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", "dev": true, + "license": "MIT", "peerDependencies": { "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, "node_modules/acorn-walk": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", - "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", + "version": "8.3.4", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.4.tgz", + "integrity": "sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==", + "license": "MIT", + "dependencies": { + "acorn": "^8.11.0" + }, "engines": { "node": ">=0.4.0" } }, "node_modules/agent-base": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.0.tgz", - "integrity": "sha512-o/zjMZRhJxny7OyEF+Op8X+efiELC7k7yOjMzgfzVqOzXqkBkWI79YoTdOtsuWd5BWhAGAuOY/Xa6xpiaWXiNg==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.1.tgz", + "integrity": "sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==", + "license": "MIT", "dependencies": { "debug": "^4.3.4" }, @@ -537,32 +502,12 @@ "node": ">= 14" } }, - "node_modules/agent-base/node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/agent-base/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - }, "node_modules/ajv": { "version": "6.12.6", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", "dev": true, + "license": "MIT", "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", @@ -575,10 +520,11 @@ } }, "node_modules/ansi-colors": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", - "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", + "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } @@ -588,6 +534,7 @@ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -597,6 +544,7 @@ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, + "license": "MIT", "dependencies": { "color-convert": "^2.0.1" }, @@ -612,6 +560,7 @@ "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", "dev": true, + "license": "ISC", "dependencies": { "normalize-path": "^3.0.0", "picomatch": "^2.0.4" @@ -623,30 +572,35 @@ "node_modules/arg": { "version": "4.1.3", "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", - "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==" + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", + "license": "MIT" }, "node_modules/argparse": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true + "dev": true, + "license": "Python-2.0" }, "node_modules/array-flatten": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", - "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==" + "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==", + "license": "MIT" }, "node_modules/asap": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/assertion-error": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", "dev": true, + "license": "MIT", "engines": { "node": "*" } @@ -655,13 +609,15 @@ "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/base64-js": { "version": "1.5.1", @@ -680,40 +636,47 @@ "type": "consulting", "url": "https://feross.org/support" } - ] + ], + "license": "MIT" }, "node_modules/bignumber.js": { "version": "9.1.2", "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.1.2.tgz", "integrity": "sha512-2/mKyZH9K85bzOEfhXDBFZTGd1CTs+5IHpeFQo9luiBG7hghdC851Pj2WAhb6E3R6b9tZj/XKhbg4fum+Kepug==", + "license": "MIT", "engines": { "node": "*" } }, "node_modules/binary-extensions": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", - "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/body-parser": { - "version": "1.20.1", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz", - "integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==", + "version": "1.20.3", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz", + "integrity": "sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==", + "license": "MIT", "dependencies": { "bytes": "3.1.2", - "content-type": "~1.0.4", + "content-type": "~1.0.5", "debug": "2.6.9", "depd": "2.0.0", "destroy": "1.2.0", "http-errors": "2.0.0", "iconv-lite": "0.4.24", "on-finished": "2.4.1", - "qs": "6.11.0", - "raw-body": "2.5.1", + "qs": "6.13.0", + "raw-body": "2.5.2", "type-is": "~1.6.18", "unpipe": "1.0.0" }, @@ -722,22 +685,40 @@ "npm": "1.2.8000 || >= 1.4.16" } }, + "node_modules/body-parser/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/body-parser/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" + }, "node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "dev": true, + "license": "MIT", "dependencies": { - "balanced-match": "^1.0.0" + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" } }, "node_modules/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", "dev": true, + "license": "MIT", "dependencies": { - "fill-range": "^7.0.1" + "fill-range": "^7.1.1" }, "engines": { "node": ">=8" @@ -747,17 +728,20 @@ "version": "1.3.1", "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/buffer-equal-constant-time": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", - "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==" + "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==", + "license": "BSD-3-Clause" }, "node_modules/bytes": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "license": "MIT", "engines": { "node": ">= 0.8" } @@ -767,6 +751,7 @@ "resolved": "https://registry.npmjs.org/c8/-/c8-8.0.1.tgz", "integrity": "sha512-EINpopxZNH1mETuI0DzRA4MZpAUH+IFiRhnmFD3vFr3vdrgxqi3VfE3KL0AIL+zDq8rC9bZqwM/VDmmoe04y7w==", "dev": true, + "license": "ISC", "dependencies": { "@bcoe/v8-coverage": "^0.2.3", "@istanbuljs/schema": "^0.1.3", @@ -789,13 +774,19 @@ } }, "node_modules/call-bind": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.5.tgz", - "integrity": "sha512-C3nQxfFZxFRVoJoGKKI8y3MOEo129NQ+FgQ08iye+Mk4zNZZGdjfs06bVTr+DBSlA66Q2VEcMki/cUCP4SercQ==", + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", + "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", + "license": "MIT", "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", "function-bind": "^1.1.2", - "get-intrinsic": "^1.2.1", - "set-function-length": "^1.1.1" + "get-intrinsic": "^1.2.4", + "set-function-length": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -806,6 +797,7 @@ "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } @@ -815,6 +807,7 @@ "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", "dev": true, + "license": "MIT", "engines": { "node": ">=10" }, @@ -823,10 +816,11 @@ } }, "node_modules/chai": { - "version": "4.3.10", - "resolved": "https://registry.npmjs.org/chai/-/chai-4.3.10.tgz", - "integrity": "sha512-0UXG04VuVbruMUYbJ6JctvH0YnC/4q3/AkT18q4NaITo91CUm0liMS9VqzT9vZhVQ/1eqPanMWjBM+Juhfb/9g==", + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/chai/-/chai-4.5.0.tgz", + "integrity": "sha512-RITGBfijLkBddZvnn8jdqoTypxvqbOLYQkGGxXzeFjVHvudaPw0HNFD9x928/eUwYWd2dPCugVqspGALTZZQKw==", "dev": true, + "license": "MIT", "dependencies": { "assertion-error": "^1.1.0", "check-error": "^1.0.3", @@ -834,7 +828,7 @@ "get-func-name": "^2.0.2", "loupe": "^2.3.6", "pathval": "^1.1.1", - "type-detect": "^4.0.8" + "type-detect": "^4.1.0" }, "engines": { "node": ">=4" @@ -845,6 +839,7 @@ "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, + "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -861,6 +856,7 @@ "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.3.tgz", "integrity": "sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg==", "dev": true, + "license": "MIT", "dependencies": { "get-func-name": "^2.0.2" }, @@ -869,16 +865,11 @@ } }, "node_modules/chokidar": { - "version": "3.5.3", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", - "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://paulmillr.com/funding/" - } - ], + "license": "MIT", "dependencies": { "anymatch": "~3.1.2", "braces": "~3.0.2", @@ -891,15 +882,32 @@ "engines": { "node": ">= 8.10.0" }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, "optionalDependencies": { "fsevents": "~2.3.2" } }, + "node_modules/chokidar/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/cliui": { "version": "8.0.1", "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", "dev": true, + "license": "ISC", "dependencies": { "string-width": "^4.2.0", "strip-ansi": "^6.0.1", @@ -914,6 +922,7 @@ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, + "license": "MIT", "dependencies": { "color-name": "~1.1.4" }, @@ -925,13 +934,15 @@ "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/combined-stream": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", "dev": true, + "license": "MIT", "dependencies": { "delayed-stream": "~1.0.0" }, @@ -940,21 +951,27 @@ } }, "node_modules/component-emitter": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", - "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==", - "dev": true + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.1.tgz", + "integrity": "sha512-T0+barUSQRTUQASh8bx02dl+DhF54GtIDY13Y3m9oWTklKbb3Wv974meRpeZ3lp1JpLVECWWNHC4vaG2XHXouQ==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } }, "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/content-disposition": { "version": "0.5.4", "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "license": "MIT", "dependencies": { "safe-buffer": "5.2.1" }, @@ -966,6 +983,7 @@ "version": "1.0.5", "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", + "license": "MIT", "engines": { "node": ">= 0.6" } @@ -974,12 +992,14 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/cookie": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", - "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==", + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.1.tgz", + "integrity": "sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==", + "license": "MIT", "engines": { "node": ">= 0.6" } @@ -987,24 +1007,28 @@ "node_modules/cookie-signature": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", - "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==" + "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==", + "license": "MIT" }, "node_modules/cookiejar": { "version": "2.1.4", "resolved": "https://registry.npmjs.org/cookiejar/-/cookiejar-2.1.4.tgz", "integrity": "sha512-LDx6oHrK+PhzLKJU9j5S7/Y3jM/mUHvD/DeI1WQmJn652iPC5Y4TBzC9l+5OMOXlyTTA+SmVUPm0HQUwpD5Jqw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/create-require": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", - "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==" + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", + "license": "MIT" }, "node_modules/cross-spawn": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", "dev": true, + "license": "MIT", "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", @@ -1015,11 +1039,20 @@ } }, "node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", + "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", + "license": "MIT", "dependencies": { - "ms": "2.0.0" + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } } }, "node_modules/decamelize": { @@ -1027,6 +1060,7 @@ "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz", "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=10" }, @@ -1035,10 +1069,11 @@ } }, "node_modules/deep-eql": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-4.1.3.tgz", - "integrity": "sha512-WaEtAOpRA1MQ0eohqZjpGD8zdI0Ovsm8mmFhaDN8dvDZzyoUMcYDnf5Y6iu7HTXxf8JDS23qWa4a+hKCDyOPzw==", + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-4.1.4.tgz", + "integrity": "sha512-SUwdGfqdKOwxCPeVYjwSyRpJ7Z+fhpwIAtmCUdZIWZ/YP5R9WAsyuSgpLVDi9bjWoN2LXHNss/dk3urXtdQxGg==", "dev": true, + "license": "MIT", "dependencies": { "type-detect": "^4.0.0" }, @@ -1050,19 +1085,24 @@ "version": "0.1.4", "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/define-data-property": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.1.tgz", - "integrity": "sha512-E7uGkTzkk1d0ByLeSc6ZsFS79Axg+m1P/VsgYsxHgiuc3tFSj+MjMIwe90FC4lOAZzNBdY7kkO2P2wKdsQ1vgQ==", + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "license": "MIT", "dependencies": { - "get-intrinsic": "^1.2.1", - "gopd": "^1.0.1", - "has-property-descriptors": "^1.0.0" + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" }, "engines": { "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/delayed-stream": { @@ -1070,6 +1110,7 @@ "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.4.0" } @@ -1078,6 +1119,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "license": "MIT", "engines": { "node": ">= 0.8" } @@ -1086,6 +1128,7 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", + "license": "MIT", "engines": { "node": ">= 0.8", "npm": "1.2.8000 || >= 1.4.16" @@ -1096,15 +1139,18 @@ "resolved": "https://registry.npmjs.org/dezalgo/-/dezalgo-1.0.4.tgz", "integrity": "sha512-rXSP0bf+5n0Qonsb+SVVfNfIsimO4HEtmnIpPHY8Q1UCzKlQrDMfdobr8nJOOsRgWCyMRqeSBQzmWUMq7zvVig==", "dev": true, + "license": "ISC", "dependencies": { "asap": "^2.0.0", "wrappy": "1" } }, "node_modules/diff": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", - "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-5.2.0.tgz", + "integrity": "sha512-uIFDxqpRZGZ6ThOk84hEfqWoHx2devRFvpTZcTHur85vImfaxUbTW9Ryh4CpCuDnToOP1CEtXKIgytHBPVff5A==", + "dev": true, + "license": "BSD-3-Clause", "engines": { "node": ">=0.3.1" } @@ -1114,6 +1160,7 @@ "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", "dev": true, + "license": "Apache-2.0", "dependencies": { "esutils": "^2.0.2" }, @@ -1125,6 +1172,7 @@ "version": "1.0.11", "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", + "license": "Apache-2.0", "dependencies": { "safe-buffer": "^5.0.1" } @@ -1132,27 +1180,52 @@ "node_modules/ee-first": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", - "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", + "license": "MIT" }, "node_modules/emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/encodeurl": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", + "license": "MIT", "engines": { "node": ">= 0.8" } }, + "node_modules/es-define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", + "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", + "license": "MIT", + "dependencies": { + "get-intrinsic": "^1.2.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, "node_modules/escalade": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } @@ -1160,13 +1233,15 @@ "node_modules/escape-html": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", - "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", + "license": "MIT" }, "node_modules/escape-string-regexp": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", "dev": true, + "license": "MIT", "engines": { "node": ">=10" }, @@ -1175,16 +1250,18 @@ } }, "node_modules/eslint": { - "version": "8.53.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.53.0.tgz", - "integrity": "sha512-N4VuiPjXDUa4xVeV/GC/RV3hQW9Nw+Y463lkWaKKXKYMvmRiRDAtfpuPFLN+E1/6ZhyR8J2ig+eVREnYgUsiag==", + "version": "8.57.1", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.1.tgz", + "integrity": "sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==", + "deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.", "dev": true, + "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.6.1", - "@eslint/eslintrc": "^2.1.3", - "@eslint/js": "8.53.0", - "@humanwhocodes/config-array": "^0.11.13", + "@eslint/eslintrc": "^2.1.4", + "@eslint/js": "8.57.1", + "@humanwhocodes/config-array": "^0.13.0", "@humanwhocodes/module-importer": "^1.0.1", "@nodelib/fs.walk": "^1.2.8", "@ungap/structured-clone": "^1.2.0", @@ -1234,6 +1311,7 @@ "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "esrecurse": "^4.3.0", "estraverse": "^5.2.0" @@ -1250,6 +1328,7 @@ "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", "dev": true, + "license": "Apache-2.0", "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, @@ -1257,68 +1336,12 @@ "url": "https://opencollective.com/eslint" } }, - "node_modules/eslint/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/eslint/node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/eslint/node_modules/glob-parent": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", - "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", - "dev": true, - "dependencies": { - "is-glob": "^4.0.3" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/eslint/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/eslint/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, "node_modules/espree": { "version": "9.6.1", "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "acorn": "^8.9.0", "acorn-jsx": "^5.3.2", @@ -1332,10 +1355,11 @@ } }, "node_modules/esquery": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", - "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", + "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { "estraverse": "^5.1.0" }, @@ -1348,6 +1372,7 @@ "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "estraverse": "^5.2.0" }, @@ -1360,6 +1385,7 @@ "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", "dev": true, + "license": "BSD-2-Clause", "engines": { "node": ">=4.0" } @@ -1369,6 +1395,7 @@ "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", "dev": true, + "license": "BSD-2-Clause", "engines": { "node": ">=0.10.0" } @@ -1377,41 +1404,43 @@ "version": "1.8.1", "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "license": "MIT", "engines": { "node": ">= 0.6" } }, "node_modules/express": { - "version": "4.18.2", - "resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz", - "integrity": "sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==", + "version": "4.21.1", + "resolved": "https://registry.npmjs.org/express/-/express-4.21.1.tgz", + "integrity": "sha512-YSFlK1Ee0/GC8QaO91tHcDxJiE/X4FbpAyQWkxAvG6AXCuR65YzK8ua6D9hvi/TzUfZMpc+BwuM1IPw8fmQBiQ==", + "license": "MIT", "dependencies": { "accepts": "~1.3.8", "array-flatten": "1.1.1", - "body-parser": "1.20.1", + "body-parser": "1.20.3", "content-disposition": "0.5.4", "content-type": "~1.0.4", - "cookie": "0.5.0", + "cookie": "0.7.1", "cookie-signature": "1.0.6", "debug": "2.6.9", "depd": "2.0.0", - "encodeurl": "~1.0.2", + "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "etag": "~1.8.1", - "finalhandler": "1.2.0", + "finalhandler": "1.3.1", "fresh": "0.5.2", "http-errors": "2.0.0", - "merge-descriptors": "1.0.1", + "merge-descriptors": "1.0.3", "methods": "~1.1.2", "on-finished": "2.4.1", "parseurl": "~1.3.3", - "path-to-regexp": "0.1.7", + "path-to-regexp": "0.1.10", "proxy-addr": "~2.0.7", - "qs": "6.11.0", + "qs": "6.13.0", "range-parser": "~1.2.1", "safe-buffer": "5.2.1", - "send": "0.18.0", - "serve-static": "1.15.0", + "send": "0.19.0", + "serve-static": "1.16.2", "setprototypeof": "1.2.0", "statuses": "2.0.1", "type-is": "~1.6.18", @@ -1422,40 +1451,61 @@ "node": ">= 0.10.0" } }, + "node_modules/express/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/express/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" + }, "node_modules/extend": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", - "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", + "license": "MIT" }, "node_modules/fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/fast-json-stable-stringify": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/fast-levenshtein": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/fast-safe-stringify": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz", "integrity": "sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/fastq": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz", - "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==", + "version": "1.17.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", + "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==", "dev": true, + "license": "ISC", "dependencies": { "reusify": "^1.0.4" } @@ -1465,6 +1515,7 @@ "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", "dev": true, + "license": "MIT", "dependencies": { "flat-cache": "^3.0.4" }, @@ -1473,10 +1524,11 @@ } }, "node_modules/fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", "dev": true, + "license": "MIT", "dependencies": { "to-regex-range": "^5.0.1" }, @@ -1485,12 +1537,13 @@ } }, "node_modules/finalhandler": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", - "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.1.tgz", + "integrity": "sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==", + "license": "MIT", "dependencies": { "debug": "2.6.9", - "encodeurl": "~1.0.2", + "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "on-finished": "2.4.1", "parseurl": "~1.3.3", @@ -1501,11 +1554,27 @@ "node": ">= 0.8" } }, + "node_modules/finalhandler/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/finalhandler/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" + }, "node_modules/find-up": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", "dev": true, + "license": "MIT", "dependencies": { "locate-path": "^6.0.0", "path-exists": "^4.0.0" @@ -1522,35 +1591,39 @@ "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", "dev": true, + "license": "BSD-3-Clause", "bin": { "flat": "cli.js" } }, "node_modules/flat-cache": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.1.1.tgz", - "integrity": "sha512-/qM2b3LUIaIgviBQovTLvijfyOQXPtSRnRK26ksj2J7rzPIecePUIpJsZ4T02Qg+xiAEKIs5K8dsHEd+VaKa/Q==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", + "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", "dev": true, + "license": "MIT", "dependencies": { "flatted": "^3.2.9", "keyv": "^4.5.3", "rimraf": "^3.0.2" }, "engines": { - "node": ">=12.0.0" + "node": "^10.12.0 || >=12.0.0" } }, "node_modules/flatted": { - "version": "3.2.9", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.9.tgz", - "integrity": "sha512-36yxDn5H7OFZQla0/jFJmbIKTdZAQHngCedGxiMmpNfEZM0sdEeT+WczLQrjK6D7o2aiyLYDnkw0R3JK0Qv1RQ==", - "dev": true + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.1.tgz", + "integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==", + "dev": true, + "license": "ISC" }, "node_modules/foreground-child": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-2.0.0.tgz", "integrity": "sha512-dCIq9FpEcyQyXKCkyzmlPTFNgrCzPudOe+mhvJU5zAtlBnGVy2yKxtfsxK2tQBThwq225jcvBjpw1Gr40uzZCA==", "dev": true, + "license": "ISC", "dependencies": { "cross-spawn": "^7.0.0", "signal-exit": "^3.0.2" @@ -1560,10 +1633,11 @@ } }, "node_modules/form-data": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", - "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.1.tgz", + "integrity": "sha512-tzN8e4TX8+kkxGPK8D5u0FNmjPUjw3lwC9lSLxxoB/+GtsJG91CO8bSWy73APlgAZzZbXEYZJuxjkHH2w+Ezhw==", "dev": true, + "license": "MIT", "dependencies": { "asynckit": "^0.4.0", "combined-stream": "^1.0.8", @@ -1578,6 +1652,7 @@ "resolved": "https://registry.npmjs.org/formidable/-/formidable-2.1.2.tgz", "integrity": "sha512-CM3GuJ57US06mlpQ47YcunuUZ9jpm8Vx+P2CGt2j7HpgkKZO/DJYQ0Bobim8G6PFQmK5lOqOOdUXboU+h73A4g==", "dev": true, + "license": "MIT", "dependencies": { "dezalgo": "^1.0.4", "hexoid": "^1.0.0", @@ -1592,6 +1667,7 @@ "version": "0.2.0", "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "license": "MIT", "engines": { "node": ">= 0.6" } @@ -1600,6 +1676,7 @@ "version": "0.5.2", "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", + "license": "MIT", "engines": { "node": ">= 0.6" } @@ -1608,7 +1685,8 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/fsevents": { "version": "2.3.3", @@ -1616,6 +1694,7 @@ "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", "dev": true, "hasInstallScript": true, + "license": "MIT", "optional": true, "os": [ "darwin" @@ -1628,28 +1707,32 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/gaxios": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-6.1.1.tgz", - "integrity": "sha512-bw8smrX+XlAoo9o1JAksBwX+hi/RG15J+NTSxmNPIclKC3ZVK6C2afwY8OSdRvOK0+ZLecUJYtj2MmjOt3Dm0w==", + "version": "6.7.1", + "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-6.7.1.tgz", + "integrity": "sha512-LDODD4TMYx7XXdpwxAVRAIAuB0bzv0s+ywFonY46k126qzQHT9ygyoa9tncmOiQmmDrik65UYsEkv3lbfqQ3yQ==", + "license": "Apache-2.0", "dependencies": { "extend": "^3.0.2", "https-proxy-agent": "^7.0.1", "is-stream": "^2.0.0", - "node-fetch": "^2.6.9" + "node-fetch": "^2.6.9", + "uuid": "^9.0.1" }, "engines": { "node": ">=14" } }, "node_modules/gcp-metadata": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-6.0.0.tgz", - "integrity": "sha512-Ozxyi23/1Ar51wjUT2RDklK+3HxqDr8TLBNK8rBBFQ7T85iIGnXnVusauj06QyqCXRFZig8LZC+TUddWbndlpQ==", + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-6.1.0.tgz", + "integrity": "sha512-Jh/AIwwgaxan+7ZUUmRLCjtchyDiqh4KjBJ5tW3plBZb5iL/BPcso8A5DlzeD9qlw0duCamnNdpFjxwaT0KyKg==", + "license": "Apache-2.0", "dependencies": { "gaxios": "^6.0.0", "json-bigint": "^1.0.0" @@ -1663,6 +1746,7 @@ "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", "dev": true, + "license": "ISC", "engines": { "node": "6.* || 8.* || >= 10.*" } @@ -1672,83 +1756,93 @@ "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.2.tgz", "integrity": "sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==", "dev": true, + "license": "MIT", "engines": { "node": "*" } }, "node_modules/get-intrinsic": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.2.tgz", - "integrity": "sha512-0gSo4ml/0j98Y3lngkFEot/zhiCeWsbYIlZ+uZOVgzLyLaUw7wxUL+nCTP0XJvJg1AXulJRI3UJi8GsbDuxdGA==", + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", + "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", + "license": "MIT", "dependencies": { + "es-errors": "^1.3.0", "function-bind": "^1.1.2", "has-proto": "^1.0.1", "has-symbols": "^1.0.3", "hasown": "^2.0.0" }, + "engines": { + "node": ">= 0.4" + }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/glob": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", - "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", + "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", + "deprecated": "Glob versions prior to v9 are no longer supported", "dev": true, + "license": "ISC", "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" + "minimatch": "^5.0.1", + "once": "^1.3.0" }, "engines": { - "node": "*" + "node": ">=12" }, "funding": { "url": "https://github.com/sponsors/isaacs" } }, "node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", "dev": true, + "license": "ISC", "dependencies": { - "is-glob": "^4.0.1" + "is-glob": "^4.0.3" }, "engines": { - "node": ">= 6" + "node": ">=10.13.0" } }, "node_modules/glob/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", "dev": true, + "license": "MIT", "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "balanced-match": "^1.0.0" } }, "node_modules/glob/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", "dev": true, + "license": "ISC", "dependencies": { - "brace-expansion": "^1.1.7" + "brace-expansion": "^2.0.1" }, "engines": { - "node": "*" + "node": ">=10" } }, "node_modules/globals": { - "version": "13.23.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.23.0.tgz", - "integrity": "sha512-XAmF0RjlrjY23MA51q3HltdlGxUpXPvg0GioKiD9X6HD28iMjo2dKC8Vqwm7lne4GNr78+RHTfliktR6ZH09wA==", + "version": "13.24.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", + "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", "dev": true, + "license": "MIT", "dependencies": { "type-fest": "^0.20.2" }, @@ -1760,14 +1854,15 @@ } }, "node_modules/google-auth-library": { - "version": "9.2.0", - "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-9.2.0.tgz", - "integrity": "sha512-1oV3p0JhNEhVbj26eF3FAJcv9MXXQt4S0wcvKZaDbl4oHq5V3UJoSbsGZGQNcjoCdhW4kDSwOs11wLlHog3fgQ==", + "version": "9.14.2", + "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-9.14.2.tgz", + "integrity": "sha512-R+FRIfk1GBo3RdlRYWPdwk8nmtVUOn6+BkDomAC46KoU8kzXzE1HLmOasSCbWUByMMAGkknVF0G5kQ69Vj7dlA==", + "license": "Apache-2.0", "dependencies": { "base64-js": "^1.3.0", "ecdsa-sig-formatter": "^1.0.11", - "gaxios": "^6.0.0", - "gcp-metadata": "^6.0.0", + "gaxios": "^6.1.1", + "gcp-metadata": "^6.1.0", "gtoken": "^7.0.0", "jws": "^4.0.0" }, @@ -1779,6 +1874,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "license": "MIT", "dependencies": { "get-intrinsic": "^1.1.3" }, @@ -1790,12 +1886,14 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/gtoken": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/gtoken/-/gtoken-7.0.1.tgz", - "integrity": "sha512-KcFVtoP1CVFtQu0aSk3AyAt2og66PFhZAlkUOuWKwzMLoulHXG5W5wE5xAnHb+yl3/wEFoqGW7/cDGMU8igDZQ==", + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/gtoken/-/gtoken-7.1.0.tgz", + "integrity": "sha512-pCcEwRi+TKpMlxAQObHDQ56KawURgyAf6jtIY046fJ5tIv3zDe/LEIubckAO8fj6JnAxLdmWkUfNyulQ2iKdEw==", + "license": "MIT", "dependencies": { "gaxios": "^6.0.0", "jws": "^4.0.0" @@ -1809,25 +1907,28 @@ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/has-property-descriptors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.1.tgz", - "integrity": "sha512-VsX8eaIewvas0xnvinAe9bw4WfIeODpGYikiWYLH+dma0Jw6KHYqWiWfhQlgOVK8D6PvjubK5Uc4P0iIhIcNVg==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "license": "MIT", "dependencies": { - "get-intrinsic": "^1.2.2" + "es-define-property": "^1.0.0" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/has-proto": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz", - "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz", + "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==", + "license": "MIT", "engines": { "node": ">= 0.4" }, @@ -1839,6 +1940,7 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "license": "MIT", "engines": { "node": ">= 0.4" }, @@ -1847,9 +1949,10 @@ } }, "node_modules/hasown": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.0.tgz", - "integrity": "sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "license": "MIT", "dependencies": { "function-bind": "^1.1.2" }, @@ -1862,6 +1965,7 @@ "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", "dev": true, + "license": "MIT", "bin": { "he": "bin/he" } @@ -1871,6 +1975,7 @@ "resolved": "https://registry.npmjs.org/hexoid/-/hexoid-1.0.0.tgz", "integrity": "sha512-QFLV0taWQOZtvIRIAdBChesmogZrtuXvVWsFHZTk2SU+anspqZ2vMnoLg7IE1+Uk16N19APic1BuF8bC8c2m5g==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -1879,12 +1984,14 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/http-errors": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "license": "MIT", "dependencies": { "depd": "2.0.0", "inherits": "2.0.4", @@ -1897,9 +2004,10 @@ } }, "node_modules/https-proxy-agent": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.2.tgz", - "integrity": "sha512-NmLNjm6ucYwtcUmL7JQC1ZQ57LmHP4lT15FQ8D61nak1rO6DH+fz5qNK2Ap5UN4ZapYICE3/0KodcLYSPsPbaA==", + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.5.tgz", + "integrity": "sha512-1e4Wqeblerz+tMKPIq2EMGiiWW1dIjZOksyHWSUm1rmuvw/how9hBHZ38lAGj5ID4Ik6EdkOw7NmWPy6LAwalw==", + "license": "MIT", "dependencies": { "agent-base": "^7.0.2", "debug": "4" @@ -1908,31 +2016,11 @@ "node": ">= 14" } }, - "node_modules/https-proxy-agent/node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/https-proxy-agent/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - }, "node_modules/iconv-lite": { "version": "0.4.24", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "license": "MIT", "dependencies": { "safer-buffer": ">= 2.1.2 < 3" }, @@ -1941,10 +2029,11 @@ } }, "node_modules/ignore": { - "version": "5.2.4", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", - "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==", + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", "dev": true, + "license": "MIT", "engines": { "node": ">= 4" } @@ -1954,6 +2043,7 @@ "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", "dev": true, + "license": "MIT", "dependencies": { "parent-module": "^1.0.0", "resolve-from": "^4.0.0" @@ -1970,6 +2060,7 @@ "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.8.19" } @@ -1978,7 +2069,9 @@ "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", "dev": true, + "license": "ISC", "dependencies": { "once": "^1.3.0", "wrappy": "1" @@ -1987,12 +2080,14 @@ "node_modules/inherits": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "license": "ISC" }, "node_modules/ipaddr.js": { "version": "1.9.1", "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "license": "MIT", "engines": { "node": ">= 0.10" } @@ -2002,6 +2097,7 @@ "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", "dev": true, + "license": "MIT", "dependencies": { "binary-extensions": "^2.0.0" }, @@ -2014,6 +2110,7 @@ "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -2023,6 +2120,7 @@ "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -2032,6 +2130,7 @@ "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", "dev": true, + "license": "MIT", "dependencies": { "is-extglob": "^2.1.1" }, @@ -2044,6 +2143,7 @@ "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.12.0" } @@ -2053,6 +2153,7 @@ "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -2062,6 +2163,7 @@ "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -2070,6 +2172,7 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "license": "MIT", "engines": { "node": ">=8" }, @@ -2082,6 +2185,7 @@ "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", "dev": true, + "license": "MIT", "engines": { "node": ">=10" }, @@ -2093,13 +2197,15 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/istanbul-lib-coverage": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz", - "integrity": "sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==", + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", + "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==", "dev": true, + "license": "BSD-3-Clause", "engines": { "node": ">=8" } @@ -2109,6 +2215,7 @@ "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz", "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { "istanbul-lib-coverage": "^3.0.0", "make-dir": "^4.0.0", @@ -2119,10 +2226,11 @@ } }, "node_modules/istanbul-reports": { - "version": "3.1.6", - "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.6.tgz", - "integrity": "sha512-TLgnMkKg3iTDsQ9PbPTdpfAK2DzjF9mqUG7RMgcQl8oFjad8ob4laGxv5XV5U9MAfx8D6tSJiUyuAwzLicaxlg==", + "version": "3.1.7", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.7.tgz", + "integrity": "sha512-BewmUXImeuRk2YY0PVbxgKAysvhRPUQE0h5QRM++nVWyubKGV0l8qQ5op8+B2DOmwSe63Jivj0BjkPQVf8fP5g==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { "html-escaper": "^2.0.0", "istanbul-lib-report": "^3.0.0" @@ -2136,6 +2244,7 @@ "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", "dev": true, + "license": "MIT", "dependencies": { "argparse": "^2.0.1" }, @@ -2147,6 +2256,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/json-bigint/-/json-bigint-1.0.0.tgz", "integrity": "sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ==", + "license": "MIT", "dependencies": { "bignumber.js": "^9.0.0" } @@ -2155,24 +2265,28 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/json-schema-traverse": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/json-stable-stringify-without-jsonify": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/jwa": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/jwa/-/jwa-2.0.0.tgz", "integrity": "sha512-jrZ2Qx916EA+fq9cEAeCROWPTfCwi1IVHqT2tapuqLEVVDKFDENFw1oL+MwrTvH6msKxsd1YTDVw6uKEcsrLEA==", + "license": "MIT", "dependencies": { "buffer-equal-constant-time": "1.0.1", "ecdsa-sig-formatter": "1.0.11", @@ -2183,6 +2297,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/jws/-/jws-4.0.0.tgz", "integrity": "sha512-KDncfTmOZoOMTFG4mBlG0qUIOlc03fmzH+ru6RgYVZhPkyiy/92Owlt/8UEN+a4TXR1FQetfIpJE8ApdvdVxTg==", + "license": "MIT", "dependencies": { "jwa": "^2.0.0", "safe-buffer": "^5.0.1" @@ -2193,6 +2308,7 @@ "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", "dev": true, + "license": "MIT", "dependencies": { "json-buffer": "3.0.1" } @@ -2202,6 +2318,7 @@ "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", "dev": true, + "license": "MIT", "dependencies": { "prelude-ls": "^1.2.1", "type-check": "~0.4.0" @@ -2215,6 +2332,7 @@ "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", "dev": true, + "license": "MIT", "dependencies": { "p-locate": "^5.0.0" }, @@ -2229,13 +2347,15 @@ "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/log-symbols": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", "dev": true, + "license": "MIT", "dependencies": { "chalk": "^4.1.0", "is-unicode-supported": "^0.1.0" @@ -2252,27 +2372,17 @@ "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.7.tgz", "integrity": "sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA==", "dev": true, + "license": "MIT", "dependencies": { "get-func-name": "^2.0.1" } }, - "node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/make-dir": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", "dev": true, + "license": "MIT", "dependencies": { "semver": "^7.5.3" }, @@ -2286,25 +2396,32 @@ "node_modules/make-error": { "version": "1.3.6", "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", - "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==" + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "license": "ISC" }, "node_modules/media-typer": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", + "license": "MIT", "engines": { "node": ">= 0.6" } }, "node_modules/merge-descriptors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", - "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==" + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz", + "integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } }, "node_modules/methods": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", + "license": "MIT", "engines": { "node": ">= 0.6" } @@ -2313,6 +2430,7 @@ "version": "1.6.0", "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "license": "MIT", "bin": { "mime": "cli.js" }, @@ -2324,6 +2442,7 @@ "version": "1.52.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "license": "MIT", "engines": { "node": ">= 0.6" } @@ -2332,6 +2451,7 @@ "version": "2.1.35", "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "license": "MIT", "dependencies": { "mime-db": "1.52.0" }, @@ -2340,44 +2460,45 @@ } }, "node_modules/minimatch": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.0.1.tgz", - "integrity": "sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "dev": true, + "license": "ISC", "dependencies": { - "brace-expansion": "^2.0.1" + "brace-expansion": "^1.1.7" }, "engines": { - "node": ">=10" + "node": "*" } }, "node_modules/mocha": { - "version": "10.2.0", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.2.0.tgz", - "integrity": "sha512-IDY7fl/BecMwFHzoqF2sg/SHHANeBoMMXFlS9r0OXKDssYE1M5O43wUY/9BVPeIvfH2zmEbBfseqN9gBQZzXkg==", - "dev": true, - "dependencies": { - "ansi-colors": "4.1.1", - "browser-stdout": "1.3.1", - "chokidar": "3.5.3", - "debug": "4.3.4", - "diff": "5.0.0", - "escape-string-regexp": "4.0.0", - "find-up": "5.0.0", - "glob": "7.2.0", - "he": "1.2.0", - "js-yaml": "4.1.0", - "log-symbols": "4.1.0", - "minimatch": "5.0.1", - "ms": "2.1.3", - "nanoid": "3.3.3", - "serialize-javascript": "6.0.0", - "strip-json-comments": "3.1.1", - "supports-color": "8.1.1", - "workerpool": "6.2.1", - "yargs": "16.2.0", - "yargs-parser": "20.2.4", - "yargs-unparser": "2.0.0" + "version": "10.7.3", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.7.3.tgz", + "integrity": "sha512-uQWxAu44wwiACGqjbPYmjo7Lg8sFrS3dQe7PP2FQI+woptP4vZXSMcfMyFL/e1yFEeEpV4RtyTpZROOKmxis+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-colors": "^4.1.3", + "browser-stdout": "^1.3.1", + "chokidar": "^3.5.3", + "debug": "^4.3.5", + "diff": "^5.2.0", + "escape-string-regexp": "^4.0.0", + "find-up": "^5.0.0", + "glob": "^8.1.0", + "he": "^1.2.0", + "js-yaml": "^4.1.0", + "log-symbols": "^4.1.0", + "minimatch": "^5.1.6", + "ms": "^2.1.3", + "serialize-javascript": "^6.0.2", + "strip-json-comments": "^3.1.1", + "supports-color": "^8.1.1", + "workerpool": "^6.5.1", + "yargs": "^16.2.0", + "yargs-parser": "^20.2.9", + "yargs-unparser": "^2.0.0" }, "bin": { "_mocha": "bin/_mocha", @@ -2385,10 +2506,16 @@ }, "engines": { "node": ">= 14.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/mochajs" + } + }, + "node_modules/mocha/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" } }, "node_modules/mocha/node_modules/cliui": { @@ -2396,55 +2523,32 @@ "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", "dev": true, + "license": "ISC", "dependencies": { "string-width": "^4.2.0", "strip-ansi": "^6.0.0", "wrap-ansi": "^7.0.0" } }, - "node_modules/mocha/node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "node_modules/mocha/node_modules/minimatch": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", "dev": true, + "license": "ISC", "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" + "brace-expansion": "^2.0.1" }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/mocha/node_modules/debug/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, - "node_modules/mocha/node_modules/diff": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz", - "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==", - "dev": true, "engines": { - "node": ">=0.3.1" + "node": ">=10" } }, - "node_modules/mocha/node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true - }, "node_modules/mocha/node_modules/supports-color": { "version": "8.1.1", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", "dev": true, + "license": "MIT", "dependencies": { "has-flag": "^4.0.0" }, @@ -2460,6 +2564,7 @@ "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", "dev": true, + "license": "MIT", "dependencies": { "cliui": "^7.0.2", "escalade": "^3.1.1", @@ -2474,41 +2579,33 @@ } }, "node_modules/mocha/node_modules/yargs-parser": { - "version": "20.2.4", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz", - "integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==", + "version": "20.2.9", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", + "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", "dev": true, + "license": "ISC", "engines": { "node": ">=10" } }, "node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" - }, - "node_modules/nanoid": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.3.tgz", - "integrity": "sha512-p1sjXuopFs0xg+fPASzQ28agW1oHD7xDsd9Xkf3T15H3c/cifrFHVwrh74PdoklAPi+i7MdRsE47vm2r6JoB+w==", - "dev": true, - "bin": { - "nanoid": "bin/nanoid.cjs" - }, - "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" - } + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" }, "node_modules/natural-compare": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/negotiator": { "version": "0.6.3", "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "license": "MIT", "engines": { "node": ">= 0.6" } @@ -2517,6 +2614,7 @@ "version": "2.7.0", "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "license": "MIT", "dependencies": { "whatwg-url": "^5.0.0" }, @@ -2537,14 +2635,19 @@ "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/object-inspect": { - "version": "1.13.1", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz", - "integrity": "sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==", + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.2.tgz", + "integrity": "sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -2553,6 +2656,7 @@ "version": "2.4.1", "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "license": "MIT", "dependencies": { "ee-first": "1.1.1" }, @@ -2565,22 +2669,24 @@ "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", "dev": true, + "license": "ISC", "dependencies": { "wrappy": "1" } }, "node_modules/optionator": { - "version": "0.9.3", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz", - "integrity": "sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==", + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", "dev": true, + "license": "MIT", "dependencies": { - "@aashutoshrathi/word-wrap": "^1.2.3", "deep-is": "^0.1.3", "fast-levenshtein": "^2.0.6", "levn": "^0.4.1", "prelude-ls": "^1.2.1", - "type-check": "^0.4.0" + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" }, "engines": { "node": ">= 0.8.0" @@ -2591,6 +2697,7 @@ "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", "dev": true, + "license": "MIT", "dependencies": { "yocto-queue": "^0.1.0" }, @@ -2606,6 +2713,7 @@ "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", "dev": true, + "license": "MIT", "dependencies": { "p-limit": "^3.0.2" }, @@ -2621,6 +2729,7 @@ "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", "dev": true, + "license": "MIT", "dependencies": { "callsites": "^3.0.0" }, @@ -2632,6 +2741,7 @@ "version": "1.3.3", "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "license": "MIT", "engines": { "node": ">= 0.8" } @@ -2641,6 +2751,7 @@ "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -2650,6 +2761,7 @@ "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -2659,20 +2771,23 @@ "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/path-to-regexp": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", - "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==" + "version": "0.1.10", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.10.tgz", + "integrity": "sha512-7lf7qcQidTku0Gu3YDPc8DJ1q7OOucfa/BSsIwjuh56VU7katFvuM8hULfkwB3Fns/rsVF7PwPKVw1sl5KQS9w==", + "license": "MIT" }, "node_modules/pathval": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz", "integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==", "dev": true, + "license": "MIT", "engines": { "node": "*" } @@ -2682,6 +2797,7 @@ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", "dev": true, + "license": "MIT", "engines": { "node": ">=8.6" }, @@ -2694,6 +2810,7 @@ "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.8.0" } @@ -2702,6 +2819,7 @@ "version": "2.0.7", "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "license": "MIT", "dependencies": { "forwarded": "0.2.0", "ipaddr.js": "1.9.1" @@ -2715,16 +2833,18 @@ "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } }, "node_modules/qs": { - "version": "6.11.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", - "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz", + "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==", + "license": "BSD-3-Clause", "dependencies": { - "side-channel": "^1.0.4" + "side-channel": "^1.0.6" }, "engines": { "node": ">=0.6" @@ -2751,13 +2871,15 @@ "type": "consulting", "url": "https://feross.org/support" } - ] + ], + "license": "MIT" }, "node_modules/randombytes": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", "dev": true, + "license": "MIT", "dependencies": { "safe-buffer": "^5.1.0" } @@ -2766,14 +2888,16 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "license": "MIT", "engines": { "node": ">= 0.6" } }, "node_modules/raw-body": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz", - "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==", + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", + "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", + "license": "MIT", "dependencies": { "bytes": "3.1.2", "http-errors": "2.0.0", @@ -2789,6 +2913,7 @@ "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", "dev": true, + "license": "MIT", "dependencies": { "picomatch": "^2.2.1" }, @@ -2801,6 +2926,7 @@ "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -2810,6 +2936,7 @@ "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", "dev": true, + "license": "MIT", "engines": { "node": ">=4" } @@ -2819,6 +2946,7 @@ "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", "dev": true, + "license": "MIT", "engines": { "iojs": ">=1.0.0", "node": ">=0.10.0" @@ -2828,7 +2956,9 @@ "version": "3.0.2", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", "dev": true, + "license": "ISC", "dependencies": { "glob": "^7.1.3" }, @@ -2839,6 +2969,28 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/rimraf/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dev": true, + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/run-parallel": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", @@ -2858,6 +3010,7 @@ "url": "https://feross.org/support" } ], + "license": "MIT", "dependencies": { "queue-microtask": "^1.2.2" } @@ -2879,21 +3032,21 @@ "type": "consulting", "url": "https://feross.org/support" } - ] + ], + "license": "MIT" }, "node_modules/safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "license": "MIT" }, "node_modules/semver": { - "version": "7.5.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", - "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, + "license": "ISC", "bin": { "semver": "bin/semver.js" }, @@ -2902,9 +3055,10 @@ } }, "node_modules/send": { - "version": "0.18.0", - "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", - "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", + "version": "0.19.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz", + "integrity": "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==", + "license": "MIT", "dependencies": { "debug": "2.6.9", "depd": "2.0.0", @@ -2924,43 +3078,67 @@ "node": ">= 0.8.0" } }, - "node_modules/send/node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + "node_modules/send/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/send/node_modules/debug/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" + }, + "node_modules/send/node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } }, "node_modules/serialize-javascript": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz", - "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==", + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz", + "integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { "randombytes": "^2.1.0" } }, "node_modules/serve-static": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", - "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", + "version": "1.16.2", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.2.tgz", + "integrity": "sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==", + "license": "MIT", "dependencies": { - "encodeurl": "~1.0.2", + "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "parseurl": "~1.3.3", - "send": "0.18.0" + "send": "0.19.0" }, "engines": { "node": ">= 0.8.0" } }, "node_modules/set-function-length": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.1.1.tgz", - "integrity": "sha512-VoaqjbBJKiWtg4yRcKBQ7g7wnGnLV3M8oLvVWwOk2PdYY6PEFegR1vezXR0tw6fZGF9csVakIRjrJiy2veSBFQ==", + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", + "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", + "license": "MIT", "dependencies": { - "define-data-property": "^1.1.1", - "get-intrinsic": "^1.2.1", + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", "gopd": "^1.0.1", - "has-property-descriptors": "^1.0.0" + "has-property-descriptors": "^1.0.2" }, "engines": { "node": ">= 0.4" @@ -2969,13 +3147,15 @@ "node_modules/setprototypeof": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", - "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", + "license": "ISC" }, "node_modules/shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", "dev": true, + "license": "MIT", "dependencies": { "shebang-regex": "^3.0.0" }, @@ -2988,18 +3168,24 @@ "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/side-channel": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", - "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz", + "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==", + "license": "MIT", "dependencies": { - "call-bind": "^1.0.0", - "get-intrinsic": "^1.0.2", - "object-inspect": "^1.9.0" + "call-bind": "^1.0.7", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.4", + "object-inspect": "^1.13.1" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -3009,12 +3195,14 @@ "version": "3.0.7", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/statuses": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "license": "MIT", "engines": { "node": ">= 0.8" } @@ -3024,6 +3212,7 @@ "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "dev": true, + "license": "MIT", "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", @@ -3038,6 +3227,7 @@ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, + "license": "MIT", "dependencies": { "ansi-regex": "^5.0.1" }, @@ -3050,6 +3240,7 @@ "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" }, @@ -3061,7 +3252,9 @@ "version": "8.1.2", "resolved": "https://registry.npmjs.org/superagent/-/superagent-8.1.2.tgz", "integrity": "sha512-6WTxW1EB6yCxV5VFOIPQruWGHqc3yI7hEmZK6h+pyk69Lk/Ut7rLUY6W/ONF2MjBuGjvmMiIpsrVJ2vjrHlslA==", + "deprecated": "Please upgrade to v9.0.0+ as we have fixed a public vulnerability with formidable dependency. Note that v9.0.0+ requires Node.js v14.18.0+. See https://github.com/ladjs/superagent/pull/1800 for insight. This project is supported and maintained by the team at Forward Email @ https://forwardemail.net", "dev": true, + "license": "MIT", "dependencies": { "component-emitter": "^1.3.0", "cookiejar": "^2.1.4", @@ -3078,28 +3271,12 @@ "node": ">=6.4.0 <13 || >=14" } }, - "node_modules/superagent/node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, "node_modules/superagent/node_modules/mime": { "version": "2.6.0", "resolved": "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz", "integrity": "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==", "dev": true, + "license": "MIT", "bin": { "mime": "cli.js" }, @@ -3107,20 +3284,15 @@ "node": ">=4.0.0" } }, - "node_modules/superagent/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, "node_modules/supertest": { - "version": "6.3.3", - "resolved": "https://registry.npmjs.org/supertest/-/supertest-6.3.3.tgz", - "integrity": "sha512-EMCG6G8gDu5qEqRQ3JjjPs6+FYT1a7Hv5ApHvtSghmOFJYtsU5S+pSb6Y2EUeCEY3CmEL3mmQ8YWlPOzQomabA==", + "version": "6.3.4", + "resolved": "https://registry.npmjs.org/supertest/-/supertest-6.3.4.tgz", + "integrity": "sha512-erY3HFDG0dPnhw4U+udPfrzXa4xhSG+n4rxfRuZWCUvjFWwKl+OxWf/7zk50s84/fAAs7vf5QAb9uRa0cCykxw==", "dev": true, + "license": "MIT", "dependencies": { "methods": "^1.1.2", - "superagent": "^8.0.5" + "superagent": "^8.1.2" }, "engines": { "node": ">=6.4.0" @@ -3131,6 +3303,7 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, + "license": "MIT", "dependencies": { "has-flag": "^4.0.0" }, @@ -3143,6 +3316,7 @@ "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", "dev": true, + "license": "ISC", "dependencies": { "@istanbuljs/schema": "^0.1.2", "glob": "^7.1.4", @@ -3152,39 +3326,41 @@ "node": ">=8" } }, - "node_modules/test-exclude/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/test-exclude/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "node_modules/test-exclude/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", "dev": true, + "license": "ISC", "dependencies": { - "brace-expansion": "^1.1.7" + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" }, "engines": { "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, "node_modules/text-table": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", "dev": true, + "license": "MIT", "dependencies": { "is-number": "^7.0.0" }, @@ -3196,6 +3372,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "license": "MIT", "engines": { "node": ">=0.6" } @@ -3203,12 +3380,37 @@ "node_modules/tr46": { "version": "0.0.3", "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", + "license": "MIT" + }, + "node_modules/ts-llmt": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/ts-llmt/-/ts-llmt-1.1.0.tgz", + "integrity": "sha512-qf6tA9ypUSWtxcCVtdAqrUUjm3DK+yrLfZeZ7yp4PmzOgqI70AIcwFFViHHLfC2fjuiHRYeMvf6GdaAXKBTcFg==", + "license": "Apache-2.0", + "dependencies": { + "typescript": "^5.4.5", + "underscore": "^1.13.6" + } + }, + "node_modules/ts-llmt/node_modules/typescript": { + "version": "5.6.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.6.3.tgz", + "integrity": "sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw==", + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } }, "node_modules/ts-node": { - "version": "10.9.1", - "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.1.tgz", - "integrity": "sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==", + "version": "10.9.2", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", + "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", + "license": "MIT", "dependencies": { "@cspotcode/source-map-support": "^0.8.0", "@tsconfig/node10": "^1.0.7", @@ -3247,11 +3449,21 @@ } } }, + "node_modules/ts-node/node_modules/diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.3.1" + } + }, "node_modules/type-check": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", "dev": true, + "license": "MIT", "dependencies": { "prelude-ls": "^1.2.1" }, @@ -3260,10 +3472,11 @@ } }, "node_modules/type-detect": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", - "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.1.0.tgz", + "integrity": "sha512-Acylog8/luQ8L7il+geoSxhEkazvkslg7PSNKOX59mbB9cOveP5aq9h74Y7YU8yDpJwetzQQrfIwtf4Wp4LKcw==", "dev": true, + "license": "MIT", "engines": { "node": ">=4" } @@ -3273,6 +3486,7 @@ "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", "dev": true, + "license": "(MIT OR CC0-1.0)", "engines": { "node": ">=10" }, @@ -3284,6 +3498,7 @@ "version": "1.6.18", "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "license": "MIT", "dependencies": { "media-typer": "0.3.0", "mime-types": "~2.1.24" @@ -3296,6 +3511,7 @@ "version": "5.1.6", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.1.6.tgz", "integrity": "sha512-zaWCozRZ6DLEWAWFrVDz1H6FVXzUSfTy5FUMWsQlU8Ym5JP9eO4xkTIROFCQvhQf61z6O/G6ugw3SgAnvvm+HA==", + "license": "Apache-2.0", "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -3305,19 +3521,22 @@ } }, "node_modules/underscore": { - "version": "1.13.6", - "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.6.tgz", - "integrity": "sha512-+A5Sja4HP1M08MaXya7p5LvjuM7K6q/2EaC0+iovj/wOcMsTzMvDFbasi/oSapiwOlt252IqsKqPjCl7huKS0A==" + "version": "1.13.7", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.7.tgz", + "integrity": "sha512-GMXzWtsc57XAtguZgaQViUOzs0KTkk8ojr3/xAxXLITqf/3EMwxC0inyETfDFjH/Krbhuep0HNbbjI9i/q3F3g==", + "license": "MIT" }, "node_modules/undici-types": { - "version": "5.25.3", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.25.3.tgz", - "integrity": "sha512-Ga1jfYwRn7+cP9v8auvEXN1rX3sWqlayd4HP7OKk4mZWylEmu3KzXDUGrQUN6Ol7qo1gPvB2e5gX6udnyEPgdA==" + "version": "6.19.8", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz", + "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==", + "license": "MIT" }, "node_modules/unpipe": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "license": "MIT", "engines": { "node": ">= 0.8" } @@ -3327,6 +3546,7 @@ "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "punycode": "^2.1.0" } @@ -3335,20 +3555,36 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", + "license": "MIT", "engines": { "node": ">= 0.4.0" } }, + "node_modules/uuid": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", + "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==", + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "license": "MIT", + "bin": { + "uuid": "dist/bin/uuid" + } + }, "node_modules/v8-compile-cache-lib": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", - "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==" + "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", + "license": "MIT" }, "node_modules/v8-to-istanbul": { - "version": "9.1.3", - "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.1.3.tgz", - "integrity": "sha512-9lDD+EVI2fjFsMWXc6dy5JJzBsVTcQ2fVkfBvncZ6xJWG9wtBhOldG+mHkSL0+V1K/xgZz0JDO5UT5hFwHUghg==", + "version": "9.3.0", + "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.3.0.tgz", + "integrity": "sha512-kiGUalWN+rgBJ/1OHZsBtU4rXZOfj/7rKQxULKlIzwzQSvMJUUNgPwJEEh7gU6xEVxC0ahoOBvN2YI8GH6FNgA==", "dev": true, + "license": "ISC", "dependencies": { "@jridgewell/trace-mapping": "^0.3.12", "@types/istanbul-lib-coverage": "^2.0.1", @@ -3359,10 +3595,11 @@ } }, "node_modules/v8-to-istanbul/node_modules/@jridgewell/trace-mapping": { - "version": "0.3.20", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.20.tgz", - "integrity": "sha512-R8LcPeWZol2zR8mmH3JeKQ6QRCFb7XgUhV9ZlGhHLGyg4wpPiPZNQOOWhFZhxKw8u//yTbNGI42Bx/3paXEQ+Q==", + "version": "0.3.25", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", "dev": true, + "license": "MIT", "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" @@ -3372,6 +3609,7 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "license": "MIT", "engines": { "node": ">= 0.8" } @@ -3379,12 +3617,14 @@ "node_modules/webidl-conversions": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", + "license": "BSD-2-Clause" }, "node_modules/whatwg-url": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "license": "MIT", "dependencies": { "tr46": "~0.0.3", "webidl-conversions": "^3.0.0" @@ -3395,6 +3635,7 @@ "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", "dev": true, + "license": "ISC", "dependencies": { "isexe": "^2.0.0" }, @@ -3405,17 +3646,29 @@ "node": ">= 8" } }, + "node_modules/word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/workerpool": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.1.tgz", - "integrity": "sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw==", - "dev": true + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.5.1.tgz", + "integrity": "sha512-Fs4dNYcsdpYSAfVxhnl1L5zTksjvOJxtC5hzMNl+1t9B8hTJTdKDyZ5ju7ztgPy+ft9tBFXoOlDNiOT9WUXZlA==", + "dev": true, + "license": "Apache-2.0" }, "node_modules/wrap-ansi": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", "dev": true, + "license": "MIT", "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", @@ -3432,28 +3685,25 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/y18n": { "version": "5.0.8", "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", "dev": true, + "license": "ISC", "engines": { "node": ">=10" } }, - "node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, "node_modules/yargs": { "version": "17.7.2", "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", "dev": true, + "license": "MIT", "dependencies": { "cliui": "^8.0.1", "escalade": "^3.1.1", @@ -3472,6 +3722,7 @@ "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", "dev": true, + "license": "ISC", "engines": { "node": ">=12" } @@ -3481,6 +3732,7 @@ "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz", "integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==", "dev": true, + "license": "MIT", "dependencies": { "camelcase": "^6.0.0", "decamelize": "^4.0.0", @@ -3495,6 +3747,7 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", + "license": "MIT", "engines": { "node": ">=6" } @@ -3504,6 +3757,7 @@ "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", "dev": true, + "license": "MIT", "engines": { "node": ">=10" }, diff --git a/llm-recs/appengine-server/package.json b/llm-recs/appengine-server/package.json index 220d94bf..cc3430c4 100644 --- a/llm-recs/appengine-server/package.json +++ b/llm-recs/appengine-server/package.json @@ -13,6 +13,7 @@ "dependencies": { "express": "^4.18.2", "google-auth-library": "^9.2.0", + "ts-llmt": "^1.0.1", "ts-node": "^10.9.1", "underscore": "^1.13.6" }, diff --git a/llm-recs/appengine-server/server.ts b/llm-recs/appengine-server/server.ts index e05be125..88c4658b 100644 --- a/llm-recs/appengine-server/server.ts +++ b/llm-recs/appengine-server/server.ts @@ -9,27 +9,30 @@ import express, { Express, Request, Response } from 'express'; import { GoogleAuth } from 'google-auth-library'; import { VertexEmbedder } from './src/text-embeddings/embedder_gaxois_vertexapi'; -import { VertexPalm2LLM, Palm2ApiOptions, Palm2ApiParams } from './src/text-templates/llm_gaxois_vertexapi_palm2'; -import * as path from 'path'; +import { VertexGeminiLLM } from 'ts-llmt/src/llm_vertexapi_gemini_1_5_googleauth'; +import { + GeminiApiOptions, + GeminiRequestOptions, +} from 'ts-llmt/src/llm_vertexapi_gemini_lib'; export const app: Express = express(); app.use(express.static('./static')); -app.use(express.json()); // for POST requests -app.use(express.urlencoded({ extended: true })); // for PUT requests +app.use(express.json()); // for POST requests +app.use(express.urlencoded({ extended: true })); // for PUT requests export interface LlmOptions { modelId?: string; // e.g. text-bison - candidateCount?: number, // e.g. 1 to 8 = number of completions - maxOutputTokens?: number, // e.g. 256, 1024 - stopSequences?: string[], // e.g. '] - temperature?: number, // e.g. 0.8 (0=deterministic, 0.7-0.9=normal, x>1=wild) - topP?: number, // e.g. 0.8 (0-1, smaller = restricts crazyiness) - topK?: number // e.g. 40 (0-numOfTokens, smaller = restricts crazyiness) + candidateCount?: number; // e.g. 1 to 8 = number of completions + maxOutputTokens?: number; // e.g. 256, 1024 + stopSequences?: string[]; // e.g. '] + temperature?: number; // e.g. 0.8 (0=deterministic, 0.7-0.9=normal, x>1=wild) + topP?: number; // e.g. 0.8 (0-1, smaller = restricts crazyiness) + topK?: number; // e.g. 40 (0-numOfTokens, smaller = restricts crazyiness) } export interface LlmRequest { - text: string - params?: LlmOptions + text: string; + params?: LlmOptions; } export interface SimpleEmbedRequest { @@ -37,11 +40,8 @@ export interface SimpleEmbedRequest { } async function main() { - const auth = new GoogleAuth({ - scopes: [ - 'https://www.googleapis.com/auth/cloud-platform', - ] + scopes: ['https://www.googleapis.com/auth/cloud-platform'], }); const projectId = await auth.getProjectId(); const client = await auth.getClient(); @@ -53,7 +53,7 @@ async function main() { app.post('/api/embed', async (req: Request, res: Response) => { console.log(`${new Date()}: /api/embed`); - const query = (req.body as SimpleEmbedRequest).text + const query = (req.body as SimpleEmbedRequest).text; if (query.trim() === '') { return res.send({ error: 'Empty string does not have an embedding.' }); } @@ -63,24 +63,21 @@ async function main() { app.post('/api/llm', async (req: Request, res: Response) => { console.log(`${new Date()}: /api/llm`); - const request = (req.body as LlmRequest) + const request = req.body as LlmRequest; // Convert from LlmRequest to VertexAI LLM request. const inputRequestParameters = { ...request.params }; delete inputRequestParameters.modelId; - const requestParameters = inputRequestParameters as Palm2ApiParams; + const requestOptions = inputRequestParameters as GeminiRequestOptions; // TODO: we now have duplicated definitions of default options, we might want to // remove one of them. - const options: Palm2ApiOptions = { - modelId: (request.params && request.params.modelId) || 'text-bison', - apiEndpoint: 'us-central1-aiplatform.googleapis.com', - requestParameters, + const options: GeminiApiOptions = { + modelId: + (request.params && request.params.modelId) || 'gemini-1.5-flash-002', + location: 'us-central1', + requestOptions, }; - const llm = new VertexPalm2LLM( - projectId, - client, - options, - ); + const llm = new VertexGeminiLLM(projectId, client, options); const response = await llm.predict(request.text, options); res.send(response); }); diff --git a/llm-recs/appengine-server/src/text-embeddings/embedder_gaxois_vertexapi.ts b/llm-recs/appengine-server/src/text-embeddings/embedder_gaxois_vertexapi.ts index 2159829b..3b77847c 100644 --- a/llm-recs/appengine-server/src/text-embeddings/embedder_gaxois_vertexapi.ts +++ b/llm-recs/appengine-server/src/text-embeddings/embedder_gaxois_vertexapi.ts @@ -6,8 +6,8 @@ * found in the LICENSE file and http://www.apache.org/licenses/LICENSE-2.0 ==============================================================================*/ -import { AuthClient } from "google-auth-library"; -import { Embedder, EmbedResponse as EmbedResponse } from "./embedder"; +import { AuthClient } from 'google-auth-library'; +import { Embedder, EmbedResponse as EmbedResponse } from './embedder'; /* Google Cloud Vertex Embedding API @@ -17,10 +17,10 @@ See: https://cloud.google.com/vertex-ai/docs/generative-ai/embeddings/get-text-e Uses Google-auth-client so that it handles refreshing tokens for API use. */ -export interface EmbedRequestParams { }; +export interface EmbedRequestParams {} export interface EmbedRequest { - instances: { content: string }[] + instances: { content: string }[]; } export interface VertexEmbedding { @@ -31,11 +31,11 @@ export interface VertexEmbedding { token_count: number; }; values: number[]; - } + }; }[]; metadata: { billableCharacterCount: number; - } + }; } export interface VertexEmbedError { @@ -44,12 +44,13 @@ export interface VertexEmbedError { details: unknown[]; message: string; status: string; - } + }; } export type VertexEmbedResponse = VertexEmbedding | VertexEmbedError; -function isErrorResponse(response: VertexEmbedResponse +function isErrorResponse( + response: VertexEmbedResponse ): response is VertexEmbedError { if ((response as VertexEmbedError).error) { return true; @@ -57,7 +58,8 @@ function isErrorResponse(response: VertexEmbedResponse return false; } -export function prepareEmbedRequest(text: string, +export function prepareEmbedRequest( + text: string, options?: EmbedRequestParams ): EmbedRequest { return { @@ -85,21 +87,21 @@ export async function sendEmbedRequest( projectId: string, client: AuthClient, req: EmbedRequest, - modelId = 'textembedding-gecko', // e.g. textembedding-gecko embedding model - apiEndpoint = 'us-central1-aiplatform.googleapis.com', + modelId = 'text-embedding-004', // e.g. textembedding-gecko embedding model + location = 'us-central1' ): Promise { return await postDataToLLM( // TODO: it may be that the url part 'us-central1' has to match // apiEndpoint. - `https://${apiEndpoint}/v1/projects/${projectId}/locations/us-central1/publishers/google/models/${modelId}:predict`, + `https://${location}-aiplatform.googleapis.com/v1/projects/${projectId}/locations/${location}/publishers/google/models/${modelId}:predict`, client, req ); } interface EmbedApiOptions { - modelId: string, - apiEndpoint: string, + modelId: string; + apiEndpoint: string; } export class VertexEmbedder implements Embedder { @@ -109,24 +111,19 @@ export class VertexEmbedder implements Embedder { apiEndpoint: 'us-central1-aiplatform.googleapis.com', }; - constructor( - public client: AuthClient, - public projectId: string, - ) { + constructor(public client: AuthClient, public projectId: string) { this.name = `VertexEmbedder:` + this.defaultOptions.modelId; } - async embed( - query: string, params?: EmbedApiOptions - ): Promise { - + async embed(query: string, params?: EmbedApiOptions): Promise { const apiRequest = prepareEmbedRequest(query); const apiResponse = await sendEmbedRequest( this.projectId, this.client, apiRequest, params ? params.modelId : this.defaultOptions.modelId, - params ? params.apiEndpoint : this.defaultOptions.apiEndpoint); + params ? params.apiEndpoint : this.defaultOptions.apiEndpoint + ); if (isErrorResponse(apiResponse)) { return { error: apiResponse.error.message }; } diff --git a/llm-recs/appengine-server/src/text-templates/fewshot_template.spec.ts b/llm-recs/appengine-server/src/text-templates/fewshot_template.spec.ts deleted file mode 100644 index a4673c32..00000000 --- a/llm-recs/appengine-server/src/text-templates/fewshot_template.spec.ts +++ /dev/null @@ -1,160 +0,0 @@ -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an Apache2 license that can be - * found in the LICENSE file and http://www.apache.org/licenses/LICENSE-2.0 -==============================================================================*/ - -import { flatten } from 'underscore'; -import { Template, escapeStr, template, nv, unEscapeStr } from './template'; -import { NamedVar } from './variable'; -import { FewShotTemplate } from './fewshot_template'; -import { expect } from 'chai'; - -// // ---------------------------------------------------------------------------- -// const movieSuggestionPrompt: Template = template``; - -// Idea: flow graphs: track the graph of substs. - -// Idea: treat lists as first class objects where the template bunches a set of -// vars, and knows how to seprate repetitions of them. - -// Idea: abstraction: generate a variable (have a stopping condition as first -// class entity. - - -describe('fewshot_template', () => { - beforeEach(() => { - }); - - it('A mini walkthrough of why this is neat...', () => { - - // ---------------------------------------------------------------------------- - // ---------------------------------------------------------------------------- - const criteriaPoints = [ - { - name: 'Concise', - description: 'not waffley.' - }, - { - name: 'No synposes', - description: 'do not give plot synopses.' - }, - { - name: 'Specific', - description: 'not vague (i.e. not "an amazing movie.", "a classic.").' - }, - ]; - const nCriteriaTempl = new FewShotTemplate(template - `(${nv('number')}) ${nv('name')}: ${nv('description')}`, - '\n'); - const numberedCriteriaPoints = - criteriaPoints.map((e, i) => { return { ...e, number: `${i + 1}` } }); - const criteriaTempl: Template = nCriteriaTempl.apply( - numberedCriteriaPoints); - - expect(criteriaTempl.escaped).to.equal( - `(1) Concise: not waffley. -(2) No synposes: do not give plot synopses. -(3) Specific: not vague (i.e. not "an amazing movie.", "a classic.").`); - - // ---------------------------------------------------------------------------- - // Probably too clever... but showing how you can have meta-templates. - // e.g. creating a common structure for propeties and values, and apply it - // to create a few-shot template with - // Move: {{movie}} - // Recommendation: {{recommendation}} - // And showing how this can be easily progamatically extended to: - // Move: {{movie}} - // Recommendation: {{recommendation}} - // Evaluation: {{evaluation}} - // The Motivation to do this is to make sure that you get consistent - // joining, e.g. ": " always separates the property from the value, and - // "\n" always separates different property-vcalue pairs. - const nPropertyValuePerLineTempl = new FewShotTemplate(template - `${nv('property')}: "${nv('value')}"`, - '\n'); - const movieAndRecList = [ - { - property: 'Movie', - value: nv('movie'), - }, - { - property: 'Recommendation', - value: nv('recommendation'), - } - ]; - const movieRecTempl = nPropertyValuePerLineTempl.apply(movieAndRecList); - const movieRecEvalTempl = - nPropertyValuePerLineTempl.apply( - [...movieAndRecList, - { - property: 'Evaluation', - value: nv('evaluation'), - }]); - - expect(movieRecEvalTempl.escaped).to.equal( - `Movie: "{{movie}}" -Recommendation: "{{recommendation}}" -Evaluation: "{{evaluation}}"`); - - // ---------------------------------------------------------------------------- - const fewShotCriticExamples = [ - { - movie: 'The Godfather', - recommendation: 'a dark and violent story of family and power', - evaluation: 'ok', - }, - { - movie: 'The Godfather', - recommendation: 'a masterpiece of cinema', - evaluation: 'Specific: the recommendation is vague, it should be more precise.' - }, - ]; - - const nCriticExamplesTempl = new FewShotTemplate( - movieRecEvalTempl, '\n\n'); - - // ---------------------------------------------------------------------------- - // Tenplates can contain other templates inline also. - const criticTempl = template - `Given the following criteria for movie recommendations: -${nv('Constitution')} - -Evaluate the following movie recommendations. -If the review is ok, the evaluation should just be "ok". - -${nv('fewShotCriticExamples')} - -${movieRecTempl} -Evaluation: "`; - - const criticWithConstitutionAndExamples = criticTempl.substs({ - Constitution: criteriaTempl.escaped, - fewShotCriticExamples: - nCriticExamplesTempl.apply(fewShotCriticExamples).escaped - }); - - expect(criticWithConstitutionAndExamples.escaped).to.equal( - `Given the following criteria for movie recommendations: -(1) Concise: not waffley. -(2) No synposes: do not give plot synopses. -(3) Specific: not vague (i.e. not "an amazing movie.", "a classic."). - -Evaluate the following movie recommendations. -If the review is ok, the evaluation should just be "ok". - -Movie: "The Godfather" -Recommendation: "a dark and violent story of family and power" -Evaluation: "ok" - -Movie: "The Godfather" -Recommendation: "a masterpiece of cinema" -Evaluation: "Specific: the recommendation is vague, it should be more precise." - -Movie: "{{movie}}" -Recommendation: "{{recommendation}}" -Evaluation: "`); - }); -}); diff --git a/llm-recs/appengine-server/src/text-templates/fewshot_template.ts b/llm-recs/appengine-server/src/text-templates/fewshot_template.ts deleted file mode 100644 index e831dc2b..00000000 --- a/llm-recs/appengine-server/src/text-templates/fewshot_template.ts +++ /dev/null @@ -1,60 +0,0 @@ -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an Apache2 license that can be - * found in the LICENSE file and http://www.apache.org/licenses/LICENSE-2.0 -==============================================================================*/ - -/* -A few shot template class. This allows separating the template from the list of -values that get subsituted int it. - -The implementation is very simple: few shot templates are treated as templates -concatendated by a join string. - -For example: - -const nameDescriptionTempl = new FewShotTempl(template - `${namedVar('n')}, can be described in detail by: ${namedVar('d')}`, - '\n'); - -See the test file (.spec) for more detailed examples. -*/ - -import { flatten } from 'underscore'; -import { Template, escapeStr, template, nv, unEscapeStr } from './template'; -import { NamedVar } from './variable'; - -// For each example substitution, substitute it into the template, and join it -// all together with the joinStr, into one big new template. -export function fewShotSubst( - templ: Template, - examples: { [Key in M]: string | NamedVar }[], - joinStr: string -): Template | N2s> { - const vars = flatten(examples.map(e => - Object.values>(e).filter( - r => typeof r !== 'string'))) as NamedVar[]; - return new Template( - examples.map(e => templ.substs(e).escaped).join(joinStr), vars); -} - -// A class representing a few shot template. -export class FewShotTemplate { - constructor(public template: Template, - public joinStr: string) { }; - - apply( - examples: { [Key in Ms]: string }[] - ): Template>; - apply( - examples: { [Key in Ms]: string | NamedVar }[] - ): Template | VarNs>; - apply( - examples: { [Key in Ms]: string | NamedVar }[] - ): Template | VarNs> { - return fewShotSubst( - this.template, examples, this.joinStr); - } -} diff --git a/llm-recs/appengine-server/src/text-templates/llm.spec.ts b/llm-recs/appengine-server/src/text-templates/llm.spec.ts deleted file mode 100644 index 678f5463..00000000 --- a/llm-recs/appengine-server/src/text-templates/llm.spec.ts +++ /dev/null @@ -1,156 +0,0 @@ -/*============================================================================== - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an Apache2 license that can be - * found in the LICENSE file and http://www.apache.org/licenses/LICENSE-2.0 -==============================================================================*/ - -/* -Showing how the LLM class works... -*/ - -import { LookupTableFakeLLM, PredictResponse, ScoreResponse, ScoredCompletion, fillTemplate } from "./llm"; -import { Palm2Response, preparePalm2Request } from "./llm_vertexapi_palm2"; -import { nv, template } from "./template"; -import { expect } from 'chai'; - -describe('llm', () => { - let fakeLLM: LookupTableFakeLLM; - let stopString = `']`; - - beforeEach(() => { - // ---------------------------------------------------------------------------- - // Setup a fake LLM... - // ---------------------------------------------------------------------------- - const fakePromptInput1 = `. -The following are short movie summaries. They are specific, not generic (no movie is just "a classic"), and they don't contain plot synopsis. They just describe my experience of the movie. - -movie: 'Fifth Element' -summary: ['a joyous sci fi that emerses you in a colourful universe', 'quirky upbeat action'] - -movie: 'Seven Samurai' -summary: ['a black and white masterpiece of cinematography', 'a slow, atmospheric, symbolic fight for all that is just'] - -movie: 'The Godfather' -summary: ['`; - - const fakePromptInput2 = `. -The following are short movie summaries. They are specific, not generic (no movie is just "a classic"), and they don't contain plot synopsis. They just describe the experience of watching the movie. It tries to tell you the essence of the movie. - -movie: 'Fifth Element' -summary: ['joyous sci fi that emerses you in a colourful universe', 'quirky upbeat action'] -synopsis: 'The 23rd century, a New York City cabbie, Korben Dallas (Bruce Willis), finds the fate of the world in his hands when Leeloo (Milla Jovovich) falls into his cab. As the embodiment of the fifth element, Leeloo needs to combine with the other four to keep the approaching Great Evil from destroying the world.' - -movie: 'Seven Samurai' -summary: ['black and white masterpiece of cinematography', 'a slow, atmospheric, symbolic fight for all that is just'] -rating (1 to 5 scale): 5 - -movie: 'The Untouchables' -summary: ['`; - - /* An approxiation for... - const request = preparePalm2Request(prompt); - const response = await sendPalm2Request(..., request) - */ - function makeFakeResponse(responses: string[]): Palm2Response { - return { - "predictions": responses.map(s => ( - { - "content": s, - "citationMetadata": { "citations": [] }, - "safetyAttributes": { "scores": [], "blocked": false, "categories": [] } - })), - "metadata": { - "tokenMetadata": { - "outputTokenCount": { "totalBillableCharacters": 279, "totalTokens": 65 }, - "inputTokenCount": { "totalBillableCharacters": 410, "totalTokens": 118 } - } - } - }; - } - - const fakeResponse1 = makeFakeResponse([ - "an operatic tale of a powerful family", - "an operatic tragedy about a powerful Italian American crime family', 'a sprawling epic of violence and betrayal", - "epic crime saga with iconic performances', 'an operatic tale of family, loyalty, and betrayal", - "a timeless mafia masterpiece', 'an operatic tale of a family\\'s descent into darkness", - ].map(s => s + stopString)); - - const fakeResponse2 = makeFakeResponse([" 80s cop drama with an amazing cast', 'stylish and suspenseful']\nrating (1 to 5 scale): 4", - " stylish and gritty gangster movie of the prohibition era', 'the classic good vs evil tale']\nrating (1 to 5 scale): 4.5\n\nmovie: 'The Shawshank Redemption'\nsummary: ['a film with a very hopeful message', 'redemption, friendship and a little bit of hope']\nrating (1 to 5 scale): 5\n", - " stylish and violent prohibition era gangster movie', 'DeNiro and Connery are excellent']\nsynopsis: 'When a bootlegger is caught by the police and is released on bail, he is given one week to leave Chicago. During this time, he hires an accountant to get all his financial affairs in order. However, the accountant is an undercover agent who plans to gather evidence and bring him to justice.'\n", - // This example shows how string escaping often fails... - " fast paced, stylish action', 'a stylish piece of filmmaking with great performances and one-liners']\nsynopsis: 'Federal agent Eliot Ness (Kevin Costner) sets out to stop bootlegger Al Capone (Robert De Niro). To get him, Ness puts together a team of 11 men who are all willing to risk their lives to bring down Capone and his associates.'\n\nmovie: 'The Shining'\nsummary: ['uncomfortable, haunting, and disorienting', 'a masterclass in horror']\nsynopsis: 'Jack Torrance (Jack Nicholson) becomes the caretaker of the Overlook Hotel, a massive, isolated resort in the Colorado mountains. His son, Danny (Danny Lloyd), possesses psychic abilities that allow him to see visions of the hotel's violent past. As Jack's sanity deteriorates, he becomes increasingly violent and Danny must find a way to escape the hotel before it's too late.'\n" - ]); - - function makeScoredCompletions(query: string, response: Palm2Response): ScoreResponse { - return { - scoredCompletions: response.predictions.map(p => { - return { query, completion: p.content, score: 0 } - }) - }; - } - - const lookupTable: { [query: string]: ScoreResponse } = {}; - lookupTable[fakePromptInput1] = makeScoredCompletions(fakePromptInput1, fakeResponse1); - lookupTable[fakePromptInput2] = makeScoredCompletions(fakePromptInput2, fakeResponse2); - fakeLLM = new LookupTableFakeLLM(lookupTable); - }); - - // ---------------------------------------------------------------------------- - // Now the tests really start... - // ---------------------------------------------------------------------------- - it('llm template filling', async () => { - const promptTempl = template`. -The following are short movie summaries. They are specific, not generic (no movie is just "a classic"), and they don't contain plot synopsis. They just describe my experience of the movie. - -movie: 'Fifth Element' -summary: ['a joyous sci fi that emerses you in a colourful universe', 'quirky upbeat action'] - -movie: 'Seven Samurai' -summary: ['a black and white masterpiece of cinematography', 'a slow, atmospheric, symbolic fight for all that is just'] - -movie: '${nv('movie')}' -summary: ['${nv('summary')}']`; - - const substsList = await fillTemplate( - fakeLLM, promptTempl.substs({ movie: 'The Godfather' })); - console.log('substsList: ', substsList); - expect(substsList.length).to.equal(4); - expect(substsList[0].substs!.summary).to.equal(`an operatic tale of a powerful family`); - expect(substsList[1].substs!.summary).to.equal(`an operatic tragedy about a powerful Italian American crime family', 'a sprawling epic of violence and betrayal`); - expect(substsList[2].substs!.summary).to.equal(`epic crime saga with iconic performances', 'an operatic tale of family, loyalty, and betrayal`); - expect(substsList[3].substs!.summary).to.equal(`a timeless mafia masterpiece', 'an operatic tale of a family\\'s descent into darkness`); - }); - - // ---------------------------------------------------------------------------- - // Now the tests really start... - // ---------------------------------------------------------------------------- - it('llm template filling with custom regexp', async () => { - const movie = "The Untouchables" - - const t = template`. -The following are short movie summaries. They are specific, not generic (no movie is just "a classic"), and they don't contain plot synopsis. They just describe the experience of watching the movie. It tries to tell you the essence of the movie. - -movie: 'Fifth Element' -summary: ['joyous sci fi that emerses you in a colourful universe', 'quirky upbeat action'] -synopsis: 'The 23rd century, a New York City cabbie, Korben Dallas (Bruce Willis), finds the fate of the world in his hands when Leeloo (Milla Jovovich) falls into his cab. As the embodiment of the fifth element, Leeloo needs to combine with the other four to keep the approaching Great Evil from destroying the world.' - -movie: 'Seven Samurai' -summary: ['black and white masterpiece of cinematography', 'a slow, atmospheric, symbolic fight for all that is just'] -rating (1 to 5 scale): 5 - -movie: '${nv('movie')}' -summary: ['${nv('summaries')}'] -rating (1 to 5 scale): ${nv('rating', { match: '[12345](\.\\d)?' })} -synopsis: '${nv('synopsis')}'`; - - const responses = await fillTemplate(fakeLLM, t.substs({ movie })); - expect(responses[0].substs!.summaries).to.equal(` 80s cop drama with an amazing cast', 'stylish and suspenseful`); - expect(responses[0].substs!.rating).to.equal(`4`); - expect(responses[1].substs!.summaries).to.equal(` stylish and gritty gangster movie of the prohibition era', 'the classic good vs evil tale`); - expect(responses[1].substs!.rating).to.equal(`4.5`); - }); -}); - diff --git a/llm-recs/appengine-server/src/text-templates/llm.ts b/llm-recs/appengine-server/src/text-templates/llm.ts deleted file mode 100644 index 2e109f90..00000000 --- a/llm-recs/appengine-server/src/text-templates/llm.ts +++ /dev/null @@ -1,94 +0,0 @@ -/*============================================================================== - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an Apache2 license that can be - * found in the LICENSE file and http://www.apache.org/licenses/LICENSE-2.0 -==============================================================================*/ - -/* -An class to wrap, and provide a common interface for LLM behaviour. -*/ - -import { Template, matchTemplate } from "./template"; - -export interface PredictResponse { - completions: string[]; -} - - -export interface ScoreRequest { - query: string; - completions: string[]; -} -export interface ScoredCompletion { - query: string; - completion: string; - score: number; -} -export interface ScoreResponse { - scoredCompletions: ScoredCompletion[]; -} - - -export abstract class LLM { - public abstract name: string; - - abstract predict(prompt: string, params?: Params): Promise; - // abstract score(request: ScoreRequest): Promise; -} - -// A Fake LLM that uses a lookup table of queries to give responses. -// It is deterministic, and if the query is not present, it returns no -// completions. -// -// TODO: maybe good to provide a version that takes the same query and gives difference responses each time, e.g. using a random seed at constructor time. -export class LookupTableFakeLLM implements LLM<{}> { - public name: string = 'fake: in memory lookup table'; - - constructor(public table: { [query: string]: ScoreResponse }) { } - - async predict(query: string): Promise { - const scoreResponse = this.table[query] - if (scoreResponse) { - const predictResponse: PredictResponse = { - completions: scoreResponse.scoredCompletions.map(c => c.completion) - }; - return predictResponse; - } - throw new Error(`No matching entry for query: ${query}`); - // return { queryCompletions: [] } - } - async score(request: ScoreRequest): Promise { - const scoreResponse: ScoreResponse = this.table[request.query] - if (scoreResponse) { - return scoreResponse; - } - return { scoredCompletions: [] } - } -} - -export interface InterpretedResponse { - substs?: { [Key in Ns]: string }, responseStr: string -}; - -export async function fillTemplate( - llm: LLM<{}>, template: Template -): Promise[]> { - const interpretedResponses = [] as InterpretedResponse[]; - // const substsResponses: ({ [Key in Ns]: string } | null)[] = []; - const parts = template.parts(); - const responses = await llm.predict(parts.prefix); - // console.log('parts.prefix: ', parts.prefix); - for (const completion of responses.completions) { - // console.log('parts', parts); - // console.log('qcompletion.completion', completion); - const match = matchTemplate(parts, completion, false); - const interpretedResponse = { responseStr: completion } as InterpretedResponse; - if (match) { - interpretedResponse.substs = match; - } - interpretedResponses.push(interpretedResponse) - } - return interpretedResponses; -} diff --git a/llm-recs/appengine-server/src/text-templates/llm_devapi_palm2.ts b/llm-recs/appengine-server/src/text-templates/llm_devapi_palm2.ts deleted file mode 100644 index 80eed7ea..00000000 --- a/llm-recs/appengine-server/src/text-templates/llm_devapi_palm2.ts +++ /dev/null @@ -1,92 +0,0 @@ -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an Apache2 license that can be - * found in the LICENSE file and http://www.apache.org/licenses/LICENSE-2.0 -==============================================================================*/ - -/* -// TODO: make more like VertexAI setup -Google Generative AI Developer API -(same models as VertexAPI but different API) -*/ - -export type HarmName = - | 'HARM_CATEGORY_DEROGATORY' - | 'HARM_CATEGORY_TOXICITY' - | 'HARM_CATEGORY_VIOLENCE' - | 'HARM_CATEGORY_SEXUAL' - | 'HARM_CATEGORY_MEDICAL' - | 'HARM_CATEGORY_DANGEROUS'; -interface HarmFilterSetting { - category: HarmName; - threshold: 1 | 2 | 3 | 4 | 5; -} - -export interface Palm2ApiRequest { - prompt: { text: string }; - temperature: number; - top_k: number; - top_p: number; - candidate_count: number; - max_output_tokens: number; - stop_sequences: string[]; - safety_settings: HarmFilterSetting[]; -} -export type Palm2RequestOptions = Omit, 'prompt'>; - -export interface Palm2Response { } - -export function preparePalm2Request(text: string, options?: Palm2RequestOptions): Palm2ApiRequest { - return { - prompt: { text }, - temperature: (options && options.temperature) || 0.7, - top_k: (options && options.top_k) || 40, - top_p: (options && options.top_p) || 0.95, - candidate_count: (options && options.candidate_count) || 4, - max_output_tokens: (options && options.max_output_tokens) || 256, - stop_sequences: (options && options.stop_sequences) || [], - safety_settings: (options && options.safety_settings) || [ - { category: 'HARM_CATEGORY_DEROGATORY', threshold: 1 }, - { category: 'HARM_CATEGORY_TOXICITY', threshold: 1 }, - { category: 'HARM_CATEGORY_VIOLENCE', threshold: 1 }, - { category: 'HARM_CATEGORY_SEXUAL', threshold: 1 }, - { category: 'HARM_CATEGORY_MEDICAL', threshold: 1 }, - { category: 'HARM_CATEGORY_DANGEROUS', threshold: 1 }, - ], - }; -} - -async function postDataToLLM(url = '', data: Palm2ApiRequest) { - // Default options are marked with * - const response = await fetch(url, { - method: 'POST', // *GET, POST, PUT, DELETE, etc. - mode: 'cors', // no-cors, *cors, same-origin - cache: 'no-cache', // *default, no-cache, reload, force-cache, only-if-cached - credentials: 'same-origin', // include, *same-origin, omit - headers: { - 'Content-Type': 'application/json', - // 'Content-Type': 'application/x-www-form-urlencoded', - }, - redirect: 'follow', // manual, *follow, error - referrerPolicy: 'no-referrer', // no-referrer, *no-referrer-when-downgrade, origin, origin-when-cross-origin, same-origin, strict-origin, strict-origin-when-cross-origin, unsafe-url - body: JSON.stringify(data), // body data type must match "Content-Type" header - }); - return response.json(); // parses JSON response into native JavaScript objects -} - -export async function sendPalm2Request( - apiKey: string, // e.g. as copied from UI in makerSuite.google.com - req: Palm2ApiRequest, - modelId = 'text-bison-001', // e.g. 'models/text-bison-001'; -): Promise { - return postDataToLLM( - `https://generativelanguage.googleapis.com/v1beta2/models/${modelId}:generateText?key=${apiKey}`, - req - ); - // .then((data) => { - // console.log(data); // JSON data parsed by `data.json()` call - // }) - // .catch((err) => console.error(err)); -} diff --git a/llm-recs/appengine-server/src/text-templates/llm_gaxois_vertexapi_palm2.ts b/llm-recs/appengine-server/src/text-templates/llm_gaxois_vertexapi_palm2.ts deleted file mode 100644 index e7e6ae2d..00000000 --- a/llm-recs/appengine-server/src/text-templates/llm_gaxois_vertexapi_palm2.ts +++ /dev/null @@ -1,206 +0,0 @@ -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an Apache2 license that can be - * found in the LICENSE file and http://www.apache.org/licenses/LICENSE-2.0 -==============================================================================*/ - -/* -Google Cloud Vertex Palm2 API -See: https://cloud.google.com/vertex-ai/docs/generative-ai/model-reference/text -(same models as Google Generative AI Developer API but different API) -*/ - -import { AuthClient } from "google-auth-library"; -import { LLM, PredictResponse } from "./llm"; -import { isErrorResponse } from "../simple-errors/simple-errors"; - -export interface Palm2ApiParams { - candidateCount: number, // 1 to 8 - maxOutputTokens: number, // 256, 1024 - stopSequences: string[], // e.g. '] - temperature: number, // e.g. 0.2 (0=deterministic, 1=wild, x>1=crazy) - topP: number, // e.g. 0.8 (0-1, smaller = restricts crazyiness) - topK: number // e.g. 40 (0-numOfTokens, smaller = restricts crazyiness) -} - -export interface Palm2ApiRequest { - instances: { content: string }[] - parameters: Palm2ApiParams -} -export type Palm2RequestOptions = Omit, 'prompt'>; - -export interface Palm2ValidResponse { - predictions: - { - content: string, - citationMetadata: { - citations: {}[] - }, - safetyAttributes: { - blocked: boolean, categories: {}[], scores: {}[] - } - }[], - metadata: { - tokenMetadata: { - outputTokenCount: { - totalBillableCharacters: number, - totalTokens: number - }, - inputTokenCount: { - totalBillableCharacters: number, - totalTokens: number - }, - } - } -} - -export interface Palm2Error { - error: { - code: number; - details: unknown[]; - message: string; - status: string; - } -} - -export const DEFAULT_PARAMS: Palm2ApiParams = { - temperature: 0.7, - topK: 40, - topP: 0.95, - candidateCount: 4, - maxOutputTokens: 256, - stopSequences: [], -}; - -export const DEFAULT_OPTIONS: Palm2ApiOptions = { - modelId: 'text-bison', - apiEndpoint: 'us-central1-aiplatform.googleapis.com', - requestParameters: DEFAULT_PARAMS, -}; - -export type Palm2Response = Palm2ValidResponse | Palm2Error; - -export function preparePalm2Request( - text: string, params?: Partial -): Palm2ApiRequest { - return { - instances: [{ content: text }], - parameters: - (params && Object.assign({ ...DEFAULT_PARAMS }, params)) || DEFAULT_PARAMS - }; -} - -async function postDataToLLM(url = '', client: AuthClient, data: Palm2ApiRequest) { - // Default options are marked with * - const response = await client.request({ - url, - method: 'POST', // *GET, POST, PUT, DELETE, etc. - headers: { - 'Content-Type': 'application/json', - }, - body: JSON.stringify(data), // body data type must match "Content-Type" header - }); - return response.data; -} - -export async function sendPalm2Request( - projectId: string, - client: AuthClient, - req: Palm2ApiRequest, - modelId = 'text-bison', // e.g. text-bison for latest text-bison model - apiEndpoint = 'us-central1-aiplatform.googleapis.com', -): Promise { - return postDataToLLM( - // TODO: it may be that the url part 'us-central1' has to match - // apiEndpoint. - `https://${apiEndpoint}/v1/projects/${projectId}/locations/us-central1/publishers/google/models/${modelId}:predict`, - client, - req - ); -} - -export interface Palm2ApiOptions { - modelId: string, - apiEndpoint: string, - requestParameters: Palm2ApiParams -} - -// TODO: consider using lodash merge... -function overideOptions( - oldOptions: Palm2ApiOptions, - newOptions?: Partial, -): Palm2ApiOptions { - const finalOptions: Palm2ApiOptions = (newOptions && - Object.assign({ ...oldOptions }, newOptions)) || oldOptions; - if (newOptions && newOptions.requestParameters) { - finalOptions.requestParameters = - Object.assign({ ...oldOptions.requestParameters }, newOptions.requestParameters); - } - return finalOptions; -} - -export class VertexPalm2LLM implements LLM { - public name: string; - public ptions: Palm2ApiOptions; - - constructor( - public projectId: string, - public client: AuthClient, - public initOptions?: Partial, - ) { - this.ptions = overideOptions(DEFAULT_OPTIONS, initOptions); - this.name = `VertexLLM:` + this.ptions.modelId; - } - - async predict( - query: string, options?: Palm2ApiOptions - ): Promise { - const usedOptions = overideOptions(this.ptions, options); - const apiRequest: Palm2ApiRequest = { - instances: [{ content: query }], - parameters: usedOptions.requestParameters - } - - const apiResponse = await sendPalm2Request( - this.projectId, - this.client, - apiRequest, - this.ptions.modelId, - this.ptions.apiEndpoint); - - // The API doesn't include the actual stop sequence that it found, so we - // can never know the true stop seqeunce, so we just pick the first one, - // and image it is that. - const stopSequences = usedOptions.requestParameters.stopSequences; - const imaginedPostfixStopSeq = stopSequences.length > 0 ? - stopSequences[0] : ''; - - if (isErrorResponse(apiResponse)) { - throw new Error(`Error in api response:` + - ` ${JSON.stringify(apiResponse.error, null, 2)}`); - } - - if (!apiResponse.predictions) { - throw new Error(`No predictions returned in api response:` + - ` ${JSON.stringify(apiResponse, null, 2)}`); - } - - // TODO: skip this and simplify? - const scoredCompletions = apiResponse.predictions.map(p => { - return { - query: query, - completion: p.content + imaginedPostfixStopSeq, - score: 1, // TODO: API doesn't provide this, so we fake it as always 1. - } - }); - - return { completions: scoredCompletions.map(c => c.completion) } - } - - // TODO: The cloud API doesn't currently support scoring. - // async score(request: ScoreRequest): Promise { - // } - -} diff --git a/llm-recs/appengine-server/src/text-templates/llm_vertexapi_palm2.ts b/llm-recs/appengine-server/src/text-templates/llm_vertexapi_palm2.ts deleted file mode 100644 index 258801f2..00000000 --- a/llm-recs/appengine-server/src/text-templates/llm_vertexapi_palm2.ts +++ /dev/null @@ -1,184 +0,0 @@ -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an Apache2 license that can be - * found in the LICENSE file and http://www.apache.org/licenses/LICENSE-2.0 -==============================================================================*/ - -/* -Google Cloud Vertex Palm2 API -See: https://cloud.google.com/vertex-ai/docs/generative-ai/model-reference/text -(same models as Google Generative AI Developer API but different API) -*/ - -import { LLM, PredictResponse } from "./llm"; - -export interface Palm2ApiParams { - candidateCount: number, // 1 to 8 - maxOutputTokens: number, // 256, 1024 - stopSequences: string[], // e.g. '] - temperature: number, // e.g. 0.2 (0=deterministic, 1=wild, x>1=crazy) - topP: number, // e.g. 0.8 (0-1, smaller = restricts crazyiness) - topK: number // e.g. 40 (0-numOfTokens, smaller = restricts crazyiness) -} - -export interface Palm2ApiRequest { - instances: { content: string }[] - parameters: Palm2ApiParams -} -export type Palm2RequestOptions = Omit, 'prompt'>; - -export interface Palm2Response { - predictions: - { - content: string, - citationMetadata: { - citations: {}[] - }, - safetyAttributes: { - blocked: boolean, categories: {}[], scores: {}[] - } - }[], - metadata: { - tokenMetadata: { - outputTokenCount: { - totalBillableCharacters: number, - totalTokens: number - }, - inputTokenCount: { - totalBillableCharacters: number, - totalTokens: number - }, - } - } -} - -export function preparePalm2Request(text: string, options?: Palm2ApiParams): Palm2ApiRequest { - return { - instances: [{ content: text }], - parameters: { - temperature: (options && options.temperature) || 0.7, - topK: (options && options.topK) || 40, - topP: (options && options.topP) || 0.95, - candidateCount: (options && options.candidateCount) || 4, - maxOutputTokens: (options && options.maxOutputTokens) || 256, - stopSequences: (options && options.stopSequences) || [], - } - }; -} - -async function postDataToLLM(url = '', accessToken: string, data: Palm2ApiRequest) { - // Default options are marked with * - const response = await fetch(url, { - method: 'POST', // *GET, POST, PUT, DELETE, etc. - mode: 'cors', // no-cors, *cors, same-origin - cache: 'no-cache', // *default, no-cache, reload, force-cache, only-if-cached - credentials: 'same-origin', // include, *same-origin, omit - headers: { - 'Content-Type': 'application/json', - 'Authorization': `Bearer ${accessToken}`, - // 'Content-Type': 'application/x-www-form-urlencoded', - }, - redirect: 'follow', // manual, *follow, error - referrerPolicy: 'no-referrer', // no-referrer, *no-referrer-when-downgrade, origin, origin-when-cross-origin, same-origin, strict-origin, strict-origin-when-cross-origin, unsafe-url - body: JSON.stringify(data), // body data type must match "Content-Type" header - }); - return response.json(); // parses JSON response into native JavaScript objects -} - -export async function sendPalm2Request( - projectId: string, - accessToken: string, - req: Palm2ApiRequest, - modelId = 'text-bison', // e.g. text-bison for latest text-bison model - apiEndpoint = 'us-central1-aiplatform.googleapis.com', -): Promise { - return postDataToLLM( - // TODO: it may be that the url part 'us-central1' has to match - // apiEndpoint. - `https://${apiEndpoint}/v1/projects/${projectId}/locations/us-central1/publishers/google/models/${modelId}:predict`, - accessToken, - req - ); - // .then((data) => { - // console.log(data); // JSON data parsed by `data.json()` call - // }) - // .catch((err) => console.error(err)); -} - -interface Palm2ApiOptions { - modelId: string, - apiEndpoint: string, - requestParameters: Palm2ApiParams -} - -export class VertexPalm2LLM implements LLM { - public name: string; - public defaultOptions: Palm2ApiOptions = { - modelId: 'text-bison', - apiEndpoint: 'us-central1-aiplatform.googleapis.com', - requestParameters: { - temperature: 0.7, - topK: 40, - topP: 0.95, - candidateCount: 4, - maxOutputTokens: 256, - stopSequences: [], - } - }; - - constructor( - public projectId: string, - public accessToken: string, - ) { - this.name = `VertexLLM:` + this.defaultOptions.modelId; - } - - // - async predict( - query: string, params?: Palm2ApiOptions - ): Promise { - - const apiParams = params ? params.requestParameters - : this.defaultOptions.requestParameters; - const apiRequest: Palm2ApiRequest = { - instances: [{ content: query }], - parameters: apiParams - } - - const apiResponse = await sendPalm2Request( - this.projectId, - this.accessToken, - apiRequest, - this.defaultOptions.modelId, - this.defaultOptions.apiEndpoint); - - // The API doesn't include the actual stop sequence that it found, so we - // can never know the true stop seqeunce, so we just pick the first one, - // and image it is that. - const imaginedPostfixStopSeq = apiParams.stopSequences.length > 0 ? - apiParams.stopSequences[0] : ''; - - if (!apiResponse.predictions) { - throw new Error(`No predictions resturned in api response:` + - ` ${JSON.stringify(apiResponse, null, 2)}`); - } - - // TODO: skip this and simplify? - const scoredCompletions = apiResponse.predictions.map(p => { - return { - query: query, - completion: p.content + imaginedPostfixStopSeq, - score: 1, // TODO: API doesn't provide this, so we fake it as always 1. - } - }); - - return { completions: scoredCompletions.map(c => c.completion) } - } - - // TODO: The cloud API doesn't currently support scoring. - // async score(request: ScoreRequest): Promise { - // } - -} diff --git a/llm-recs/appengine-server/src/text-templates/scripts/run_test_devapi_palm2.ts b/llm-recs/appengine-server/src/text-templates/scripts/run_test_devapi_palm2.ts deleted file mode 100644 index 341e5d0c..00000000 --- a/llm-recs/appengine-server/src/text-templates/scripts/run_test_devapi_palm2.ts +++ /dev/null @@ -1,69 +0,0 @@ -/*============================================================================== - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an Apache2 license that can be - * found in the LICENSE file and http://www.apache.org/licenses/LICENSE-2.0 -==============================================================================*/ - -/* Test call makersuite.google.com developer API for Palm2 LLM. - -Usage: - -PALM2_GENAI_API_KEY="copy the api key from makersuite.google.com/app/apikey" -npx ts-node --esm ./run_test_devapi_palm2.ts \ - --apiKey=${PALM2_GENAI_API_KEY} - -Where PALM2_GENAI_API_KEY envionment variable should be set before running, -e.g. copy/pasted from MakerSuite UI API Key section at -https://makersuite.google.com/app/apikey - -Note: this will only work from IP addresses in supported countries. - -*/ -import { sendPalm2Request, preparePalm2Request } from '../llm_devapi_palm2'; - -import * as yargs from 'yargs'; - -interface Params { - apiKey: string; -} - -async function run(args: Params): Promise { - - const prompt = ` -The following are short movie summaries. They are specific, not generic (no movie is just "a classic"), and they don't contain plot synopsis. They just describe my experience of the movie. - -movie: 'Fifth Element' -summary: ['a joyous sci fi that emerses you in a colourful universe', 'quirky upbeat action'] - -movie: 'Seven Samurai' -summary: ['a black and white masterpiece of cinematography', 'a slow, atmospheric, symbolic fight for all that is just'] - -movie: 'The Godfather' -summary: [' -`; - - const request = preparePalm2Request(prompt); - request.stop_sequences.push(`']`); - const response = await sendPalm2Request(args.apiKey, request); - console.log(JSON.stringify(response)); -} - -// ---------------------------------------------------------------------------- -const args = yargs - .option('apiKey', { - describe: 'The API Key from MakerSuite UI. See: ' - + 'https://makersuite.google.com/app/apikey', - demandOption: true, - type: 'string', - }).help().argv; - -run(args as Params) - .then(() => { - console.log('Success!'); - }) - .catch(e => { - console.error('Failed: ', e); - throw Error('Failed'); - }); diff --git a/llm-recs/appengine-server/src/text-templates/scripts/run_vertexapi_palm2_fetch_predict.ts b/llm-recs/appengine-server/src/text-templates/scripts/run_vertexapi_palm2_fetch_predict.ts deleted file mode 100644 index 280ac110..00000000 --- a/llm-recs/appengine-server/src/text-templates/scripts/run_vertexapi_palm2_fetch_predict.ts +++ /dev/null @@ -1,118 +0,0 @@ -/*============================================================================== - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an Apache2 license that can be - * found in the LICENSE file and http://www.apache.org/licenses/LICENSE-2.0 -==============================================================================*/ - -/* Test call to The Google-Cloud-Vertex-AI-API Palm2 LLM. - -Assumes: node is installed (you have the npx command). -See https://github.com/nvm-sh/nvm - -Usage: - -npx ts-node --esm ./run_vertexapi_palm2_fetch_predict.ts \ - --project=$(gcloud config get-value project) \ - --accessToken=$(gcloud auth print-access-token) \ - --movie="The Untouchables" - -Assumes that you have run: - gcloud config set project ${YOUR_GOOGLE_CLOUD_PROJECT_ID} -*/ -import { VertexPalm2LLM } from '../llm_vertexapi_palm2'; -import { FewShotTemplate } from '../fewshot_template'; - -import * as yargs from 'yargs'; -import { nv, template } from '../template'; -import { fillTemplate } from '../llm'; - -interface Params { - accessToken: string, - project: string, - movie: string, -} - -function prettyMovieRec(index: number, movie: string, summaries: string): string { - const outputFormat = template` ----- ${nv('index')} ---- -I think you'll find the movie ${nv('movie')}: - -${nv('bullets')} - -Do you like my summary?`; - const splitSummaries = summaries.split(`', '`).map( - summaryPoint => { return { summaryPoint } }) - const outputBullets = new FewShotTemplate( - template`* ${nv('summaryPoint')}`, '\n\n'); - const bullets = outputBullets.apply(splitSummaries).stringify(); - // Notice the nice type error is I try and and stringify, but forgot to - // fill in the template... - // Type 'Error_CannotStringifyTemplateWithVars<"index">' is not assignable - // to type 'string'. - // return outputFormat.substs({ movie, bullets }).stringify(); - return outputFormat.substs({ movie, bullets, index: `${index}` }).stringify(); -} - - -async function run(args: Params): Promise { - // Notice the few-shot prompt doesn't always have a synopsis or rating, but - // we want to always generate them. - const t = template` -The following are short movie summaries. They are specific, not generic (no movie is just "a classic"), and they don't contain plot synopsis. They just describe the experience of watching the movie. It tries to tell you the essence of the movie. - -movie: 'Fifth Element' -summary: ['joyous sci fi that emerses you in a colourful universe', 'quirky upbeat action'] -synopsis: 'The 23rd century, a New York City cabbie, Korben Dallas (Bruce Willis), finds the fate of the world in his hands when Leeloo (Milla Jovovich) falls into his cab. As the embodiment of the fifth element, Leeloo needs to combine with the other four to keep the approaching Great Evil from destroying the world.' - -movie: 'Seven Samurai' -summary: ['black and white masterpiece of cinematography', 'a slow, atmospheric, symbolic fight for all that is just'] -rating (1 to 5 scale): 5 - -movie: '${nv('movie')}' -summary: ['${nv('summaries')}'] -rating (1 to 5 scale): ${nv('rating', { match: '[12345](.\\d)?' })} -synopsis: '${nv('synopsis')}'`; - - const llm = new VertexPalm2LLM( - args.project, - args.accessToken, - ); - const templateToFill = t.substs({ movie: args.movie }); - const responses = await fillTemplate(llm, templateToFill); - const badlyFormedResponsesCount = responses.filter(r => !r.substs).length; - console.log(`badlyFormedResponses count: ${badlyFormedResponsesCount}`); - console.log(`responses: ${JSON.stringify(responses, null, 2)} `); - - responses.filter(r => r.substs).forEach( - (r, i) => console.log(prettyMovieRec(i, args.movie, r.substs!.summaries)) - ); -} - -// ---------------------------------------------------------------------------- -const args = yargs - .option('accessToken', { - describe: 'Google Cloud Auth Token ' + - 'e.g. echo $(gcloud auth print-access-token)', - demandOption: true, - type: 'string', - }).option('project', { - describe: 'The Google Cloud Project to use (it must have the VertexAI ' + - 'API enabled).', - demandOption: true, - type: 'string', - }).option('movie', { - describe: 'The name of a movie to get a review of', - demandOption: true, - type: 'string', - }).help().argv; - -run(args as Params) - .then(() => { - console.log('Success!'); - }) - .catch(e => { - console.error('Failed: ', e); - throw Error('Failed'); - }); diff --git a/llm-recs/appengine-server/src/text-templates/scripts/run_vertexapi_palm2_gaxois_predict.ts b/llm-recs/appengine-server/src/text-templates/scripts/run_vertexapi_palm2_gaxois_predict.ts deleted file mode 100644 index 316add95..00000000 --- a/llm-recs/appengine-server/src/text-templates/scripts/run_vertexapi_palm2_gaxois_predict.ts +++ /dev/null @@ -1,120 +0,0 @@ -/*============================================================================== - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an Apache2 license that can be - * found in the LICENSE file and http://www.apache.org/licenses/LICENSE-2.0 -==============================================================================*/ - -/* Test call to The Google-Cloud-Vertex-AI-API Palm2 LLM. - -Assumes: node is installed (you have the npx command). -See https://github.com/nvm-sh/nvm - -Usage: - -npx ts-node --esm ./run_vertexapi_palm2_gaxois_predict.ts \ - --project=$(gcloud config get-value project) \ - --movie="The Untouchables" - -Assumes that you have run: - gcloud config set project ${YOUR_GOOGLE_CLOUD_PROJECT_ID} -*/ -import { VertexPalm2LLM } from '../llm_gaxois_vertexapi_palm2'; -import { FewShotTemplate } from '../fewshot_template'; -import { GoogleAuth } from 'google-auth-library'; - -import * as yargs from 'yargs'; -import { nv, template } from '../template'; -import { fillTemplate } from '../llm'; - -interface Params { - project: string, - movie: string, -} - -function prettyMovieRec(index: number, movie: string, summaries: string): string { - const outputFormat = template` ----- ${nv('index')} ---- -I think you'll find the movie ${nv('movie')}: - -${nv('bullets')} - -Do you like my summary?`; - const splitSummaries = summaries.split(`', '`).map( - summaryPoint => { return { summaryPoint } }) - const outputBullets = new FewShotTemplate( - template`* ${nv('summaryPoint')}`, '\n\n'); - const bullets = outputBullets.apply(splitSummaries).stringify(); - // Notice the nice type error is I try and and stringify, but forgot to - // fill in the template... - // Type 'Error_CannotStringifyTemplateWithVars<"index">' is not assignable - // to type 'string'. - // return outputFormat.substs({ movie, bullets }).stringify(); - return outputFormat.substs({ movie, bullets, index: `${index}` }).stringify(); -} - - -async function run(args: Params): Promise { - // Notice the few-shot prompt doesn't always have a synopsis or rating, but - // we want to always generate them. - const t = template` -The following are short movie summaries. They are specific, not generic (no movie is just "a classic"), and they don't contain plot synopsis. They just describe the experience of watching the movie. It tries to tell you the essence of the movie. - -movie: 'Fifth Element' -summary: ['joyous sci fi that emerses you in a colourful universe', 'quirky upbeat action'] -synopsis: 'The 23rd century, a New York City cabbie, Korben Dallas (Bruce Willis), finds the fate of the world in his hands when Leeloo (Milla Jovovich) falls into his cab. As the embodiment of the fifth element, Leeloo needs to combine with the other four to keep the approaching Great Evil from destroying the world.' - -movie: 'Seven Samurai' -summary: ['black and white masterpiece of cinematography', 'a slow, atmospheric, symbolic fight for all that is just'] -rating (1 to 5 scale): 5 - -movie: '${nv('movie')}' -summary: ['${nv('summaries')}'] -rating (1 to 5 scale): ${nv('rating', { match: '[12345](.\\d)?' })} -synopsis: '${nv('synopsis')}'`; - - const auth = new GoogleAuth({ - scopes: [ - 'https://www.googleapis.com/auth/cloud-platform', - ] - }); - const projectId = args.project || await auth.getProjectId(); - const client = await auth.getClient(); - - const llm = new VertexPalm2LLM( - projectId, - client, - ); - const templateToFill = t.substs({ movie: args.movie }); - const responses = await fillTemplate(llm, templateToFill); - const badlyFormedResponsesCount = responses.filter(r => !r.substs).length; - console.log(`badlyFormedResponses count: ${badlyFormedResponsesCount}`); - console.log(`responses: ${JSON.stringify(responses, null, 2)} `); - - responses.filter(r => r.substs).forEach( - (r, i) => console.log(prettyMovieRec(i, args.movie, r.substs!.summaries)) - ); -} - -// ---------------------------------------------------------------------------- -const args = yargs - .option('project', { - describe: 'The Google Cloud Project to use (it must have the VertexAI ' + - 'API enabled).', - demandOption: true, - type: 'string', - }).option('movie', { - describe: 'The name of a movie to get a review of', - demandOption: true, - type: 'string', - }).help().argv; - -run(args as Params) - .then(() => { - console.log('Success!'); - }) - .catch(e => { - console.error('Failed: ', e); - throw Error('Failed'); - }); diff --git a/llm-recs/appengine-server/src/text-templates/scripts/run_vertexapi_palm2_rawSend.ts b/llm-recs/appengine-server/src/text-templates/scripts/run_vertexapi_palm2_rawSend.ts deleted file mode 100644 index e358a906..00000000 --- a/llm-recs/appengine-server/src/text-templates/scripts/run_vertexapi_palm2_rawSend.ts +++ /dev/null @@ -1,69 +0,0 @@ -/*============================================================================== - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an Apache2 license that can be - * found in the LICENSE file and http://www.apache.org/licenses/LICENSE-2.0 -==============================================================================*/ - -/* Test call to The Google-Cloud-Vertex-AI-API Palm2 LLM. - -Usage: - -npx ts-node --esm ./run_vertexapi_palm2_rawSend.ts \ - --project=$(gcloud config get-value project) \ - --accessToken=$(gcloud auth print-access-token) -*/ -import { sendPalm2Request, preparePalm2Request } from '../llm_vertexapi_palm2'; - -import * as yargs from 'yargs'; - -interface Params { - accessToken: string, - project: string, -} - -async function run(args: Params): Promise { - - const prompt = ` -The following are short movie summaries. They are specific, not generic (no movie is just "a classic"), and they don't contain plot synopsis. They just describe the experience of watching the movie. It tries to tell you the essence of the movie. - -movie: 'Fifth Element' -summary: ['joyous sci fi that emerses you in a colourful universe', 'quirky upbeat action'] - -movie: 'Seven Samurai' -summary: ['black and white masterpiece of cinematography', 'a slow, atmospheric, symbolic fight for all that is just'] - -movie: 'The Godfather' -summary: [' -`; - - const request = preparePalm2Request(prompt); - request.parameters.stopSequences.push(`']`); - const response = await sendPalm2Request( - args.project, args.accessToken, request); - console.log(JSON.stringify(response)); -} - -// ---------------------------------------------------------------------------- -const args = yargs - .option('accessToken', { - describe: 'Google Cloud Auth Token ' + - 'e.g. echo $(gcloud auth print-access-token)', - demandOption: true, - type: 'string', - }).option('project', { - describe: 'The Google Cloud Project to use (it must have the VertexAI ' + - 'API enabled).', - demandOption: true, - type: 'string', - }).help().argv; - -run(args as Params) - .then(() => { - console.log('Success!'); - }) - .catch(e => { - console.error('Failed: ', e); - throw Error('Failed'); - }); diff --git a/llm-recs/appengine-server/src/text-templates/scripts/tsconfig.json b/llm-recs/appengine-server/src/text-templates/scripts/tsconfig.json deleted file mode 100644 index 9c944856..00000000 --- a/llm-recs/appengine-server/src/text-templates/scripts/tsconfig.json +++ /dev/null @@ -1,24 +0,0 @@ -/* To learn more about this file see: https://angular.io/config/tsconfig. */ -{ - // See: https://github.com/tsconfig/bases - "extends": "@tsconfig/node18/tsconfig.json", - - // Most ts-node options can be specified here using their programmatic names. - "ts-node": { - // It is faster to skip typechecking. - // Remove if you want ts-node to do typechecking. - "transpileOnly": true, - - "files": true, - - "compilerOptions": { - // compilerOptions specified here will override those declared below, - // but *only* in ts-node. Useful if you want ts-node and tsc to use - // different options with a single tsconfig.json. - "esModuleInterop": true - } - }, - "compilerOptions": { - // typescript options here - } -} diff --git a/llm-recs/appengine-server/src/text-templates/template.spec.ts b/llm-recs/appengine-server/src/text-templates/template.spec.ts deleted file mode 100644 index c6ab5d0d..00000000 --- a/llm-recs/appengine-server/src/text-templates/template.spec.ts +++ /dev/null @@ -1,277 +0,0 @@ -/*============================================================================== - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an Apache2 license that can be - * found in the LICENSE file and http://www.apache.org/licenses/LICENSE-2.0 -==============================================================================*/ - -import { Template, escapeStr, template, nv, unEscapeStr, matchTemplate } from './template'; -import { expect } from 'chai'; - -describe('template', () => { - beforeEach(() => { - }); - - it('A mini walkthrough of why this is neat...', () => { - // You can make temnplates quite naturally: you can define your variables, - // and then just use them in a simple interpreted string. - const thingVar = nv('thing'); - const thing2Var = nv('thing2') - const whatIsAtoB = template`what is a ${thingVar} to ${thing2Var}?`; - - // You could also of course just inline define them... - template`what is a ${nv('thing')} to ${nv('thing2')}?`; - - // Arguments can be auto-completed by IDE. e.g. the first you can reference - // the variables form the 'vars' paramter of a template. e.g. this lets you - // do string substituion in the template `whatIsAtoB` as follows where the - // subparams of vars are 'thing' or 'thing2'; those are the only variables - // in the template, and are auto-completed, and anything else is an 'as you - // type' type error. - let whatIsTabletoB = whatIsAtoB.vars.thing.substStr('table'); - expect(whatIsTabletoB.escaped).to.equal( - 'what is a table to {{thing2}}?'); - - // You can also reference the var names directly using a template's - // substution call, like so (and get editor auto-completion): - whatIsTabletoB.substStr('thing2', 'chair'); - - // And errors are checked as you type, e.g. - // - // whatIsTabletoB.substStr('thing', 'chair'); - // ^^^^^^^ - // Error: Argument of type '"thing"' is not assignable to parameter of - // type '"thing2"' - - // Or you can use the map substitution and even do multiple substitutions at - // once. - whatIsAtoB.substs({ thing: 'table', thing2: 'chair' }); - - // Variables can be progamatrically renamed in templates. - const whatIsAtoTarget = - whatIsAtoB.vars.thing2.renameVar('target'); - // Note: the nice automatic type inference: - // whatIsAtoTarget: Template<'thing', 'target'> - expect(Object.keys(whatIsAtoTarget.vars).sort()).to.deep.equal( - ['thing', 'target'].sort()); - expect(whatIsAtoTarget.escaped).to.equal( - 'what is a {{thing}} to {{target}}?'); - - // Variables can also be merged progamatrically too. - const whatIsThingtoItself = - whatIsAtoB.mergeVars(['thing', 'thing2'], 'thing'); - // Note: the nice automatic type inference: - // whatIsThingtoItself: Template<'thing'> - // - // We can verify that we merged 'thing', 'thing2' into 'thing' - expect(Object.keys(whatIsThingtoItself.vars).sort()).to.deep.equal( - ['thing'].sort()); - - // And we can verify the underlying escaped string value of the template - // like so: - expect(whatIsThingtoItself.escaped).to.equal( - 'what is a {{thing}} to {{thing}}?'); - - // You can also substitute variables for templates. New extra variables are - // corrected added in the newly created template. (whatIsTabletoBigB has the - // variable 'bigThing' and only that one) - const bigThingVar = nv('bigThing'); - const big = template`big ${bigThingVar}`; - const whatIsTabletoBigB = - whatIsTabletoB.vars.thing2.substTempl(big); - - // When you make new templates, you can also just use other templates as - // part of them... - const fooAndBig = template`foo ${whatIsTabletoBigB}`; - expect(fooAndBig.escaped).to.equal( - 'foo what is a table to big {{bigThing}}?'); - - // Also, variables are properies, so you can do things like check if they - // occur in other escaped string templates too. - expect(fooAndBig.vars.bigThing.occurs(big.escaped)) - .to.equal(true); - }); - - it('Replacing a var with a string', () => { - const thingVar = nv('thing'); - const p = new Template(`what is a ${thingVar}?`, - [thingVar]); - - expect(p.varList()[0]).to.equal(thingVar); - - const p2 = p.vars.thing.substStr('bar'); - - expect(p2.varList().length).to.equal(0); - expect(p2.escaped).to.equal('what is a bar?'); - }); - - it('Replacing a var with a template', () => { - const thingVar = nv('thing'); - const p = new Template(`what is a ${thingVar}?`, - [thingVar]); - - const bigVar = nv('bigThingName') - const p2 = new Template(`big ${bigVar}`, [bigVar]); - - const p3 = p.vars.thing.substTempl(p2); - - expect(p3.escaped).to.equal(`what is a big {{bigThingName}}?`); - expect(p3.vars.bigThingName.name).to.equal(`bigThingName`); - }); - - it('make a template with vars', () => { - const thingVar = nv('thing'); - const thing2Var = nv('thing2') - const p = template`what is a ${thingVar} to ${thing2Var}?`; - console.log('p.template', p.escaped); - - const bigThingVar = nv('bigThing') - const p2 = template`big ${bigThingVar}`; - - const p3 = p.vars.thing.substTempl(p2); - - expect(p3.escaped).to.equal(`what is a big {{bigThing}} to {{thing2}}?`); - expect(p3.vars.bigThing.name).to.equal(`bigThing`); - }); - - it('templates substition by the variable parameter', () => { - const thingVar = nv('thing'); - const thing2Var = nv('thing2') - const p = template`what is a ${thingVar} to ${thing2Var}?`; - - // Cool thing about this: for the first argument, the variable, is - // auto-completed, and errors are checked as you type. - // e.g. first argument is auto-completed to 'thing' or 'thing2'. - const p2 = p.vars.thing.substStr('table'); - }); - - it('escaping', () => { - const s = 'blah \\\\ {{foo}}'; - expect(escapeStr(s)).to.equal('blah \\\\\\\\ \\{\\{foo}}'); - }); - - it('unescaping', () => { - const s = 'blah \\\\ \\{\\{foo}}'; - expect(unEscapeStr(s)).to.equal('blah \\ {{foo}}'); - }); - - it('parts', () => { - const t = template`what is an ${nv('x')} to a ${nv('y')} anyway?`; - const parts = t.parts(); - expect(parts.prefix).to.equal('what is an '); - expect(parts.variables.map(x => x.postfix)).to.deep.equal([' to a ', ' anyway?']); - expect(parts.variables.map(x => x.variable.name)).to.deep.equal(['x', 'y']); - }); - - it('parts template matching', () => { - const t = template`what is an ${nv('x')} to a ${nv('y')} anyway?`; - const parts = t.parts(); - const s1 = 'what is an bug to a fly anyway?'; - const m1 = matchTemplate(parts, s1); - expect(m1).to.deep.equal({ x: 'bug', y: 'fly' }); - - const s2 = 'what is an bug to a pants!'; - const m2 = matchTemplate(parts, s2); - expect(m2).to.deep.equal({ x: 'bug', y: 'pants!' }); - - const s3 = 'bonkers!' - const m3 = matchTemplate(parts, s3); - expect(m3).to.equal(null); - - const s4 = 'what is an bugfoo'; - const m4 = matchTemplate(parts, s4); - expect(m4).to.deep.equal({ x: 'bugfoo', y: '' }); - }); - - it('parts template matching with match-string', () => { - const t = template`what is an ${nv('x', { match: '[12345]' })} to a ${nv('y')} anyway?`; - - const parts = t.parts(); - const s1 = 'what is an 3 to a fly anyway?'; - const m1 = matchTemplate(parts, s1); - expect(m1).to.deep.equal({ x: '3', y: 'fly' }); - - const s2 = 'what is an 2 to a pants!'; - const m2 = matchTemplate(parts, s2); - expect(m2).to.deep.equal({ x: '2', y: 'pants!' }); - - const s3 = 'bonkers!' - const m3 = matchTemplate(parts, s3); - expect(m3).to.equal(null); - - const s4 = 'what is an 4'; - const m4 = matchTemplate(parts, s4); - expect(m4).to.deep.equal({ x: '4', y: '' }); - - const s5 = 'what is an foo to a pants!'; - const m5 = matchTemplate(parts, s5); - expect(m5).to.equal(null); - - const s6 = 'what is an 2 and a 3?'; - const m6 = matchTemplate(parts, s6); - expect(m6).to.deep.equal({ x: '2', y: '' }); - }); - - - // it('parts template matching with match-string', () => { - // const t = template`']\nrating: `; - - // const parts = - // ` 80s cop drama with an amazing cast', 'stylish and suspenseful'] - // rating (1 to 5 scale): 4` - - // const parts = t.parts(); - // const s1 = 'what is an 3 to a fly anyway?'; - // const m1 = matchTemplate(parts, s1); - // expect(m1).to.equal({ x: '3', y: 'fly' }); - - // const s2 = 'what is an 2 to a pants!'; - // const m2 = matchTemplate(parts, s2); - // expect(m2).to.equal({ x: '2', y: 'pants!' }); - - // const s3 = 'bonkers!' - // const m3 = matchTemplate(parts, s3); - // expect(m3).to.equal(null); - - // const s4 = 'what is an 4'; - // const m4 = matchTemplate(parts, s4); - // expect(m4).to.equal({ x: '4', y: '' }); - - // const s5 = 'what is an foo to a pants!'; - // const m5 = matchTemplate(parts, s5); - // expect(m5).to.equal(null); - - // const s6 = 'what is an 2 and a 3?'; - // const m6 = matchTemplate(parts, s6); - // expect(m6).to.equal({ x: '2', y: '' }); - // }); - - - - it('TypeScript BUG: ', () => { - const thingVar = nv('thing'); - const thing2Var = nv('thing2') - const p = template`what is a ${thingVar} to ${thing2Var}?`; - - const bigThingVar = nv('bigThing') - const p2 = template`big ${bigThingVar}`; - const p4 = template`foo ${bigThingVar}, bar ${thingVar}, and ${thing2Var}`; - - // BUG, the following line produces this error: - /* -Argument of type 'Template<"thing" | "person">' is not assignable to parameter of type 'Variable<"bigThing"> | Template<"bigThing">'. -Type 'Template<"thing" | "thing2">' is not assignable to type 'Template<"bigThing">'. -Types of property 'vars' are incompatible. - Property 'bigThing' is missing in type '{ thing: Variable<"thing">; person: Variable<"person">; }' but required in type '{ bigThing: Variable<"bigThing">; }'.ts(2345) - */ - // const p3 = template`foo ${p2}, bar ${p}`; - - // TODO: complete the test once the bug is fixed... - // expect(p3.template).to.equal( - // `foo what is {{thing}} to {{person}}, bar {{bigThing}}?`); - // expect(p3.vars.bigThing.name).to.equal(bigThingHole.name); - // expect(p3.vars.person.name).to.equal(personHole.name); - }); -}); - diff --git a/llm-recs/appengine-server/src/text-templates/template.ts b/llm-recs/appengine-server/src/text-templates/template.ts deleted file mode 100644 index aafaa7ad..00000000 --- a/llm-recs/appengine-server/src/text-templates/template.ts +++ /dev/null @@ -1,460 +0,0 @@ -/*============================================================================== - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an Apache2 license that can be - * found in the LICENSE file and http://www.apache.org/licenses/LICENSE-2.0 -==============================================================================*/ - -/* -An implementation of string-templates in TypeScript. The approach is to create a -Template clas which has the template types (Template) parameterized by a set -of string literal types (S). Each string literal in S is the name of a variable -in the template. The number of instances of a variable in a template does not -change the type, but the names of variables do. - -Various nice compositional utilities are then provided, e.g. substitution, -string-interpretation with variables and even templates. - -To see how this can be used, see the test files (.spec.ts), and specifically the -fewshot_template.spec.ts for some neat applications. - -One quirk of this is that when a template has no variables (it's just a literal -string), its type is `Template`. - - -Other notes: - -TO CONSIDER: provide an "noIdent" utility for templates to be more readable in -code blocks (e.g. s/\n\s+/\n/g). Maybe something fancy to allow \n. to be used -for real indent, but the "." gets ignored. - -It is probably also quite reasonable to think of templates as a list-type of -strings where each string is a variable name. But then you need to do list -motifications in your types, which is not well supported by typescript. - -Even set operations are not that well supported. e.g. we can't check if a string -overlaps in two types and produce a type error when it happens. One challenge -with trying to do do this is that it would make type checking conditions -constrains need to be carried around. - -e.g. you might get types T s.t. A & B = 0 - -That might need much deeper thinking in TS. But I think it would also be quite -wonderful. See ... - -TODO: verify list manipulations are not well supported by TypeScript typing. - -TODO: see if there is a different base-type for empty vars that can be used. I -spent a while looking at this, and I think never is probably the only one that -can be used. - -TODO: Move to using lists, where order is defined by first occurance. This -allows parsing of outputs from an LLM to be well typed and know what variable -will come next. - -*/ - -import { RegExpVar, NamedVar, SPLIT_REGEXP, RegExpVarOptions } from './variable'; - -// ---------------------------------------------------------------------------- -// Escaping -// ---------------------------------------------------------------------------- -// Simple escaping/unescaping when we have variables represented as: -// {{VarName}} -// escaping: blah \ {{ foo... ===> blah \\ \{\{ foo... -// unescaping: blah \\ \{\{ foo... ===> blah \ {{ foo... -export function escapeStr(s: string): string { - return s.replaceAll('\\', '\\\\').replaceAll('{', '\\{'); - // Can be done in a single pass... TODO: test sure faster... - // return s.replaceAll(/\\|\{/g, (m:string) => `\\${m}`); -} -export function unEscapeStr(s: string): string { - return s.replaceAll('\\\\', '\\').replaceAll('\\{', '{'); -} - -export function nv(name: N, options?: RegExpVarOptions) - : NamedVar { - return new RegExpVar(name, options); -} - -export interface Error_CannotStringifyTemplateWithVars { - _Error_CannotStringifyTemplateWithVars: T; -}; - -export type IfNeverElse = [T] extends [never] ? IfNeverT : ElseT; - -export interface TemplatePart { - variable: NamedVar, - postfix: string -}; - -export interface TemplateParts { - prefix: string; - variables: TemplatePart[] -}; - -// Escape a string so that it can be matched literally in a regexp expression. -// "$&" is the matched string. i.e. the character we need to escape. -function escapeStringInMatch(s: string) { - return s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); -} -// $$ is the results in writing out $, so $$$$ ends up as "$$" in the final -// string. e.g. $ ==> $$ -function escapeStringInReplacement(s: string) { - return s.replace(/\$/g, '$$$$'); -} - -// ---------------------------------------------------------------------------- -// Given a string, match the string against the template parts filling in the -// variables, returning the variable substitutions. -export function matchTemplate( - parts: TemplateParts, - s: string, - matchPrefix = true, -): { [Key in Ns]: string } | null { - const substs = {} as { [Key in Ns]: string }; - - if (matchPrefix) { - const prefixMatch = s.match(`^${escapeStringInMatch(parts.prefix)}`); - if (prefixMatch) { - s = s.slice(prefixMatch[0].length); - } else { - return null; - } - } - - for (const v of parts.variables) { - if (s.length === 0) { - substs[v.variable.name] = ''; - } - // If the var is the last thing in the template, then the whole response - // is the variable. - if (v.postfix === '') { - substs[v.variable.name] = s; - s = ''; - } - - if (!v.variable.contentMatchStr) { - // Match variable as free text, and require postfix or EOS to indicate - // variable end. - const varAndPostfixRegexp = new RegExp( - `^(.+?)(${escapeStringInMatch(v.postfix)}|$)`); - const varAndPostfixMatch = s.match(varAndPostfixRegexp); - - if (!varAndPostfixMatch) { - // if there is no match, then this variable has not been found or is the - // empty string. We treat that as a failure to fill in the variable. - // - // If this was the first variable, then no varaibles have been found, and - // we can directly fail and say that no variable was matched. - if (Object.keys(substs).length === 0) { - return null; - } - substs[v.variable.name] = ''; - // Setting s = '' will make all future vars null. - s = ''; - } else { - substs[v.variable.name] = varAndPostfixMatch[1]; - s = s.slice(varAndPostfixMatch[0].length); - } - } else { - // We have a special variable constraint, so match it first, then postfix. - const varRegexp = new RegExp(`^(${v.variable.contentMatchStr})`); - const varMatch = s.match(varRegexp); - if (!varMatch) { - - // if there is no match, then this variable has not been found or is the - // empty string. We treat that as a failure to fill in the variable. - // - // If this was the first variable, then no varaibles have been found, and - // we can directly fail and say that no variable was matched. - if (Object.keys(substs).length === 0) { - return null; - } - substs[v.variable.name] = ''; - // Setting s = '' will make all future vars null. - s = ''; - } else { - substs[v.variable.name] = varMatch[1]; - s = s.slice(varMatch[0].length); - } - - const postfixRegexp = new RegExp(escapeStringInMatch(v.postfix)); - const postfixMatch = s.match(postfixRegexp); - if (!postfixMatch) { - s = ''; - } else { - s = s.slice(postfixMatch[0].length); - } - } - } - return substs; -} - - -type NameToVarMap = { [Key in Ns]: TemplVar }; -// type SpecificName = string extends Ns ? never : Ns; -// type VarNames = NamedVar>; - -// ---------------------------------------------------------------------------- -// Ns = All variable names in the template. -// N = This variable name. -// TODO: consider this being a subclass of NamedVar... -export class TemplVar { - constructor(public template: Template, public rawVariable: NamedVar) { - if (!rawVariable.occurs(template.escaped)) { - console.error(`Template is missing a variable.\n` + - `Variable: ${this.name}\n` + - `Template: ${template.escaped}`) - } - }; - - get name(): N { - return this.rawVariable.name; - } - - // TODO: think about what if the "replacement" has variables in it? - // Right now we depend on doing this in the renameVar code. But we could - // imagine using a special kind of string type for escaped strings. - substStr(replacement: string): Template> { - const newTemplate = this.rawVariable.subst(this.template.escaped, replacement); - const newVarList = ( - [...this.template.varList().filter(v => v.name !== this.name) - ] as NamedVar>[]); - - return new Template(newTemplate, newVarList); - } - // TODO: maybe create a constraint that N2s must be dispoint with Ns? - substTempl(p: Template): Template | N2s> { - let newTemplate = this.template.escaped; - const subTemplate: Template = p; - newTemplate = this.rawVariable.subst( - newTemplate, subTemplate.escaped) - const newVarList = ( - [...this.template.varList().filter(v => v.name !== this.name), - ...subTemplate.varList()] as NamedVar | N2s>[]); - return new Template(newTemplate, newVarList); - } - - // TODO: would be better if I could express H3 is not member of Hs. - renameVar( - newName: Exclude, // N2 should not be in Ns! If so, this is never. - ): Template | N2> { - return this.unsafeRenameVar(newName as N2); - } - - unsafeRenameVar( - newName: N2, - ): Template | N2> { - const newVar = nv(newName); - const newTemplate = this.rawVariable.subst(this.template.escaped, newVar.literal); - const newVarList = ( - [...this.template.varList().filter(v => v.name !== this.name), - newVar] as NamedVar | N2>[]); - return new Template(newTemplate, newVarList); - } - - occurs(s: string): boolean { - return this.rawVariable.occurs(s); - } -} - -export class ExtraVarError extends Error { } - -const VAR_REGEXP = /\{\{(?[^(\}\})]*)\}\}/g; - -// ---------------------------------------------------------------------------- -// ---------------------------------------------------------------------------- -export class Template { - public vars: NameToVarMap; - - constructor(public escaped: string, vars: NamedVar[]) { - - const varsNamesInTemplate = - [...escaped.matchAll(VAR_REGEXP)].map(m => m.groups!['name']); - - this.vars = {} as NameToVarMap; - for (const v of vars.map(v => new TemplVar(this, v))) { - this.vars[v.name] = v; - } - - const extraVarsNamesInTemplateSet = new Set(varsNamesInTemplate); - const extraDelcaredVarNameSet = new Set(Object.keys(this.vars)); - extraDelcaredVarNameSet.forEach(v => { - if (extraVarsNamesInTemplateSet.delete(v)) { - extraDelcaredVarNameSet.delete(v); - } - }); - // TODO: consider if we want these to be allowed/not via options in - // the constructor? - if (extraVarsNamesInTemplateSet.size > 0) { - throw new ExtraVarError(`Template has undeclared variables: ` - + `${[...extraVarsNamesInTemplateSet]}.These should be declared` - + `constructor, or escaped.`); - } - if (extraDelcaredVarNameSet.size > 0) { - console.warn(`Extra vars were declared that don't exist in the ` - + `template, this is probably not intentional. The extra vars ` - + `are: ${[...extraDelcaredVarNameSet]}`); - } - } - - varList(): NamedVar[] { - return Object.values(this.vars) - .map(v => (v as TemplVar>).rawVariable); - } - - // TODO: would be better if I could express M is not member of Hs. - mergeVars( - varsToMerge: OldNs[], - mergedVar: Exclude>, - ): Template | M> { - // TODO: make a more efficient version that does it all at once instead of - // incrementally. - let newTempl = this as Template; - for (const v of varsToMerge) { - newTempl = newTempl.vars[v as unknown as Ns] - .unsafeRenameVar(mergedVar) as unknown as Template; - } - return newTempl as Template | M>; - } - - substStr(v: N, replacement: string): - Template> { - return this.vars[v].substStr(replacement); - }; - - substTempl( - v: N, replacement: Template - ): Template | N2s> { - return this.vars[v].substTempl(replacement); - } - - // substs(replacements: { [Key in S]: string }) - // : Template> { - // let newTempl = this as unknown as Template>; - // for (const k of (Object.keys(replacements) as S[])) { - // newTempl = (newTempl as unknown as Template).vars[k] - // .substStr(replacements[k]); - // } - // return newTempl; - // }; - - // TODO: can we make replacenments into templates? - // - // declare substs( - // replacements: { [Key in S]: string | NamedVar } - // ): Template | N2s>; - - substs( - replacements: { [Key in S]: string | NamedVar } - ): Template | (string extends N2s ? never : N2s)> { - type Return = Template | (string extends N2s ? never : N2s)> - let newTempl = this as unknown as Return; - for (const k of (Object.keys(replacements) as S[])) { - const r = replacements[k] - if (typeof r === 'string') { - newTempl = (newTempl as unknown as Template).vars[k] - .substStr(r) as Return; - } else { - newTempl = (newTempl as unknown as Template).vars[k] - .unsafeRenameVar(r.name) as Return; - } - } - return newTempl; - }; - - // CONSIDER: Make conditional type that errors is there is overlap on the - // variable names. Ideally this would be supported as a first class thing by - // TypeScript. - concat(secondPart: Template) - : Template { - const vars = [...this.varList(), ...secondPart.varList() - ] as NamedVar[]; - return new Template(this.escaped.concat(secondPart.escaped), vars); - } - - // Maybe templates should actually be a list objects where the object is the - // string-part and the variable parts, and a final string... (or initial - // string)? - parts(): TemplateParts { - const l = this.escaped.split(SPLIT_REGEXP); - // Note split using a regexp will result in parts.length > 0; so l.shift - // will always be defined. - const prefix = unEscapeStr(l.shift()!); - const parts = [] as TemplatePart[]; - while (l.length > 0) { - // prefix is defined because l.length > 0 - const variable = this.vars[l.shift() as Ns].rawVariable; - const postfix = unEscapeStr(l.shift()!); - parts.push({ variable, postfix }); - } - return { prefix, variables: parts }; - } - - stringify(): IfNeverElse> { - return unEscapeStr(this.escaped) as IfNeverElse>; - } - - // Can we define a generic subst? that takes a string or template replacement? - // subst(n: N, replacement: Templ | string): - // Templ | N2s> { - // if (typeof replacement === 'string') { - // return this.vars[n].substStr(replacement); - // } - // return this.vars[n].substTempl(replacement); - // } -} - - -// type TemplateArg = NamedVar | Template | string - -type TemplateArgName = T extends (NamedVar | Template | string) ? Hs : never; - -/** - * Helper function to make templates. This is intended to be the main way - * templates are created. - */ -export function template< - // Hs extends string - Args extends (NamedVar | Template | string)[] ->( - strings: TemplateStringsArray, - // ...args: TemplateArg[] - ...args: Args - // (NamedVar | Template | string)[] -): Template> { - const varSet = new Set>; - args.forEach( - a => { - if (a instanceof String || typeof (a) === 'string') { - return; - } - if (a instanceof Template) { - a.varList().forEach(v => varSet.add( - v as TemplateArgName)); - } - // TODO: support raw strings? - // else if (typeof a === 'string') { - // varSet.add(a) - // } - else if (a instanceof NamedVar) { - varSet.add(a as TemplateArgName); - } - }); - - return new Template( - strings.map((s, i) => { - if (i >= args.length) { - return s; - } - const a = args[i]; - return escapeStr(s) + ( - a instanceof Template ? a.escaped - : (a instanceof String || typeof (a) === 'string') ? a - : (a as NamedVar).literal); - }).join(''), - [...varSet] - ); -} diff --git a/llm-recs/appengine-server/src/text-templates/variable.spec.ts b/llm-recs/appengine-server/src/text-templates/variable.spec.ts deleted file mode 100644 index 563eb169..00000000 --- a/llm-recs/appengine-server/src/text-templates/variable.spec.ts +++ /dev/null @@ -1,42 +0,0 @@ -/*============================================================================== - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an Apache2 license that can be - * found in the LICENSE file and http://www.apache.org/licenses/LICENSE-2.0 -==============================================================================*/ - -import { RegExpVar } from './variable'; -import { expect } from 'chai'; - -describe('named variables', () => { - beforeEach(() => { - }); - - it('occurs', () => { - // You can prompts quite vaturally, you define your variables, and then - // just use them in a string interpretation. - const thingVar = new RegExpVar('thing'); - const bigThingVar = new RegExpVar('bigThing'); - // Variables are first class properies, and you can do stuff with them. - expect(bigThingVar.occurs('blah {{bigThing}}')).to.equal(true); - expect(thingVar.occurs('blah {{bigthing}}')).to.equal(false); - }); - - it('Substituting a var in a string', () => { - const thingVar = new RegExpVar('thing'); - const s2 = thingVar.subst(`what is a ${thingVar}?`, 'bar'); - expect(s2).to.equal('what is a bar?'); - }); - - // Sadly there is no way to override loose equality for classes in JS. - // it('equals', () => { - // // You can prompts quite vaturally, you define your variables, and then - // // just use them in a string interpretation. - // const thingVar = new RegExpVar('thing'); - // const thingVar2 = new RegExpVar('thing'); - // // Variables are first class properies, and you can do stuff with them. - // expect(thingVar == thingVar2).toBeTruthy(); - // }); -}); - diff --git a/llm-recs/appengine-server/src/text-templates/variable.ts b/llm-recs/appengine-server/src/text-templates/variable.ts deleted file mode 100644 index ecb39d70..00000000 --- a/llm-recs/appengine-server/src/text-templates/variable.ts +++ /dev/null @@ -1,112 +0,0 @@ -/*============================================================================== - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an Apache2 license that can be - * found in the LICENSE file and http://www.apache.org/licenses/LICENSE-2.0 -==============================================================================*/ - -/* -An implementation of named nariables that can occur in a string template. -*/ - -export abstract class NamedVar { - public abstract contentMatchStr?: string; - - constructor(public name: N) { }; - - // Apply the substitution, replacing this variable in `s` with the value - // string. - public abstract subst(s: string, value: string): string; - - // Split the string whereever this variable occurs. - public abstract split(s: string): string[]; - - // Returns true if 's' contains occurances of this variable. - // Properties: - // Forall s, s': if (!x.occurs(s)) then (x.applyFn(s, s') === s) - // (x.split(s).length === 1) <=iff=> (x.occurs(s) === false) - public occurs(s: string): boolean { - return Object.values(this.split(s)).length > 1; - } - - // Provides a literal string for the substitution. - // Key property: - // Forall s: x.applyFn(s, x.literalStr()) === s - public abstract literal: string; -} - - -// Assumes that regexp matches /.*${literal}.*/ -// (Required for the RegExpVar literal/applyFn property. -export interface RegExpVarOptions { - // A regexp-string that the content of this variable must match. - // The reason this is not a full RegExp is that it cannot specify regexp - // flags, e.g. /.../g - // It also should not include the $ or ^ markers (match end/start of regexp. - // This is intented to be part of the regexp used to control generation, or - // match the output in a template. - match?: string, - - // Optional string that much match right after the variable. - postVarMatch?: string; -} - -// Example usage: -// const r = 'did you know that a {{foo}} is a {{bar}}.'.split(VAR_REGEXP); -// r = ['did you know that a ', '{{foo}}', ' is a ', '{{bar}}', '.'] -// Property: every other value (the odd indexes) is a variable. -// We could use `\\{\\{([^(\\}\\})]*)\\}\\}` as our regexp to also remove -// variable marker parenthesis, but we don't do that because it's good to be -// able to easily visually inspect what's what. Maybe we'll change it later. -// export const VAR_REGEXP_STR = `(\\{\\{.*?\\}\\})`; -export const VAR_REGEXP_STR = `(\\{\\{[^(\\}\\})]*\\}\\})`; -// export const SPLIT_REGEXP_STR = `\\{\\{(.*?)\\}\\}`; -export const SPLIT_REGEXP_STR = `\\{\\{([^(\\}\\})]*)\\}\\}`; -export const SPLIT_REGEXP = new RegExp(SPLIT_REGEXP_STR, 'g'); -export const VAR_REGEXP = new RegExp(VAR_REGEXP_STR, 'g'); -export const PREFIX_REGEXP = new RegExp(`$([^(\\{\\{)]*)`); - -export class RegExpVar extends NamedVar { - // A regexp that the content of this variable must match. - // contentRegexp: RegExp; - - // The matcher for the literal in the template. - literalRegExp: RegExp; - - // This is the actual string value in the template that the variable has. - // The template's escaping must make sure that this cannot occcur as part of - // the template, except as this variable. - literal: string; - - // Regexp as a string to match content. - public contentMatchStr?: string; - - constructor(name: N, options?: RegExpVarOptions) { - super(name); - if (options && options.match) { - this.contentMatchStr = options.match; - } - // else { - // this.contentMatchStr = '.+?'; - //} - this.literal = `{{${this.name}}}`; - // TODO: consider doing this automatically by escaling this.literal - this.literalRegExp = new RegExp(`\\{\\{${this.name}\\}\\}`, 'g'); - } - - // static splitAllVars(s: string): string[] { - // return s.split(VAR_REGEXP); - // } - - public subst(s: string, value: string): string { - return s.replace(this.literalRegExp, value); - } - public split(s: string): string[] { - return s.split(this.literalRegExp); - } - - override toString(): string { - return this.literal; - } -} diff --git a/llm-recs/llm-recs-webclient/package-lock.json b/llm-recs/llm-recs-webclient/package-lock.json index 82c01404..da62214d 100644 --- a/llm-recs/llm-recs-webclient/package-lock.json +++ b/llm-recs/llm-recs-webclient/package-lock.json @@ -19,6 +19,7 @@ "@angular/platform-browser-dynamic": "^17.0.6", "@angular/router": "^17.0.6", "rxjs": "~7.8.0", + "ts-llmt": "^1.1.0", "tslib": "^2.3.0", "underscore": "^1.13.6", "zone.js": "~0.14.2" @@ -12968,6 +12969,29 @@ "tree-kill": "cli.js" } }, + "node_modules/ts-llmt": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/ts-llmt/-/ts-llmt-1.1.0.tgz", + "integrity": "sha512-qf6tA9ypUSWtxcCVtdAqrUUjm3DK+yrLfZeZ7yp4PmzOgqI70AIcwFFViHHLfC2fjuiHRYeMvf6GdaAXKBTcFg==", + "license": "Apache-2.0", + "dependencies": { + "typescript": "^5.4.5", + "underscore": "^1.13.6" + } + }, + "node_modules/ts-llmt/node_modules/typescript": { + "version": "5.6.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.6.3.tgz", + "integrity": "sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw==", + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, "node_modules/ts-node": { "version": "10.9.1", "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.1.tgz", diff --git a/llm-recs/llm-recs-webclient/package.json b/llm-recs/llm-recs-webclient/package.json index 3b9635c0..1cdd065a 100644 --- a/llm-recs/llm-recs-webclient/package.json +++ b/llm-recs/llm-recs-webclient/package.json @@ -21,6 +21,7 @@ "@angular/platform-browser-dynamic": "^17.0.6", "@angular/router": "^17.0.6", "rxjs": "~7.8.0", + "ts-llmt": "^1.1.0", "tslib": "^2.3.0", "underscore": "^1.13.6", "zone.js": "~0.14.2" @@ -31,13 +32,13 @@ "@angular/compiler-cli": "^17.0.6", "@tsconfig/node18": "^18.2.2", "@types/gapi": "^0.0.47", + "@types/gapi.auth2": "^0.0.60", "@types/gapi.client.drive-v3": "^0.0.4", + "@types/gapi.client.sheets-v4": "^0.0.4", "@types/google.accounts": "^0.0.14", "@types/jasmine": "~4.3.0", "@types/underscore": "^1.11.12", "@types/yargs": "^17.0.29", - "@types/gapi.auth2": "^0.0.60", - "@types/gapi.client.sheets-v4": "^0.0.4", "jasmine-core": "~4.6.0", "jose": "^5.1.0", "karma": "~6.4.0", @@ -49,4 +50,4 @@ "typescript": "~5.2.2", "yargs": "^17.7.2" } -} +} \ No newline at end of file diff --git a/llm-recs/llm-recs-webclient/src/app/services/item-interpreter.service.ts b/llm-recs/llm-recs-webclient/src/app/services/item-interpreter.service.ts index 3fbd60d0..ca6394c0 100644 --- a/llm-recs/llm-recs-webclient/src/app/services/item-interpreter.service.ts +++ b/llm-recs/llm-recs-webclient/src/app/services/item-interpreter.service.ts @@ -8,10 +8,16 @@ import { Injectable } from '@angular/core'; import { LmApiService } from './lm-api.service'; -import { expInterpTempl, characteristicsTempl } from '../../lib/recommender-prompts/item-interpreter'; -import { fillTemplate } from 'src/lib/text-templates/llm'; -import { matchFewShotTemplate } from 'src/lib/text-templates/fewshot_template'; -import { ErrorResponse, isErrorResponse } from 'src/lib/simple-errors/simple-errors'; +import { + expInterpTempl, + characteristicsTempl, +} from '../../lib/recommender-prompts/item-interpreter'; +import { fillTemplate } from 'ts-llmt/dist/llm'; +import { matchFewShotTemplate } from 'ts-llmt'; +import { + ErrorResponse, + isErrorResponse, +} from 'src/lib/simple-errors/simple-errors'; export interface InterpretedItem { entityTitle: string; @@ -21,26 +27,28 @@ export interface InterpretedItem { } @Injectable({ - providedIn: 'root' + providedIn: 'root', }) export class ItemInterpreterService { - constructor( // TODO: use this with a prompt to do smarter interpretation. - private lmApiService: LmApiService, - // public interpretationPrompt: Template - ) { } + private lmApiService: LmApiService + ) // public interpretationPrompt: Template + {} - async interpretItemText(text: string): Promise { + async interpretItemText( + text: string + ): Promise { const responses = await fillTemplate( this.lmApiService.llm, - expInterpTempl.substs({ experience: text })); + expInterpTempl.substs({ experience: text }) + ); if (isErrorResponse(responses)) { return responses; } - const badlyFormedResponsesCount = responses.filter(r => !r.substs).length; + const badlyFormedResponsesCount = responses.filter((r) => !r.substs).length; console.log(`badlyFormedResponses count: ${badlyFormedResponsesCount}`); console.log(`responses: ${JSON.stringify(responses, null, 2)} `); @@ -56,8 +64,10 @@ export class ItemInterpreterService { const sentiment = substs.likedOrDisliked; const charMatches = matchFewShotTemplate( - characteristicsTempl, substs.characteristics); - const keys = charMatches.map(c => c.substs.characteristic); + characteristicsTempl, + substs.characteristics + ); + const keys = charMatches.map((c) => c.substs.characteristic); return { entityTitle: title, text, sentiment, keys }; } } diff --git a/llm-recs/llm-recs-webclient/src/app/services/lm-api.service.ts b/llm-recs/llm-recs-webclient/src/app/services/lm-api.service.ts index a5089727..8b20de49 100644 --- a/llm-recs/llm-recs-webclient/src/app/services/lm-api.service.ts +++ b/llm-recs/llm-recs-webclient/src/app/services/lm-api.service.ts @@ -9,14 +9,14 @@ import { Injectable } from '@angular/core'; // import { VertexPalm2LLM } from '../lib/text-templates/llm_vertexapi_palm2'; import { SimpleEmbedder } from 'src/lib/text-embeddings/embedder_api'; -import { SimpleLlm } from 'src/lib/text-templates/llm_api'; +import { SimpleLlm } from 'ts-llmt/dist/llm_api'; // TODO: Unclear to me if this is needed or helpful... // // The value of having a service here is that the same LLM object can be used // throughout the app. @Injectable({ - providedIn: 'root' + providedIn: 'root', }) export class LmApiService { public llm: SimpleLlm; diff --git a/llm-recs/llm-recs-webclient/src/app/services/vertex-api.service.ts b/llm-recs/llm-recs-webclient/src/app/services/vertex-api.service.ts index f618933a..2d52ac98 100644 --- a/llm-recs/llm-recs-webclient/src/app/services/vertex-api.service.ts +++ b/llm-recs/llm-recs-webclient/src/app/services/vertex-api.service.ts @@ -7,7 +7,7 @@ ==============================================================================*/ import { Inject, Injectable } from '@angular/core'; -import { VertexPalm2LLM } from '../../lib/text-templates/llm_vertexapi_palm2'; +import { VertexGeminiLLM } from 'ts-llmt/dist/llm_vertexapi_gemini_1_5_authtoken'; import { VertexEmbedder } from 'src/lib/text-embeddings/embedder_vertexapi'; // TODO: Unclear to me if this is needed or helpful... @@ -15,22 +15,22 @@ import { VertexEmbedder } from 'src/lib/text-embeddings/embedder_vertexapi'; // The value of having a service here is that the same LLM object can be used // throughout the app. @Injectable({ - providedIn: 'root' + providedIn: 'root', }) export class VertexApiService { - public llm: VertexPalm2LLM; + public llm: VertexGeminiLLM; public embedder: VertexEmbedder; constructor() { const project = localStorage.getItem('projectId') || 'no project set'; const token = localStorage.getItem('accessToken') || 'no access token set'; - this.llm = new VertexPalm2LLM(project, token); + this.llm = new VertexGeminiLLM(project, token); this.embedder = new VertexEmbedder(project, token); } set accessToken(token: string) { - console.log(`accessToken update ${token}.`) + console.log(`accessToken update ${token}.`); this.llm.accessToken = token; localStorage.setItem('accessToken', token); } @@ -39,7 +39,7 @@ export class VertexApiService { } set projectId(project: string) { - console.log(`projectId update ${project}.`) + console.log(`projectId update ${project}.`); this.llm.projectId = project; localStorage.setItem('projectId', project); } diff --git a/llm-recs/llm-recs-webclient/src/lib/recommender-prompts/item-interpreter.ts b/llm-recs/llm-recs-webclient/src/lib/recommender-prompts/item-interpreter.ts index fd1785ea..d4ea3b92 100644 --- a/llm-recs/llm-recs-webclient/src/lib/recommender-prompts/item-interpreter.ts +++ b/llm-recs/llm-recs-webclient/src/lib/recommender-prompts/item-interpreter.ts @@ -5,25 +5,35 @@ * Use of this source code is governed by an Apache2 license that can be * found in the LICENSE file and http://www.apache.org/licenses/LICENSE-2.0 ==============================================================================*/ -import { Template, escapeStr, template, nv, unEscapeStr } from '../text-templates/template'; -import { FewShotTemplate } from '../text-templates/fewshot_template'; +import { + Template, + escapeStr, + template, + nv, + unEscapeStr, + FewShotTemplate, +} from 'ts-llmt'; interface Experience { experience: string; - aboutEntity: string, - likedOrDisliked: string, + aboutEntity: string; + likedOrDisliked: string; characteristics: string[]; } interface ExperienceTemplEntry { experience: string; - aboutEntity: string, - likedOrDisliked: string, + aboutEntity: string; + likedOrDisliked: string; characteristics: string; } -export const characteristicsTempl = new FewShotTemplate(template`${nv('characteristic')}`, - '\n '); +export const characteristicsTempl = new FewShotTemplate( + template`${nv( + 'characteristic' + )}`, + '\n ' +); const criteriaPoints: Experience[] = [ { @@ -34,35 +44,42 @@ const criteriaPoints: Experience[] = [ 'Peaceful', 'Tons of old growth trees and benches', 'Great for walking, jogging, picnic, or just sitting and relaxing', - 'Like a mini version of Central Park in New York' - ] + 'Like a mini version of Central Park in New York', + ], }, { experience: 'Spirited Away: breathtakingly beautiful.', aboutEntity: 'Spirited Away', likedOrDisliked: 'Liked', - characteristics: ['Visually stunning', 'Great story', 'Heartwarming'] + characteristics: ['Visually stunning', 'Great story', 'Heartwarming'], }, ]; - const experienceTemplEntries: ExperienceTemplEntry[] = criteriaPoints.map( (item) => { const { experience, aboutEntity, likedOrDisliked } = item; const characteristics = characteristicsTempl.apply( - item.characteristics.map(s => { return { characteristic: s }; }) + item.characteristics.map((s) => { + return { characteristic: s }; + }) ).escaped; return { - experience, aboutEntity, likedOrDisliked, characteristics + experience, + aboutEntity, + likedOrDisliked, + characteristics, }; - }) + } +); -const itemExperienceTempl = template`${nv('experience')} +const itemExperienceTempl = template`${nv( + 'experience' +)} ${nv('aboutEntity')} ${nv('likedOrDisliked')} ${nv('characteristics')} -` +`; const itemExperiencesTempl = new FewShotTemplate(itemExperienceTempl, '\n\n'); @@ -73,9 +90,11 @@ ${nv('pastExperiences')} ${itemExperienceTempl}`; // Example usage. -const pastFewShotItemExperiences = itemExperiencesTempl.apply(experienceTemplEntries); +const pastFewShotItemExperiences = itemExperiencesTempl.apply( + experienceTemplEntries +); export const expInterpTempl = itemInterpreterTempl.substs({ pastExperiences: pastFewShotItemExperiences.escaped, // experience: 'The Garden of Forking Paths: like it' -}); \ No newline at end of file +}); diff --git a/llm-recs/llm-recs-webclient/src/lib/text-templates/fewshot_template.spec.ts b/llm-recs/llm-recs-webclient/src/lib/text-templates/fewshot_template.spec.ts deleted file mode 100644 index 633a567c..00000000 --- a/llm-recs/llm-recs-webclient/src/lib/text-templates/fewshot_template.spec.ts +++ /dev/null @@ -1,201 +0,0 @@ -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an Apache2 license that can be - * found in the LICENSE file and http://www.apache.org/licenses/LICENSE-2.0 -==============================================================================*/ - -import { flatten } from 'underscore'; -import { Template, escapeStr, template, nv, unEscapeStr, matchTemplate } from './template'; -import { NamedVar } from './variable'; -import { FewShotTemplate, matchFewShotTemplate } from './fewshot_template'; - -// // ---------------------------------------------------------------------------- -// const movieSuggestionPrompt: Template = template``; - -// Idea: flow graphs: track the graph of substs. - -// Idea: treat lists as first class objects where the template bunches a set of -// vars, and knows how to seprate repetitions of them. - -// Idea: abstraction: generate a variable (have a stopping condition as first -// class entity. - - -describe('fewshot_template', () => { - beforeEach(() => { - }); - - it('A mini walkthrough of why this is neat...', () => { - - // ---------------------------------------------------------------------------- - // ---------------------------------------------------------------------------- - const criteriaPoints = [ - { - name: 'Concise', - description: 'not waffley.' - }, - { - name: 'No synposes', - description: 'do not give plot synopses.' - }, - { - name: 'Specific', - description: 'not vague (i.e. not "an amazing movie.", "a classic.").' - }, - ]; - const nCriteriaTempl = new FewShotTemplate(template - `(${nv('number')}) ${nv('name')}: ${nv('description')}`, - '\n'); - const numberedCriteriaPoints = - criteriaPoints.map((e, i) => { return { ...e, number: `${i + 1}` } }); - const criteriaTempl: Template = nCriteriaTempl.apply( - numberedCriteriaPoints); - - expect(criteriaTempl.escaped).toEqual( - `(1) Concise: not waffley. -(2) No synposes: do not give plot synopses. -(3) Specific: not vague (i.e. not "an amazing movie.", "a classic.").`); - - // ---------------------------------------------------------------------------- - // Probably too clever... but showing how you can have meta-templates. - // e.g. creating a common structure for propeties and values, and apply it - // to create a few-shot template with - // Move: {{movie}} - // Recommendation: {{recommendation}} - // And showing how this can be easily progamatically extended to: - // Move: {{movie}} - // Recommendation: {{recommendation}} - // Evaluation: {{evaluation}} - // The Motivation to do this is to make sure that you get consistent - // joining, e.g. ": " always separates the property from the value, and - // "\n" always separates different property-vcalue pairs. - const nPropertyValuePerLineTempl = new FewShotTemplate(template - `${nv('property')}: "${nv('value')}"`, - '\n'); - const movieAndRecList = [ - { - property: 'Movie', - value: nv('movie'), - }, - { - property: 'Recommendation', - value: nv('recommendation'), - } - ]; - const movieRecTempl = nPropertyValuePerLineTempl.apply(movieAndRecList); - const movieRecEvalTempl = - nPropertyValuePerLineTempl.apply( - [...movieAndRecList, - { - property: 'Evaluation', - value: nv('evaluation'), - }]); - - expect(movieRecEvalTempl.escaped).toEqual( - `Movie: "{{movie}}" -Recommendation: "{{recommendation}}" -Evaluation: "{{evaluation}}"`); - - // ---------------------------------------------------------------------------- - const fewShotCriticExamples = [ - { - movie: 'The Godfather', - recommendation: 'a dark and violent story of family and power', - evaluation: 'ok', - }, - { - movie: 'The Godfather', - recommendation: 'a masterpiece of cinema', - evaluation: 'Specific: the recommendation is vague, it should be more precise.' - }, - ]; - - const nCriticExamplesTempl = new FewShotTemplate( - movieRecEvalTempl, '\n\n'); - - // ---------------------------------------------------------------------------- - // Tenplates can contain other templates inline also. - const criticTempl = template - `Given the following criteria for movie recommendations: -${nv('Constitution')} - -Evaluate the following movie recommendations. -If the review is ok, the evaluation should just be "ok". - -${nv('fewShotCriticExamples')} - -${movieRecTempl} -Evaluation: "`; - - const criticWithConstitutionAndExamples = criticTempl.substs({ - Constitution: criteriaTempl.escaped, - fewShotCriticExamples: - nCriticExamplesTempl.apply(fewShotCriticExamples).escaped - }); - - expect(criticWithConstitutionAndExamples.escaped).toEqual( - `Given the following criteria for movie recommendations: -(1) Concise: not waffley. -(2) No synposes: do not give plot synopses. -(3) Specific: not vague (i.e. not "an amazing movie.", "a classic."). - -Evaluate the following movie recommendations. -If the review is ok, the evaluation should just be "ok". - -Movie: "The Godfather" -Recommendation: "a dark and violent story of family and power" -Evaluation: "ok" - -Movie: "The Godfather" -Recommendation: "a masterpiece of cinema" -Evaluation: "Specific: the recommendation is vague, it should be more precise." - -Movie: "{{movie}}" -Recommendation: "{{recommendation}}" -Evaluation: "`); - }); - - it('parts template matching with multi-line match-string', () => { - const itemExperienceTempl = template`Short experience description: "${nv('experience')}" -About: ${nv('aboutEntity')} (${nv('aboutDetails')}) -Liked or Disliked: ${nv('likedOrDisliked')}, because: -[ - ${nv('characteristics')} -]`; - - const t = itemExperienceTempl.substs({ - experience: 'The Garden of Forking Paths: like it' - }); - - const parts = t.parts(); - const s1 = "The Garden of Forking Paths (short story by Jorge Luis Borges)\nLiked or Disliked: Liked, because:\n[\n \"Intriguing\",\n \"Philosophical\",\n \"Thought-provoking\"\n]\n\nfoo foo\n]"; - const m1 = matchTemplate(parts, s1, false); - expect(m1.substs).toEqual({ - aboutEntity: 'The Garden of Forking Paths', - aboutDetails: 'short story by Jorge Luis Borges', - likedOrDisliked: 'Liked', - characteristics: '\"Intriguing\",\n \"Philosophical\",\n \"Thought-provoking\"' - }); - }); - - it('match fewshot template', () => { - const templ = new FewShotTemplate(template - `(${nv('id')}) ${nv('property')}: "${nv('value')}"`, - '\n'); - - const str = `(1) Concise: "not waffley" -(2) No synposes: "do not give plot synopses" -(3) Specific: "not vague (i.e. not 'an amazing movie.', 'a classic.')"`; - - const m = matchFewShotTemplate(templ, str); - expect(m.length).toEqual(3); - expect(m[0].substs).toEqual({ id: '1', property: 'Concise', value: 'not waffley' }); - expect(m[0].curPart).toEqual(undefined); - expect(m[1].substs).toEqual({ id: '2', property: 'No synposes', value: 'do not give plot synopses' }); - expect(m[1].curPart).toEqual(undefined); - expect(m[2].substs).toEqual({ id: '3', property: 'Specific', value: 'not vague (i.e. not \'an amazing movie.\', \'a classic.\')' }); - expect(m[2].curPart).toEqual(undefined); - }); -}); diff --git a/llm-recs/llm-recs-webclient/src/lib/text-templates/fewshot_template.ts b/llm-recs/llm-recs-webclient/src/lib/text-templates/fewshot_template.ts deleted file mode 100644 index 2235084b..00000000 --- a/llm-recs/llm-recs-webclient/src/lib/text-templates/fewshot_template.ts +++ /dev/null @@ -1,97 +0,0 @@ -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an Apache2 license that can be - * found in the LICENSE file and http://www.apache.org/licenses/LICENSE-2.0 -==============================================================================*/ - -/* -A few shot template class. This allows separating the template from the list of -values that get subsituted int it. - -The implementation is very simple: few shot templates are treated as templates -concatendated by a join string. - -For example: - -const nameDescriptionTempl = new FewShotTempl(template - `${namedVar('n')}, can be described in detail by: ${namedVar('d')}`, - '\n'); - -See the test file (.spec) for more detailed examples. -*/ - -import { flatten } from 'underscore'; -import { Template, escapeStr, template, nv, unEscapeStr, matchTemplate, TemplateMatch, escapeStringInMatch } from './template'; -import { NamedVar } from './variable'; - -// For each example substitution, substitute it into the template, and join it -// all together with the joinStr, into one big new template. -export function fewShotSubst( - templ: Template, - examples: { [Key in M]: string | NamedVar }[], - joinStr: string -): Template | N2s> { - const vars = flatten(examples.map(e => - Object.values>(e).filter( - r => typeof r !== 'string'))) as NamedVar[]; - return new Template | N2s>( - examples.map(e => templ.substs(e).escaped).join(joinStr), vars); -} - -// A class representing a few shot template. -export class FewShotTemplate { - constructor(public template: Template, - public joinStr: string) { }; - - apply( - examples: { [Key in Ms]: string }[] - ): Template | VarNs>; - apply( - examples: { [Key in Ms]: string | NamedVar }[] - ): Template | VarNs>; - apply( - examples: { [Key in Ms]: string | NamedVar }[] - ): Template | VarNs> { - return fewShotSubst( - this.template, examples, this.joinStr); - } -} - -export function matchFewShotTemplate( - fewShotTempl: FewShotTemplate, str: string -): TemplateMatch[] { - const matches: TemplateMatch[] = []; - const parts = fewShotTempl.template.parts(); - let match = matchTemplate(parts, str); - matches.push(match); - while ( - match.matchedPartsCount === match.parts.variables.length && - match.finalStr !== '' - ) { - let nextStr = match.finalStr - const sepMatch = match.finalStr.match( - `^${escapeStringInMatch(fewShotTempl.joinStr)}`); - if (sepMatch) { - nextStr = match.finalStr.slice(sepMatch[0].length); - } else { - return matches; - } - match = matchTemplate(parts, nextStr); - matches.push(match); - } - return matches; -} - - -function apply2( - a: Set, - bmap: { [Key in Ms]: string }[] -): Set> { - const a2 = new Set>(a as any); - Object.keys(bmap).forEach(n => a2.delete(n as any)); - return a2; -} - -const r2 = apply2(new Set(['a','b','c']), [{ a: 'a', b: 'b'}]); \ No newline at end of file diff --git a/llm-recs/llm-recs-webclient/src/lib/text-templates/llm.spec.ts b/llm-recs/llm-recs-webclient/src/lib/text-templates/llm.spec.ts deleted file mode 100644 index 6e4d7bdb..00000000 --- a/llm-recs/llm-recs-webclient/src/lib/text-templates/llm.spec.ts +++ /dev/null @@ -1,156 +0,0 @@ -/*============================================================================== - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an Apache2 license that can be - * found in the LICENSE file and http://www.apache.org/licenses/LICENSE-2.0 -==============================================================================*/ - -/* -Showing how the LLM class works... -*/ - -import { LookupTableFakeLLM, PredictResponse, ScoreResponse, ScoredCompletion, assertNoErrorResponse, fillTemplate, isErrorResponse } from "./llm"; -import { Palm2Response, preparePalm2Request } from "./llm_vertexapi_palm2"; -import { nv, template } from "./template"; - -describe('llm', () => { - let fakeLLM: LookupTableFakeLLM; - let stopString = `']`; - - beforeEach(() => { - // ---------------------------------------------------------------------------- - // Setup a fake LLM... - // ---------------------------------------------------------------------------- - const fakePromptInput1 = `. -The following are short movie summaries. They are specific, not generic (no movie is just "a classic"), and they don't contain plot synopsis. They just describe my experience of the movie. - -movie: 'Fifth Element' -summary: ['a joyous sci fi that emerses you in a colourful universe', 'quirky upbeat action'] - -movie: 'Seven Samurai' -summary: ['a black and white masterpiece of cinematography', 'a slow, atmospheric, symbolic fight for all that is just'] - -movie: 'The Godfather' -summary: ['`; - - const fakePromptInput2 = `. -The following are short movie summaries. They are specific, not generic (no movie is just "a classic"), and they don't contain plot synopsis. They just describe the experience of watching the movie. It tries to tell you the essence of the movie. - -movie: 'Fifth Element' -summary: ['joyous sci fi that emerses you in a colourful universe', 'quirky upbeat action'] -synopsis: 'The 23rd century, a New York City cabbie, Korben Dallas (Bruce Willis), finds the fate of the world in his hands when Leeloo (Milla Jovovich) falls into his cab. As the embodiment of the fifth element, Leeloo needs to combine with the other four to keep the approaching Great Evil from destroying the world.' - -movie: 'Seven Samurai' -summary: ['black and white masterpiece of cinematography', 'a slow, atmospheric, symbolic fight for all that is just'] -rating (1 to 5 scale): 5 - -movie: 'The Untouchables' -summary: ['`; - - /* An approxiation for... - const request = preparePalm2Request(prompt); - const response = await sendPalm2Request(..., request) - */ - function makeFakeResponse(responses: string[]): Palm2Response { - return { - "predictions": responses.map(s => ( - { - "content": s, - "citationMetadata": { "citations": [] }, - "safetyAttributes": { "scores": [], "blocked": false, "categories": [] } - })), - "metadata": { - "tokenMetadata": { - "outputTokenCount": { "totalBillableCharacters": 279, "totalTokens": 65 }, - "inputTokenCount": { "totalBillableCharacters": 410, "totalTokens": 118 } - } - } - }; - } - - const fakeResponse1 = makeFakeResponse([ - "an operatic tale of a powerful family", - "an operatic tragedy about a powerful Italian American crime family', 'a sprawling epic of violence and betrayal", - "epic crime saga with iconic performances', 'an operatic tale of family, loyalty, and betrayal", - "a timeless mafia masterpiece', 'an operatic tale of a family\\'s descent into darkness", - ].map(s => s + stopString)); - - const fakeResponse2 = makeFakeResponse([" 80s cop drama with an amazing cast', 'stylish and suspenseful']\nrating (1 to 5 scale): 4", - " stylish and gritty gangster movie of the prohibition era', 'the classic good vs evil tale']\nrating (1 to 5 scale): 4.5\n\nmovie: 'The Shawshank Redemption'\nsummary: ['a film with a very hopeful message', 'redemption, friendship and a little bit of hope']\nrating (1 to 5 scale): 5\n", - " stylish and violent prohibition era gangster movie', 'DeNiro and Connery are excellent']\nsynopsis: 'When a bootlegger is caught by the police and is released on bail, he is given one week to leave Chicago. During this time, he hires an accountant to get all his financial affairs in order. However, the accountant is an undercover agent who plans to gather evidence and bring him to justice.'\n", - // This example shows how string escaping often fails... - " fast paced, stylish action', 'a stylish piece of filmmaking with great performances and one-liners']\nsynopsis: 'Federal agent Eliot Ness (Kevin Costner) sets out to stop bootlegger Al Capone (Robert De Niro). To get him, Ness puts together a team of 11 men who are all willing to risk their lives to bring down Capone and his associates.'\n\nmovie: 'The Shining'\nsummary: ['uncomfortable, haunting, and disorienting', 'a masterclass in horror']\nsynopsis: 'Jack Torrance (Jack Nicholson) becomes the caretaker of the Overlook Hotel, a massive, isolated resort in the Colorado mountains. His son, Danny (Danny Lloyd), possesses psychic abilities that allow him to see visions of the hotel's violent past. As Jack's sanity deteriorates, he becomes increasingly violent and Danny must find a way to escape the hotel before it's too late.'\n" - ]); - - function makeScoredCompletions(query: string, response: Palm2Response): ScoreResponse { - return { - scoredCompletions: response.predictions.map(p => { - return { query, completion: p.content, score: 0 } - }) - }; - } - - const lookupTable: { [query: string]: ScoreResponse } = {}; - lookupTable[fakePromptInput1] = makeScoredCompletions(fakePromptInput1, fakeResponse1); - lookupTable[fakePromptInput2] = makeScoredCompletions(fakePromptInput2, fakeResponse2); - fakeLLM = new LookupTableFakeLLM(lookupTable); - }); - - // ---------------------------------------------------------------------------- - // Now the tests really start... - // ---------------------------------------------------------------------------- - it('llm template filling', async () => { - const promptTempl = template`. -The following are short movie summaries. They are specific, not generic (no movie is just "a classic"), and they don't contain plot synopsis. They just describe my experience of the movie. - -movie: 'Fifth Element' -summary: ['a joyous sci fi that emerses you in a colourful universe', 'quirky upbeat action'] - -movie: 'Seven Samurai' -summary: ['a black and white masterpiece of cinematography', 'a slow, atmospheric, symbolic fight for all that is just'] - -movie: '${nv('movie')}' -summary: ['${nv('summary')}']`; - - const substsList = await fillTemplate( - fakeLLM, promptTempl.substs({ movie: 'The Godfather' })); - assertNoErrorResponse(substsList); - expect(substsList.length).toEqual(4); - expect(substsList[0].substs!.summary).toEqual(`an operatic tale of a powerful family`); - expect(substsList[1].substs!.summary).toEqual(`an operatic tragedy about a powerful Italian American crime family', 'a sprawling epic of violence and betrayal`); - expect(substsList[2].substs!.summary).toEqual(`epic crime saga with iconic performances', 'an operatic tale of family, loyalty, and betrayal`); - expect(substsList[3].substs!.summary).toEqual(`a timeless mafia masterpiece', 'an operatic tale of a family\\'s descent into darkness`); - }); - - // ---------------------------------------------------------------------------- - // Now the tests really start... - // ---------------------------------------------------------------------------- - it('llm template filling with custom regexp', async () => { - const movie = "The Untouchables" - - const t = template`. -The following are short movie summaries. They are specific, not generic (no movie is just "a classic"), and they don't contain plot synopsis. They just describe the experience of watching the movie. It tries to tell you the essence of the movie. - -movie: 'Fifth Element' -summary: ['joyous sci fi that emerses you in a colourful universe', 'quirky upbeat action'] -synopsis: 'The 23rd century, a New York City cabbie, Korben Dallas (Bruce Willis), finds the fate of the world in his hands when Leeloo (Milla Jovovich) falls into his cab. As the embodiment of the fifth element, Leeloo needs to combine with the other four to keep the approaching Great Evil from destroying the world.' - -movie: 'Seven Samurai' -summary: ['black and white masterpiece of cinematography', 'a slow, atmospheric, symbolic fight for all that is just'] -rating (1 to 5 scale): 5 - -movie: '${nv('movie')}' -summary: ['${nv('summaries')}'] -rating (1 to 5 scale): ${nv('rating', { match: '[12345](\.\\d)?' })} -synopsis: '${nv('synopsis')}'`; - - const responses = await fillTemplate(fakeLLM, t.substs({ movie })); - assertNoErrorResponse(responses); - expect(responses[0].substs!.summaries).toEqual(` 80s cop drama with an amazing cast', 'stylish and suspenseful`); - expect(responses[0].substs!.rating).toEqual(`4`); - expect(responses[1].substs!.summaries).toEqual(` stylish and gritty gangster movie of the prohibition era', 'the classic good vs evil tale`); - expect(responses[1].substs!.rating).toEqual(`4.5`); - }); -}); - diff --git a/llm-recs/llm-recs-webclient/src/lib/text-templates/llm.ts b/llm-recs/llm-recs-webclient/src/lib/text-templates/llm.ts deleted file mode 100644 index 125686df..00000000 --- a/llm-recs/llm-recs-webclient/src/lib/text-templates/llm.ts +++ /dev/null @@ -1,96 +0,0 @@ -/*============================================================================== - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an Apache2 license that can be - * found in the LICENSE file and http://www.apache.org/licenses/LICENSE-2.0 -==============================================================================*/ - -/* -An class to wrap, and provide a common interface for LLM behaviour. -*/ - -import { ErrorResponse, isErrorResponse } from "../simple-errors/simple-errors"; -import { Template, matchTemplate } from "./template"; - -export interface PredictResponse { - completions: string[]; -} - -export interface ScoreRequest { - query: string; - completions: string[]; -} -export interface ScoredCompletion { - query: string; - completion: string; - score: number; -} -export interface ScoreResponse { - scoredCompletions: ScoredCompletion[]; -} - -export abstract class LLM { - public abstract name: string; - - abstract predict(prompt: string, params?: Params): Promise; - // abstract score(request: ScoreRequest): Promise; -} - -// A Fake LLM that uses a lookup table of queries to give responses. -// It is deterministic, and if the query is not present, it returns no -// completions. -// -// TODO: maybe good to provide a version that takes the same query and gives difference responses each time, e.g. using a random seed at constructor time. -export class LookupTableFakeLLM implements LLM<{}> { - public name: string = 'fake: in memory lookup table'; - - constructor(public table: { [query: string]: ScoreResponse }) { } - - async predict(query: string): Promise { - const scoreResponse = this.table[query] - if (scoreResponse) { - const predictResponse: PredictResponse = { - completions: scoreResponse.scoredCompletions.map(c => c.completion) - }; - return predictResponse; - } - throw new Error(`No matching entry for query: ${query}`); - // return { queryCompletions: [] } - } - async score(request: ScoreRequest): Promise { - const scoreResponse: ScoreResponse = this.table[request.query] - if (scoreResponse) { - return scoreResponse; - } - return { scoredCompletions: [] } - } -} - -export interface InterpretedResponse { - substs?: { [Key in Ns]: string }, responseStr: string -}; - -export async function fillTemplate( - llm: LLM<{}>, template: Template -): Promise[] | ErrorResponse> { - const interpretedResponses = [] as InterpretedResponse[]; - // const substsResponses: ({ [Key in Ns]: string } | null)[] = []; - const parts = template.parts(); - const responses = await llm.predict(parts.prefix); - if (isErrorResponse(responses)) { - return responses; - } - // console.log('parts.prefix: ', parts.prefix); - for (const completion of responses.completions) { - // console.log('parts', parts); - // console.log('qcompletion.completion', completion); - const match = matchTemplate(parts, completion, false); - const interpretedResponse = { responseStr: completion } as InterpretedResponse; - if (match) { - interpretedResponse.substs = match.substs; - } - interpretedResponses.push(interpretedResponse) - } - return interpretedResponses; -} diff --git a/llm-recs/llm-recs-webclient/src/lib/text-templates/llm_api.ts b/llm-recs/llm-recs-webclient/src/lib/text-templates/llm_api.ts deleted file mode 100644 index 90d19bff..00000000 --- a/llm-recs/llm-recs-webclient/src/lib/text-templates/llm_api.ts +++ /dev/null @@ -1,80 +0,0 @@ -/*============================================================================== - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an Apache2 license that can be - * found in the LICENSE file and http://www.apache.org/licenses/LICENSE-2.0 -==============================================================================*/ - -/* -An class to wrap, and provide a common interface for LLM behaviour. -*/ -import { LLM, PredictResponse } from "./llm"; -import { ErrorResponse } from "../simple-errors/simple-errors"; - -export interface LlmOptions { - modelId?: string; // e.g. text-bison - candidateCount?: number, // e.g. 1 to 8 = number of completions - maxOutputTokens?: number, // e.g. 256, 1024 - stopSequences?: string[], // e.g. '] - temperature?: number, // e.g. 0.8 (0=deterministic, 0.7-0.9=normal, x>1=wild) - topP?: number, // e.g. 0.8 (0-1, smaller = restricts crazyiness) - topK?: number // e.g. 40 (0-numOfTokens, smaller = restricts crazyiness) -} - -export interface LlmRequest { - text: string - params?: LlmOptions -} - -async function sendLlmRequest(request: LlmRequest): Promise { - // Default options are marked with * - const response = await fetch(`/api/llm`, { - method: 'POST', // *GET, POST, PUT, DELETE, etc. - mode: 'cors', // no-cors, *cors, same-origin - cache: 'no-cache', // *default, no-cache, reload, force-cache, only-if-cached - credentials: 'same-origin', // include, *same-origin, omit - headers: { - 'Content-Type': 'application/json', - }, - redirect: 'follow', // manual, *follow, error - referrerPolicy: 'no-referrer', // no-referrer, *no-referrer-when-downgrade, origin, origin-when-cross-origin, same-origin, strict-origin, strict-origin-when-cross-origin, unsafe-url - body: JSON.stringify(request), // body data type must match "Content-Type" header - }); - console.log(response); - if (response.status !== 200) { - return { - error: `${response.status}: response.statusText` - }; - } - let prediction: PredictResponse; - try { - prediction = (await response.json() as PredictResponse) - } catch (err) { - console.error('invalid json in response.body: ', response.body); - return { - error: `response is not valid JSON.` - }; - } - return prediction; // parses JSON response into native JavaScript objects -} - -export class SimpleLlm implements LLM { - public name: string; - public defaultOptions: LlmOptions = {}; - - constructor(initialOptions?: LlmOptions) { - this.name = `SimpleLlm` - if (initialOptions) { - this.defaultOptions = initialOptions; - } - } - async predict(text: string, params?: LlmOptions): Promise { - const usedParams = { ...this.defaultOptions }; - if (params) { - Object.assign(usedParams, params); - } - const apiResponse = await sendLlmRequest({ text, params: usedParams }); - return apiResponse - } -} diff --git a/llm-recs/llm-recs-webclient/src/lib/text-templates/llm_devapi_palm2.ts b/llm-recs/llm-recs-webclient/src/lib/text-templates/llm_devapi_palm2.ts deleted file mode 100644 index 80eed7ea..00000000 --- a/llm-recs/llm-recs-webclient/src/lib/text-templates/llm_devapi_palm2.ts +++ /dev/null @@ -1,92 +0,0 @@ -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an Apache2 license that can be - * found in the LICENSE file and http://www.apache.org/licenses/LICENSE-2.0 -==============================================================================*/ - -/* -// TODO: make more like VertexAI setup -Google Generative AI Developer API -(same models as VertexAPI but different API) -*/ - -export type HarmName = - | 'HARM_CATEGORY_DEROGATORY' - | 'HARM_CATEGORY_TOXICITY' - | 'HARM_CATEGORY_VIOLENCE' - | 'HARM_CATEGORY_SEXUAL' - | 'HARM_CATEGORY_MEDICAL' - | 'HARM_CATEGORY_DANGEROUS'; -interface HarmFilterSetting { - category: HarmName; - threshold: 1 | 2 | 3 | 4 | 5; -} - -export interface Palm2ApiRequest { - prompt: { text: string }; - temperature: number; - top_k: number; - top_p: number; - candidate_count: number; - max_output_tokens: number; - stop_sequences: string[]; - safety_settings: HarmFilterSetting[]; -} -export type Palm2RequestOptions = Omit, 'prompt'>; - -export interface Palm2Response { } - -export function preparePalm2Request(text: string, options?: Palm2RequestOptions): Palm2ApiRequest { - return { - prompt: { text }, - temperature: (options && options.temperature) || 0.7, - top_k: (options && options.top_k) || 40, - top_p: (options && options.top_p) || 0.95, - candidate_count: (options && options.candidate_count) || 4, - max_output_tokens: (options && options.max_output_tokens) || 256, - stop_sequences: (options && options.stop_sequences) || [], - safety_settings: (options && options.safety_settings) || [ - { category: 'HARM_CATEGORY_DEROGATORY', threshold: 1 }, - { category: 'HARM_CATEGORY_TOXICITY', threshold: 1 }, - { category: 'HARM_CATEGORY_VIOLENCE', threshold: 1 }, - { category: 'HARM_CATEGORY_SEXUAL', threshold: 1 }, - { category: 'HARM_CATEGORY_MEDICAL', threshold: 1 }, - { category: 'HARM_CATEGORY_DANGEROUS', threshold: 1 }, - ], - }; -} - -async function postDataToLLM(url = '', data: Palm2ApiRequest) { - // Default options are marked with * - const response = await fetch(url, { - method: 'POST', // *GET, POST, PUT, DELETE, etc. - mode: 'cors', // no-cors, *cors, same-origin - cache: 'no-cache', // *default, no-cache, reload, force-cache, only-if-cached - credentials: 'same-origin', // include, *same-origin, omit - headers: { - 'Content-Type': 'application/json', - // 'Content-Type': 'application/x-www-form-urlencoded', - }, - redirect: 'follow', // manual, *follow, error - referrerPolicy: 'no-referrer', // no-referrer, *no-referrer-when-downgrade, origin, origin-when-cross-origin, same-origin, strict-origin, strict-origin-when-cross-origin, unsafe-url - body: JSON.stringify(data), // body data type must match "Content-Type" header - }); - return response.json(); // parses JSON response into native JavaScript objects -} - -export async function sendPalm2Request( - apiKey: string, // e.g. as copied from UI in makerSuite.google.com - req: Palm2ApiRequest, - modelId = 'text-bison-001', // e.g. 'models/text-bison-001'; -): Promise { - return postDataToLLM( - `https://generativelanguage.googleapis.com/v1beta2/models/${modelId}:generateText?key=${apiKey}`, - req - ); - // .then((data) => { - // console.log(data); // JSON data parsed by `data.json()` call - // }) - // .catch((err) => console.error(err)); -} diff --git a/llm-recs/llm-recs-webclient/src/lib/text-templates/llm_vertexapi_palm2.ts b/llm-recs/llm-recs-webclient/src/lib/text-templates/llm_vertexapi_palm2.ts deleted file mode 100644 index fddaf1ff..00000000 --- a/llm-recs/llm-recs-webclient/src/lib/text-templates/llm_vertexapi_palm2.ts +++ /dev/null @@ -1,193 +0,0 @@ -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an Apache2 license that can be - * found in the LICENSE file and http://www.apache.org/licenses/LICENSE-2.0 -==============================================================================*/ - -/* -Google Cloud Vertex Palm2 API -See: https://cloud.google.com/vertex-ai/docs/generative-ai/model-reference/text -(same models as Google Generative AI Developer API but different API) -*/ - -import { LLM, PredictResponse } from "./llm"; - -export interface Palm2ApiParams { - candidateCount?: number, // 1 to 8 - maxOutputTokens?: number, // 256, 1024 - stopSequences?: string[], // e.g. '] - temperature?: number, // e.g. 0.2 (0=deterministic, 1=wild, x>1=crazy) - topP?: number, // e.g. 0.8 (0-1, smaller = restricts crazyiness) - topK?: number // e.g. 40 (0-numOfTokens, smaller = restricts crazyiness) -} - -// The underlying Google Cloud Vertex AI LLM API -export interface Palm2ApiRequest { - instances: { content: string }[] - parameters: Palm2ApiParams -} -export type Palm2RequestOptions = Omit, 'prompt'>; - -export interface Palm2Response { - predictions: - { - content: string, - citationMetadata: { - citations: {}[] - }, - safetyAttributes: { - blocked: boolean, categories: {}[], scores: {}[] - } - }[], - metadata: { - tokenMetadata: { - outputTokenCount: { - totalBillableCharacters: number, - totalTokens: number - }, - inputTokenCount: { - totalBillableCharacters: number, - totalTokens: number - }, - } - } -} - -export function preparePalm2Request( - text: string, options?: Palm2ApiParams -): Palm2ApiRequest { - return { - instances: [{ content: text }], - parameters: { - temperature: (options && options.temperature) || 0.7, - topK: (options && options.topK) || 40, - topP: (options && options.topP) || 0.95, - candidateCount: (options && options.candidateCount) || 4, - maxOutputTokens: (options && options.maxOutputTokens) || 256, - stopSequences: (options && options.stopSequences) || [], - } - }; -} - -async function postDataToLLM(url = '', accessToken: string, data: Palm2ApiRequest) { - // Default options are marked with * - const response = await fetch(url, { - method: 'POST', // *GET, POST, PUT, DELETE, etc. - mode: 'cors', // no-cors, *cors, same-origin - cache: 'no-cache', // *default, no-cache, reload, force-cache, only-if-cached - credentials: 'same-origin', // include, *same-origin, omit - headers: { - 'Content-Type': 'application/json', - 'Authorization': `Bearer ${accessToken}`, - // 'Content-Type': 'application/x-www-form-urlencoded', - }, - redirect: 'follow', // manual, *follow, error - referrerPolicy: 'no-referrer', // no-referrer, *no-referrer-when-downgrade, origin, origin-when-cross-origin, same-origin, strict-origin, strict-origin-when-cross-origin, unsafe-url - body: JSON.stringify(data), // body data type must match "Content-Type" header - }); - return response.json(); // parses JSON response into native JavaScript objects -} - -export async function sendPalm2Request( - projectId: string, - accessToken: string, - req: Palm2ApiRequest, - modelId = 'text-bison', // e.g. text-bison for latest text-bison model - apiEndpoint = 'us-central1-aiplatform.googleapis.com', -): Promise { - return postDataToLLM( - // TODO: it may be that the url part 'us-central1' has to match - // apiEndpoint. - `https://${apiEndpoint}/v1/projects/${projectId}/locations/us-central1/publishers/google/models/${modelId}:predict`, - accessToken, - req - ); - // .then((data) => { - // console.log(data); // JSON data parsed by `data.json()` call - // }) - // .catch((err) => console.error(err)); -} - -export interface Palm2ApiOptions { - modelId: string, - apiEndpoint: string, - requestParameters: Palm2ApiParams -} - -export class VertexPalm2LLM implements LLM { - public name: string; - public defaultOptions: Palm2ApiOptions = { - modelId: 'text-bison', - apiEndpoint: 'us-central1-aiplatform.googleapis.com', - requestParameters: { - temperature: 0.7, - topK: 40, - topP: 0.95, - candidateCount: 4, - maxOutputTokens: 256, - stopSequences: [], - } - }; - - constructor( - public projectId: string, - public accessToken: string, - ) { - this.name = `VertexLLM:` + this.defaultOptions.modelId; - } - - // - async predict( - query: string, params?: Palm2ApiOptions - ): Promise { - - const apiParams = params ? params.requestParameters - : this.defaultOptions.requestParameters; - const apiRequest: Palm2ApiRequest = { - instances: [{ content: query }], - parameters: apiParams - } - - const apiResponse = await sendPalm2Request( - this.projectId, - this.accessToken, - apiRequest, - this.defaultOptions.modelId, - this.defaultOptions.apiEndpoint); - - // HACKING around an API bug. :( - // - // The API doesn't include the actual stop sequence that it found, so we - // can never know the true stop seqeunce, so we just pick the first one, - // and image it is that. - // - // A bug has been filed. - let imaginedPostfixStopSeq = ''; - if (apiParams.stopSequences && apiParams.stopSequences.length > 0) { - imaginedPostfixStopSeq = apiParams.stopSequences[0]; - } - - if (!apiResponse.predictions) { - throw new Error(`No predictions resturned in api response:` + - ` ${JSON.stringify(apiResponse, null, 2)}`); - } - - // TODO: skip this and simplify? - const scoredCompletions = apiResponse.predictions.map(p => { - return { - query: query, - completion: p.content + imaginedPostfixStopSeq, - score: 1, // TODO: API doesn't provide this, so we fake it as always 1. - } - }); - - return { completions: scoredCompletions.map(c => c.completion) } - } - - // TODO: The cloud API doesn't currently support scoring. - // async score(request: ScoreRequest): Promise { - // } - -} diff --git a/llm-recs/llm-recs-webclient/src/lib/text-templates/scripts/run_test_devapi_palm2.ts b/llm-recs/llm-recs-webclient/src/lib/text-templates/scripts/run_test_devapi_palm2.ts deleted file mode 100644 index 341e5d0c..00000000 --- a/llm-recs/llm-recs-webclient/src/lib/text-templates/scripts/run_test_devapi_palm2.ts +++ /dev/null @@ -1,69 +0,0 @@ -/*============================================================================== - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an Apache2 license that can be - * found in the LICENSE file and http://www.apache.org/licenses/LICENSE-2.0 -==============================================================================*/ - -/* Test call makersuite.google.com developer API for Palm2 LLM. - -Usage: - -PALM2_GENAI_API_KEY="copy the api key from makersuite.google.com/app/apikey" -npx ts-node --esm ./run_test_devapi_palm2.ts \ - --apiKey=${PALM2_GENAI_API_KEY} - -Where PALM2_GENAI_API_KEY envionment variable should be set before running, -e.g. copy/pasted from MakerSuite UI API Key section at -https://makersuite.google.com/app/apikey - -Note: this will only work from IP addresses in supported countries. - -*/ -import { sendPalm2Request, preparePalm2Request } from '../llm_devapi_palm2'; - -import * as yargs from 'yargs'; - -interface Params { - apiKey: string; -} - -async function run(args: Params): Promise { - - const prompt = ` -The following are short movie summaries. They are specific, not generic (no movie is just "a classic"), and they don't contain plot synopsis. They just describe my experience of the movie. - -movie: 'Fifth Element' -summary: ['a joyous sci fi that emerses you in a colourful universe', 'quirky upbeat action'] - -movie: 'Seven Samurai' -summary: ['a black and white masterpiece of cinematography', 'a slow, atmospheric, symbolic fight for all that is just'] - -movie: 'The Godfather' -summary: [' -`; - - const request = preparePalm2Request(prompt); - request.stop_sequences.push(`']`); - const response = await sendPalm2Request(args.apiKey, request); - console.log(JSON.stringify(response)); -} - -// ---------------------------------------------------------------------------- -const args = yargs - .option('apiKey', { - describe: 'The API Key from MakerSuite UI. See: ' - + 'https://makersuite.google.com/app/apikey', - demandOption: true, - type: 'string', - }).help().argv; - -run(args as Params) - .then(() => { - console.log('Success!'); - }) - .catch(e => { - console.error('Failed: ', e); - throw Error('Failed'); - }); diff --git a/llm-recs/llm-recs-webclient/src/lib/text-templates/scripts/run_vertexapi_palm2_predict.ts b/llm-recs/llm-recs-webclient/src/lib/text-templates/scripts/run_vertexapi_palm2_predict.ts deleted file mode 100644 index 2bff7059..00000000 --- a/llm-recs/llm-recs-webclient/src/lib/text-templates/scripts/run_vertexapi_palm2_predict.ts +++ /dev/null @@ -1,118 +0,0 @@ -/*============================================================================== - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an Apache2 license that can be - * found in the LICENSE file and http://www.apache.org/licenses/LICENSE-2.0 -==============================================================================*/ - -/* Test call to The Google-Cloud-Vertex-AI-API Palm2 LLM. - -Assumes: node is installed (you have the npx command). -See https://github.com/nvm-sh/nvm - -Usage: - -npx ts-node --esm ./run_vertexapi_palm2_predict.ts \ - --project=$(gcloud config get-value project) \ - --accessToken=$(gcloud auth print-access-token) \ - --movie="The Untouchables" - -Assumes that you have run: - gcloud config set project ${YOUR_GOOGLE_CLOUD_PROJECT_ID} -*/ -import { VertexPalm2LLM } from '../llm_vertexapi_palm2'; -import { FewShotTemplate } from '../fewshot_template'; - -import * as yargs from 'yargs'; -import { nv, template } from '../template'; -import { fillTemplate } from '../llm'; - -interface Params { - accessToken: string, - project: string, - movie: string, -} - -function prettyMovieRec(index: number, movie: string, summaries: string): string { - const outputFormat = template` ----- ${nv('index')} ---- -I think you'll find the movie ${nv('movie')}: - -${nv('bullets')} - -Do you like my summary?`; - const splitSummaries = summaries.split(`', '`).map( - summaryPoint => { return { summaryPoint } }) - const outputBullets = new FewShotTemplate( - template`* ${nv('summaryPoint')}`, '\n\n'); - const bullets = outputBullets.apply(splitSummaries).stringify(); - // Notice the nice type error is I try and and stringify, but forgot to - // fill in the template... - // Type 'Error_CannotStringifyTemplateWithVars<"index">' is not assignable - // to type 'string'. - // return outputFormat.substs({ movie, bullets }).stringify(); - return outputFormat.substs({ movie, bullets, index: `${index}` }).stringify(); -} - - -async function run(args: Params): Promise { - // Notice the few-shot prompt doesn't always have a synopsis or rating, but - // we want to always generate them. - const t = template` -The following are short movie summaries. They are specific, not generic (no movie is just "a classic"), and they don't contain plot synopsis. They just describe the experience of watching the movie. It tries to tell you the essence of the movie. - -movie: 'Fifth Element' -summary: ['joyous sci fi that emerses you in a colourful universe', 'quirky upbeat action'] -synopsis: 'The 23rd century, a New York City cabbie, Korben Dallas (Bruce Willis), finds the fate of the world in his hands when Leeloo (Milla Jovovich) falls into his cab. As the embodiment of the fifth element, Leeloo needs to combine with the other four to keep the approaching Great Evil from destroying the world.' - -movie: 'Seven Samurai' -summary: ['black and white masterpiece of cinematography', 'a slow, atmospheric, symbolic fight for all that is just'] -rating (1 to 5 scale): 5 - -movie: '${nv('movie')}' -summary: ['${nv('summaries')}'] -rating (1 to 5 scale): ${nv('rating', { match: '[12345](.\\d)?' })} -synopsis: '${nv('synopsis')}'`; - - const llm = new VertexPalm2LLM( - args.project, - args.accessToken, - ); - const templateToFill = t.substs({ movie: args.movie }); - const responses = await fillTemplate(llm, templateToFill); - const badlyFormedResponsesCount = responses.filter(r => !r.substs).length; - console.log(`badlyFormedResponses count: ${badlyFormedResponsesCount}`); - console.log(`responses: ${JSON.stringify(responses, null, 2)} `); - - responses.filter(r => r.substs).forEach( - (r, i) => console.log(prettyMovieRec(i, args.movie, r.substs!.summaries)) - ); -} - -// ---------------------------------------------------------------------------- -const args = yargs - .option('accessToken', { - describe: 'Google Cloud Auth Token ' + - 'e.g. echo $(gcloud auth print-access-token)', - demandOption: true, - type: 'string', - }).option('project', { - describe: 'The Google Cloud Project to use (it must have the VertexAI ' + - 'API enabled).', - demandOption: true, - type: 'string', - }).option('movie', { - describe: 'The name of a movie to get a review of', - demandOption: true, - type: 'string', - }).help().argv; - -run(args as Params) - .then(() => { - console.log('Success!'); - }) - .catch(e => { - console.error('Failed: ', e); - throw Error('Failed'); - }); diff --git a/llm-recs/llm-recs-webclient/src/lib/text-templates/scripts/run_vertexapi_palm2_predict_rec_test.ts b/llm-recs/llm-recs-webclient/src/lib/text-templates/scripts/run_vertexapi_palm2_predict_rec_test.ts deleted file mode 100644 index 83bad048..00000000 --- a/llm-recs/llm-recs-webclient/src/lib/text-templates/scripts/run_vertexapi_palm2_predict_rec_test.ts +++ /dev/null @@ -1,85 +0,0 @@ -/*============================================================================== - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an Apache2 license that can be - * found in the LICENSE file and http://www.apache.org/licenses/LICENSE-2.0 -==============================================================================*/ - -/* Test call to The Google-Cloud-Vertex-AI-API Palm2 LLM. - -Assumes: node is installed (you have the npx command). -See https://github.com/nvm-sh/nvm - -Usage: - -npx ts-node --esm ./run_vertexapi_palm2_predict_rec_test.ts \ - --project=$(gcloud config get-value project) \ - --accessToken=$(gcloud auth print-access-token) \ - --experience="The Garden of Forking Paths: like it" - -Assumes that you have run: - gcloud config set project ${YOUR_GOOGLE_CLOUD_PROJECT_ID} -*/ -import { VertexPalm2LLM } from '../llm_vertexapi_palm2'; -import { FewShotTemplate } from '../fewshot_template'; -import { expInterpTempl } from '../../recommender-prompts/item-interpreter'; - - -import * as yargs from 'yargs'; -import { nv, template } from '../template'; -import { fillTemplate } from '../llm'; - -interface Params { - accessToken: string, - project: string, - experience: string, -} - - - - -async function run(args: Params): Promise { - - const llm = new VertexPalm2LLM( - args.project, - args.accessToken, - ); - const templateToFill = expInterpTempl.substs({ experience: args.experience }); - console.log('template: \n\n', templateToFill.escaped); - console.log('\n\n'); - const responses = await fillTemplate(llm, templateToFill); - const badlyFormedResponsesCount = responses.filter(r => !r.substs).length; - console.log(`badlyFormedResponses count: ${badlyFormedResponsesCount}`); - console.log(`responses: ${JSON.stringify(responses, null, 2)} `); - - responses.filter(r => r.substs).forEach( - (r, i) => console.log(i, JSON.stringify(r.substs, null, 2))); -} - -// ---------------------------------------------------------------------------- -const args = yargs - .option('accessToken', { - describe: 'Google Cloud Auth Token ' + - 'e.g. echo $(gcloud auth print-access-token)', - demandOption: true, - type: 'string', - }).option('project', { - describe: 'The Google Cloud Project to use (it must have the VertexAI ' + - 'API enabled).', - demandOption: true, - type: 'string', - }).option('experience', { - describe: 'Short text of an experience.', - demandOption: true, - type: 'string', - }).help().argv; - -run(args as Params) - .then(() => { - console.log('Success!'); - }) - .catch(e => { - console.error('Failed: ', e); - throw Error('Failed'); - }); diff --git a/llm-recs/llm-recs-webclient/src/lib/text-templates/scripts/run_vertexapi_palm2_rawSend.ts b/llm-recs/llm-recs-webclient/src/lib/text-templates/scripts/run_vertexapi_palm2_rawSend.ts deleted file mode 100644 index 1e34ef38..00000000 --- a/llm-recs/llm-recs-webclient/src/lib/text-templates/scripts/run_vertexapi_palm2_rawSend.ts +++ /dev/null @@ -1,70 +0,0 @@ -/*============================================================================== - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an Apache2 license that can be - * found in the LICENSE file and http://www.apache.org/licenses/LICENSE-2.0 -==============================================================================*/ - -/* Test call to The Google-Cloud-Vertex-AI-API Palm2 LLM. - -Usage: - -npx ts-node --esm ./run_vertexapi_palm2_rawSend.ts \ - --project=$(gcloud config get-value project) \ - --accessToken=$(gcloud auth print-access-token) -*/ -import { sendPalm2Request, preparePalm2Request } from '../llm_vertexapi_palm2'; - -import * as yargs from 'yargs'; - -interface Params { - accessToken: string, - project: string, -} - -async function run(args: Params): Promise { - - const prompt = ` -The following are short movie summaries. They are specific, not generic (no movie is just "a classic"), and they don't contain plot synopsis. They just describe the experience of watching the movie. It tries to tell you the essence of the movie. - -movie: 'Fifth Element' -summary: ['joyous sci fi that emerses you in a colourful universe', 'quirky upbeat action'] - -movie: 'Seven Samurai' -summary: ['black and white masterpiece of cinematography', 'a slow, atmospheric, symbolic fight for all that is just'] - -movie: 'The Godfather' -summary: [' -`; - - const request = preparePalm2Request(prompt); - request.parameters.stopSequences = []; - request.parameters.stopSequences.push(`']`); - const response = await sendPalm2Request( - args.project, args.accessToken, request); - console.log(JSON.stringify(response)); -} - -// ---------------------------------------------------------------------------- -const args = yargs - .option('accessToken', { - describe: 'Google Cloud Auth Token ' + - 'e.g. echo $(gcloud auth print-access-token)', - demandOption: true, - type: 'string', - }).option('project', { - describe: 'The Google Cloud Project to use (it must have the VertexAI ' + - 'API enabled).', - demandOption: true, - type: 'string', - }).help().argv; - -run(args as Params) - .then(() => { - console.log('Success!'); - }) - .catch(e => { - console.error('Failed: ', e); - throw Error('Failed'); - }); diff --git a/llm-recs/llm-recs-webclient/src/lib/text-templates/scripts/tsconfig.json b/llm-recs/llm-recs-webclient/src/lib/text-templates/scripts/tsconfig.json deleted file mode 100644 index 9c944856..00000000 --- a/llm-recs/llm-recs-webclient/src/lib/text-templates/scripts/tsconfig.json +++ /dev/null @@ -1,24 +0,0 @@ -/* To learn more about this file see: https://angular.io/config/tsconfig. */ -{ - // See: https://github.com/tsconfig/bases - "extends": "@tsconfig/node18/tsconfig.json", - - // Most ts-node options can be specified here using their programmatic names. - "ts-node": { - // It is faster to skip typechecking. - // Remove if you want ts-node to do typechecking. - "transpileOnly": true, - - "files": true, - - "compilerOptions": { - // compilerOptions specified here will override those declared below, - // but *only* in ts-node. Useful if you want ts-node and tsc to use - // different options with a single tsconfig.json. - "esModuleInterop": true - } - }, - "compilerOptions": { - // typescript options here - } -} diff --git a/llm-recs/llm-recs-webclient/src/lib/text-templates/template.spec.ts b/llm-recs/llm-recs-webclient/src/lib/text-templates/template.spec.ts deleted file mode 100644 index 56d50f2e..00000000 --- a/llm-recs/llm-recs-webclient/src/lib/text-templates/template.spec.ts +++ /dev/null @@ -1,291 +0,0 @@ -/*============================================================================== - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an Apache2 license that can be - * found in the LICENSE file and http://www.apache.org/licenses/LICENSE-2.0 -==============================================================================*/ - -import { Template, escapeStr, template, nv, unEscapeStr, matchTemplate } from './template'; - -describe('template', () => { - beforeEach(() => { - }); - - it('A mini walkthrough of why this is neat...', () => { - // You can make temnplates quite naturally: you can define your variables, - // and then just use them in a simple interpreted string. - const thingVar = nv('thing'); - const thing2Var = nv('thing2') - const whatIsAtoB = template`what is a ${thingVar} to ${thing2Var}?`; - - // You could also of course just inline define them... - template`what is a ${nv('thing')} to ${nv('thing2')}?`; - - // Arguments can be auto-completed by IDE. e.g. the first you can reference - // the variables form the 'vars' paramter of a template. e.g. this lets you - // do string substituion in the template `whatIsAtoB` as follows where the - // subparams of vars are 'thing' or 'thing2'; those are the only variables - // in the template, and are auto-completed, and anything else is an 'as you - // type' type error. - let whatIsTabletoB = whatIsAtoB.vars.thing.substStr('table'); - expect(whatIsTabletoB.escaped).toEqual( - 'what is a table to {{thing2}}?'); - - // You can also reference the var names directly using a template's - // substution call, like so (and get editor auto-completion): - whatIsTabletoB.substStr('thing2', 'chair'); - - // And errors are checked as you type, e.g. - // - // whatIsTabletoB.substStr('thing', 'chair'); - // ^^^^^^^ - // Error: Argument of type '"thing"' is not assignable to parameter of - // type '"thing2"' - - // Or you can use the map substitution and even do multiple substitutions at - // once. - whatIsAtoB.substs({ thing: 'table', thing2: 'chair' }); - - // Variables can be progamatrically renamed in templates. - const whatIsAtoTarget = - whatIsAtoB.vars.thing2.renameVar('target'); - // Note: the nice automatic type inference: - // whatIsAtoTarget: Template<'thing', 'target'> - expect(Object.keys(whatIsAtoTarget.vars).sort()).toEqual( - ['thing', 'target'].sort()); - expect(whatIsAtoTarget.escaped).toEqual( - 'what is a {{thing}} to {{target}}?'); - - // Variables can also be merged progamatrically too. - const whatIsThingtoItself = - whatIsAtoB.mergeVars(['thing', 'thing2'], 'thing'); - // Note: the nice automatic type inference: - // whatIsThingtoItself: Template<'thing'> - // - // We can verify that we merged 'thing', 'thing2' into 'thing' - expect(Object.keys(whatIsThingtoItself.vars).sort()).toEqual( - ['thing'].sort()); - - // And we can verify the underlying escaped string value of the template - // like so: - expect(whatIsThingtoItself.escaped).toEqual( - 'what is a {{thing}} to {{thing}}?'); - - // You can also substitute variables for templates. New extra variables are - // corrected added in the newly created template. (whatIsTabletoBigB has the - // variable 'bigThing' and only that one) - const bigThingVar = nv('bigThing'); - const big = template`big ${bigThingVar}`; - const whatIsTabletoBigB = - whatIsTabletoB.vars.thing2.substTempl(big); - - // When you make new templates, you can also just use other templates as - // part of them... - const fooAndBig = template`foo ${whatIsTabletoBigB}`; - expect(fooAndBig.escaped).toEqual( - 'foo what is a table to big {{bigThing}}?'); - - // Also, variables are properies, so you can do things like check if they - // occur in other escaped string templates too. - expect(fooAndBig.vars.bigThing.occurs(big.escaped)) - .toBeTruthy(); - }); - - it('Replacing a var with a string', () => { - const thingVar = nv('thing'); - const p = new Template(`what is a ${thingVar}?`, - [thingVar]); - - expect(p.varList()[0]).toBe(thingVar); - - const p2 = p.vars.thing.substStr('bar'); - - expect(p2.varList().length).toBe(0); - expect(p2.escaped).toEqual('what is a bar?'); - }); - - it('Replacing a var with a template', () => { - const thingVar = nv('thing'); - const p = new Template(`what is a ${thingVar}?`, - [thingVar]); - - const bigVar = nv('bigThingName') - const p2 = new Template(`big ${bigVar}`, [bigVar]); - - const p3 = p.vars.thing.substTempl(p2); - - expect(p3.escaped).toEqual(`what is a big {{bigThingName}}?`); - expect(p3.vars.bigThingName.name).toEqual(`bigThingName`); - }); - - it('make a template with vars', () => { - const thingVar = nv('thing'); - const thing2Var = nv('thing2') - const p = template`what is a ${thingVar} to ${thing2Var}?`; - - const bigThingVar = nv('bigThing') - const p2 = template`big ${bigThingVar}`; - - const p3 = p.vars.thing.substTempl(p2); - - expect(p3.escaped).toEqual(`what is a big {{bigThing}} to {{thing2}}?`); - expect(p3.vars.bigThing.name).toEqual(`bigThing`); - }); - - it('templates substition by the variable parameter', () => { - const thingVar = nv('thing'); - const thing2Var = nv('thing2') - const p = template`what is a ${thingVar} to ${thing2Var}?`; - - // Cool thing about this: for the first argument, the variable, is - // auto-completed, and errors are checked as you type. - // e.g. first argument is auto-completed to 'thing' or 'thing2'. - const p2 = p.vars.thing.substStr('table'); - }); - - it('escaping', () => { - const s = 'blah \\\\ {{foo}}'; - expect(escapeStr(s)).toEqual('blah \\\\\\\\ \\{\\{foo}}'); - }); - - it('unescaping', () => { - const s = 'blah \\\\ \\{\\{foo}}'; - expect(unEscapeStr(s)).toEqual('blah \\ {{foo}}'); - }); - - it('parts', () => { - const t = template`what is an ${nv('x')} to a ${nv('y')} anyway?`; - const parts = t.parts(); - expect(parts.prefix).toEqual('what is an '); - expect(parts.variables.map(x => x.postfix)).toEqual([' to a ', ' anyway?']); - expect(parts.variables.map(x => x.variable.name)).toEqual(['x', 'y']); - }); - - it('parts template matching', () => { - const t = template`what is an ${nv('x')} to a ${nv('y')} anyway?`; - const parts = t.parts(); - - const s1 = 'what is an bug to a fly anyway?'; - const m1 = matchTemplate(parts, s1); - expect(m1.substs).toEqual({ x: 'bug', y: 'fly' }); - expect(m1.curPart).toEqual(undefined); - - const s2 = 'what is an bug to a pants!'; - const m2 = matchTemplate(parts, s2); - expect(m2.substs).toEqual({ x: 'bug', y: 'pants!' }); - expect(m2.curPart!.variable.name).toEqual('y'); - expect(m2.finalStr).toEqual(''); - - const s3 = 'bonkers!' - const m3 = matchTemplate(parts, s3); - expect(m3.finalStr).toEqual(m3.str); - - const s4 = 'what is an bugfoo'; - const m4 = matchTemplate(parts, s4); - expect(m4.substs).toEqual({ x: 'bugfoo', y: '' }); - expect(m4.curPart?.variable.name).toEqual('y'); - expect(m4.finalStr).toEqual('') - }); - - it('parts template matching with match-string', () => { - const t = template`what is an ${nv('x', { match: '[12345]' })} to a ${nv('y')} anyway?`; - const parts = t.parts(); - - const s1 = 'what is an 3 to a fly anyway?'; - const m1 = matchTemplate(parts, s1); - expect(m1.substs).toEqual({ x: '3', y: 'fly' }); - - const s2 = 'what is an 2 to a pants!'; - const m2 = matchTemplate(parts, s2); - expect(m2.substs).toEqual({ x: '2', y: 'pants!' }); - - const s3 = 'bonkers!' - const m3 = matchTemplate(parts, s3); - expect(m3.finalStr).toEqual(m3.str); - - const s4 = 'what is an 4'; - const m4 = matchTemplate(parts, s4); - expect(m4.substs).toEqual({ x: '4', y: '' }); - - const s5 = 'what is an foo to a pants!'; - const m5 = matchTemplate(parts, s5); - expect(m5.curPart?.variable.name).toEqual('x'); - expect(m5.matchedPartsCount).toEqual(0); - - const s6 = 'what is an 2 and a 3?'; - const m6 = matchTemplate(parts, s6); - expect(m6.substs).toEqual({ x: '2', y: '' }); - }); - - it('parts template matching with longer match-string', () => { - const t = template`what is an ${nv('x', { match: '[12345]' })} to a ${nv('y')} anyway?`; - - const parts = t.parts(); - const s1 = 'what is an 3 to a fly anyway? and more'; - const m1 = matchTemplate(parts, s1); - expect(m1.substs).toEqual({ x: '3', y: 'fly' }); - expect(m1.finalStr).toEqual(' and more'); - }); - - // it('parts template matching with match-string', () => { - // const t = template`']\nrating: `; - - // const parts = - // ` 80s cop drama with an amazing cast', 'stylish and suspenseful'] - // rating (1 to 5 scale): 4` - - // const parts = t.parts(); - // const s1 = 'what is an 3 to a fly anyway?'; - // const m1 = matchTemplate(parts, s1); - // expect(m1).toEqual({ x: '3', y: 'fly' }); - - // const s2 = 'what is an 2 to a pants!'; - // const m2 = matchTemplate(parts, s2); - // expect(m2).toEqual({ x: '2', y: 'pants!' }); - - // const s3 = 'bonkers!' - // const m3 = matchTemplate(parts, s3); - // expect(m3).toEqual(null); - - // const s4 = 'what is an 4'; - // const m4 = matchTemplate(parts, s4); - // expect(m4).toEqual({ x: '4', y: '' }); - - // const s5 = 'what is an foo to a pants!'; - // const m5 = matchTemplate(parts, s5); - // expect(m5).toEqual(null); - - // const s6 = 'what is an 2 and a 3?'; - // const m6 = matchTemplate(parts, s6); - // expect(m6).toEqual({ x: '2', y: '' }); - // }); - - - - it('TypeScript BUG: ', () => { - const thingVar = nv('thing'); - const thing2Var = nv('thing2') - const p = template`what is a ${thingVar} to ${thing2Var}?`; - - const bigThingVar = nv('bigThing') - const p2 = template`big ${bigThingVar}`; - const p4 = template`foo ${bigThingVar}, bar ${thingVar}, and ${thing2Var}`; - - // BUG, the following line produces this error: - /* -Argument of type 'Template<"thing" | "person">' is not assignable to parameter of type 'Variable<"bigThing"> | Template<"bigThing">'. -Type 'Template<"thing" | "thing2">' is not assignable to type 'Template<"bigThing">'. -Types of property 'vars' are incompatible. - Property 'bigThing' is missing in type '{ thing: Variable<"thing">; person: Variable<"person">; }' but required in type '{ bigThing: Variable<"bigThing">; }'.ts(2345) - */ - // const p3 = template`foo ${p2}, bar ${p}`; - - // TODO: complete the test once the bug is fixed... - // expect(p3.template).toEqual( - // `foo what is {{thing}} to {{person}}, bar {{bigThing}}?`); - // expect(p3.vars.bigThing.name).toEqual(bigThingHole.name); - // expect(p3.vars.person.name).toEqual(personHole.name); - }); -}); - diff --git a/llm-recs/llm-recs-webclient/src/lib/text-templates/template.ts b/llm-recs/llm-recs-webclient/src/lib/text-templates/template.ts deleted file mode 100644 index dd090b31..00000000 --- a/llm-recs/llm-recs-webclient/src/lib/text-templates/template.ts +++ /dev/null @@ -1,488 +0,0 @@ -/*============================================================================== - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an Apache2 license that can be - * found in the LICENSE file and http://www.apache.org/licenses/LICENSE-2.0 -==============================================================================*/ - -/* -An implementation of string-templates in TypeScript. The approach is to create a -Template clas which has the template types (Template) parameterized by a set -of string literal types (S). Each string literal in S is the name of a variable -in the template. The number of instances of a variable in a template does not -change the type, but the names of variables do. - -Various nice compositional utilities are then provided, e.g. substitution, -string-interpretation with variables and even templates. - -To see how this can be used, see the test files (.spec.ts), and specifically the -fewshot_template.spec.ts for some neat applications. - -One quirk of this is that when a template has no variables (it's just a literal -string), its type is `Template`. - - -Other notes: - -TO CONSIDER: provide an "noIdent" utility for templates to be more readable in -code blocks (e.g. s/\n\s+/\n/g). Maybe something fancy to allow \n. to be used -for real indent, but the "." gets ignored. - -It is probably also quite reasonable to think of templates as a list-type of -strings where each string is a variable name. But then you need to do list -motifications in your types, which is not well supported by typescript. - -Even set operations are not that well supported. e.g. we can't check if a string -overlaps in two types and produce a type error when it happens. One challenge -with trying to do do this is that it would make type checking conditions -constrains need to be carried around. - -e.g. you might get types T s.t. A & B = 0 - -That might need much deeper thinking in TS. But I think it would also be quite -wonderful. See ... - -TODO: verify list manipulations are not well supported by TypeScript typing. - -TODO: see if there is a different base-type for empty vars that can be used. I -spent a while looking at this, and I think never is probably the only one that -can be used. - -TODO: Move to using lists, where order is defined by first occurance. This -allows parsing of outputs from an LLM to be well typed and know what variable -will come next. - -*/ - -import { RegExpVar, NamedVar, SPLIT_REGEXP, RegExpVarOptions } from './variable'; - -// ---------------------------------------------------------------------------- -// Escaping -// ---------------------------------------------------------------------------- -// Simple escaping/unescaping when we have variables represented as: -// {{VarName}} -// escaping: blah \ {{ foo... ===> blah \\ \{\{ foo... -// unescaping: blah \\ \{\{ foo... ===> blah \ {{ foo... -export function escapeStr(s: string): string { - return s.replaceAll('\\', '\\\\').replaceAll('{', '\\{'); - // Can be done in a single pass... TODO: test sure faster... - // return s.replaceAll(/\\|\{/g, (m:string) => `\\${m}`); -} -export function unEscapeStr(s: string): string { - return s.replaceAll('\\\\', '\\').replaceAll('\\{', '{'); -} - -export function nv(name: N, options?: RegExpVarOptions) - : NamedVar { - return new RegExpVar(name, options); -} - -export interface Error_CannotStringifyTemplateWithVars { - _Error_CannotStringifyTemplateWithVars: T; -}; - -export type IfNeverElse = [T] extends [never] ? IfNeverT : ElseT; - -export interface TemplatePart { - variable: NamedVar, - postfix: string -}; - -export interface TemplateParts { - prefix: string; - variables: TemplatePart[] -}; - -// Escape a string so that it can be matched literally in a regexp expression. -// "$&" is the matched string. i.e. the character we need to escape. -export function escapeStringInMatch(s: string) { - return s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); -} -// $$ is the results in writing out $, so $$$$ ends up as "$$" in the final -// string. e.g. $ ==> $$ -export function escapeStringInReplacement(s: string) { - return s.replace(/\$/g, '$$$$'); -} - -export interface TemplateMatch { - // The template parts to be matched. - parts: TemplateParts, - // The substitutions for the variable-parts in the template. - substs: { [Key in Ns]: string } - // The string matched by this template. - str: string, - // This is not set when all variables in the template were fully matched, - // and the final post-fix was empty indicating that the final variable can't - // be further added to. Otherwise curPart is the final variable being matched, - // which may be added to further. - curPart?: TemplatePart, - matchedPartsCount: number, - // this is '' when the full string `str` was matched. - finalStr: string, -} - -// type TemplateMatch = -// PartialMatch | FullMatch | NoMatch; - - -// ---------------------------------------------------------------------------- -// Given a string, match the string against the template parts filling in the -// variables, returning the variable substitutions. -export function matchTemplate( - parts: TemplateParts, - strToMatch: string, - matchPrefix = true, -): TemplateMatch { - const match: TemplateMatch = { - parts, - str: strToMatch, - substs: {} as { [Key in Ns]: string }, - matchedPartsCount: 0, - finalStr: strToMatch, - } - parts.variables.forEach(v => match.substs[v.variable.name] = ''); - // const substs = {} as { [Key in Ns]: string }; - - if (matchPrefix) { - const prefixMatch = match.finalStr.match(`^${escapeStringInMatch(parts.prefix)}`); - if (prefixMatch) { - match.finalStr = match.finalStr.slice(prefixMatch[0].length); - } else { - return match; - } - } - - for (const v of parts.variables) { - match.curPart = v; - - // If the var is the last thing in the template, then the whole response - // is the variable. - if (v.postfix === '') { - match.substs[v.variable.name] = match.finalStr; - match.finalStr = ''; - } - - if (match.finalStr.length === 0) { - return match; - } - - if (!v.variable.contentMatchStr) { - if (v.postfix !== '') { - // Match variable as free text, and require postfix or EOS to indicate - // variable end. - // - // Note: the 's' flag makes '.' in regexp match all char (otherwise it - // doesn't match newlines). - const varAndPostfixRegexp = new RegExp( - `^(.+?)(${escapeStringInMatch(v.postfix)}|$)`, 's'); - const varAndPostfixMatch = match.finalStr.match(varAndPostfixRegexp); - - if (!varAndPostfixMatch) { - // if there is no match, then this variable has not been found or is the - // empty string. We treat that as a failure to fill in the variable. - // - // If this was the first variable, then no varaibles have been found, and - // we can directly fail and say that no variable was matched. - return match; - } else { - match.substs[v.variable.name] = varAndPostfixMatch[1]; - match.finalStr = match.finalStr.slice(varAndPostfixMatch[0].length); - if (varAndPostfixMatch[2] === v.postfix) { - delete match.curPart; - match.matchedPartsCount++; - } - } - } - } else { - // We have a special variable constraint, so match it first, then postfix. - const varRegexp = new RegExp(`^(${v.variable.contentMatchStr})`); - const varMatch = match.finalStr.match(varRegexp); - if (!varMatch) { - return match; - } else { - match.substs[v.variable.name] = varMatch[1]; - match.finalStr = match.finalStr.slice(varMatch[0].length); - } - if (v.postfix !== '') { - const postfixRegexp = new RegExp(escapeStringInMatch(v.postfix)); - const postfixMatch = match.finalStr.match(postfixRegexp); - if (!postfixMatch) { - return match - } else { - match.finalStr = match.finalStr.slice(postfixMatch[0].length); - delete match.curPart; - match.matchedPartsCount++; - } - } - } - } - return match; -} - - -type NameToVarMap = { [Key in Ns]: TemplVar }; -// type SpecificName = string extends Ns ? never : Ns; -// type VarNames = NamedVar>; - -// ---------------------------------------------------------------------------- -// Ns = All variable names in the template. -// N = This variable name. -// TODO: consider this being a subclass of NamedVar... -export class TemplVar { - constructor(public template: Template, public rawVariable: NamedVar) { - if (!rawVariable.occurs(template.escaped)) { - console.error(`Template is missing a variable.\n` + - `Variable: ${this.name}\n` + - `Template: ${template.escaped}`) - } - }; - - get name(): N { - return this.rawVariable.name; - } - - // TODO: think about what if the "replacement" has variables in it? - // Right now we depend on doing this in the renameVar code. But we could - // imagine using a special kind of string type for escaped strings. - substStr(replacement: string): Template> { - const newTemplate = this.rawVariable.subst(this.template.escaped, replacement); - const newVarList = ( - [...this.template.varList().filter(v => v.name !== this.name) - ] as NamedVar>[]); - - return new Template(newTemplate, newVarList); - } - // TODO: maybe create a constraint that N2s must be dispoint with Ns? - substTempl(p: Template): Template | N2s> { - let newTemplate = this.template.escaped; - const subTemplate: Template = p; - newTemplate = this.rawVariable.subst( - newTemplate, subTemplate.escaped) - const newVarList = ( - [...this.template.varList().filter(v => v.name !== this.name), - ...subTemplate.varList()] as NamedVar | N2s>[]); - return new Template(newTemplate, newVarList); - } - - // TODO: would be better if I could express H3 is not member of Hs. - renameVar( - newName: Exclude, // N2 should not be in Ns! If so, this is never. - ): Template | N2> { - return this.unsafeRenameVar(newName as N2); - } - - unsafeRenameVar( - newName: N2, - ): Template | N2> { - const newVar = nv(newName); - const newTemplate = this.rawVariable.subst(this.template.escaped, newVar.literal); - const newVarList = ( - [...this.template.varList().filter(v => v.name !== this.name), - newVar] as NamedVar | N2>[]); - return new Template(newTemplate, newVarList); - } - - occurs(s: string): boolean { - return this.rawVariable.occurs(s); - } -} - -export class ExtraVarError extends Error { } - -const VAR_REGEXP = /\{\{(?[^(\}\})]*)\}\}/g; - -// ---------------------------------------------------------------------------- -// ---------------------------------------------------------------------------- -export class Template { - public vars: NameToVarMap; - - constructor(public escaped: string, vars: NamedVar[]) { - - const varsNamesInTemplate = - [...escaped.matchAll(VAR_REGEXP)].map(m => m.groups!['name']); - - this.vars = {} as NameToVarMap; - for (const v of vars.map(v => new TemplVar(this, v))) { - this.vars[v.name] = v; - } - - const extraVarsNamesInTemplateSet = new Set(varsNamesInTemplate); - const extraDelcaredVarNameSet = new Set(Object.keys(this.vars)); - extraDelcaredVarNameSet.forEach(v => { - if (extraVarsNamesInTemplateSet.delete(v)) { - extraDelcaredVarNameSet.delete(v); - } - }); - // TODO: consider if we want these to be allowed/not via options in - // the constructor? - if (extraVarsNamesInTemplateSet.size > 0) { - throw new ExtraVarError(`Template has undeclared variables: ` - + `${[...extraVarsNamesInTemplateSet]}.These should be declared` - + `constructor, or escaped.`); - } - if (extraDelcaredVarNameSet.size > 0) { - console.warn(`Extra vars were declared that don't exist in the ` - + `template, this is probably not intentional. The extra vars ` - + `are: ${[...extraDelcaredVarNameSet]}`); - } - } - - varList(): NamedVar[] { - return Object.values(this.vars) - .map(v => (v as TemplVar>).rawVariable); - } - - // TODO: would be better if I could express M is not member of Hs. - mergeVars( - varsToMerge: OldNs[], - mergedVar: Exclude>, - ): Template | M> { - // TODO: make a more efficient version that does it all at once instead of - // incrementally. - let newTempl = this as Template; - for (const v of varsToMerge) { - newTempl = newTempl.vars[v as unknown as Ns] - .unsafeRenameVar(mergedVar) as unknown as Template; - } - return newTempl as Template | M>; - } - - substStr(v: N, replacement: string): - Template> { - return this.vars[v].substStr(replacement); - }; - - substTempl( - v: N, replacement: Template - ): Template | N2s> { - return this.vars[v].substTempl(replacement); - } - - // substs(replacements: { [Key in S]: string }) - // : Template> { - // let newTempl = this as unknown as Template>; - // for (const k of (Object.keys(replacements) as S[])) { - // newTempl = (newTempl as unknown as Template).vars[k] - // .substStr(replacements[k]); - // } - // return newTempl; - // }; - - // TODO: can we make replacenments into templates? - // - // declare substs( - // replacements: { [Key in S]: string | NamedVar } - // ): Template | N2s>; - - substs( - replacements: { [Key in S]: string | NamedVar } - ): Template | (string extends N2s ? never : N2s)> { - type Return = Template | (string extends N2s ? never : N2s)> - let newTempl = this as unknown as Return; - for (const k of (Object.keys(replacements) as S[])) { - const r = replacements[k] - if (typeof r === 'string') { - newTempl = (newTempl as unknown as Template).vars[k] - .substStr(r) as Return; - } else { - newTempl = (newTempl as unknown as Template).vars[k] - .unsafeRenameVar(r.name) as Return; - } - } - return newTempl; - }; - - // CONSIDER: Make conditional type that errors is there is overlap on the - // variable names. Ideally this would be supported as a first class thing by - // TypeScript. - concat(secondPart: Template) - : Template { - const vars = [...this.varList(), ...secondPart.varList() - ] as NamedVar[]; - return new Template(this.escaped.concat(secondPart.escaped), vars); - } - - // Maybe templates should actually be a list objects where the object is the - // string-part and the variable parts, and a final string... (or initial - // string)? - parts(): TemplateParts { - const l = this.escaped.split(SPLIT_REGEXP); - // Note split using a regexp will result in parts.length > 0; so l.shift - // will always be defined. - const prefix = unEscapeStr(l.shift()!); - const parts = [] as TemplatePart[]; - while (l.length > 0) { - // prefix is defined because l.length > 0 - const variable = this.vars[l.shift() as Ns].rawVariable; - const postfix = unEscapeStr(l.shift()!); - parts.push({ variable, postfix }); - } - return { prefix, variables: parts }; - } - - stringify(): IfNeverElse> { - return unEscapeStr(this.escaped) as IfNeverElse>; - } - - // Can we define a generic subst? that takes a string or template replacement? - // subst(n: N, replacement: Templ | string): - // Templ | N2s> { - // if (typeof replacement === 'string') { - // return this.vars[n].substStr(replacement); - // } - // return this.vars[n].substTempl(replacement); - // } -} - - -// type TemplateArg = NamedVar | Template | string - -type TemplateArgName = T extends (NamedVar | Template | string) ? Hs : never; - -/** - * Helper function to make templates. This is intended to be the main way - * templates are created. - */ -export function template< - // Hs extends string - Args extends (NamedVar | Template | string)[] ->( - strings: TemplateStringsArray, - // ...args: TemplateArg[] - ...args: Args - // (NamedVar | Template | string)[] -): Template> { - const varSet = new Set>; - args.forEach( - a => { - if (a instanceof String || typeof (a) === 'string') { - return; - } - if (a instanceof Template) { - a.varList().forEach(v => varSet.add( - v as TemplateArgName)); - } - // TODO: support raw strings? - // else if (typeof a === 'string') { - // varSet.add(a) - // } - else if (a instanceof NamedVar) { - varSet.add(a as TemplateArgName); - } - }); - - return new Template( - strings.map((s, i) => { - if (i >= args.length) { - return s; - } - const a = args[i]; - return escapeStr(s) + ( - a instanceof Template ? a.escaped - : (a instanceof String || typeof (a) === 'string') ? a - : (a as NamedVar).literal); - }).join(''), - [...varSet] - ); -} diff --git a/llm-recs/llm-recs-webclient/src/lib/text-templates/variable.spec.ts b/llm-recs/llm-recs-webclient/src/lib/text-templates/variable.spec.ts deleted file mode 100644 index 5d352045..00000000 --- a/llm-recs/llm-recs-webclient/src/lib/text-templates/variable.spec.ts +++ /dev/null @@ -1,41 +0,0 @@ -/*============================================================================== - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an Apache2 license that can be - * found in the LICENSE file and http://www.apache.org/licenses/LICENSE-2.0 -==============================================================================*/ - -import { RegExpVar } from './variable'; - -describe('named variables', () => { - beforeEach(() => { - }); - - it('occurs', () => { - // You can prompts quite vaturally, you define your variables, and then - // just use them in a string interpretation. - const thingVar = new RegExpVar('thing'); - const bigThingVar = new RegExpVar('bigThing'); - // Variables are first class properies, and you can do stuff with them. - expect(bigThingVar.occurs('blah {{bigThing}}')).toBeTruthy(); - expect(thingVar.occurs('blah {{bigthing}}')).toBeFalsy(); - }); - - it('Substituting a var in a string', () => { - const thingVar = new RegExpVar('thing'); - const s2 = thingVar.subst(`what is a ${thingVar}?`, 'bar'); - expect(s2).toEqual('what is a bar?'); - }); - - // Sadly there is no way to override loose equality for classes in JS. - // it('equals', () => { - // // You can prompts quite vaturally, you define your variables, and then - // // just use them in a string interpretation. - // const thingVar = new RegExpVar('thing'); - // const thingVar2 = new RegExpVar('thing'); - // // Variables are first class properies, and you can do stuff with them. - // expect(thingVar == thingVar2).toBeTruthy(); - // }); -}); - diff --git a/llm-recs/llm-recs-webclient/src/lib/text-templates/variable.ts b/llm-recs/llm-recs-webclient/src/lib/text-templates/variable.ts deleted file mode 100644 index ecb39d70..00000000 --- a/llm-recs/llm-recs-webclient/src/lib/text-templates/variable.ts +++ /dev/null @@ -1,112 +0,0 @@ -/*============================================================================== - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an Apache2 license that can be - * found in the LICENSE file and http://www.apache.org/licenses/LICENSE-2.0 -==============================================================================*/ - -/* -An implementation of named nariables that can occur in a string template. -*/ - -export abstract class NamedVar { - public abstract contentMatchStr?: string; - - constructor(public name: N) { }; - - // Apply the substitution, replacing this variable in `s` with the value - // string. - public abstract subst(s: string, value: string): string; - - // Split the string whereever this variable occurs. - public abstract split(s: string): string[]; - - // Returns true if 's' contains occurances of this variable. - // Properties: - // Forall s, s': if (!x.occurs(s)) then (x.applyFn(s, s') === s) - // (x.split(s).length === 1) <=iff=> (x.occurs(s) === false) - public occurs(s: string): boolean { - return Object.values(this.split(s)).length > 1; - } - - // Provides a literal string for the substitution. - // Key property: - // Forall s: x.applyFn(s, x.literalStr()) === s - public abstract literal: string; -} - - -// Assumes that regexp matches /.*${literal}.*/ -// (Required for the RegExpVar literal/applyFn property. -export interface RegExpVarOptions { - // A regexp-string that the content of this variable must match. - // The reason this is not a full RegExp is that it cannot specify regexp - // flags, e.g. /.../g - // It also should not include the $ or ^ markers (match end/start of regexp. - // This is intented to be part of the regexp used to control generation, or - // match the output in a template. - match?: string, - - // Optional string that much match right after the variable. - postVarMatch?: string; -} - -// Example usage: -// const r = 'did you know that a {{foo}} is a {{bar}}.'.split(VAR_REGEXP); -// r = ['did you know that a ', '{{foo}}', ' is a ', '{{bar}}', '.'] -// Property: every other value (the odd indexes) is a variable. -// We could use `\\{\\{([^(\\}\\})]*)\\}\\}` as our regexp to also remove -// variable marker parenthesis, but we don't do that because it's good to be -// able to easily visually inspect what's what. Maybe we'll change it later. -// export const VAR_REGEXP_STR = `(\\{\\{.*?\\}\\})`; -export const VAR_REGEXP_STR = `(\\{\\{[^(\\}\\})]*\\}\\})`; -// export const SPLIT_REGEXP_STR = `\\{\\{(.*?)\\}\\}`; -export const SPLIT_REGEXP_STR = `\\{\\{([^(\\}\\})]*)\\}\\}`; -export const SPLIT_REGEXP = new RegExp(SPLIT_REGEXP_STR, 'g'); -export const VAR_REGEXP = new RegExp(VAR_REGEXP_STR, 'g'); -export const PREFIX_REGEXP = new RegExp(`$([^(\\{\\{)]*)`); - -export class RegExpVar extends NamedVar { - // A regexp that the content of this variable must match. - // contentRegexp: RegExp; - - // The matcher for the literal in the template. - literalRegExp: RegExp; - - // This is the actual string value in the template that the variable has. - // The template's escaping must make sure that this cannot occcur as part of - // the template, except as this variable. - literal: string; - - // Regexp as a string to match content. - public contentMatchStr?: string; - - constructor(name: N, options?: RegExpVarOptions) { - super(name); - if (options && options.match) { - this.contentMatchStr = options.match; - } - // else { - // this.contentMatchStr = '.+?'; - //} - this.literal = `{{${this.name}}}`; - // TODO: consider doing this automatically by escaling this.literal - this.literalRegExp = new RegExp(`\\{\\{${this.name}\\}\\}`, 'g'); - } - - // static splitAllVars(s: string): string[] { - // return s.split(VAR_REGEXP); - // } - - public subst(s: string, value: string): string { - return s.replace(this.literalRegExp, value); - } - public split(s: string): string[] { - return s.split(this.literalRegExp); - } - - override toString(): string { - return this.literal; - } -}