diff --git a/.github/workflows/all_plugins.yaml b/.github/workflows/all_plugins.yaml index 75ff80a9cabf..75c3496fbe95 100644 --- a/.github/workflows/all_plugins.yaml +++ b/.github/workflows/all_plugins.yaml @@ -123,7 +123,7 @@ jobs: melos exec -c 1 --scope="*example*" --dir-exists="web" -- \ "flutter build web" swift-integration: - runs-on: macos-latest + runs-on: macos-15 timeout-minutes: 30 env: FLUTTER_DEPENDENCIES: "cloud_firestore firebase_remote_config cloud_functions firebase_database firebase_auth firebase_storage firebase_analytics firebase_messaging firebase_app_check firebase_in_app_messaging firebase_performance firebase_dynamic_links firebase_crashlytics firebase_ml_model_downloader firebase_app_installations" diff --git a/.github/workflows/scripts/functions/package-lock.json b/.github/workflows/scripts/functions/package-lock.json index 7b93503efa03..e48eda2f586d 100644 --- a/.github/workflows/scripts/functions/package-lock.json +++ b/.github/workflows/scripts/functions/package-lock.json @@ -7,8 +7,8 @@ "name": "functions", "hasInstallScript": true, "dependencies": { - "firebase-admin": "^11.5.0", - "firebase-functions": "^4.5.0" + "firebase-admin": "^13.2.0", + "firebase-functions": "^6.3.2" }, "devDependencies": { "firebase-functions-test": "^0.2.0", @@ -18,172 +18,174 @@ "node": "20" } }, - "node_modules/@babel/parser": { - "version": "7.23.6", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.6.tgz", - "integrity": "sha512-Z2uID7YJ7oNvAI20O9X0bblw7Qqs8Q2hFy0R9tAfnfLkp5MW0UH9eUvnDSnFwKZ0AvgS1ucqR4KzvVHgnke1VQ==", - "optional": true, - "bin": { - "parser": "bin/babel-parser.js" - }, - "engines": { - "node": ">=6.0.0" - } - }, "node_modules/@fastify/busboy": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@fastify/busboy/-/busboy-1.2.1.tgz", - "integrity": "sha512-7PQA7EH43S0CxcOa9OeAnaeA0oQ+e/DHNPZwSQM9CQHW76jle5+OvLdibRp/Aafs9KXbLhxyjOTkRjWUbQEd3Q==", - "dependencies": { - "text-decoding": "^1.0.0" - }, - "engines": { - "node": ">=14" - } + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@fastify/busboy/-/busboy-3.1.1.tgz", + "integrity": "sha512-5DGmA8FTdB2XbDeEwc/5ZXBl6UbBAyBOOLlPuBnZ/N1SwdH9Ii+cOX3tBROlDgcTXxjOYnLMVoKk9+FXAw0CJw==" + }, + "node_modules/@firebase/app-check-interop-types": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@firebase/app-check-interop-types/-/app-check-interop-types-0.3.3.tgz", + "integrity": "sha512-gAlxfPLT2j8bTI/qfe3ahl2I2YcBQ8cFIBdhAQA4I2f3TndcO+22YizyGYuttLHPQEpWkhmpFW60VCFEPg4g5A==" }, "node_modules/@firebase/app-types": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/@firebase/app-types/-/app-types-0.9.0.tgz", - "integrity": "sha512-AeweANOIo0Mb8GiYm3xhTEBVCmPwTYAu9Hcd2qSkLuga/6+j9b1Jskl5bpiSQWy9eJ/j5pavxj6eYogmnuzm+Q==" + "version": "0.9.3", + "resolved": "https://registry.npmjs.org/@firebase/app-types/-/app-types-0.9.3.tgz", + "integrity": "sha512-kRVpIl4vVGJ4baogMDINbyrIOtOxqhkZQg4jTq3l8Lw6WSk0xfpEYzezFu+Kl4ve4fbPl79dvwRtaFqAC/ucCw==" }, "node_modules/@firebase/auth-interop-types": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/@firebase/auth-interop-types/-/auth-interop-types-0.2.1.tgz", - "integrity": "sha512-VOaGzKp65MY6P5FI84TfYKBXEPi6LmOCSMMzys6o2BN2LOsqy7pCuZCup7NYnfbk5OkkQKzvIfHOzTm0UDpkyg==" + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/@firebase/auth-interop-types/-/auth-interop-types-0.2.4.tgz", + "integrity": "sha512-JPgcXKCuO+CWqGDnigBtvo09HeBs5u/Ktc2GaFj2m01hLarbxthLNm7Fk8iOP1aqAtXV+fnnGj7U28xmk7IwVA==" }, "node_modules/@firebase/component": { - "version": "0.6.4", - "resolved": "https://registry.npmjs.org/@firebase/component/-/component-0.6.4.tgz", - "integrity": "sha512-rLMyrXuO9jcAUCaQXCMjCMUsWrba5fzHlNK24xz5j2W6A/SRmK8mZJ/hn7V0fViLbxC0lPMtrK1eYzk6Fg03jA==", + "version": "0.6.13", + "resolved": "https://registry.npmjs.org/@firebase/component/-/component-0.6.13.tgz", + "integrity": "sha512-I/Eg1NpAtZ8AAfq8mpdfXnuUpcLxIDdCDtTzWSh+FXnp/9eCKJ3SNbOCKrUCyhLzNa2SiPJYruei0sxVjaOTeg==", "dependencies": { - "@firebase/util": "1.9.3", + "@firebase/util": "1.11.0", "tslib": "^2.1.0" + }, + "engines": { + "node": ">=18.0.0" } }, "node_modules/@firebase/database": { - "version": "0.14.4", - "resolved": "https://registry.npmjs.org/@firebase/database/-/database-0.14.4.tgz", - "integrity": "sha512-+Ea/IKGwh42jwdjCyzTmeZeLM3oy1h0mFPsTy6OqCWzcu/KFqRAr5Tt1HRCOBlNOdbh84JPZC47WLU18n2VbxQ==", - "dependencies": { - "@firebase/auth-interop-types": "0.2.1", - "@firebase/component": "0.6.4", - "@firebase/logger": "0.4.0", - "@firebase/util": "1.9.3", + "version": "1.0.14", + "resolved": "https://registry.npmjs.org/@firebase/database/-/database-1.0.14.tgz", + "integrity": "sha512-9nxYtkHAG02/Nh2Ssms1T4BbWPPjiwohCvkHDUl4hNxnki1kPgsLo5xe9kXNzbacOStmVys+RUXvwzynQSKmUQ==", + "dependencies": { + "@firebase/app-check-interop-types": "0.3.3", + "@firebase/auth-interop-types": "0.2.4", + "@firebase/component": "0.6.13", + "@firebase/logger": "0.4.4", + "@firebase/util": "1.11.0", "faye-websocket": "0.11.4", "tslib": "^2.1.0" + }, + "engines": { + "node": ">=18.0.0" } }, "node_modules/@firebase/database-compat": { - "version": "0.3.4", - "resolved": "https://registry.npmjs.org/@firebase/database-compat/-/database-compat-0.3.4.tgz", - "integrity": "sha512-kuAW+l+sLMUKBThnvxvUZ+Q1ZrF/vFJ58iUY9kAcbX48U03nVzIF6Tmkf0p3WVQwMqiXguSgtOPIB6ZCeF+5Gg==", - "dependencies": { - "@firebase/component": "0.6.4", - "@firebase/database": "0.14.4", - "@firebase/database-types": "0.10.4", - "@firebase/logger": "0.4.0", - "@firebase/util": "1.9.3", + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@firebase/database-compat/-/database-compat-2.0.5.tgz", + "integrity": "sha512-CNf1UbvWh6qIaSf4sn6sx2DTDz/em/D7QxULH1LTxxDQHr9+CeYGvlAqrKnk4ZH0P0eIHyQFQU7RwkUJI0B9gQ==", + "dependencies": { + "@firebase/component": "0.6.13", + "@firebase/database": "1.0.14", + "@firebase/database-types": "1.0.10", + "@firebase/logger": "0.4.4", + "@firebase/util": "1.11.0", "tslib": "^2.1.0" + }, + "engines": { + "node": ">=18.0.0" } }, "node_modules/@firebase/database-types": { - "version": "0.10.4", - "resolved": "https://registry.npmjs.org/@firebase/database-types/-/database-types-0.10.4.tgz", - "integrity": "sha512-dPySn0vJ/89ZeBac70T+2tWWPiJXWbmRygYv0smT5TfE3hDrQ09eKMF3Y+vMlTdrMWq7mUdYW5REWPSGH4kAZQ==", + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/@firebase/database-types/-/database-types-1.0.10.tgz", + "integrity": "sha512-mH6RC1E9/Pv8jf1/p+M8YFTX+iu+iHDN89hecvyO7wHrI4R1V0TXjxOHvX3nLJN1sfh0CWG6CHZ0VlrSmK/cwg==", "dependencies": { - "@firebase/app-types": "0.9.0", - "@firebase/util": "1.9.3" + "@firebase/app-types": "0.9.3", + "@firebase/util": "1.11.0" } }, "node_modules/@firebase/logger": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/@firebase/logger/-/logger-0.4.0.tgz", - "integrity": "sha512-eRKSeykumZ5+cJPdxxJRgAC3G5NknY2GwEbKfymdnXtnT0Ucm4pspfR6GT4MUQEDuJwRVbVcSx85kgJulMoFFA==", + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/@firebase/logger/-/logger-0.4.4.tgz", + "integrity": "sha512-mH0PEh1zoXGnaR8gD1DeGeNZtWFKbnz9hDO91dIml3iou1gpOnLqXQ2dJfB71dj6dpmUjcQ6phY3ZZJbjErr9g==", "dependencies": { "tslib": "^2.1.0" + }, + "engines": { + "node": ">=18.0.0" } }, "node_modules/@firebase/util": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/@firebase/util/-/util-1.9.3.tgz", - "integrity": "sha512-DY02CRhOZwpzO36fHpuVysz6JZrscPiBXD0fXp6qSrL9oNOx5KWICKdR95C0lSITzxp0TZosVyHqzatE8JbcjA==", + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/@firebase/util/-/util-1.11.0.tgz", + "integrity": "sha512-PzSrhIr++KI6y4P6C/IdgBNMkEx0Ex6554/cYd0Hm+ovyFSJtJXqb/3OSIdnBoa2cpwZT1/GW56EmRc5qEc5fQ==", + "hasInstallScript": true, "dependencies": { "tslib": "^2.1.0" + }, + "engines": { + "node": ">=18.0.0" } }, "node_modules/@google-cloud/firestore": { - "version": "6.8.0", - "resolved": "https://registry.npmjs.org/@google-cloud/firestore/-/firestore-6.8.0.tgz", - "integrity": "sha512-JRpk06SmZXLGz0pNx1x7yU3YhkUXheKgH5hbDZ4kMsdhtfV5qPLJLRI4wv69K0cZorIk+zTMOwptue7hizo0eA==", + "version": "7.11.0", + "resolved": "https://registry.npmjs.org/@google-cloud/firestore/-/firestore-7.11.0.tgz", + "integrity": "sha512-88uZ+jLsp1aVMj7gh3EKYH1aulTAMFAp8sH/v5a9w8q8iqSG27RiWLoxSAFr/XocZ9hGiWH1kEnBw+zl3xAgNA==", "optional": true, "dependencies": { + "@opentelemetry/api": "^1.3.0", "fast-deep-equal": "^3.1.1", "functional-red-black-tree": "^1.0.1", - "google-gax": "^3.5.7", - "protobufjs": "^7.2.5" + "google-gax": "^4.3.3", + "protobufjs": "^7.2.6" }, "engines": { - "node": ">=12.0.0" + "node": ">=14.0.0" } }, "node_modules/@google-cloud/paginator": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/@google-cloud/paginator/-/paginator-3.0.7.tgz", - "integrity": "sha512-jJNutk0arIQhmpUUQJPJErsojqo834KcyB6X7a1mxuic8i1tKXxde8E69IZxNZawRIlZdIK2QY4WALvlK5MzYQ==", + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/@google-cloud/paginator/-/paginator-5.0.2.tgz", + "integrity": "sha512-DJS3s0OVH4zFDB1PzjxAsHqJT6sKVbRwwML0ZBP9PbU7Yebtu/7SWMRzvO2J3nUi9pRNITCfu4LJeooM2w4pjg==", "optional": true, "dependencies": { "arrify": "^2.0.0", "extend": "^3.0.2" }, "engines": { - "node": ">=10" + "node": ">=14.0.0" } }, "node_modules/@google-cloud/projectify": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@google-cloud/projectify/-/projectify-3.0.0.tgz", - "integrity": "sha512-HRkZsNmjScY6Li8/kb70wjGlDDyLkVk3KvoEo9uIoxSjYLJasGiCch9+PqRVDOCGUFvEIqyogl+BeqILL4OJHA==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@google-cloud/projectify/-/projectify-4.0.0.tgz", + "integrity": "sha512-MmaX6HeSvyPbWGwFq7mXdo0uQZLGBYCwziiLIGq5JVX+/bdI3SAq6bP98trV5eTWfLuvsMcIC1YJOF2vfteLFA==", "optional": true, "engines": { - "node": ">=12.0.0" + "node": ">=14.0.0" } }, "node_modules/@google-cloud/promisify": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@google-cloud/promisify/-/promisify-3.0.1.tgz", - "integrity": "sha512-z1CjRjtQyBOYL+5Qr9DdYIfrdLBe746jRTYfaYU6MeXkqp7UfYs/jX16lFFVzZ7PGEJvqZNqYUEtb1mvDww4pA==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@google-cloud/promisify/-/promisify-4.0.0.tgz", + "integrity": "sha512-Orxzlfb9c67A15cq2JQEyVc7wEsmFBmHjZWZYQMUyJ1qivXyMwdyNOs9odi79hze+2zqdTtu1E19IM/FtqZ10g==", "optional": true, "engines": { - "node": ">=12" + "node": ">=14" } }, "node_modules/@google-cloud/storage": { - "version": "6.12.0", - "resolved": "https://registry.npmjs.org/@google-cloud/storage/-/storage-6.12.0.tgz", - "integrity": "sha512-78nNAY7iiZ4O/BouWMWTD/oSF2YtYgYB3GZirn0To6eBOugjXVoK+GXgUXOl+HlqbAOyHxAVXOlsj3snfbQ1dw==", + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/@google-cloud/storage/-/storage-7.16.0.tgz", + "integrity": "sha512-7/5LRgykyOfQENcm6hDKP8SX/u9XxE5YOiWOkgkwcoO+cG8xT/cyOvp9wwN3IxfdYgpHs8CE7Nq2PKX2lNaEXw==", "optional": true, "dependencies": { - "@google-cloud/paginator": "^3.0.7", - "@google-cloud/projectify": "^3.0.0", - "@google-cloud/promisify": "^3.0.0", + "@google-cloud/paginator": "^5.0.0", + "@google-cloud/projectify": "^4.0.0", + "@google-cloud/promisify": "<4.1.0", "abort-controller": "^3.0.0", "async-retry": "^1.3.3", - "compressible": "^2.0.12", - "duplexify": "^4.0.0", - "ent": "^2.2.0", - "extend": "^3.0.2", - "fast-xml-parser": "^4.2.2", - "gaxios": "^5.0.0", - "google-auth-library": "^8.0.1", + "duplexify": "^4.1.3", + "fast-xml-parser": "^4.4.1", + "gaxios": "^6.0.2", + "google-auth-library": "^9.6.3", + "html-entities": "^2.5.2", "mime": "^3.0.0", - "mime-types": "^2.0.8", "p-limit": "^3.0.1", - "retry-request": "^5.0.0", - "teeny-request": "^8.0.0", + "retry-request": "^7.0.0", + "teeny-request": "^9.0.0", "uuid": "^8.0.0" }, "engines": { - "node": ">=12" + "node": ">=14" } }, "node_modules/@google-cloud/storage/node_modules/uuid": { @@ -196,27 +198,27 @@ } }, "node_modules/@grpc/grpc-js": { - "version": "1.8.22", - "resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.8.22.tgz", - "integrity": "sha512-oAjDdN7fzbUi+4hZjKG96MR6KTEubAeMpQEb+77qy+3r0Ua5xTFuie6JOLr4ZZgl5g+W5/uRTS2M1V8mVAFPuA==", + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.13.2.tgz", + "integrity": "sha512-nnR5nmL6lxF8YBqb6gWvEgLdLh/Fn+kvAdX5hUOnt48sNSb0riz/93ASd2E5gvanPA41X6Yp25bIfGRp1SMb2g==", "optional": true, "dependencies": { - "@grpc/proto-loader": "^0.7.0", - "@types/node": ">=12.12.47" + "@grpc/proto-loader": "^0.7.13", + "@js-sdsl/ordered-map": "^4.4.2" }, "engines": { - "node": "^8.13.0 || >=10.10.0" + "node": ">=12.10.0" } }, "node_modules/@grpc/proto-loader": { - "version": "0.7.10", - "resolved": "https://registry.npmjs.org/@grpc/proto-loader/-/proto-loader-0.7.10.tgz", - "integrity": "sha512-CAqDfoaQ8ykFd9zqBDn4k6iWT9loLAlc2ETmDFS9JCD70gDcnA4L3AFEo2iV7KyAtAAHFW9ftq1Fz+Vsgq80RQ==", + "version": "0.7.13", + "resolved": "https://registry.npmjs.org/@grpc/proto-loader/-/proto-loader-0.7.13.tgz", + "integrity": "sha512-AiXO/bfe9bmxBjxxtYxFAXGZvMaN5s8kO+jBHAJCON8rJoB5YS/D6X7ZNc6XQkuHNmyl4CYaMI1fJ/Gn27RGGw==", "optional": true, "dependencies": { "lodash.camelcase": "^4.3.0", "long": "^5.0.0", - "protobufjs": "^7.2.4", + "protobufjs": "^7.2.5", "yargs": "^17.7.2" }, "bin": { @@ -226,16 +228,23 @@ "node": ">=6" } }, - "node_modules/@jsdoc/salty": { - "version": "0.2.7", - "resolved": "https://registry.npmjs.org/@jsdoc/salty/-/salty-0.2.7.tgz", - "integrity": "sha512-mh8LbS9d4Jq84KLw8pzho7XC2q2/IJGiJss3xwRoLD1A+EE16SjN4PfaG4jRCzKegTFLlN0Zd8SdUPE6XdoPFg==", + "node_modules/@js-sdsl/ordered-map": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/@js-sdsl/ordered-map/-/ordered-map-4.4.2.tgz", + "integrity": "sha512-iUKgm52T8HOE/makSxjqoWhe95ZJA1/G1sYsGev2JDKUSS14KAgg1LHb+Ba+IPow0xflbnSkOsZcO08C7w1gYw==", + "optional": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/js-sdsl" + } + }, + "node_modules/@opentelemetry/api": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/api/-/api-1.9.0.tgz", + "integrity": "sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg==", "optional": true, - "dependencies": { - "lodash": "^4.17.21" - }, "engines": { - "node": ">=v12.0.0" + "node": ">=8.0.0" } }, "node_modules/@protobufjs/aspromise": { @@ -310,6 +319,12 @@ "@types/node": "*" } }, + "node_modules/@types/caseless": { + "version": "0.12.5", + "resolved": "https://registry.npmjs.org/@types/caseless/-/caseless-0.12.5.tgz", + "integrity": "sha512-hWtVTC2q7hc7xZ/RLbxapMvDMgUnDvKvMOpKal4DrMyfGBUfB1oKaZlIRr6mJL+If3bAP6sV/QneGzF6tJjZDg==", + "optional": true + }, "node_modules/@types/connect": { "version": "3.4.33", "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.33.tgz", @@ -324,12 +339,13 @@ "integrity": "sha512-vt+kDhq/M2ayberEtJcIN/hxXy1Pk+59g2FV/ZQceeaTyCtCucjL2Q7FXlFjtWn4n15KCr1NE2lNNFhp0lEThw==" }, "node_modules/@types/express": { - "version": "4.17.3", - "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.3.tgz", - "integrity": "sha512-I8cGRJj3pyOLs/HndoP+25vOqhqWkAZsWMEmq1qXy/b/M3ppufecUwaK2/TVDVxcV61/iSdhykUjQQ2DLSrTdg==", + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.21.tgz", + "integrity": "sha512-ejlPM315qwLpaQlQDTjPdsUFSc6ZsP4AN6AlWnogPjQ7CVi7PYF3YVz+CY3jE2pwYf7E/7HlDAN0rV2GxTG0HQ==", "dependencies": { "@types/body-parser": "*", - "@types/express-serve-static-core": "*", + "@types/express-serve-static-core": "^4.17.33", + "@types/qs": "*", "@types/serve-static": "*" } }, @@ -343,30 +359,15 @@ "@types/range-parser": "*" } }, - "node_modules/@types/glob": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/@types/glob/-/glob-8.1.0.tgz", - "integrity": "sha512-IO+MJPVhoqz+28h1qLAcBEH2+xHMK6MTyHJc7MTnnYb6wsoLR29POVGJ7LycmVXIqyy/4/2ShP5sUwTXuOwb/w==", - "optional": true, - "dependencies": { - "@types/minimatch": "^5.1.2", - "@types/node": "*" - } - }, "node_modules/@types/jsonwebtoken": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/@types/jsonwebtoken/-/jsonwebtoken-9.0.1.tgz", - "integrity": "sha512-c5ltxazpWabia/4UzhIoaDcIza4KViOQhdbjRlfcIGVnsE3c3brkz9Z+F/EeJIECOQP7W7US2hNE930cWWkPiw==", + "version": "9.0.9", + "resolved": "https://registry.npmjs.org/@types/jsonwebtoken/-/jsonwebtoken-9.0.9.tgz", + "integrity": "sha512-uoe+GxEuHbvy12OUQct2X9JenKM3qAscquYymuQN4fMWG9DBQtykrQEFcAbVACF7qaLw9BePSodUL0kquqBJpQ==", "dependencies": { + "@types/ms": "*", "@types/node": "*" } }, - "node_modules/@types/linkify-it": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/@types/linkify-it/-/linkify-it-3.0.5.tgz", - "integrity": "sha512-yg6E+u0/+Zjva+buc3EIb+29XEg4wltq7cSmd4Uc2EE/1nUVmxyzpX6gUXD0V8jIrG0r7YeOGVIbYRkxeooCtw==", - "optional": true - }, "node_modules/@types/lodash": { "version": "4.14.161", "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.161.tgz", @@ -379,39 +380,22 @@ "integrity": "sha512-MqTGEo5bj5t157U6fA/BiDynNkn0YknVdh48CMPkTSpFTVmvao5UQmm7uEF6xBEo7qIMAlY/JSleYaE6VOdpaA==", "optional": true }, - "node_modules/@types/markdown-it": { - "version": "12.2.3", - "resolved": "https://registry.npmjs.org/@types/markdown-it/-/markdown-it-12.2.3.tgz", - "integrity": "sha512-GKMHFfv3458yYy+v/N8gjufHO6MSZKCOXpZc5GXIWWy8uldwfmPn98vp81gZ5f9SVw8YYBctgfJ22a2d7AOMeQ==", - "optional": true, - "dependencies": { - "@types/linkify-it": "*", - "@types/mdurl": "*" - } - }, - "node_modules/@types/mdurl": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/@types/mdurl/-/mdurl-1.0.5.tgz", - "integrity": "sha512-6L6VymKTzYSrEf4Nev4Xa1LCHKrlTlYCBMTlQKFuddo1CvQcE52I0mwfOJayueUC7MJuXOeHTcIU683lzd0cUA==", - "optional": true - }, "node_modules/@types/mime": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/@types/mime/-/mime-2.0.3.tgz", "integrity": "sha512-Jus9s4CDbqwocc5pOAnh8ShfrnMcPHuJYzVcSUU7lrh8Ni5HuIqX3oilL86p3dlTrk0LzHRCgA/GQ7uNCw6l2Q==" }, - "node_modules/@types/minimatch": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-5.1.2.tgz", - "integrity": "sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA==", - "optional": true + "node_modules/@types/ms": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@types/ms/-/ms-2.1.0.tgz", + "integrity": "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==" }, "node_modules/@types/node": { - "version": "20.10.4", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.10.4.tgz", - "integrity": "sha512-D08YG6rr8X90YB56tSIuBaddy/UXAA9RKJoFvrsnogAum/0pmjkgi4+2nx96A330FmioegBWmEYQ+syqCFaveg==", + "version": "22.14.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.14.0.tgz", + "integrity": "sha512-Kmpl+z84ILoG+3T/zQFyAJsU6EPTmOCj8/2+83fSN6djd6I4o7uOuGIH6vq3PrjY5BGitSbFuMN18j3iknubbA==", "dependencies": { - "undici-types": "~5.26.4" + "undici-types": "~6.21.0" } }, "node_modules/@types/qs": { @@ -424,14 +408,16 @@ "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.3.tgz", "integrity": "sha512-ewFXqrQHlFsgc09MK5jP5iR7vumV/BYayNC6PgJO2LPe8vrnNFyjQjSppfEngITi0qvfKtzFvgKymGheFM9UOA==" }, - "node_modules/@types/rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@types/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-F3OznnSLAUxFrCEu/L5PY8+ny8DtcFRjx7fZZ9bycvXRi3KPTRS9HOitGZwvPg0juRhXFWIeKX58cnX5YqLohQ==", + "node_modules/@types/request": { + "version": "2.48.12", + "resolved": "https://registry.npmjs.org/@types/request/-/request-2.48.12.tgz", + "integrity": "sha512-G3sY+NpsA9jnwm0ixhAFQSJ3Q9JkpLZpJbI3GMv0mIAT0y3mRabYeINzal5WOChIiaTEGQYlHOKgkaM9EisWHw==", "optional": true, "dependencies": { - "@types/glob": "*", - "@types/node": "*" + "@types/caseless": "*", + "@types/node": "*", + "@types/tough-cookie": "*", + "form-data": "^2.5.0" } }, "node_modules/@types/serve-static": { @@ -443,6 +429,12 @@ "@types/mime": "*" } }, + "node_modules/@types/tough-cookie": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-4.0.5.tgz", + "integrity": "sha512-/Ad8+nIOV7Rl++6f1BdKxFSMgmoqEoYbHRpPcx3JEfv8VRsQe9Z4mCXeJBzxs7mbHY/XOZZuXlRNfhpVPbs6ZA==", + "optional": true + }, "node_modules/abort-controller": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", @@ -467,37 +459,12 @@ "node": ">= 0.6" } }, - "node_modules/acorn": { - "version": "8.11.2", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.2.tgz", - "integrity": "sha512-nc0Axzp/0FILLEVsm4fNwLCwMttvhEI263QtVPQcbpfZZ3ts0hLsZGOpE6czNlid7CJ9MlyH8reXkpsf3YUY4w==", - "optional": true, - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/acorn-jsx": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", - "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", - "optional": true, - "peerDependencies": { - "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" - } - }, "node_modules/agent-base": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", - "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", - "optional": true, - "dependencies": { - "debug": "4" - }, + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.3.tgz", + "integrity": "sha512-jRR5wdylq8CkOe6hei19GGZnxM6rBGwFl3Bg0YItGDimvjGtAvdZk4Pu6Cl4u4Igsws4a1fd1Vq3ezrhn4KmFw==", "engines": { - "node": ">= 6.0.0" + "node": ">= 14" } }, "node_modules/ansi-regex": { @@ -524,12 +491,6 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "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==", - "optional": true - }, "node_modules/array-flatten": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", @@ -553,10 +514,10 @@ "retry": "0.13.1" } }, - "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==", + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", "optional": true }, "node_modules/base64-js": { @@ -576,24 +537,16 @@ "type": "consulting", "url": "https://feross.org/support" } - ], - "optional": true + ] }, "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==", - "optional": true, + "version": "9.2.0", + "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.2.0.tgz", + "integrity": "sha512-JocpCSOixzy5XFJi2ub6IMmV/G9i8Lrm2lZvwBv9xPdglmZM0ufDVBbjbrfU/zuLvBfD7Bv2eYxz9i+OHTgkew==", "engines": { "node": "*" } }, - "node_modules/bluebird": { - "version": "3.7.2", - "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", - "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==", - "optional": true - }, "node_modules/body-parser": { "version": "1.20.3", "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz", @@ -630,15 +583,6 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" }, - "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==", - "optional": true, - "dependencies": { - "balanced-match": "^1.0.0" - } - }, "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", @@ -670,32 +614,16 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/catharsis": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/catharsis/-/catharsis-0.9.0.tgz", - "integrity": "sha512-prMTQVpcns/tzFgFVkVp6ak6RykZyWb3gu8ckUpd6YkTlacOd3DXGJjIpD4Q6zJirizvaiAjSSHlOsA+6sNh2A==", - "optional": true, - "dependencies": { - "lodash": "^4.17.15" - }, - "engines": { - "node": ">= 10" - } - }, - "node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "optional": true, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" }, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "node": ">= 0.4" } }, "node_modules/cliui": { @@ -730,24 +658,18 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "optional": true }, - "node_modules/compressible": { - "version": "2.0.18", - "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", - "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", + "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==", "optional": true, "dependencies": { - "mime-db": ">= 1.43.0 < 2" + "delayed-stream": "~1.0.0" }, "engines": { - "node": ">= 0.6" + "node": ">= 0.8" } }, - "node_modules/concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "optional": true - }, "node_modules/content-disposition": { "version": "0.5.4", "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", @@ -793,11 +715,11 @@ } }, "node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", + "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", "dependencies": { - "ms": "2.1.2" + "ms": "^2.1.3" }, "engines": { "node": ">=6.0" @@ -808,12 +730,6 @@ } } }, - "node_modules/deep-is": { - "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==", - "optional": true - }, "node_modules/define-data-property": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", @@ -830,6 +746,15 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "optional": true, + "engines": { + "node": ">=0.4.0" + } + }, "node_modules/depd": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", @@ -847,16 +772,29 @@ "npm": "1.2.8000 || >= 1.4.16" } }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/duplexify": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-4.1.2.tgz", - "integrity": "sha512-fz3OjcNCHmRP12MJoZMPglx8m4rrFP8rovnk4vT8Fs+aonZoCwGg10dSsQsfP/E62eZcPTMSMP6686fu9Qlqtw==", + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-4.1.3.tgz", + "integrity": "sha512-M3BmBhwJRZsSx38lZyhE53Csddgzl5R7xGJNk7CVddZD6CcmwMCH8J+7AprIrQKH7TonKxaCjcv27Qmf+sQ+oA==", "optional": true, "dependencies": { "end-of-stream": "^1.4.1", "inherits": "^2.0.3", "readable-stream": "^3.1.1", - "stream-shift": "^1.0.0" + "stream-shift": "^1.0.2" } }, "node_modules/ecdsa-sig-formatter": { @@ -895,28 +833,10 @@ "once": "^1.4.0" } }, - "node_modules/ent": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/ent/-/ent-2.2.0.tgz", - "integrity": "sha512-GHrMyVZQWvTIdDtpiEXdHZnFQKzeO09apj8Cbl4pKWy4i0Oprcq17usfDt5aO63swf0JOeMWjWQE/LzgSRuWpA==", - "optional": true - }, - "node_modules/entities": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-2.1.0.tgz", - "integrity": "sha512-hCx1oky9PFrJ611mf0ifBLBRW8lUUVRlFolb5gWRfIELabBlbp9xZvrqZLZAs+NxFnbfQoeGd8wDkygjg7U85w==", - "optional": true, - "funding": { - "url": "https://github.com/fb55/entities?sponsor=1" - } - }, "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==", - "dependencies": { - "get-intrinsic": "^1.2.4" - }, + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", "engines": { "node": ">= 0.4" } @@ -929,119 +849,45 @@ "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==", - "optional": true, - "engines": { - "node": ">=6" - } - }, - "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==" - }, - "node_modules/escape-string-regexp": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", - "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", - "optional": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/escodegen": { - "version": "1.14.3", - "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.14.3.tgz", - "integrity": "sha512-qFcX0XJkdg+PB3xjZZG/wKSuT1PnQWx57+TVSjIMmILd2yC/6ByYElPwJnslDsuWuSAp4AwJGumarAAmJch5Kw==", - "optional": true, + "node_modules/es-object-atoms": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", "dependencies": { - "esprima": "^4.0.1", - "estraverse": "^4.2.0", - "esutils": "^2.0.2", - "optionator": "^0.8.1" - }, - "bin": { - "escodegen": "bin/escodegen.js", - "esgenerate": "bin/esgenerate.js" - }, - "engines": { - "node": ">=4.0" + "es-errors": "^1.3.0" }, - "optionalDependencies": { - "source-map": "~0.6.1" - } - }, - "node_modules/escodegen/node_modules/estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", - "optional": true, "engines": { - "node": ">=4.0" - } - }, - "node_modules/eslint-visitor-keys": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", - "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", - "optional": true, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" + "node": ">= 0.4" } }, - "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==", + "node_modules/es-set-tostringtag": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", + "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", "optional": true, "dependencies": { - "acorn": "^8.9.0", - "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^3.4.1" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "optional": true, - "bin": { - "esparse": "bin/esparse.js", - "esvalidate": "bin/esvalidate.js" + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" }, "engines": { - "node": ">=4" + "node": ">= 0.4" } }, - "node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", "optional": true, "engines": { - "node": ">=4.0" + "node": ">=6" } }, - "node_modules/esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "optional": true, - "engines": { - "node": ">=0.10.0" - } + "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==" }, "node_modules/etag": { "version": "1.8.1", @@ -1129,8 +975,15 @@ "node_modules/extend": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", - "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", - "optional": true + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" + }, + "node_modules/farmhash-modern": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/farmhash-modern/-/farmhash-modern-1.1.0.tgz", + "integrity": "sha512-6ypT4XfgqJk/F3Yuv4SX26I3doUjt0GTG4a+JgWxXQpxXzTBq8fPUeGHfcYMMDPHJHm3yPOSjaeBwBGAHWXCdA==", + "engines": { + "node": ">=18.0.0" + } }, "node_modules/fast-deep-equal": { "version": "3.1.3", @@ -1138,35 +991,19 @@ "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", "optional": true }, - "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==", - "optional": true - }, - "node_modules/fast-text-encoding": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/fast-text-encoding/-/fast-text-encoding-1.0.6.tgz", - "integrity": "sha512-VhXlQgj9ioXCqGstD37E/HBeqEGV/qOD/kmbVG8h5xKBYvM1L3lR1Zn4555cQ8GkYbJa8aJSipLPndE1k6zK2w==", - "optional": true - }, "node_modules/fast-xml-parser": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-4.4.1.tgz", - "integrity": "sha512-xkjOecfnKGkSsOwtZ5Pz7Us/T6mrbPQrq0nh+aCO5V9nk5NLWmasAHumTKjiPJPWANe+kAZ84Jc8ooJkzZ88Sw==", + "version": "4.5.3", + "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-4.5.3.tgz", + "integrity": "sha512-RKihhV+SHsIUGXObeVy9AXiBbFwkVk7Syp8XgwN5U3JV416+Gwp/GO9i0JYKmikykgz/UHRrrV4ROuZEo/T0ig==", "funding": [ { "type": "github", "url": "https://github.com/sponsors/NaturalIntelligence" - }, - { - "type": "paypal", - "url": "https://paypal.me/naturalintelligence" } ], "optional": true, "dependencies": { - "strnum": "^1.0.5" + "strnum": "^1.1.1" }, "bin": { "fxparser": "src/cli/cli.js" @@ -1222,37 +1059,38 @@ "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" }, "node_modules/firebase-admin": { - "version": "11.11.1", - "resolved": "https://registry.npmjs.org/firebase-admin/-/firebase-admin-11.11.1.tgz", - "integrity": "sha512-UyEbq+3u6jWzCYbUntv/HuJiTixwh36G1R9j0v71mSvGAx/YZEWEW7uSGLYxBYE6ckVRQoKMr40PYUEzrm/4dg==", - "dependencies": { - "@fastify/busboy": "^1.2.1", - "@firebase/database-compat": "^0.3.4", - "@firebase/database-types": "^0.10.4", - "@types/node": ">=12.12.47", + "version": "13.2.0", + "resolved": "https://registry.npmjs.org/firebase-admin/-/firebase-admin-13.2.0.tgz", + "integrity": "sha512-qQBTKo0QWCDaWwISry989pr8YfZSSk00rNCKaucjOgltEm3cCYzEe4rODqBd1uUwma+Iu5jtAzg89Nfsjr3fGg==", + "dependencies": { + "@fastify/busboy": "^3.0.0", + "@firebase/database-compat": "^2.0.0", + "@firebase/database-types": "^1.0.6", + "@types/node": "^22.8.7", + "farmhash-modern": "^1.1.0", + "google-auth-library": "^9.14.2", "jsonwebtoken": "^9.0.0", - "jwks-rsa": "^3.0.1", + "jwks-rsa": "^3.1.0", "node-forge": "^1.3.1", - "uuid": "^9.0.0" + "uuid": "^11.0.2" }, "engines": { - "node": ">=14" + "node": ">=18" }, "optionalDependencies": { - "@google-cloud/firestore": "^6.8.0", - "@google-cloud/storage": "^6.9.5" + "@google-cloud/firestore": "^7.11.0", + "@google-cloud/storage": "^7.14.0" } }, "node_modules/firebase-functions": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/firebase-functions/-/firebase-functions-4.5.0.tgz", - "integrity": "sha512-y6HsasHtGLfXCp3Pfrz+JA19lO9hSzYiNxFDIDMffrfcsG7UbXzv0zfi2ASadMVRoDCaox5ppZBa1QJxZbctPQ==", + "version": "6.3.2", + "resolved": "https://registry.npmjs.org/firebase-functions/-/firebase-functions-6.3.2.tgz", + "integrity": "sha512-FC3A1/nhqt1ZzxRnj5HZLScQaozAcFSD/vSR8khqSoFNOfxuXgwJS6ZABTB7+v+iMD5z6Mmxw6OfqITUBuI7OQ==", "dependencies": { "@types/cors": "^2.8.5", - "@types/express": "4.17.3", + "@types/express": "^4.17.21", "cors": "^2.8.5", - "express": "^4.17.1", - "node-fetch": "^2.6.7", + "express": "^4.21.0", "protobufjs": "^7.2.2" }, "bin": { @@ -1262,7 +1100,7 @@ "node": ">=14.10.0" }, "peerDependencies": { - "firebase-admin": "^10.0.0 || ^11.0.0" + "firebase-admin": "^11.10.0 || ^12.0.0 || ^13.0.0" } }, "node_modules/firebase-functions-test": { @@ -1282,6 +1120,22 @@ "firebase-functions": ">=2.0.0" } }, + "node_modules/form-data": { + "version": "2.5.3", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.5.3.tgz", + "integrity": "sha512-XHIrMD0NpDrNM/Ckf7XJiBbLl57KEhT3+i3yY+eWm+cqYZJQTZrKo8Y8AWKnuV5GT4scfuUGt9LzNoIx3dU1nQ==", + "optional": true, + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "es-set-tostringtag": "^2.1.0", + "mime-types": "^2.1.35", + "safe-buffer": "^5.2.1" + }, + "engines": { + "node": ">= 0.12" + } + }, "node_modules/forwarded": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", @@ -1298,12 +1152,6 @@ "node": ">= 0.6" } }, - "node_modules/fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", - "optional": true - }, "node_modules/function-bind": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", @@ -1319,31 +1167,43 @@ "optional": true }, "node_modules/gaxios": { - "version": "5.1.3", - "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-5.1.3.tgz", - "integrity": "sha512-95hVgBRgEIRQQQHIbnxBXeHbW4TqFk4ZDJW7wmVtvYar72FdhRIo1UGOLS2eRAKCPEdPBWu+M7+A33D9CdX9rA==", - "optional": true, + "version": "6.7.1", + "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-6.7.1.tgz", + "integrity": "sha512-LDODD4TMYx7XXdpwxAVRAIAuB0bzv0s+ywFonY46k126qzQHT9ygyoa9tncmOiQmmDrik65UYsEkv3lbfqQ3yQ==", "dependencies": { "extend": "^3.0.2", - "https-proxy-agent": "^5.0.0", + "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": ">=12" + "node": ">=14" } }, - "node_modules/gcp-metadata": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-5.3.0.tgz", - "integrity": "sha512-FNTkdNEnBdlqF2oatizolQqNANMrcqJt6AAYt99B3y1aLLC8Hc5IOBb+ZnnzllodEEf6xMBp6wRcBbc16fa65w==", - "optional": true, - "dependencies": { - "gaxios": "^5.0.0", - "json-bigint": "^1.0.0" + "node_modules/gaxios/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" + ], + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/gcp-metadata": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-6.1.1.tgz", + "integrity": "sha512-a4tiq7E0/5fTjxPAaH4jpjkSv/uCaU2p5KC6HVGrvl0cDjA8iBZv4vv1gyzlmK0ZUKqwpOyQMKzZQe3lTit77A==", + "dependencies": { + "gaxios": "^6.1.1", + "google-logging-utils": "^0.0.2", + "json-bigint": "^1.0.0" }, "engines": { - "node": ">=12" + "node": ">=14" } }, "node_modules/get-caller-file": { @@ -1356,15 +1216,20 @@ } }, "node_modules/get-intrinsic": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", - "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", "function-bind": "^1.1.2", - "has-proto": "^1.0.1", - "has-symbols": "^1.0.3", - "hasown": "^2.0.0" + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" }, "engines": { "node": ">= 0.4" @@ -1373,152 +1238,99 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/glob": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", - "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", - "optional": true, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^5.0.1", - "once": "^1.3.0" + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" }, "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" + "node": ">= 0.4" } }, "node_modules/google-auth-library": { - "version": "8.9.0", - "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-8.9.0.tgz", - "integrity": "sha512-f7aQCJODJFmYWN6PeNKzgvy9LI2tYmXnzpNDHEjG5sDNPgGb2FXQyTBnXeSH+PAtpKESFD+LmHw3Ox3mN7e1Fg==", - "optional": true, + "version": "9.15.1", + "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-9.15.1.tgz", + "integrity": "sha512-Jb6Z0+nvECVz+2lzSMt9u98UsoakXxA2HGHMCxh+so3n90XgYWkq5dur19JAJV7ONiJY22yBTyJB1TSkvPq9Ng==", "dependencies": { - "arrify": "^2.0.0", "base64-js": "^1.3.0", "ecdsa-sig-formatter": "^1.0.11", - "fast-text-encoding": "^1.0.0", - "gaxios": "^5.0.0", - "gcp-metadata": "^5.3.0", - "gtoken": "^6.1.0", - "jws": "^4.0.0", - "lru-cache": "^6.0.0" + "gaxios": "^6.1.1", + "gcp-metadata": "^6.1.0", + "gtoken": "^7.0.0", + "jws": "^4.0.0" }, "engines": { - "node": ">=12" + "node": ">=14" } }, "node_modules/google-gax": { - "version": "3.6.1", - "resolved": "https://registry.npmjs.org/google-gax/-/google-gax-3.6.1.tgz", - "integrity": "sha512-g/lcUjGcB6DSw2HxgEmCDOrI/CByOwqRvsuUvNalHUK2iPPPlmAIpbMbl62u0YufGMr8zgE3JL7th6dCb1Ry+w==", + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/google-gax/-/google-gax-4.4.1.tgz", + "integrity": "sha512-Phyp9fMfA00J3sZbJxbbB4jC55b7DBjE3F6poyL3wKMEBVKA79q6BGuHcTiM28yOzVql0NDbRL8MLLh8Iwk9Dg==", "optional": true, "dependencies": { - "@grpc/grpc-js": "~1.8.0", - "@grpc/proto-loader": "^0.7.0", + "@grpc/grpc-js": "^1.10.9", + "@grpc/proto-loader": "^0.7.13", "@types/long": "^4.0.0", - "@types/rimraf": "^3.0.2", "abort-controller": "^3.0.0", "duplexify": "^4.0.0", - "fast-text-encoding": "^1.0.3", - "google-auth-library": "^8.0.2", - "is-stream-ended": "^0.1.4", - "node-fetch": "^2.6.1", + "google-auth-library": "^9.3.0", + "node-fetch": "^2.7.0", "object-hash": "^3.0.0", - "proto3-json-serializer": "^1.0.0", - "protobufjs": "7.2.4", - "protobufjs-cli": "1.1.1", - "retry-request": "^5.0.0" - }, - "bin": { - "compileProtos": "build/tools/compileProtos.js", - "minifyProtoJson": "build/tools/minify.js" + "proto3-json-serializer": "^2.0.2", + "protobufjs": "^7.3.2", + "retry-request": "^7.0.0", + "uuid": "^9.0.1" }, "engines": { - "node": ">=12" + "node": ">=14" } }, - "node_modules/google-gax/node_modules/protobufjs": { - "version": "7.2.4", - "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.2.4.tgz", - "integrity": "sha512-AT+RJgD2sH8phPmCf7OUZR8xGdcJRga4+1cOaXJ64hvcSkVhNcRHOwIxUatPH15+nj59WAGTDv3LSGZPEQbJaQ==", - "hasInstallScript": true, + "node_modules/google-gax/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" + ], "optional": true, - "dependencies": { - "@protobufjs/aspromise": "^1.1.2", - "@protobufjs/base64": "^1.1.2", - "@protobufjs/codegen": "^2.0.4", - "@protobufjs/eventemitter": "^1.1.0", - "@protobufjs/fetch": "^1.1.0", - "@protobufjs/float": "^1.0.2", - "@protobufjs/inquire": "^1.1.0", - "@protobufjs/path": "^1.1.2", - "@protobufjs/pool": "^1.1.0", - "@protobufjs/utf8": "^1.1.0", - "@types/node": ">=13.7.0", - "long": "^5.0.0" - }, - "engines": { - "node": ">=12.0.0" + "bin": { + "uuid": "dist/bin/uuid" } }, - "node_modules/google-p12-pem": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/google-p12-pem/-/google-p12-pem-4.0.1.tgz", - "integrity": "sha512-WPkN4yGtz05WZ5EhtlxNDWPhC4JIic6G8ePitwUWy4l+XPVYec+a0j0Ts47PDtW59y3RwAhUd9/h9ZZ63px6RQ==", - "optional": true, - "dependencies": { - "node-forge": "^1.3.1" - }, - "bin": { - "gp12-pem": "build/src/bin/gp12-pem.js" - }, + "node_modules/google-logging-utils": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/google-logging-utils/-/google-logging-utils-0.0.2.tgz", + "integrity": "sha512-NEgUnEcBiP5HrPzufUkBzJOD/Sxsco3rLNo1F1TNf7ieU8ryUzBhqba8r756CjLX7rn3fHl6iLEwPYuqpoKgQQ==", "engines": { - "node": ">=12.0.0" + "node": ">=14" } }, "node_modules/gopd": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", - "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", - "dependencies": { - "get-intrinsic": "^1.1.3" + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/graceful-fs": { - "version": "4.2.11", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", - "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", - "optional": true - }, "node_modules/gtoken": { - "version": "6.1.2", - "resolved": "https://registry.npmjs.org/gtoken/-/gtoken-6.1.2.tgz", - "integrity": "sha512-4ccGpzz7YAr7lxrT2neugmXQ3hP9ho2gcaityLVkiUecAiwiy60Ii8gRbZeOsXV19fYaRjgBSshs8kXw+NKCPQ==", - "optional": true, + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/gtoken/-/gtoken-7.1.0.tgz", + "integrity": "sha512-pCcEwRi+TKpMlxAQObHDQ56KawURgyAf6jtIY046fJ5tIv3zDe/LEIubckAO8fj6JnAxLdmWkUfNyulQ2iKdEw==", "dependencies": { - "gaxios": "^5.0.1", - "google-p12-pem": "^4.0.0", + "gaxios": "^6.0.0", "jws": "^4.0.0" }, "engines": { - "node": ">=12.0.0" - } - }, - "node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "optional": true, - "engines": { - "node": ">=8" + "node": ">=14.0.0" } }, "node_modules/has-property-descriptors": { @@ -1532,10 +1344,10 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/has-proto": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz", - "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==", + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", "engines": { "node": ">= 0.4" }, @@ -1543,10 +1355,14 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/has-symbols": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", - "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "optional": true, + "dependencies": { + "has-symbols": "^1.0.3" + }, "engines": { "node": ">= 0.4" }, @@ -1565,6 +1381,22 @@ "node": ">= 0.4" } }, + "node_modules/html-entities": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-2.6.0.tgz", + "integrity": "sha512-kig+rMn/QOVRvr7c86gQ8lWXq+Hkv6CbAH1hLu+RG338StTpE8Z0b44SDVaqVu7HGKf27frdmUYEs9hTUX/cLQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/mdevils" + }, + { + "type": "patreon", + "url": "https://patreon.com/mdevils" + } + ], + "optional": true + }, "node_modules/http-errors": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", @@ -1581,9 +1413,9 @@ } }, "node_modules/http-parser-js": { - "version": "0.5.8", - "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.8.tgz", - "integrity": "sha512-SGeBX54F94Wgu5RH3X5jsDtf4eHyRogWX1XGT3b4HuW3tQPM4AaBzoUji/4AAJNXCEOWZ5O0DgZmJw1947gD5Q==" + "version": "0.5.9", + "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.9.tgz", + "integrity": "sha512-n1XsPy3rXVxlqxVioEWdC+0+M+SQw0DpJynwtOPo1X+ZlvdzTLtDBIJJlDQTnwZIFJrZSzSGmIOUdP8tu+SgLw==" }, "node_modules/http-proxy-agent": { "version": "5.0.0", @@ -1599,17 +1431,28 @@ "node": ">= 6" } }, - "node_modules/https-proxy-agent": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", - "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", + "node_modules/http-proxy-agent/node_modules/agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", "optional": true, "dependencies": { - "agent-base": "6", "debug": "4" }, "engines": { - "node": ">= 6" + "node": ">= 6.0.0" + } + }, + "node_modules/https-proxy-agent": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", + "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", + "dependencies": { + "agent-base": "^7.1.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" } }, "node_modules/iconv-lite": { @@ -1623,16 +1466,6 @@ "node": ">=0.10.0" } }, - "node_modules/inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "optional": true, - "dependencies": { - "once": "^1.3.0", - "wrappy": "1" - } - }, "node_modules/inherits": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", @@ -1659,7 +1492,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", - "optional": true, "engines": { "node": ">=8" }, @@ -1667,63 +1499,18 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/is-stream-ended": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/is-stream-ended/-/is-stream-ended-0.1.4.tgz", - "integrity": "sha512-xj0XPvmr7bQFTvirqnFr50o0hQIh6ZItDqloxt5aJrR4NQsYeSsyFQERYGCAzfindAcnKjINnwEEgLx4IqVzQw==", - "optional": true - }, "node_modules/jose": { - "version": "4.15.5", - "resolved": "https://registry.npmjs.org/jose/-/jose-4.15.5.tgz", - "integrity": "sha512-jc7BFxgKPKi94uOvEmzlSWFFe2+vASyXaKUpdQKatWAESU2MWjDfFf0fdfc83CDKcA5QecabZeNLyfhe3yKNkg==", + "version": "4.15.9", + "resolved": "https://registry.npmjs.org/jose/-/jose-4.15.9.tgz", + "integrity": "sha512-1vUQX+IdDMVPj4k8kOxgUqlcK518yluMuGZwqlr44FS1ppZB/5GWh4rZG89erpOBOJjU/OBsnCVFfapsRz6nEA==", "funding": { "url": "https://github.com/sponsors/panva" } }, - "node_modules/js2xmlparser": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/js2xmlparser/-/js2xmlparser-4.0.2.tgz", - "integrity": "sha512-6n4D8gLlLf1n5mNLQPRfViYzu9RATblzPEtm1SthMX1Pjao0r9YI9nw7ZIfRxQMERS87mcswrg+r/OYrPRX6jA==", - "optional": true, - "dependencies": { - "xmlcreate": "^2.0.4" - } - }, - "node_modules/jsdoc": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/jsdoc/-/jsdoc-4.0.2.tgz", - "integrity": "sha512-e8cIg2z62InH7azBBi3EsSEqrKx+nUtAS5bBcYTSpZFA+vhNPyhv8PTFZ0WsjOPDj04/dOLlm08EDcQJDqaGQg==", - "optional": true, - "dependencies": { - "@babel/parser": "^7.20.15", - "@jsdoc/salty": "^0.2.1", - "@types/markdown-it": "^12.2.3", - "bluebird": "^3.7.2", - "catharsis": "^0.9.0", - "escape-string-regexp": "^2.0.0", - "js2xmlparser": "^4.0.2", - "klaw": "^3.0.0", - "markdown-it": "^12.3.2", - "markdown-it-anchor": "^8.4.1", - "marked": "^4.0.10", - "mkdirp": "^1.0.4", - "requizzle": "^0.2.3", - "strip-json-comments": "^3.1.0", - "underscore": "~1.13.2" - }, - "bin": { - "jsdoc": "jsdoc.js" - }, - "engines": { - "node": ">=12.0.0" - } - }, "node_modules/json-bigint": { "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==", - "optional": true, "dependencies": { "bignumber.js": "^9.0.0" } @@ -1766,7 +1553,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/jwa/-/jwa-2.0.0.tgz", "integrity": "sha512-jrZ2Qx916EA+fq9cEAeCROWPTfCwi1IVHqT2tapuqLEVVDKFDENFw1oL+MwrTvH6msKxsd1YTDVw6uKEcsrLEA==", - "optional": true, "dependencies": { "buffer-equal-constant-time": "1.0.1", "ecdsa-sig-formatter": "1.0.11", @@ -1774,78 +1560,35 @@ } }, "node_modules/jwks-rsa": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/jwks-rsa/-/jwks-rsa-3.0.1.tgz", - "integrity": "sha512-UUOZ0CVReK1QVU3rbi9bC7N5/le8ziUj0A2ef1Q0M7OPD2KvjEYizptqIxGIo6fSLYDkqBrazILS18tYuRc8gw==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/jwks-rsa/-/jwks-rsa-3.2.0.tgz", + "integrity": "sha512-PwchfHcQK/5PSydeKCs1ylNym0w/SSv8a62DgHJ//7x2ZclCoinlsjAfDxAAbpoTPybOum/Jgy+vkvMmKz89Ww==", "dependencies": { - "@types/express": "^4.17.14", - "@types/jsonwebtoken": "^9.0.0", + "@types/express": "^4.17.20", + "@types/jsonwebtoken": "^9.0.4", "debug": "^4.3.4", - "jose": "^4.10.4", + "jose": "^4.15.4", "limiter": "^1.1.5", - "lru-memoizer": "^2.1.4" + "lru-memoizer": "^2.2.0" }, "engines": { "node": ">=14" } }, - "node_modules/jwks-rsa/node_modules/@types/express": { - "version": "4.17.17", - "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.17.tgz", - "integrity": "sha512-Q4FmmuLGBG58btUnfS1c1r/NQdlp3DMfGDGig8WhfpA2YRUtEkxAjkZb0yvplJGYdF1fsQ81iMDcH24sSCNC/Q==", - "dependencies": { - "@types/body-parser": "*", - "@types/express-serve-static-core": "^4.17.33", - "@types/qs": "*", - "@types/serve-static": "*" - } - }, "node_modules/jws": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/jws/-/jws-4.0.0.tgz", "integrity": "sha512-KDncfTmOZoOMTFG4mBlG0qUIOlc03fmzH+ru6RgYVZhPkyiy/92Owlt/8UEN+a4TXR1FQetfIpJE8ApdvdVxTg==", - "optional": true, "dependencies": { "jwa": "^2.0.0", "safe-buffer": "^5.0.1" } }, - "node_modules/klaw": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/klaw/-/klaw-3.0.0.tgz", - "integrity": "sha512-0Fo5oir+O9jnXu5EefYbVK+mHMBeEVEy2cmctR1O1NECcCkPRreJKrS6Qt/j3KC2C148Dfo9i3pCmCMsdqGr0g==", - "optional": true, - "dependencies": { - "graceful-fs": "^4.1.9" - } - }, - "node_modules/levn": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", - "integrity": "sha512-0OO4y2iOHix2W6ujICbKIaEQXvFQHue65vUG3pb5EUomzPI90z9hsA1VsO/dbIIpC53J8gxM9Q4Oho0jrCM/yA==", - "optional": true, - "dependencies": { - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2" - }, - "engines": { - "node": ">= 0.8.0" - } - }, "node_modules/limiter": { "version": "1.1.5", "resolved": "https://registry.npmjs.org/limiter/-/limiter-1.1.5.tgz", "integrity": "sha512-FWWMIEOxz3GwUI4Ts/IvgVy6LPvoMPgjMdQ185nN6psJyBJ4yOpzqm695/h5umdLJg2vW3GR5iG11MAkR2AzJA==" }, - "node_modules/linkify-it": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-3.0.3.tgz", - "integrity": "sha512-ynTsyrFSdE5oZ/O9GEf00kPngmOfVwazR5GKDq6EYfhlpFug3J2zybX56a2PRRpc9P+FuSoGNAwjlbDs9jJBPQ==", - "optional": true, - "dependencies": { - "uc.micro": "^1.0.1" - } - }, "node_modules/lodash": { "version": "4.17.21", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", @@ -1879,72 +1622,22 @@ } }, "node_modules/lru-memoizer": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/lru-memoizer/-/lru-memoizer-2.2.0.tgz", - "integrity": "sha512-QfOZ6jNkxCcM/BkIPnFsqDhtrazLRsghi9mBwFAzol5GCvj4EkFT899Za3+QwikCg5sRX8JstioBDwOxEyzaNw==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/lru-memoizer/-/lru-memoizer-2.3.0.tgz", + "integrity": "sha512-GXn7gyHAMhO13WSKrIiNfztwxodVsP8IoZ3XfrJV4yH2x0/OeTO/FIaAHTY5YekdGgW94njfuKmyyt1E0mR6Ug==", "dependencies": { "lodash.clonedeep": "^4.5.0", - "lru-cache": "~4.0.0" + "lru-cache": "6.0.0" } }, - "node_modules/lru-memoizer/node_modules/lru-cache": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.0.2.tgz", - "integrity": "sha512-uQw9OqphAGiZhkuPlpFGmdTU2tEuhxTourM/19qGJrxBPHAr/f8BT1a0i/lOclESnGatdJG/UCkP9kZB/Lh1iw==", - "dependencies": { - "pseudomap": "^1.0.1", - "yallist": "^2.0.0" - } - }, - "node_modules/lru-memoizer/node_modules/yallist": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", - "integrity": "sha512-ncTzHV7NvsQZkYe1DW7cbDLm0YpzHmZF5r/iyP3ZnQtMiJ+pjzisCiMNI+Sj+xQF5pXhSHxSB3uDbsBTzY/c2A==" - }, - "node_modules/markdown-it": { - "version": "12.3.2", - "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-12.3.2.tgz", - "integrity": "sha512-TchMembfxfNVpHkbtriWltGWc+m3xszaRD0CZup7GFFhzIgQqxIfn3eGj1yZpfuflzPvfkt611B2Q/Bsk1YnGg==", - "optional": true, - "dependencies": { - "argparse": "^2.0.1", - "entities": "~2.1.0", - "linkify-it": "^3.0.1", - "mdurl": "^1.0.1", - "uc.micro": "^1.0.5" - }, - "bin": { - "markdown-it": "bin/markdown-it.js" - } - }, - "node_modules/markdown-it-anchor": { - "version": "8.6.7", - "resolved": "https://registry.npmjs.org/markdown-it-anchor/-/markdown-it-anchor-8.6.7.tgz", - "integrity": "sha512-FlCHFwNnutLgVTflOYHPW2pPcl2AACqVzExlkGQNsi4CJgqOHN7YTgDd4LuhgN1BFO3TS0vLAruV1Td6dwWPJA==", - "optional": true, - "peerDependencies": { - "@types/markdown-it": "*", - "markdown-it": "*" - } - }, - "node_modules/marked": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/marked/-/marked-4.3.0.tgz", - "integrity": "sha512-PRsaiG84bK+AMvxziE/lCFss8juXjNaWzVbN5tXAm4XjeaS9NAHhop+PjQxz2A9h8Q4M/xGmzP8vqNwy6JeK0A==", - "optional": true, - "bin": { - "marked": "bin/marked.js" - }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", "engines": { - "node": ">= 12" + "node": ">= 0.4" } }, - "node_modules/mdurl": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz", - "integrity": "sha512-/sKlQJCBYVY9Ers9hqzKou4H6V5UWc/M59TH2dvkt+84itfnq7uFOMLpOiOS4ujvHP4etln18fmIxA5R5fll0g==", - "optional": true - }, "node_modules/media-typer": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", @@ -2000,43 +1693,10 @@ "node": ">= 0.6" } }, - "node_modules/minimatch": { - "version": "5.1.6", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", - "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", - "optional": true, - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/minimist": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", - "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", - "optional": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/mkdirp": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", - "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", - "optional": true, - "bin": { - "mkdirp": "bin/cmd.js" - }, - "engines": { - "node": ">=10" - } - }, "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==" + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" }, "node_modules/negotiator": { "version": "0.6.3", @@ -2121,23 +1781,6 @@ "wrappy": "1" } }, - "node_modules/optionator": { - "version": "0.8.3", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", - "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", - "optional": true, - "dependencies": { - "deep-is": "~0.1.3", - "fast-levenshtein": "~2.0.6", - "levn": "~0.3.0", - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2", - "word-wrap": "~1.2.3" - }, - "engines": { - "node": ">= 0.8.0" - } - }, "node_modules/p-limit": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", @@ -2161,45 +1804,27 @@ "node": ">= 0.8" } }, - "node_modules/path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", - "optional": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/path-to-regexp": { "version": "0.1.12", "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.12.tgz", "integrity": "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==" }, - "node_modules/prelude-ls": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", - "integrity": "sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w==", - "optional": true, - "engines": { - "node": ">= 0.8.0" - } - }, "node_modules/proto3-json-serializer": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/proto3-json-serializer/-/proto3-json-serializer-1.1.1.tgz", - "integrity": "sha512-AwAuY4g9nxx0u52DnSMkqqgyLHaW/XaPLtaAo3y/ZCfeaQB/g4YDH4kb8Wc/mWzWvu0YjOznVnfn373MVZZrgw==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/proto3-json-serializer/-/proto3-json-serializer-2.0.2.tgz", + "integrity": "sha512-SAzp/O4Yh02jGdRc+uIrGoe87dkN/XtwxfZ4ZyafJHymd79ozp5VG5nyZ7ygqPM5+cpLDjjGnYFUkngonyDPOQ==", "optional": true, "dependencies": { - "protobufjs": "^7.0.0" + "protobufjs": "^7.2.5" }, "engines": { - "node": ">=12.0.0" + "node": ">=14.0.0" } }, "node_modules/protobufjs": { - "version": "7.2.5", - "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.2.5.tgz", - "integrity": "sha512-gGXRSXvxQ7UiPgfw8gevrfRWcTlSbOFg+p/N+JVJEK5VhueL2miT6qTymqAmjr1Q5WbOCyJbyrk6JfWKwlFn6A==", + "version": "7.4.0", + "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.4.0.tgz", + "integrity": "sha512-mRUWCc3KUU4w1jU8sGxICXH/gNS94DvI1gxqDvBzhj1JpcsimQkYiOJfwsPUykUI5ZaspFbSgmBLER8IrQ3tqw==", "hasInstallScript": true, "dependencies": { "@protobufjs/aspromise": "^1.1.2", @@ -2219,34 +1844,6 @@ "node": ">=12.0.0" } }, - "node_modules/protobufjs-cli": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/protobufjs-cli/-/protobufjs-cli-1.1.1.tgz", - "integrity": "sha512-VPWMgIcRNyQwWUv8OLPyGQ/0lQY/QTQAVN5fh+XzfDwsVw1FZ2L3DM/bcBf8WPiRz2tNpaov9lPZfNcmNo6LXA==", - "optional": true, - "dependencies": { - "chalk": "^4.0.0", - "escodegen": "^1.13.0", - "espree": "^9.0.0", - "estraverse": "^5.1.0", - "glob": "^8.0.0", - "jsdoc": "^4.0.0", - "minimist": "^1.2.0", - "semver": "^7.1.2", - "tmp": "^0.2.1", - "uglify-js": "^3.7.7" - }, - "bin": { - "pbjs": "bin/pbjs", - "pbts": "bin/pbts" - }, - "engines": { - "node": ">=12.0.0" - }, - "peerDependencies": { - "protobufjs": "^7.0.0" - } - }, "node_modules/proxy-addr": { "version": "2.0.7", "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", @@ -2259,11 +1856,6 @@ "node": ">= 0.10" } }, - "node_modules/pseudomap": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", - "integrity": "sha512-b/YwNhb8lk1Zz2+bXXpS/LK9OisiZZ1SNsSLxN1x2OXVEhW2Ckr/7mWE5vrC1ZTiJlD9g19jWszTmJsB+oEpFQ==" - }, "node_modules/qs": { "version": "6.13.0", "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz", @@ -2305,110 +1897,45 @@ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", "optional": true, - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", - "optional": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/requizzle": { - "version": "0.2.4", - "resolved": "https://registry.npmjs.org/requizzle/-/requizzle-0.2.4.tgz", - "integrity": "sha512-JRrFk1D4OQ4SqovXOgdav+K8EAhSB/LJZqCz8tbX0KObcdeM15Ss59ozWMBWmmINMagCwmqn4ZNryUGpBsl6Jw==", - "optional": true, - "dependencies": { - "lodash": "^4.17.21" - } - }, - "node_modules/retry": { - "version": "0.13.1", - "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz", - "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==", - "optional": true, - "engines": { - "node": ">= 4" - } - }, - "node_modules/retry-request": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/retry-request/-/retry-request-5.0.2.tgz", - "integrity": "sha512-wfI3pk7EE80lCIXprqh7ym48IHYdwmAAzESdbU8Q9l7pnRCk9LEhpbOTNKjz6FARLm/Bl5m+4F0ABxOkYUujSQ==", - "optional": true, - "dependencies": { - "debug": "^4.1.1", - "extend": "^3.0.2" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "optional": true, - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" }, - "funding": { - "url": "https://github.com/sponsors/isaacs" + "engines": { + "node": ">= 6" } }, - "node_modules/rimraf/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==", + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", "optional": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "engines": { + "node": ">=0.10.0" } }, - "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==", + "node_modules/retry": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz", + "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==", "optional": true, - "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": ">= 4" } }, - "node_modules/rimraf/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/retry-request": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/retry-request/-/retry-request-7.0.2.tgz", + "integrity": "sha512-dUOvLMJ0/JJYEn8NrpOaGNE7X3vpI5XlZS/u0ANjqtcZVKnIxP7IgCFwrKTxENw29emmwug53awKtaMm4i9g5w==", "optional": true, "dependencies": { - "brace-expansion": "^1.1.7" + "@types/request": "^2.48.8", + "extend": "^3.0.2", + "teeny-request": "^9.0.0" }, "engines": { - "node": "*" + "node": ">=14" } }, "node_modules/safe-buffer": { @@ -2482,11 +2009,6 @@ "node": ">=4" } }, - "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/serve-static": { "version": "1.16.2", "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.2.tgz", @@ -2547,15 +2069,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "optional": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/statuses": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", @@ -2574,9 +2087,9 @@ } }, "node_modules/stream-shift": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.1.tgz", - "integrity": "sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.3.tgz", + "integrity": "sha512-76ORR0DO1o1hlKwTbi/DM3EXWGf3ZJYO8cXX5RJwnul2DEg2oyoZyjLNoQM8WsvZiFKCRfC1O0J7iCvie3RZmQ==", "optional": true }, "node_modules/string_decoder": { @@ -2614,22 +2127,16 @@ "node": ">=8" } }, - "node_modules/strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "optional": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/strnum": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/strnum/-/strnum-1.0.5.tgz", - "integrity": "sha512-J8bbNyKKXl5qYcR36TIO8W3mVGVHrmmxsd5PAItGkmyzwJvybiw2IVq5nqd0i4LSNSkB/sx9VHllbfFdr9k1JA==", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/strnum/-/strnum-1.1.2.tgz", + "integrity": "sha512-vrN+B7DBIoTTZjnPNewwhx6cBA/H+IS7rfW68n7XxC1y7uoiGQBxaKzqucGUgavX15dJgiGztLJ8vxuEzwqBdA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/NaturalIntelligence" + } + ], "optional": true }, "node_modules/stubs": { @@ -2638,49 +2145,58 @@ "integrity": "sha512-PdHt7hHUJKxvTCgbKX9C1V/ftOcjJQgz8BZwNfV5c4B6dcGqlpelTbJ999jBGZ2jYiPAwcX5dP6oBwVlBlUbxw==", "optional": true }, - "node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "optional": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/teeny-request": { - "version": "8.0.3", - "resolved": "https://registry.npmjs.org/teeny-request/-/teeny-request-8.0.3.tgz", - "integrity": "sha512-jJZpA5He2y52yUhA7pyAGZlgQpcB+xLjcN0eUFxr9c8hP/H7uOXbBNVo/O0C/xVfJLJs680jvkFgVJEEvk9+ww==", + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/teeny-request/-/teeny-request-9.0.0.tgz", + "integrity": "sha512-resvxdc6Mgb7YEThw6G6bExlXKkv6+YbuzGg9xuXxSgxJF7Ozs+o8Y9+2R3sArdWdW8nOokoQb1yrpFB0pQK2g==", "optional": true, "dependencies": { "http-proxy-agent": "^5.0.0", "https-proxy-agent": "^5.0.0", - "node-fetch": "^2.6.1", + "node-fetch": "^2.6.9", "stream-events": "^1.0.5", "uuid": "^9.0.0" }, "engines": { - "node": ">=12" + "node": ">=14" } }, - "node_modules/text-decoding": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/text-decoding/-/text-decoding-1.0.0.tgz", - "integrity": "sha512-/0TJD42KDnVwKmDK6jj3xP7E2MG7SHAOG4tyTgyUCRPdHwvkquYNLEQltmdMa3owq3TkddCVcTsoctJI8VQNKA==" + "node_modules/teeny-request/node_modules/agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "optional": true, + "dependencies": { + "debug": "4" + }, + "engines": { + "node": ">= 6.0.0" + } }, - "node_modules/tmp": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.1.tgz", - "integrity": "sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ==", + "node_modules/teeny-request/node_modules/https-proxy-agent": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", + "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", "optional": true, "dependencies": { - "rimraf": "^3.0.0" + "agent-base": "6", + "debug": "4" }, "engines": { - "node": ">=8.17.0" + "node": ">= 6" + } + }, + "node_modules/teeny-request/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" + ], + "optional": true, + "bin": { + "uuid": "dist/bin/uuid" } }, "node_modules/toidentifier": { @@ -2697,21 +2213,9 @@ "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" }, "node_modules/tslib": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", - "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==" - }, - "node_modules/type-check": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", - "integrity": "sha512-ZCmOJdvOWDBYJlzAoFkC+Q0+bUyEOS1ltgp1MGU03fqHG+dbi9tBFU2Rd9QKiDZFAYrhPh2JUf7rZRIuHRKtOg==", - "optional": true, - "dependencies": { - "prelude-ls": "~1.1.2" - }, - "engines": { - "node": ">= 0.8.0" - } + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==" }, "node_modules/type-is": { "version": "1.6.18", @@ -2738,34 +2242,10 @@ "node": ">=4.2.0" } }, - "node_modules/uc.micro": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.6.tgz", - "integrity": "sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==", - "optional": true - }, - "node_modules/uglify-js": { - "version": "3.17.4", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.17.4.tgz", - "integrity": "sha512-T9q82TJI9e/C1TAxYvfb16xO120tMVFZrGA3f9/P4424DNu6ypK103y0GPFVa17yotwSyZW5iYXgjYHkGrJW/g==", - "optional": true, - "bin": { - "uglifyjs": "bin/uglifyjs" - }, - "engines": { - "node": ">=0.8.0" - } - }, - "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==", - "optional": true - }, "node_modules/undici-types": { - "version": "5.26.5", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", - "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==" + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", + "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==" }, "node_modules/unpipe": { "version": "1.0.0", @@ -2790,15 +2270,15 @@ } }, "node_modules/uuid": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", - "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==", + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-11.1.0.tgz", + "integrity": "sha512-0/A9rDy9P7cJ+8w1c9WD9V//9Wj15Ce2MPz8Ri6032usz+NfePxx5AcN3bN+r6ZL6jEo066/yNYB3tn4pQEx+A==", "funding": [ "https://github.com/sponsors/broofa", "https://github.com/sponsors/ctavan" ], "bin": { - "uuid": "dist/bin/uuid" + "uuid": "dist/esm/bin/uuid" } }, "node_modules/vary": { @@ -2844,15 +2324,6 @@ "webidl-conversions": "^3.0.0" } }, - "node_modules/word-wrap": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", - "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", - "optional": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/wrap-ansi": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", @@ -2876,12 +2347,6 @@ "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", "optional": true }, - "node_modules/xmlcreate": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/xmlcreate/-/xmlcreate-2.0.4.tgz", - "integrity": "sha512-nquOebG4sngPmGPICTS5EnxqhKbCmz5Ox5hsszI2T6U5qdrJizBc+0ilYSEjTSzU0yZcmvppztXe/5Al5fUwdg==", - "optional": true - }, "node_modules/y18n": { "version": "5.0.8", "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", @@ -2937,106 +2402,104 @@ } }, "dependencies": { - "@babel/parser": { - "version": "7.23.6", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.6.tgz", - "integrity": "sha512-Z2uID7YJ7oNvAI20O9X0bblw7Qqs8Q2hFy0R9tAfnfLkp5MW0UH9eUvnDSnFwKZ0AvgS1ucqR4KzvVHgnke1VQ==", - "optional": true - }, "@fastify/busboy": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@fastify/busboy/-/busboy-1.2.1.tgz", - "integrity": "sha512-7PQA7EH43S0CxcOa9OeAnaeA0oQ+e/DHNPZwSQM9CQHW76jle5+OvLdibRp/Aafs9KXbLhxyjOTkRjWUbQEd3Q==", - "requires": { - "text-decoding": "^1.0.0" - } + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@fastify/busboy/-/busboy-3.1.1.tgz", + "integrity": "sha512-5DGmA8FTdB2XbDeEwc/5ZXBl6UbBAyBOOLlPuBnZ/N1SwdH9Ii+cOX3tBROlDgcTXxjOYnLMVoKk9+FXAw0CJw==" + }, + "@firebase/app-check-interop-types": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@firebase/app-check-interop-types/-/app-check-interop-types-0.3.3.tgz", + "integrity": "sha512-gAlxfPLT2j8bTI/qfe3ahl2I2YcBQ8cFIBdhAQA4I2f3TndcO+22YizyGYuttLHPQEpWkhmpFW60VCFEPg4g5A==" }, "@firebase/app-types": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/@firebase/app-types/-/app-types-0.9.0.tgz", - "integrity": "sha512-AeweANOIo0Mb8GiYm3xhTEBVCmPwTYAu9Hcd2qSkLuga/6+j9b1Jskl5bpiSQWy9eJ/j5pavxj6eYogmnuzm+Q==" + "version": "0.9.3", + "resolved": "https://registry.npmjs.org/@firebase/app-types/-/app-types-0.9.3.tgz", + "integrity": "sha512-kRVpIl4vVGJ4baogMDINbyrIOtOxqhkZQg4jTq3l8Lw6WSk0xfpEYzezFu+Kl4ve4fbPl79dvwRtaFqAC/ucCw==" }, "@firebase/auth-interop-types": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/@firebase/auth-interop-types/-/auth-interop-types-0.2.1.tgz", - "integrity": "sha512-VOaGzKp65MY6P5FI84TfYKBXEPi6LmOCSMMzys6o2BN2LOsqy7pCuZCup7NYnfbk5OkkQKzvIfHOzTm0UDpkyg==" + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/@firebase/auth-interop-types/-/auth-interop-types-0.2.4.tgz", + "integrity": "sha512-JPgcXKCuO+CWqGDnigBtvo09HeBs5u/Ktc2GaFj2m01hLarbxthLNm7Fk8iOP1aqAtXV+fnnGj7U28xmk7IwVA==" }, "@firebase/component": { - "version": "0.6.4", - "resolved": "https://registry.npmjs.org/@firebase/component/-/component-0.6.4.tgz", - "integrity": "sha512-rLMyrXuO9jcAUCaQXCMjCMUsWrba5fzHlNK24xz5j2W6A/SRmK8mZJ/hn7V0fViLbxC0lPMtrK1eYzk6Fg03jA==", + "version": "0.6.13", + "resolved": "https://registry.npmjs.org/@firebase/component/-/component-0.6.13.tgz", + "integrity": "sha512-I/Eg1NpAtZ8AAfq8mpdfXnuUpcLxIDdCDtTzWSh+FXnp/9eCKJ3SNbOCKrUCyhLzNa2SiPJYruei0sxVjaOTeg==", "requires": { - "@firebase/util": "1.9.3", + "@firebase/util": "1.11.0", "tslib": "^2.1.0" } }, "@firebase/database": { - "version": "0.14.4", - "resolved": "https://registry.npmjs.org/@firebase/database/-/database-0.14.4.tgz", - "integrity": "sha512-+Ea/IKGwh42jwdjCyzTmeZeLM3oy1h0mFPsTy6OqCWzcu/KFqRAr5Tt1HRCOBlNOdbh84JPZC47WLU18n2VbxQ==", + "version": "1.0.14", + "resolved": "https://registry.npmjs.org/@firebase/database/-/database-1.0.14.tgz", + "integrity": "sha512-9nxYtkHAG02/Nh2Ssms1T4BbWPPjiwohCvkHDUl4hNxnki1kPgsLo5xe9kXNzbacOStmVys+RUXvwzynQSKmUQ==", "requires": { - "@firebase/auth-interop-types": "0.2.1", - "@firebase/component": "0.6.4", - "@firebase/logger": "0.4.0", - "@firebase/util": "1.9.3", + "@firebase/app-check-interop-types": "0.3.3", + "@firebase/auth-interop-types": "0.2.4", + "@firebase/component": "0.6.13", + "@firebase/logger": "0.4.4", + "@firebase/util": "1.11.0", "faye-websocket": "0.11.4", "tslib": "^2.1.0" } }, "@firebase/database-compat": { - "version": "0.3.4", - "resolved": "https://registry.npmjs.org/@firebase/database-compat/-/database-compat-0.3.4.tgz", - "integrity": "sha512-kuAW+l+sLMUKBThnvxvUZ+Q1ZrF/vFJ58iUY9kAcbX48U03nVzIF6Tmkf0p3WVQwMqiXguSgtOPIB6ZCeF+5Gg==", + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@firebase/database-compat/-/database-compat-2.0.5.tgz", + "integrity": "sha512-CNf1UbvWh6qIaSf4sn6sx2DTDz/em/D7QxULH1LTxxDQHr9+CeYGvlAqrKnk4ZH0P0eIHyQFQU7RwkUJI0B9gQ==", "requires": { - "@firebase/component": "0.6.4", - "@firebase/database": "0.14.4", - "@firebase/database-types": "0.10.4", - "@firebase/logger": "0.4.0", - "@firebase/util": "1.9.3", + "@firebase/component": "0.6.13", + "@firebase/database": "1.0.14", + "@firebase/database-types": "1.0.10", + "@firebase/logger": "0.4.4", + "@firebase/util": "1.11.0", "tslib": "^2.1.0" } }, "@firebase/database-types": { - "version": "0.10.4", - "resolved": "https://registry.npmjs.org/@firebase/database-types/-/database-types-0.10.4.tgz", - "integrity": "sha512-dPySn0vJ/89ZeBac70T+2tWWPiJXWbmRygYv0smT5TfE3hDrQ09eKMF3Y+vMlTdrMWq7mUdYW5REWPSGH4kAZQ==", + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/@firebase/database-types/-/database-types-1.0.10.tgz", + "integrity": "sha512-mH6RC1E9/Pv8jf1/p+M8YFTX+iu+iHDN89hecvyO7wHrI4R1V0TXjxOHvX3nLJN1sfh0CWG6CHZ0VlrSmK/cwg==", "requires": { - "@firebase/app-types": "0.9.0", - "@firebase/util": "1.9.3" + "@firebase/app-types": "0.9.3", + "@firebase/util": "1.11.0" } }, "@firebase/logger": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/@firebase/logger/-/logger-0.4.0.tgz", - "integrity": "sha512-eRKSeykumZ5+cJPdxxJRgAC3G5NknY2GwEbKfymdnXtnT0Ucm4pspfR6GT4MUQEDuJwRVbVcSx85kgJulMoFFA==", + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/@firebase/logger/-/logger-0.4.4.tgz", + "integrity": "sha512-mH0PEh1zoXGnaR8gD1DeGeNZtWFKbnz9hDO91dIml3iou1gpOnLqXQ2dJfB71dj6dpmUjcQ6phY3ZZJbjErr9g==", "requires": { "tslib": "^2.1.0" } }, "@firebase/util": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/@firebase/util/-/util-1.9.3.tgz", - "integrity": "sha512-DY02CRhOZwpzO36fHpuVysz6JZrscPiBXD0fXp6qSrL9oNOx5KWICKdR95C0lSITzxp0TZosVyHqzatE8JbcjA==", + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/@firebase/util/-/util-1.11.0.tgz", + "integrity": "sha512-PzSrhIr++KI6y4P6C/IdgBNMkEx0Ex6554/cYd0Hm+ovyFSJtJXqb/3OSIdnBoa2cpwZT1/GW56EmRc5qEc5fQ==", "requires": { "tslib": "^2.1.0" } }, "@google-cloud/firestore": { - "version": "6.8.0", - "resolved": "https://registry.npmjs.org/@google-cloud/firestore/-/firestore-6.8.0.tgz", - "integrity": "sha512-JRpk06SmZXLGz0pNx1x7yU3YhkUXheKgH5hbDZ4kMsdhtfV5qPLJLRI4wv69K0cZorIk+zTMOwptue7hizo0eA==", + "version": "7.11.0", + "resolved": "https://registry.npmjs.org/@google-cloud/firestore/-/firestore-7.11.0.tgz", + "integrity": "sha512-88uZ+jLsp1aVMj7gh3EKYH1aulTAMFAp8sH/v5a9w8q8iqSG27RiWLoxSAFr/XocZ9hGiWH1kEnBw+zl3xAgNA==", "optional": true, "requires": { + "@opentelemetry/api": "^1.3.0", "fast-deep-equal": "^3.1.1", "functional-red-black-tree": "^1.0.1", - "google-gax": "^3.5.7", - "protobufjs": "^7.2.5" + "google-gax": "^4.3.3", + "protobufjs": "^7.2.6" } }, "@google-cloud/paginator": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/@google-cloud/paginator/-/paginator-3.0.7.tgz", - "integrity": "sha512-jJNutk0arIQhmpUUQJPJErsojqo834KcyB6X7a1mxuic8i1tKXxde8E69IZxNZawRIlZdIK2QY4WALvlK5MzYQ==", + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/@google-cloud/paginator/-/paginator-5.0.2.tgz", + "integrity": "sha512-DJS3s0OVH4zFDB1PzjxAsHqJT6sKVbRwwML0ZBP9PbU7Yebtu/7SWMRzvO2J3nUi9pRNITCfu4LJeooM2w4pjg==", "optional": true, "requires": { "arrify": "^2.0.0", @@ -3044,40 +2507,37 @@ } }, "@google-cloud/projectify": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@google-cloud/projectify/-/projectify-3.0.0.tgz", - "integrity": "sha512-HRkZsNmjScY6Li8/kb70wjGlDDyLkVk3KvoEo9uIoxSjYLJasGiCch9+PqRVDOCGUFvEIqyogl+BeqILL4OJHA==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@google-cloud/projectify/-/projectify-4.0.0.tgz", + "integrity": "sha512-MmaX6HeSvyPbWGwFq7mXdo0uQZLGBYCwziiLIGq5JVX+/bdI3SAq6bP98trV5eTWfLuvsMcIC1YJOF2vfteLFA==", "optional": true }, "@google-cloud/promisify": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@google-cloud/promisify/-/promisify-3.0.1.tgz", - "integrity": "sha512-z1CjRjtQyBOYL+5Qr9DdYIfrdLBe746jRTYfaYU6MeXkqp7UfYs/jX16lFFVzZ7PGEJvqZNqYUEtb1mvDww4pA==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@google-cloud/promisify/-/promisify-4.0.0.tgz", + "integrity": "sha512-Orxzlfb9c67A15cq2JQEyVc7wEsmFBmHjZWZYQMUyJ1qivXyMwdyNOs9odi79hze+2zqdTtu1E19IM/FtqZ10g==", "optional": true }, "@google-cloud/storage": { - "version": "6.12.0", - "resolved": "https://registry.npmjs.org/@google-cloud/storage/-/storage-6.12.0.tgz", - "integrity": "sha512-78nNAY7iiZ4O/BouWMWTD/oSF2YtYgYB3GZirn0To6eBOugjXVoK+GXgUXOl+HlqbAOyHxAVXOlsj3snfbQ1dw==", + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/@google-cloud/storage/-/storage-7.16.0.tgz", + "integrity": "sha512-7/5LRgykyOfQENcm6hDKP8SX/u9XxE5YOiWOkgkwcoO+cG8xT/cyOvp9wwN3IxfdYgpHs8CE7Nq2PKX2lNaEXw==", "optional": true, "requires": { - "@google-cloud/paginator": "^3.0.7", - "@google-cloud/projectify": "^3.0.0", - "@google-cloud/promisify": "^3.0.0", + "@google-cloud/paginator": "^5.0.0", + "@google-cloud/projectify": "^4.0.0", + "@google-cloud/promisify": "<4.1.0", "abort-controller": "^3.0.0", "async-retry": "^1.3.3", - "compressible": "^2.0.12", - "duplexify": "^4.0.0", - "ent": "^2.2.0", - "extend": "^3.0.2", - "fast-xml-parser": "^4.2.2", - "gaxios": "^5.0.0", - "google-auth-library": "^8.0.1", + "duplexify": "^4.1.3", + "fast-xml-parser": "^4.4.1", + "gaxios": "^6.0.2", + "google-auth-library": "^9.6.3", + "html-entities": "^2.5.2", "mime": "^3.0.0", - "mime-types": "^2.0.8", "p-limit": "^3.0.1", - "retry-request": "^5.0.0", - "teeny-request": "^8.0.0", + "retry-request": "^7.0.0", + "teeny-request": "^9.0.0", "uuid": "^8.0.0" }, "dependencies": { @@ -3090,35 +2550,38 @@ } }, "@grpc/grpc-js": { - "version": "1.8.22", - "resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.8.22.tgz", - "integrity": "sha512-oAjDdN7fzbUi+4hZjKG96MR6KTEubAeMpQEb+77qy+3r0Ua5xTFuie6JOLr4ZZgl5g+W5/uRTS2M1V8mVAFPuA==", + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.13.2.tgz", + "integrity": "sha512-nnR5nmL6lxF8YBqb6gWvEgLdLh/Fn+kvAdX5hUOnt48sNSb0riz/93ASd2E5gvanPA41X6Yp25bIfGRp1SMb2g==", "optional": true, "requires": { - "@grpc/proto-loader": "^0.7.0", - "@types/node": ">=12.12.47" + "@grpc/proto-loader": "^0.7.13", + "@js-sdsl/ordered-map": "^4.4.2" } }, "@grpc/proto-loader": { - "version": "0.7.10", - "resolved": "https://registry.npmjs.org/@grpc/proto-loader/-/proto-loader-0.7.10.tgz", - "integrity": "sha512-CAqDfoaQ8ykFd9zqBDn4k6iWT9loLAlc2ETmDFS9JCD70gDcnA4L3AFEo2iV7KyAtAAHFW9ftq1Fz+Vsgq80RQ==", + "version": "0.7.13", + "resolved": "https://registry.npmjs.org/@grpc/proto-loader/-/proto-loader-0.7.13.tgz", + "integrity": "sha512-AiXO/bfe9bmxBjxxtYxFAXGZvMaN5s8kO+jBHAJCON8rJoB5YS/D6X7ZNc6XQkuHNmyl4CYaMI1fJ/Gn27RGGw==", "optional": true, "requires": { "lodash.camelcase": "^4.3.0", "long": "^5.0.0", - "protobufjs": "^7.2.4", + "protobufjs": "^7.2.5", "yargs": "^17.7.2" } }, - "@jsdoc/salty": { - "version": "0.2.7", - "resolved": "https://registry.npmjs.org/@jsdoc/salty/-/salty-0.2.7.tgz", - "integrity": "sha512-mh8LbS9d4Jq84KLw8pzho7XC2q2/IJGiJss3xwRoLD1A+EE16SjN4PfaG4jRCzKegTFLlN0Zd8SdUPE6XdoPFg==", - "optional": true, - "requires": { - "lodash": "^4.17.21" - } + "@js-sdsl/ordered-map": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/@js-sdsl/ordered-map/-/ordered-map-4.4.2.tgz", + "integrity": "sha512-iUKgm52T8HOE/makSxjqoWhe95ZJA1/G1sYsGev2JDKUSS14KAgg1LHb+Ba+IPow0xflbnSkOsZcO08C7w1gYw==", + "optional": true + }, + "@opentelemetry/api": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/api/-/api-1.9.0.tgz", + "integrity": "sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg==", + "optional": true }, "@protobufjs/aspromise": { "version": "1.1.2", @@ -3189,6 +2652,12 @@ "@types/node": "*" } }, + "@types/caseless": { + "version": "0.12.5", + "resolved": "https://registry.npmjs.org/@types/caseless/-/caseless-0.12.5.tgz", + "integrity": "sha512-hWtVTC2q7hc7xZ/RLbxapMvDMgUnDvKvMOpKal4DrMyfGBUfB1oKaZlIRr6mJL+If3bAP6sV/QneGzF6tJjZDg==", + "optional": true + }, "@types/connect": { "version": "3.4.33", "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.33.tgz", @@ -3203,12 +2672,13 @@ "integrity": "sha512-vt+kDhq/M2ayberEtJcIN/hxXy1Pk+59g2FV/ZQceeaTyCtCucjL2Q7FXlFjtWn4n15KCr1NE2lNNFhp0lEThw==" }, "@types/express": { - "version": "4.17.3", - "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.3.tgz", - "integrity": "sha512-I8cGRJj3pyOLs/HndoP+25vOqhqWkAZsWMEmq1qXy/b/M3ppufecUwaK2/TVDVxcV61/iSdhykUjQQ2DLSrTdg==", + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.21.tgz", + "integrity": "sha512-ejlPM315qwLpaQlQDTjPdsUFSc6ZsP4AN6AlWnogPjQ7CVi7PYF3YVz+CY3jE2pwYf7E/7HlDAN0rV2GxTG0HQ==", "requires": { "@types/body-parser": "*", - "@types/express-serve-static-core": "*", + "@types/express-serve-static-core": "^4.17.33", + "@types/qs": "*", "@types/serve-static": "*" } }, @@ -3222,30 +2692,15 @@ "@types/range-parser": "*" } }, - "@types/glob": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/@types/glob/-/glob-8.1.0.tgz", - "integrity": "sha512-IO+MJPVhoqz+28h1qLAcBEH2+xHMK6MTyHJc7MTnnYb6wsoLR29POVGJ7LycmVXIqyy/4/2ShP5sUwTXuOwb/w==", - "optional": true, - "requires": { - "@types/minimatch": "^5.1.2", - "@types/node": "*" - } - }, "@types/jsonwebtoken": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/@types/jsonwebtoken/-/jsonwebtoken-9.0.1.tgz", - "integrity": "sha512-c5ltxazpWabia/4UzhIoaDcIza4KViOQhdbjRlfcIGVnsE3c3brkz9Z+F/EeJIECOQP7W7US2hNE930cWWkPiw==", + "version": "9.0.9", + "resolved": "https://registry.npmjs.org/@types/jsonwebtoken/-/jsonwebtoken-9.0.9.tgz", + "integrity": "sha512-uoe+GxEuHbvy12OUQct2X9JenKM3qAscquYymuQN4fMWG9DBQtykrQEFcAbVACF7qaLw9BePSodUL0kquqBJpQ==", "requires": { + "@types/ms": "*", "@types/node": "*" } }, - "@types/linkify-it": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/@types/linkify-it/-/linkify-it-3.0.5.tgz", - "integrity": "sha512-yg6E+u0/+Zjva+buc3EIb+29XEg4wltq7cSmd4Uc2EE/1nUVmxyzpX6gUXD0V8jIrG0r7YeOGVIbYRkxeooCtw==", - "optional": true - }, "@types/lodash": { "version": "4.14.161", "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.161.tgz", @@ -3258,39 +2713,22 @@ "integrity": "sha512-MqTGEo5bj5t157U6fA/BiDynNkn0YknVdh48CMPkTSpFTVmvao5UQmm7uEF6xBEo7qIMAlY/JSleYaE6VOdpaA==", "optional": true }, - "@types/markdown-it": { - "version": "12.2.3", - "resolved": "https://registry.npmjs.org/@types/markdown-it/-/markdown-it-12.2.3.tgz", - "integrity": "sha512-GKMHFfv3458yYy+v/N8gjufHO6MSZKCOXpZc5GXIWWy8uldwfmPn98vp81gZ5f9SVw8YYBctgfJ22a2d7AOMeQ==", - "optional": true, - "requires": { - "@types/linkify-it": "*", - "@types/mdurl": "*" - } - }, - "@types/mdurl": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/@types/mdurl/-/mdurl-1.0.5.tgz", - "integrity": "sha512-6L6VymKTzYSrEf4Nev4Xa1LCHKrlTlYCBMTlQKFuddo1CvQcE52I0mwfOJayueUC7MJuXOeHTcIU683lzd0cUA==", - "optional": true - }, "@types/mime": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/@types/mime/-/mime-2.0.3.tgz", "integrity": "sha512-Jus9s4CDbqwocc5pOAnh8ShfrnMcPHuJYzVcSUU7lrh8Ni5HuIqX3oilL86p3dlTrk0LzHRCgA/GQ7uNCw6l2Q==" }, - "@types/minimatch": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-5.1.2.tgz", - "integrity": "sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA==", - "optional": true + "@types/ms": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@types/ms/-/ms-2.1.0.tgz", + "integrity": "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==" }, "@types/node": { - "version": "20.10.4", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.10.4.tgz", - "integrity": "sha512-D08YG6rr8X90YB56tSIuBaddy/UXAA9RKJoFvrsnogAum/0pmjkgi4+2nx96A330FmioegBWmEYQ+syqCFaveg==", + "version": "22.14.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.14.0.tgz", + "integrity": "sha512-Kmpl+z84ILoG+3T/zQFyAJsU6EPTmOCj8/2+83fSN6djd6I4o7uOuGIH6vq3PrjY5BGitSbFuMN18j3iknubbA==", "requires": { - "undici-types": "~5.26.4" + "undici-types": "~6.21.0" } }, "@types/qs": { @@ -3303,14 +2741,16 @@ "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.3.tgz", "integrity": "sha512-ewFXqrQHlFsgc09MK5jP5iR7vumV/BYayNC6PgJO2LPe8vrnNFyjQjSppfEngITi0qvfKtzFvgKymGheFM9UOA==" }, - "@types/rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@types/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-F3OznnSLAUxFrCEu/L5PY8+ny8DtcFRjx7fZZ9bycvXRi3KPTRS9HOitGZwvPg0juRhXFWIeKX58cnX5YqLohQ==", + "@types/request": { + "version": "2.48.12", + "resolved": "https://registry.npmjs.org/@types/request/-/request-2.48.12.tgz", + "integrity": "sha512-G3sY+NpsA9jnwm0ixhAFQSJ3Q9JkpLZpJbI3GMv0mIAT0y3mRabYeINzal5WOChIiaTEGQYlHOKgkaM9EisWHw==", "optional": true, "requires": { - "@types/glob": "*", - "@types/node": "*" + "@types/caseless": "*", + "@types/node": "*", + "@types/tough-cookie": "*", + "form-data": "^2.5.0" } }, "@types/serve-static": { @@ -3322,6 +2762,12 @@ "@types/mime": "*" } }, + "@types/tough-cookie": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-4.0.5.tgz", + "integrity": "sha512-/Ad8+nIOV7Rl++6f1BdKxFSMgmoqEoYbHRpPcx3JEfv8VRsQe9Z4mCXeJBzxs7mbHY/XOZZuXlRNfhpVPbs6ZA==", + "optional": true + }, "abort-controller": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", @@ -3340,27 +2786,10 @@ "negotiator": "0.6.3" } }, - "acorn": { - "version": "8.11.2", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.2.tgz", - "integrity": "sha512-nc0Axzp/0FILLEVsm4fNwLCwMttvhEI263QtVPQcbpfZZ3ts0hLsZGOpE6czNlid7CJ9MlyH8reXkpsf3YUY4w==", - "optional": true - }, - "acorn-jsx": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", - "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", - "optional": true, - "requires": {} - }, "agent-base": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", - "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", - "optional": true, - "requires": { - "debug": "4" - } + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.3.tgz", + "integrity": "sha512-jRR5wdylq8CkOe6hei19GGZnxM6rBGwFl3Bg0YItGDimvjGtAvdZk4Pu6Cl4u4Igsws4a1fd1Vq3ezrhn4KmFw==" }, "ansi-regex": { "version": "5.0.1", @@ -3377,12 +2806,6 @@ "color-convert": "^2.0.1" } }, - "argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "optional": true - }, "array-flatten": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", @@ -3403,29 +2826,21 @@ "retry": "0.13.1" } }, - "balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", "optional": true }, "base64-js": { "version": "1.5.1", "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", - "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", - "optional": true + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==" }, "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==", - "optional": true - }, - "bluebird": { - "version": "3.7.2", - "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", - "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==", - "optional": true + "version": "9.2.0", + "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.2.0.tgz", + "integrity": "sha512-JocpCSOixzy5XFJi2ub6IMmV/G9i8Lrm2lZvwBv9xPdglmZM0ufDVBbjbrfU/zuLvBfD7Bv2eYxz9i+OHTgkew==" }, "body-parser": { "version": "1.20.3", @@ -3461,15 +2876,6 @@ } } }, - "brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "optional": true, - "requires": { - "balanced-match": "^1.0.0" - } - }, "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", @@ -3492,23 +2898,13 @@ "set-function-length": "^1.2.1" } }, - "catharsis": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/catharsis/-/catharsis-0.9.0.tgz", - "integrity": "sha512-prMTQVpcns/tzFgFVkVp6ak6RykZyWb3gu8ckUpd6YkTlacOd3DXGJjIpD4Q6zJirizvaiAjSSHlOsA+6sNh2A==", - "optional": true, - "requires": { - "lodash": "^4.17.15" - } - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "optional": true, + "call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" } }, "cliui": { @@ -3537,21 +2933,15 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "optional": true }, - "compressible": { - "version": "2.0.18", - "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", - "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", + "combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", "optional": true, "requires": { - "mime-db": ">= 1.43.0 < 2" + "delayed-stream": "~1.0.0" } }, - "concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "optional": true - }, "content-disposition": { "version": "0.5.4", "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", @@ -3585,19 +2975,13 @@ } }, "debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", + "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", "requires": { - "ms": "2.1.2" + "ms": "^2.1.3" } }, - "deep-is": { - "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==", - "optional": true - }, "define-data-property": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", @@ -3608,6 +2992,12 @@ "gopd": "^1.0.1" } }, + "delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "optional": true + }, "depd": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", @@ -3618,16 +3008,26 @@ "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==" }, + "dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "requires": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + } + }, "duplexify": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-4.1.2.tgz", - "integrity": "sha512-fz3OjcNCHmRP12MJoZMPglx8m4rrFP8rovnk4vT8Fs+aonZoCwGg10dSsQsfP/E62eZcPTMSMP6686fu9Qlqtw==", + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-4.1.3.tgz", + "integrity": "sha512-M3BmBhwJRZsSx38lZyhE53Csddgzl5R7xGJNk7CVddZD6CcmwMCH8J+7AprIrQKH7TonKxaCjcv27Qmf+sQ+oA==", "optional": true, "requires": { "end-of-stream": "^1.4.1", "inherits": "^2.0.3", "readable-stream": "^3.1.1", - "stream-shift": "^1.0.0" + "stream-shift": "^1.0.2" } }, "ecdsa-sig-formatter": { @@ -3663,103 +3063,46 @@ "once": "^1.4.0" } }, - "ent": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/ent/-/ent-2.2.0.tgz", - "integrity": "sha512-GHrMyVZQWvTIdDtpiEXdHZnFQKzeO09apj8Cbl4pKWy4i0Oprcq17usfDt5aO63swf0JOeMWjWQE/LzgSRuWpA==", - "optional": true - }, - "entities": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-2.1.0.tgz", - "integrity": "sha512-hCx1oky9PFrJ611mf0ifBLBRW8lUUVRlFolb5gWRfIELabBlbp9xZvrqZLZAs+NxFnbfQoeGd8wDkygjg7U85w==", - "optional": true - }, "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==", - "requires": { - "get-intrinsic": "^1.2.4" - } + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==" }, "es-errors": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==" }, - "escalade": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", - "optional": true - }, - "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==" - }, - "escape-string-regexp": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", - "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", - "optional": true - }, - "escodegen": { - "version": "1.14.3", - "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.14.3.tgz", - "integrity": "sha512-qFcX0XJkdg+PB3xjZZG/wKSuT1PnQWx57+TVSjIMmILd2yC/6ByYElPwJnslDsuWuSAp4AwJGumarAAmJch5Kw==", - "optional": true, + "es-object-atoms": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", "requires": { - "esprima": "^4.0.1", - "estraverse": "^4.2.0", - "esutils": "^2.0.2", - "optionator": "^0.8.1", - "source-map": "~0.6.1" - }, - "dependencies": { - "estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", - "optional": true - } + "es-errors": "^1.3.0" } }, - "eslint-visitor-keys": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", - "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", - "optional": true - }, - "espree": { - "version": "9.6.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", - "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", + "es-set-tostringtag": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", + "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", "optional": true, "requires": { - "acorn": "^8.9.0", - "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^3.4.1" + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" } }, - "esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "optional": true - }, - "estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", "optional": true }, - "esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "optional": true + "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==" }, "etag": { "version": "1.8.1", @@ -3833,8 +3176,12 @@ "extend": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", - "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", - "optional": true + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" + }, + "farmhash-modern": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/farmhash-modern/-/farmhash-modern-1.1.0.tgz", + "integrity": "sha512-6ypT4XfgqJk/F3Yuv4SX26I3doUjt0GTG4a+JgWxXQpxXzTBq8fPUeGHfcYMMDPHJHm3yPOSjaeBwBGAHWXCdA==" }, "fast-deep-equal": { "version": "3.1.3", @@ -3842,25 +3189,13 @@ "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", "optional": true }, - "fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", - "optional": true - }, - "fast-text-encoding": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/fast-text-encoding/-/fast-text-encoding-1.0.6.tgz", - "integrity": "sha512-VhXlQgj9ioXCqGstD37E/HBeqEGV/qOD/kmbVG8h5xKBYvM1L3lR1Zn4555cQ8GkYbJa8aJSipLPndE1k6zK2w==", - "optional": true - }, "fast-xml-parser": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-4.4.1.tgz", - "integrity": "sha512-xkjOecfnKGkSsOwtZ5Pz7Us/T6mrbPQrq0nh+aCO5V9nk5NLWmasAHumTKjiPJPWANe+kAZ84Jc8ooJkzZ88Sw==", + "version": "4.5.3", + "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-4.5.3.tgz", + "integrity": "sha512-RKihhV+SHsIUGXObeVy9AXiBbFwkVk7Syp8XgwN5U3JV416+Gwp/GO9i0JYKmikykgz/UHRrrV4ROuZEo/T0ig==", "optional": true, "requires": { - "strnum": "^1.0.5" + "strnum": "^1.1.1" } }, "faye-websocket": { @@ -3906,32 +3241,33 @@ } }, "firebase-admin": { - "version": "11.11.1", - "resolved": "https://registry.npmjs.org/firebase-admin/-/firebase-admin-11.11.1.tgz", - "integrity": "sha512-UyEbq+3u6jWzCYbUntv/HuJiTixwh36G1R9j0v71mSvGAx/YZEWEW7uSGLYxBYE6ckVRQoKMr40PYUEzrm/4dg==", + "version": "13.2.0", + "resolved": "https://registry.npmjs.org/firebase-admin/-/firebase-admin-13.2.0.tgz", + "integrity": "sha512-qQBTKo0QWCDaWwISry989pr8YfZSSk00rNCKaucjOgltEm3cCYzEe4rODqBd1uUwma+Iu5jtAzg89Nfsjr3fGg==", "requires": { - "@fastify/busboy": "^1.2.1", - "@firebase/database-compat": "^0.3.4", - "@firebase/database-types": "^0.10.4", - "@google-cloud/firestore": "^6.8.0", - "@google-cloud/storage": "^6.9.5", - "@types/node": ">=12.12.47", + "@fastify/busboy": "^3.0.0", + "@firebase/database-compat": "^2.0.0", + "@firebase/database-types": "^1.0.6", + "@google-cloud/firestore": "^7.11.0", + "@google-cloud/storage": "^7.14.0", + "@types/node": "^22.8.7", + "farmhash-modern": "^1.1.0", + "google-auth-library": "^9.14.2", "jsonwebtoken": "^9.0.0", - "jwks-rsa": "^3.0.1", + "jwks-rsa": "^3.1.0", "node-forge": "^1.3.1", - "uuid": "^9.0.0" + "uuid": "^11.0.2" } }, "firebase-functions": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/firebase-functions/-/firebase-functions-4.5.0.tgz", - "integrity": "sha512-y6HsasHtGLfXCp3Pfrz+JA19lO9hSzYiNxFDIDMffrfcsG7UbXzv0zfi2ASadMVRoDCaox5ppZBa1QJxZbctPQ==", + "version": "6.3.2", + "resolved": "https://registry.npmjs.org/firebase-functions/-/firebase-functions-6.3.2.tgz", + "integrity": "sha512-FC3A1/nhqt1ZzxRnj5HZLScQaozAcFSD/vSR8khqSoFNOfxuXgwJS6ZABTB7+v+iMD5z6Mmxw6OfqITUBuI7OQ==", "requires": { "@types/cors": "^2.8.5", - "@types/express": "4.17.3", + "@types/express": "^4.17.21", "cors": "^2.8.5", - "express": "^4.17.1", - "node-fetch": "^2.6.7", + "express": "^4.21.0", "protobufjs": "^7.2.2" } }, @@ -3945,6 +3281,19 @@ "lodash": "^4.17.5" } }, + "form-data": { + "version": "2.5.3", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.5.3.tgz", + "integrity": "sha512-XHIrMD0NpDrNM/Ckf7XJiBbLl57KEhT3+i3yY+eWm+cqYZJQTZrKo8Y8AWKnuV5GT4scfuUGt9LzNoIx3dU1nQ==", + "optional": true, + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "es-set-tostringtag": "^2.1.0", + "mime-types": "^2.1.35", + "safe-buffer": "^5.2.1" + } + }, "forwarded": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", @@ -3955,12 +3304,6 @@ "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==" }, - "fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", - "optional": true - }, "function-bind": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", @@ -3973,24 +3316,31 @@ "optional": true }, "gaxios": { - "version": "5.1.3", - "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-5.1.3.tgz", - "integrity": "sha512-95hVgBRgEIRQQQHIbnxBXeHbW4TqFk4ZDJW7wmVtvYar72FdhRIo1UGOLS2eRAKCPEdPBWu+M7+A33D9CdX9rA==", - "optional": true, + "version": "6.7.1", + "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-6.7.1.tgz", + "integrity": "sha512-LDODD4TMYx7XXdpwxAVRAIAuB0bzv0s+ywFonY46k126qzQHT9ygyoa9tncmOiQmmDrik65UYsEkv3lbfqQ3yQ==", "requires": { "extend": "^3.0.2", - "https-proxy-agent": "^5.0.0", + "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" + }, + "dependencies": { + "uuid": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", + "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==" + } } }, "gcp-metadata": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-5.3.0.tgz", - "integrity": "sha512-FNTkdNEnBdlqF2oatizolQqNANMrcqJt6AAYt99B3y1aLLC8Hc5IOBb+ZnnzllodEEf6xMBp6wRcBbc16fa65w==", - "optional": true, + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-6.1.1.tgz", + "integrity": "sha512-a4tiq7E0/5fTjxPAaH4jpjkSv/uCaU2p5KC6HVGrvl0cDjA8iBZv4vv1gyzlmK0ZUKqwpOyQMKzZQe3lTit77A==", "requires": { - "gaxios": "^5.0.0", + "gaxios": "^6.1.1", + "google-logging-utils": "^0.0.2", "json-bigint": "^1.0.0" } }, @@ -4001,132 +3351,91 @@ "optional": true }, "get-intrinsic": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", - "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", "requires": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", "function-bind": "^1.1.2", - "has-proto": "^1.0.1", - "has-symbols": "^1.0.3", - "hasown": "^2.0.0" + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" } }, - "glob": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", - "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", - "optional": true, + "get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^5.0.1", - "once": "^1.3.0" + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" } }, "google-auth-library": { - "version": "8.9.0", - "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-8.9.0.tgz", - "integrity": "sha512-f7aQCJODJFmYWN6PeNKzgvy9LI2tYmXnzpNDHEjG5sDNPgGb2FXQyTBnXeSH+PAtpKESFD+LmHw3Ox3mN7e1Fg==", - "optional": true, + "version": "9.15.1", + "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-9.15.1.tgz", + "integrity": "sha512-Jb6Z0+nvECVz+2lzSMt9u98UsoakXxA2HGHMCxh+so3n90XgYWkq5dur19JAJV7ONiJY22yBTyJB1TSkvPq9Ng==", "requires": { - "arrify": "^2.0.0", "base64-js": "^1.3.0", "ecdsa-sig-formatter": "^1.0.11", - "fast-text-encoding": "^1.0.0", - "gaxios": "^5.0.0", - "gcp-metadata": "^5.3.0", - "gtoken": "^6.1.0", - "jws": "^4.0.0", - "lru-cache": "^6.0.0" + "gaxios": "^6.1.1", + "gcp-metadata": "^6.1.0", + "gtoken": "^7.0.0", + "jws": "^4.0.0" } }, "google-gax": { - "version": "3.6.1", - "resolved": "https://registry.npmjs.org/google-gax/-/google-gax-3.6.1.tgz", - "integrity": "sha512-g/lcUjGcB6DSw2HxgEmCDOrI/CByOwqRvsuUvNalHUK2iPPPlmAIpbMbl62u0YufGMr8zgE3JL7th6dCb1Ry+w==", + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/google-gax/-/google-gax-4.4.1.tgz", + "integrity": "sha512-Phyp9fMfA00J3sZbJxbbB4jC55b7DBjE3F6poyL3wKMEBVKA79q6BGuHcTiM28yOzVql0NDbRL8MLLh8Iwk9Dg==", "optional": true, "requires": { - "@grpc/grpc-js": "~1.8.0", - "@grpc/proto-loader": "^0.7.0", + "@grpc/grpc-js": "^1.10.9", + "@grpc/proto-loader": "^0.7.13", "@types/long": "^4.0.0", - "@types/rimraf": "^3.0.2", "abort-controller": "^3.0.0", "duplexify": "^4.0.0", - "fast-text-encoding": "^1.0.3", - "google-auth-library": "^8.0.2", - "is-stream-ended": "^0.1.4", - "node-fetch": "^2.6.1", + "google-auth-library": "^9.3.0", + "node-fetch": "^2.7.0", "object-hash": "^3.0.0", - "proto3-json-serializer": "^1.0.0", - "protobufjs": "7.2.4", - "protobufjs-cli": "1.1.1", - "retry-request": "^5.0.0" + "proto3-json-serializer": "^2.0.2", + "protobufjs": "^7.3.2", + "retry-request": "^7.0.0", + "uuid": "^9.0.1" }, "dependencies": { - "protobufjs": { - "version": "7.2.4", - "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.2.4.tgz", - "integrity": "sha512-AT+RJgD2sH8phPmCf7OUZR8xGdcJRga4+1cOaXJ64hvcSkVhNcRHOwIxUatPH15+nj59WAGTDv3LSGZPEQbJaQ==", - "optional": true, - "requires": { - "@protobufjs/aspromise": "^1.1.2", - "@protobufjs/base64": "^1.1.2", - "@protobufjs/codegen": "^2.0.4", - "@protobufjs/eventemitter": "^1.1.0", - "@protobufjs/fetch": "^1.1.0", - "@protobufjs/float": "^1.0.2", - "@protobufjs/inquire": "^1.1.0", - "@protobufjs/path": "^1.1.2", - "@protobufjs/pool": "^1.1.0", - "@protobufjs/utf8": "^1.1.0", - "@types/node": ">=13.7.0", - "long": "^5.0.0" - } + "uuid": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", + "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==", + "optional": true } } }, - "google-p12-pem": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/google-p12-pem/-/google-p12-pem-4.0.1.tgz", - "integrity": "sha512-WPkN4yGtz05WZ5EhtlxNDWPhC4JIic6G8ePitwUWy4l+XPVYec+a0j0Ts47PDtW59y3RwAhUd9/h9ZZ63px6RQ==", - "optional": true, - "requires": { - "node-forge": "^1.3.1" - } + "google-logging-utils": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/google-logging-utils/-/google-logging-utils-0.0.2.tgz", + "integrity": "sha512-NEgUnEcBiP5HrPzufUkBzJOD/Sxsco3rLNo1F1TNf7ieU8ryUzBhqba8r756CjLX7rn3fHl6iLEwPYuqpoKgQQ==" }, "gopd": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", - "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", - "requires": { - "get-intrinsic": "^1.1.3" - } - }, - "graceful-fs": { - "version": "4.2.11", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", - "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", - "optional": true + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==" }, "gtoken": { - "version": "6.1.2", - "resolved": "https://registry.npmjs.org/gtoken/-/gtoken-6.1.2.tgz", - "integrity": "sha512-4ccGpzz7YAr7lxrT2neugmXQ3hP9ho2gcaityLVkiUecAiwiy60Ii8gRbZeOsXV19fYaRjgBSshs8kXw+NKCPQ==", - "optional": true, + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/gtoken/-/gtoken-7.1.0.tgz", + "integrity": "sha512-pCcEwRi+TKpMlxAQObHDQ56KawURgyAf6jtIY046fJ5tIv3zDe/LEIubckAO8fj6JnAxLdmWkUfNyulQ2iKdEw==", "requires": { - "gaxios": "^5.0.1", - "google-p12-pem": "^4.0.0", + "gaxios": "^6.0.0", "jws": "^4.0.0" } }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "optional": true - }, "has-property-descriptors": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", @@ -4135,15 +3444,19 @@ "es-define-property": "^1.0.0" } }, - "has-proto": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz", - "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==" - }, "has-symbols": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", - "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==" + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==" + }, + "has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "optional": true, + "requires": { + "has-symbols": "^1.0.3" + } }, "hasown": { "version": "2.0.2", @@ -4153,6 +3466,12 @@ "function-bind": "^1.1.2" } }, + "html-entities": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-2.6.0.tgz", + "integrity": "sha512-kig+rMn/QOVRvr7c86gQ8lWXq+Hkv6CbAH1hLu+RG338StTpE8Z0b44SDVaqVu7HGKf27frdmUYEs9hTUX/cLQ==", + "optional": true + }, "http-errors": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", @@ -4166,9 +3485,9 @@ } }, "http-parser-js": { - "version": "0.5.8", - "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.8.tgz", - "integrity": "sha512-SGeBX54F94Wgu5RH3X5jsDtf4eHyRogWX1XGT3b4HuW3tQPM4AaBzoUji/4AAJNXCEOWZ5O0DgZmJw1947gD5Q==" + "version": "0.5.9", + "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.9.tgz", + "integrity": "sha512-n1XsPy3rXVxlqxVioEWdC+0+M+SQw0DpJynwtOPo1X+ZlvdzTLtDBIJJlDQTnwZIFJrZSzSGmIOUdP8tu+SgLw==" }, "http-proxy-agent": { "version": "5.0.0", @@ -4179,15 +3498,25 @@ "@tootallnate/once": "2", "agent-base": "6", "debug": "4" + }, + "dependencies": { + "agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "optional": true, + "requires": { + "debug": "4" + } + } } }, "https-proxy-agent": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", - "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", - "optional": true, + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", + "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", "requires": { - "agent-base": "6", + "agent-base": "^7.1.2", "debug": "4" } }, @@ -4199,16 +3528,6 @@ "safer-buffer": ">= 2.1.2 < 3" } }, - "inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "optional": true, - "requires": { - "once": "^1.3.0", - "wrappy": "1" - } - }, "inherits": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", @@ -4228,57 +3547,17 @@ "is-stream": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", - "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", - "optional": true - }, - "is-stream-ended": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/is-stream-ended/-/is-stream-ended-0.1.4.tgz", - "integrity": "sha512-xj0XPvmr7bQFTvirqnFr50o0hQIh6ZItDqloxt5aJrR4NQsYeSsyFQERYGCAzfindAcnKjINnwEEgLx4IqVzQw==", - "optional": true + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==" }, "jose": { - "version": "4.15.5", - "resolved": "https://registry.npmjs.org/jose/-/jose-4.15.5.tgz", - "integrity": "sha512-jc7BFxgKPKi94uOvEmzlSWFFe2+vASyXaKUpdQKatWAESU2MWjDfFf0fdfc83CDKcA5QecabZeNLyfhe3yKNkg==" - }, - "js2xmlparser": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/js2xmlparser/-/js2xmlparser-4.0.2.tgz", - "integrity": "sha512-6n4D8gLlLf1n5mNLQPRfViYzu9RATblzPEtm1SthMX1Pjao0r9YI9nw7ZIfRxQMERS87mcswrg+r/OYrPRX6jA==", - "optional": true, - "requires": { - "xmlcreate": "^2.0.4" - } - }, - "jsdoc": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/jsdoc/-/jsdoc-4.0.2.tgz", - "integrity": "sha512-e8cIg2z62InH7azBBi3EsSEqrKx+nUtAS5bBcYTSpZFA+vhNPyhv8PTFZ0WsjOPDj04/dOLlm08EDcQJDqaGQg==", - "optional": true, - "requires": { - "@babel/parser": "^7.20.15", - "@jsdoc/salty": "^0.2.1", - "@types/markdown-it": "^12.2.3", - "bluebird": "^3.7.2", - "catharsis": "^0.9.0", - "escape-string-regexp": "^2.0.0", - "js2xmlparser": "^4.0.2", - "klaw": "^3.0.0", - "markdown-it": "^12.3.2", - "markdown-it-anchor": "^8.4.1", - "marked": "^4.0.10", - "mkdirp": "^1.0.4", - "requizzle": "^0.2.3", - "strip-json-comments": "^3.1.0", - "underscore": "~1.13.2" - } + "version": "4.15.9", + "resolved": "https://registry.npmjs.org/jose/-/jose-4.15.9.tgz", + "integrity": "sha512-1vUQX+IdDMVPj4k8kOxgUqlcK518yluMuGZwqlr44FS1ppZB/5GWh4rZG89erpOBOJjU/OBsnCVFfapsRz6nEA==" }, "json-bigint": { "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==", - "optional": true, "requires": { "bignumber.js": "^9.0.0" } @@ -4319,7 +3598,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/jwa/-/jwa-2.0.0.tgz", "integrity": "sha512-jrZ2Qx916EA+fq9cEAeCROWPTfCwi1IVHqT2tapuqLEVVDKFDENFw1oL+MwrTvH6msKxsd1YTDVw6uKEcsrLEA==", - "optional": true, "requires": { "buffer-equal-constant-time": "1.0.1", "ecdsa-sig-formatter": "1.0.11", @@ -4327,74 +3605,32 @@ } }, "jwks-rsa": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/jwks-rsa/-/jwks-rsa-3.0.1.tgz", - "integrity": "sha512-UUOZ0CVReK1QVU3rbi9bC7N5/le8ziUj0A2ef1Q0M7OPD2KvjEYizptqIxGIo6fSLYDkqBrazILS18tYuRc8gw==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/jwks-rsa/-/jwks-rsa-3.2.0.tgz", + "integrity": "sha512-PwchfHcQK/5PSydeKCs1ylNym0w/SSv8a62DgHJ//7x2ZclCoinlsjAfDxAAbpoTPybOum/Jgy+vkvMmKz89Ww==", "requires": { - "@types/express": "^4.17.14", - "@types/jsonwebtoken": "^9.0.0", + "@types/express": "^4.17.20", + "@types/jsonwebtoken": "^9.0.4", "debug": "^4.3.4", - "jose": "^4.10.4", + "jose": "^4.15.4", "limiter": "^1.1.5", - "lru-memoizer": "^2.1.4" - }, - "dependencies": { - "@types/express": { - "version": "4.17.17", - "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.17.tgz", - "integrity": "sha512-Q4FmmuLGBG58btUnfS1c1r/NQdlp3DMfGDGig8WhfpA2YRUtEkxAjkZb0yvplJGYdF1fsQ81iMDcH24sSCNC/Q==", - "requires": { - "@types/body-parser": "*", - "@types/express-serve-static-core": "^4.17.33", - "@types/qs": "*", - "@types/serve-static": "*" - } - } + "lru-memoizer": "^2.2.0" } }, "jws": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/jws/-/jws-4.0.0.tgz", "integrity": "sha512-KDncfTmOZoOMTFG4mBlG0qUIOlc03fmzH+ru6RgYVZhPkyiy/92Owlt/8UEN+a4TXR1FQetfIpJE8ApdvdVxTg==", - "optional": true, "requires": { "jwa": "^2.0.0", "safe-buffer": "^5.0.1" } }, - "klaw": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/klaw/-/klaw-3.0.0.tgz", - "integrity": "sha512-0Fo5oir+O9jnXu5EefYbVK+mHMBeEVEy2cmctR1O1NECcCkPRreJKrS6Qt/j3KC2C148Dfo9i3pCmCMsdqGr0g==", - "optional": true, - "requires": { - "graceful-fs": "^4.1.9" - } - }, - "levn": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", - "integrity": "sha512-0OO4y2iOHix2W6ujICbKIaEQXvFQHue65vUG3pb5EUomzPI90z9hsA1VsO/dbIIpC53J8gxM9Q4Oho0jrCM/yA==", - "optional": true, - "requires": { - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2" - } - }, "limiter": { "version": "1.1.5", "resolved": "https://registry.npmjs.org/limiter/-/limiter-1.1.5.tgz", "integrity": "sha512-FWWMIEOxz3GwUI4Ts/IvgVy6LPvoMPgjMdQ185nN6psJyBJ4yOpzqm695/h5umdLJg2vW3GR5iG11MAkR2AzJA==" }, - "linkify-it": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-3.0.3.tgz", - "integrity": "sha512-ynTsyrFSdE5oZ/O9GEf00kPngmOfVwazR5GKDq6EYfhlpFug3J2zybX56a2PRRpc9P+FuSoGNAwjlbDs9jJBPQ==", - "optional": true, - "requires": { - "uc.micro": "^1.0.1" - } - }, "lodash": { "version": "4.17.21", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", @@ -4425,61 +3661,18 @@ } }, "lru-memoizer": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/lru-memoizer/-/lru-memoizer-2.2.0.tgz", - "integrity": "sha512-QfOZ6jNkxCcM/BkIPnFsqDhtrazLRsghi9mBwFAzol5GCvj4EkFT899Za3+QwikCg5sRX8JstioBDwOxEyzaNw==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/lru-memoizer/-/lru-memoizer-2.3.0.tgz", + "integrity": "sha512-GXn7gyHAMhO13WSKrIiNfztwxodVsP8IoZ3XfrJV4yH2x0/OeTO/FIaAHTY5YekdGgW94njfuKmyyt1E0mR6Ug==", "requires": { "lodash.clonedeep": "^4.5.0", - "lru-cache": "~4.0.0" - }, - "dependencies": { - "lru-cache": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.0.2.tgz", - "integrity": "sha512-uQw9OqphAGiZhkuPlpFGmdTU2tEuhxTourM/19qGJrxBPHAr/f8BT1a0i/lOclESnGatdJG/UCkP9kZB/Lh1iw==", - "requires": { - "pseudomap": "^1.0.1", - "yallist": "^2.0.0" - } - }, - "yallist": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", - "integrity": "sha512-ncTzHV7NvsQZkYe1DW7cbDLm0YpzHmZF5r/iyP3ZnQtMiJ+pjzisCiMNI+Sj+xQF5pXhSHxSB3uDbsBTzY/c2A==" - } - } - }, - "markdown-it": { - "version": "12.3.2", - "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-12.3.2.tgz", - "integrity": "sha512-TchMembfxfNVpHkbtriWltGWc+m3xszaRD0CZup7GFFhzIgQqxIfn3eGj1yZpfuflzPvfkt611B2Q/Bsk1YnGg==", - "optional": true, - "requires": { - "argparse": "^2.0.1", - "entities": "~2.1.0", - "linkify-it": "^3.0.1", - "mdurl": "^1.0.1", - "uc.micro": "^1.0.5" + "lru-cache": "6.0.0" } }, - "markdown-it-anchor": { - "version": "8.6.7", - "resolved": "https://registry.npmjs.org/markdown-it-anchor/-/markdown-it-anchor-8.6.7.tgz", - "integrity": "sha512-FlCHFwNnutLgVTflOYHPW2pPcl2AACqVzExlkGQNsi4CJgqOHN7YTgDd4LuhgN1BFO3TS0vLAruV1Td6dwWPJA==", - "optional": true, - "requires": {} - }, - "marked": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/marked/-/marked-4.3.0.tgz", - "integrity": "sha512-PRsaiG84bK+AMvxziE/lCFss8juXjNaWzVbN5tXAm4XjeaS9NAHhop+PjQxz2A9h8Q4M/xGmzP8vqNwy6JeK0A==", - "optional": true - }, - "mdurl": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz", - "integrity": "sha512-/sKlQJCBYVY9Ers9hqzKou4H6V5UWc/M59TH2dvkt+84itfnq7uFOMLpOiOS4ujvHP4etln18fmIxA5R5fll0g==", - "optional": true + "math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==" }, "media-typer": { "version": "0.3.0", @@ -4515,31 +3708,10 @@ "mime-db": "1.52.0" } }, - "minimatch": { - "version": "5.1.6", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", - "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", - "optional": true, - "requires": { - "brace-expansion": "^2.0.1" - } - }, - "minimist": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", - "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", - "optional": true - }, - "mkdirp": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", - "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", - "optional": true - }, "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" }, "negotiator": { "version": "0.6.3", @@ -4592,20 +3764,6 @@ "wrappy": "1" } }, - "optionator": { - "version": "0.8.3", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", - "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", - "optional": true, - "requires": { - "deep-is": "~0.1.3", - "fast-levenshtein": "~2.0.6", - "levn": "~0.3.0", - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2", - "word-wrap": "~1.2.3" - } - }, "p-limit": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", @@ -4620,36 +3778,24 @@ "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==" }, - "path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", - "optional": true - }, "path-to-regexp": { "version": "0.1.12", "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.12.tgz", "integrity": "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==" }, - "prelude-ls": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", - "integrity": "sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w==", - "optional": true - }, "proto3-json-serializer": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/proto3-json-serializer/-/proto3-json-serializer-1.1.1.tgz", - "integrity": "sha512-AwAuY4g9nxx0u52DnSMkqqgyLHaW/XaPLtaAo3y/ZCfeaQB/g4YDH4kb8Wc/mWzWvu0YjOznVnfn373MVZZrgw==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/proto3-json-serializer/-/proto3-json-serializer-2.0.2.tgz", + "integrity": "sha512-SAzp/O4Yh02jGdRc+uIrGoe87dkN/XtwxfZ4ZyafJHymd79ozp5VG5nyZ7ygqPM5+cpLDjjGnYFUkngonyDPOQ==", "optional": true, "requires": { - "protobufjs": "^7.0.0" + "protobufjs": "^7.2.5" } }, "protobufjs": { - "version": "7.2.5", - "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.2.5.tgz", - "integrity": "sha512-gGXRSXvxQ7UiPgfw8gevrfRWcTlSbOFg+p/N+JVJEK5VhueL2miT6qTymqAmjr1Q5WbOCyJbyrk6JfWKwlFn6A==", + "version": "7.4.0", + "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.4.0.tgz", + "integrity": "sha512-mRUWCc3KUU4w1jU8sGxICXH/gNS94DvI1gxqDvBzhj1JpcsimQkYiOJfwsPUykUI5ZaspFbSgmBLER8IrQ3tqw==", "requires": { "@protobufjs/aspromise": "^1.1.2", "@protobufjs/base64": "^1.1.2", @@ -4665,24 +3811,6 @@ "long": "^5.0.0" } }, - "protobufjs-cli": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/protobufjs-cli/-/protobufjs-cli-1.1.1.tgz", - "integrity": "sha512-VPWMgIcRNyQwWUv8OLPyGQ/0lQY/QTQAVN5fh+XzfDwsVw1FZ2L3DM/bcBf8WPiRz2tNpaov9lPZfNcmNo6LXA==", - "optional": true, - "requires": { - "chalk": "^4.0.0", - "escodegen": "^1.13.0", - "espree": "^9.0.0", - "estraverse": "^5.1.0", - "glob": "^8.0.0", - "jsdoc": "^4.0.0", - "minimist": "^1.2.0", - "semver": "^7.1.2", - "tmp": "^0.2.1", - "uglify-js": "^3.7.7" - } - }, "proxy-addr": { "version": "2.0.7", "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", @@ -4692,11 +3820,6 @@ "ipaddr.js": "1.9.1" } }, - "pseudomap": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", - "integrity": "sha512-b/YwNhb8lk1Zz2+bXXpS/LK9OisiZZ1SNsSLxN1x2OXVEhW2Ckr/7mWE5vrC1ZTiJlD9g19jWszTmJsB+oEpFQ==" - }, "qs": { "version": "6.13.0", "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz", @@ -4738,15 +3861,6 @@ "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", "optional": true }, - "requizzle": { - "version": "0.2.4", - "resolved": "https://registry.npmjs.org/requizzle/-/requizzle-0.2.4.tgz", - "integrity": "sha512-JRrFk1D4OQ4SqovXOgdav+K8EAhSB/LJZqCz8tbX0KObcdeM15Ss59ozWMBWmmINMagCwmqn4ZNryUGpBsl6Jw==", - "optional": true, - "requires": { - "lodash": "^4.17.21" - } - }, "retry": { "version": "0.13.1", "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz", @@ -4754,57 +3868,14 @@ "optional": true }, "retry-request": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/retry-request/-/retry-request-5.0.2.tgz", - "integrity": "sha512-wfI3pk7EE80lCIXprqh7ym48IHYdwmAAzESdbU8Q9l7pnRCk9LEhpbOTNKjz6FARLm/Bl5m+4F0ABxOkYUujSQ==", - "optional": true, - "requires": { - "debug": "^4.1.1", - "extend": "^3.0.2" - } - }, - "rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/retry-request/-/retry-request-7.0.2.tgz", + "integrity": "sha512-dUOvLMJ0/JJYEn8NrpOaGNE7X3vpI5XlZS/u0ANjqtcZVKnIxP7IgCFwrKTxENw29emmwug53awKtaMm4i9g5w==", "optional": true, "requires": { - "glob": "^7.1.3" - }, - "dependencies": { - "brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "optional": true, - "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "optional": true, - "requires": { - "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" - } - }, - "minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "optional": true, - "requires": { - "brace-expansion": "^1.1.7" - } - } + "@types/request": "^2.48.8", + "extend": "^3.0.2", + "teeny-request": "^9.0.0" } }, "safe-buffer": { @@ -4864,11 +3935,6 @@ "version": "1.6.0", "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==" - }, - "ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" } } }, @@ -4919,12 +3985,6 @@ "object-inspect": "^1.13.1" } }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "optional": true - }, "statuses": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", @@ -4940,9 +4000,9 @@ } }, "stream-shift": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.1.tgz", - "integrity": "sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.3.tgz", + "integrity": "sha512-76ORR0DO1o1hlKwTbi/DM3EXWGf3ZJYO8cXX5RJwnul2DEg2oyoZyjLNoQM8WsvZiFKCRfC1O0J7iCvie3RZmQ==", "optional": true }, "string_decoder": { @@ -4974,16 +4034,10 @@ "ansi-regex": "^5.0.1" } }, - "strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "optional": true - }, "strnum": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/strnum/-/strnum-1.0.5.tgz", - "integrity": "sha512-J8bbNyKKXl5qYcR36TIO8W3mVGVHrmmxsd5PAItGkmyzwJvybiw2IVq5nqd0i4LSNSkB/sx9VHllbfFdr9k1JA==", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/strnum/-/strnum-1.1.2.tgz", + "integrity": "sha512-vrN+B7DBIoTTZjnPNewwhx6cBA/H+IS7rfW68n7XxC1y7uoiGQBxaKzqucGUgavX15dJgiGztLJ8vxuEzwqBdA==", "optional": true }, "stubs": { @@ -4992,40 +4046,44 @@ "integrity": "sha512-PdHt7hHUJKxvTCgbKX9C1V/ftOcjJQgz8BZwNfV5c4B6dcGqlpelTbJ999jBGZ2jYiPAwcX5dP6oBwVlBlUbxw==", "optional": true }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "optional": true, - "requires": { - "has-flag": "^4.0.0" - } - }, "teeny-request": { - "version": "8.0.3", - "resolved": "https://registry.npmjs.org/teeny-request/-/teeny-request-8.0.3.tgz", - "integrity": "sha512-jJZpA5He2y52yUhA7pyAGZlgQpcB+xLjcN0eUFxr9c8hP/H7uOXbBNVo/O0C/xVfJLJs680jvkFgVJEEvk9+ww==", + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/teeny-request/-/teeny-request-9.0.0.tgz", + "integrity": "sha512-resvxdc6Mgb7YEThw6G6bExlXKkv6+YbuzGg9xuXxSgxJF7Ozs+o8Y9+2R3sArdWdW8nOokoQb1yrpFB0pQK2g==", "optional": true, "requires": { "http-proxy-agent": "^5.0.0", "https-proxy-agent": "^5.0.0", - "node-fetch": "^2.6.1", + "node-fetch": "^2.6.9", "stream-events": "^1.0.5", "uuid": "^9.0.0" - } - }, - "text-decoding": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/text-decoding/-/text-decoding-1.0.0.tgz", - "integrity": "sha512-/0TJD42KDnVwKmDK6jj3xP7E2MG7SHAOG4tyTgyUCRPdHwvkquYNLEQltmdMa3owq3TkddCVcTsoctJI8VQNKA==" - }, - "tmp": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.1.tgz", - "integrity": "sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ==", - "optional": true, - "requires": { - "rimraf": "^3.0.0" + }, + "dependencies": { + "agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "optional": true, + "requires": { + "debug": "4" + } + }, + "https-proxy-agent": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", + "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", + "optional": true, + "requires": { + "agent-base": "6", + "debug": "4" + } + }, + "uuid": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", + "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==", + "optional": true + } } }, "toidentifier": { @@ -5039,18 +4097,9 @@ "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" }, "tslib": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", - "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==" - }, - "type-check": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", - "integrity": "sha512-ZCmOJdvOWDBYJlzAoFkC+Q0+bUyEOS1ltgp1MGU03fqHG+dbi9tBFU2Rd9QKiDZFAYrhPh2JUf7rZRIuHRKtOg==", - "optional": true, - "requires": { - "prelude-ls": "~1.1.2" - } + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==" }, "type-is": { "version": "1.6.18", @@ -5067,28 +4116,10 @@ "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", "dev": true }, - "uc.micro": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.6.tgz", - "integrity": "sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==", - "optional": true - }, - "uglify-js": { - "version": "3.17.4", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.17.4.tgz", - "integrity": "sha512-T9q82TJI9e/C1TAxYvfb16xO120tMVFZrGA3f9/P4424DNu6ypK103y0GPFVa17yotwSyZW5iYXgjYHkGrJW/g==", - "optional": true - }, - "underscore": { - "version": "1.13.6", - "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.6.tgz", - "integrity": "sha512-+A5Sja4HP1M08MaXya7p5LvjuM7K6q/2EaC0+iovj/wOcMsTzMvDFbasi/oSapiwOlt252IqsKqPjCl7huKS0A==", - "optional": true - }, "undici-types": { - "version": "5.26.5", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", - "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==" + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", + "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==" }, "unpipe": { "version": "1.0.0", @@ -5107,9 +4138,9 @@ "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=" }, "uuid": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", - "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==" + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-11.1.0.tgz", + "integrity": "sha512-0/A9rDy9P7cJ+8w1c9WD9V//9Wj15Ce2MPz8Ri6032usz+NfePxx5AcN3bN+r6ZL6jEo066/yNYB3tn4pQEx+A==" }, "vary": { "version": "1.1.2", @@ -5145,12 +4176,6 @@ "webidl-conversions": "^3.0.0" } }, - "word-wrap": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", - "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", - "optional": true - }, "wrap-ansi": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", @@ -5168,12 +4193,6 @@ "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", "optional": true }, - "xmlcreate": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/xmlcreate/-/xmlcreate-2.0.4.tgz", - "integrity": "sha512-nquOebG4sngPmGPICTS5EnxqhKbCmz5Ox5hsszI2T6U5qdrJizBc+0ilYSEjTSzU0yZcmvppztXe/5Al5fUwdg==", - "optional": true - }, "y18n": { "version": "5.0.8", "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", diff --git a/.github/workflows/scripts/functions/package.json b/.github/workflows/scripts/functions/package.json index e6561975ef4b..15dbe63c1a59 100644 --- a/.github/workflows/scripts/functions/package.json +++ b/.github/workflows/scripts/functions/package.json @@ -14,8 +14,8 @@ }, "main": "lib/index.js", "dependencies": { - "firebase-admin": "^11.5.0", - "firebase-functions": "^4.5.0" + "firebase-admin": "^13.2.0", + "firebase-functions": "^6.3.2" }, "devDependencies": { "firebase-functions-test": "^0.2.0", diff --git a/.github/workflows/scripts/functions/src/index.ts b/.github/workflows/scripts/functions/src/index.ts index 6d587bf363a7..659834d2e991 100644 --- a/.github/workflows/scripts/functions/src/index.ts +++ b/.github/workflows/scripts/functions/src/index.ts @@ -2,72 +2,99 @@ import * as assert from 'assert'; import * as functions from 'firebase-functions'; import * as functionsv2 from 'firebase-functions/v2'; + // For example app. // noinspection JSUnusedGlobalSymbols export const listFruit = functions.https.onCall(() => { return ['Apple', 'Banana', 'Cherry', 'Date', 'Fig', 'Grapes']; }); -export const listfruits2ndgen = functionsv2.https.onCall(() => { - return ['Apple', 'Banana', 'Cherry', 'Date', 'Fig', 'Grapes']; +export const listfruits2ndgen = functionsv2.https.onCall((res, req) => { + const fruitList = ['Apple', 'Banana', 'Cherry', 'Date', 'Fig', 'Grapes']; + const allFruits = fruitList.map(async (fruit) => { + if (res.acceptsStreaming) { + req?.sendChunk(fruit) + } + }) + return Promise.all(allFruits); }); // For e2e testing a custom region. // noinspection JSUnusedGlobalSymbols -export const testFunctionCustomRegion = functions - .region('europe-west1') - .https.onCall(() => 'europe-west1'); + +export const testFunctionCustomRegion = functions.https.onCall( + { + region: 'europe-west1' + }, + () => 'europe-west1' +); // For e2e testing timeouts. -export const testFunctionTimeout = functions.https.onCall((data) => { +export const testFunctionTimeout = functions.https.onCall((req, res) => { + const data = req.data console.log(JSON.stringify({ data })); - return new Promise((resolve, reject) => { - if (data && data.testTimeout) { - setTimeout( - () => resolve({ timeLimit: 'exceeded' }), - parseInt(data.testTimeout, 10) - ); - } else { - reject( - new functions.https.HttpsError( - 'invalid-argument', - 'testTimeout must be provided.' - ) - ); - } + + const timeoutMs = parseInt(data?.testTimeout, 10); + + if (isNaN(timeoutMs)) { + throw new functions.https.HttpsError( + 'invalid-argument', + 'testTimeout must be provided.' + ); + } + + if (req.acceptsStreaming) { + setTimeout(() => { + res?.sendChunk({ timeLimit: 'exceeded' }); + }, timeoutMs); + + return new Promise((resolve) => { + setTimeout(resolve, timeoutMs + 100); + }); + } + + return new Promise((resolve) => { + setTimeout(() => resolve({ timeLimit: 'exceeded' }), timeoutMs); }); + }); // For e2e testing errors & return values. // noinspection JSUnusedGlobalSymbols -export const testFunctionDefaultRegion = functions.https.onCall((data) => { +export const testFunctionDefaultRegion = functions.https.onCall((req, res) => { + const data = req.data; console.log(JSON.stringify({ data })); - if (typeof data === 'undefined') { - return 'undefined'; - } + + const sendResponse = (value: any) => { + if (req.acceptsStreaming && res) { + res.sendChunk(value); + return value; + } + return value; + }; if (typeof data === 'string') { - return 'string'; + return sendResponse('string'); } if (typeof data === 'number') { - return 'number'; + return sendResponse('number'); } if (typeof data === 'boolean') { - return 'boolean'; + return sendResponse('boolean'); } if (data === null) { - return 'null'; + return sendResponse('null'); } if (Array.isArray(data)) { - return 'array'; + return sendResponse('array'); } - if(data.type === 'rawData') { - return data; + if (data.type === 'rawData') { + return sendResponse(data); } const sampleData: { @@ -153,9 +180,45 @@ export const testFunctionDefaultRegion = functions.https.onCall((data) => { ); } - return outputData; + return sendResponse(outputData); }); export const testMapConvertType = functions.https.onCall((data) => ({ foo: 'bar', })); + +export const testStream = functions.https.onCall((req, res) => { + const data = req.data; + if (data === null || undefined) { + if (req.acceptsStreaming) { + res?.sendChunk('null'); + } + return + } + + const results = []; + results.push(data) + + const allResults = results.map(async (result) => { + if (req.acceptsStreaming) { + res?.sendChunk(result); + } + return result; + }); + return Promise.all(allResults); +}) + +export const testStreamResponse = functions.https.onCall(async (request, response) => { + const fruits = ['Apple', 'Mango', 'Banana'] + + const allFruits = fruits.map(async (fruit) => { + // Stream each fruit as it resolves! + if (request.acceptsStreaming) { + response?.sendChunk(fruit); + } + return fruit; + }); + + // Fallback for non-streaming clients + return Promise.all(allFruits); +}); \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index cb16c363add4..e07a73f8f9bb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,68 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## 2025-04-28 - [BoM 3.10.0](https://github.com/firebase/flutterfire/blob/main/VERSIONS.md#flutter-bom-3100-2025-04-28) + +### Changes + +--- + +Packages with breaking changes: + + - There are no breaking changes in this release. + +Packages with other changes: + + - [`cloud_firestore` - `v5.6.7`](#cloud_firestore---v567) + - [`cloud_firestore_platform_interface` - `v6.6.7`](#cloud_firestore_platform_interface---v667) + - [`cloud_functions` - `v5.5.0`](#cloud_functions---v550) + - [`cloud_functions_platform_interface` - `v5.7.0`](#cloud_functions_platform_interface---v570) + - [`cloud_functions_web` - `v4.11.0`](#cloud_functions_web---v4110) + - [`firebase_auth` - `v5.5.3`](#firebase_auth---v553) + - [`firebase_vertexai` - `v1.6.0`](#firebase_vertexai---v160) + - [`cloud_firestore_web` - `v4.4.7`](#cloud_firestore_web---v447) + - [`firebase_data_connect` - `v0.1.4+1`](#firebase_data_connect---v0141) + +Packages with dependency updates only: + +> Packages listed below depend on other packages in this workspace that have had changes. Their versions have been incremented to bump the minimum dependency versions of the packages they depend upon in this project. + + - `cloud_firestore_web` - `v4.4.7` + - `firebase_data_connect` - `v0.1.4+1` + +--- + +#### `cloud_firestore` - `v5.6.7` + + - **FIX**(firestore): Change asserts to throw argumentError ([#17302](https://github.com/firebase/flutterfire/issues/17302)). ([ec1e6a5e](https://github.com/firebase/flutterfire/commit/ec1e6a5eef149680b2750900d1f16d8074e09b38)) + - **FIX**(cloud_firestore): correct nanoseconds calculation for pre-1970 dates ([#17195](https://github.com/firebase/flutterfire/issues/17195)). ([a13deae3](https://github.com/firebase/flutterfire/commit/a13deae3334045fb1a48817ff9300cbe0696d177)) + +#### `cloud_firestore_platform_interface` - `v6.6.7` + + - **FIX**(cloud_firestore): correct nanoseconds calculation for pre-1970 dates ([#17195](https://github.com/firebase/flutterfire/issues/17195)). ([a13deae3](https://github.com/firebase/flutterfire/commit/a13deae3334045fb1a48817ff9300cbe0696d177)) + +#### `cloud_functions` - `v5.5.0` + + - **FEAT**(cloud_functions): add support for cloud functions stream ([#17214](https://github.com/firebase/flutterfire/issues/17214)). ([509e0f3c](https://github.com/firebase/flutterfire/commit/509e0f3cc984a7b56a67979b4b27aff72defdd55)) + +#### `cloud_functions_platform_interface` - `v5.7.0` + + - **FEAT**(cloud_functions): add support for cloud functions stream ([#17214](https://github.com/firebase/flutterfire/issues/17214)). ([509e0f3c](https://github.com/firebase/flutterfire/commit/509e0f3cc984a7b56a67979b4b27aff72defdd55)) + +#### `cloud_functions_web` - `v4.11.0` + + - **FEAT**(cloud_functions): add support for cloud functions stream ([#17214](https://github.com/firebase/flutterfire/issues/17214)). ([509e0f3c](https://github.com/firebase/flutterfire/commit/509e0f3cc984a7b56a67979b4b27aff72defdd55)) + +#### `firebase_auth` - `v5.5.3` + + - **FIX**(auth,iOS): include missing email and credential in account-exists-with-different-credential error ([#17180](https://github.com/firebase/flutterfire/issues/17180)). ([2a0bdc64](https://github.com/firebase/flutterfire/commit/2a0bdc64086e99f8a98bd18b472b36bcfe05a9a4)) + +#### `firebase_vertexai` - `v1.6.0` + + - **FIX**(vertexai): add missing HarmBlockThreshold to exported APIs ([#17249](https://github.com/firebase/flutterfire/issues/17249)). ([59d902c6](https://github.com/firebase/flutterfire/commit/59d902c63bd1bd040f5357cb6a341db446429430)) + - **FEAT**(vertexai): Live API breaking changes ([#17299](https://github.com/firebase/flutterfire/issues/17299)). ([69cd2a64](https://github.com/firebase/flutterfire/commit/69cd2a640d25e0f2b623f2e631d090ead8af140d)) + + ## 2025-03-31 - [BoM 3.9.0](https://github.com/firebase/flutterfire/blob/main/VERSIONS.md#flutter-bom-390-2025-03-31) ### Changes diff --git a/VERSIONS.md b/VERSIONS.md index bfc96b47ac32..dc6fa2f92180 100644 --- a/VERSIONS.md +++ b/VERSIONS.md @@ -4,6 +4,45 @@ This document is listing all the compatible versions of the FlutterFire plugins. # Versions +## [Flutter BoM 3.10.0 (2025-04-28)](https://github.com/firebase/flutterfire/blob/main/CHANGELOG.md#2025-04-28) + +Install this version using FlutterFire CLI + +```bash +flutterfire install 3.10.0 +``` + +### Included Native Firebase SDK Versions +| Firebase SDK | Version | Link | +|--------------|---------|------| +| Android SDK | 33.11.0 | [Release Notes](https://firebase.google.com/support/release-notes/android) | +| iOS SDK | 11.10.0 | [Release Notes](https://firebase.google.com/support/release-notes/ios) | +| Web SDK | 11.5.0 | [Release Notes](https://firebase.google.com/support/release-notes/js) | +| Windows SDK | 12.7.0 | [Release Notes](https://firebase.google.com/support/release-notes/cpp-relnotes) | + +### FlutterFire Plugin Versions +| Plugin | Version | Dart Version | Flutter Version | +|--------|---------|--------------|-----------------| +| [cloud_firestore](https://pub.dev/packages/cloud_firestore/versions/5.6.7) | 5.6.7 | >=3.2.0 <4.0.0 | >=3.3.0 | +| [cloud_functions](https://pub.dev/packages/cloud_functions/versions/5.5.0) | 5.5.0 | >=3.2.0 <4.0.0 | >=3.3.0 | +| [firebase_analytics](https://pub.dev/packages/firebase_analytics/versions/11.4.5) | 11.4.5 | >=3.2.0 <4.0.0 | >=3.3.0 | +| [firebase_app_check](https://pub.dev/packages/firebase_app_check/versions/0.3.2+5) | 0.3.2+5 | >=3.2.0 <4.0.0 | >=3.3.0 | +| [firebase_app_installations](https://pub.dev/packages/firebase_app_installations/versions/0.3.2+5) | 0.3.2+5 | >=3.2.0 <4.0.0 | >=3.3.0 | +| [firebase_auth](https://pub.dev/packages/firebase_auth/versions/5.5.3) | 5.5.3 | >=3.2.0 <4.0.0 | >=3.16.0 | +| [firebase_core](https://pub.dev/packages/firebase_core/versions/3.13.0) | 3.13.0 | >=3.2.0 <4.0.0 | >=3.3.0 | +| [firebase_crashlytics](https://pub.dev/packages/firebase_crashlytics/versions/4.3.5) | 4.3.5 | >=3.2.0 <4.0.0 | >=3.3.0 | +| [firebase_data_connect](https://pub.dev/packages/firebase_data_connect/versions/0.1.4+1) | 0.1.4+1 | >=3.2.0 <4.0.0 | >=3.3.0 | +| [firebase_database](https://pub.dev/packages/firebase_database/versions/11.3.5) | 11.3.5 | >=3.2.0 <4.0.0 | >=3.3.0 | +| [firebase_dynamic_links](https://pub.dev/packages/firebase_dynamic_links/versions/6.1.5) | 6.1.5 | >=3.2.0 <4.0.0 | >=3.3.0 | +| [firebase_in_app_messaging](https://pub.dev/packages/firebase_in_app_messaging/versions/0.8.1+5) | 0.8.1+5 | >=3.2.0 <4.0.0 | >=3.3.0 | +| [firebase_messaging](https://pub.dev/packages/firebase_messaging/versions/15.2.5) | 15.2.5 | >=3.2.0 <4.0.0 | >=3.3.0 | +| [firebase_ml_model_downloader](https://pub.dev/packages/firebase_ml_model_downloader/versions/0.3.3+3) | 0.3.3+3 | >=3.2.0 <4.0.0 | >=3.3.0 | +| [firebase_performance](https://pub.dev/packages/firebase_performance/versions/0.10.1+5) | 0.10.1+5 | >=3.2.0 <4.0.0 | >=3.3.0 | +| [firebase_remote_config](https://pub.dev/packages/firebase_remote_config/versions/5.4.3) | 5.4.3 | >=3.2.0 <4.0.0 | >=3.3.0 | +| [firebase_storage](https://pub.dev/packages/firebase_storage/versions/12.4.5) | 12.4.5 | >=3.2.0 <4.0.0 | >=3.3.0 | +| [firebase_vertexai](https://pub.dev/packages/firebase_vertexai/versions/1.6.0) | 1.6.0 | >=3.2.0 <4.0.0 | >=3.16.0 | + + ## [Flutter BoM 3.9.0 (2025-03-31)](https://github.com/firebase/flutterfire/blob/main/CHANGELOG.md#2025-03-31) Install this version using FlutterFire CLI diff --git a/docs/cloud-messaging/receive.md b/docs/cloud-messaging/receive.md index 65850719d761..27f02d081d8a 100644 --- a/docs/cloud-messaging/receive.md +++ b/docs/cloud-messaging/receive.md @@ -529,13 +529,13 @@ At this point, everything should still be running normally. The final step is in ```objc #import "NotificationService.h" #import "FirebaseMessaging.h" - #import "FirebaseAuth.h" // Add this line if you are using FirebaseAuth phone authentication + #import // Add this line if you are using FirebaseAuth phone authentication #import // Add this line if you are using FirebaseAuth phone authentication - @interface NotificationService () + @interface NotificationService () - @property (nonatomic, strong) void (^contentHandler)(UNNotificationContent *contentToDeliver); - @property (nonatomic, strong) UNMutableNotificationContent *bestAttemptContent; + @property(nonatomic) void (^contentHandler)(UNNotificationContent *contentToDeliver); + @property(nonatomic) UNMutableNotificationContent *bestAttemptContent; @end diff --git a/packages/cloud_firestore/cloud_firestore/CHANGELOG.md b/packages/cloud_firestore/cloud_firestore/CHANGELOG.md index d7edf59571fc..6905bc30cfcd 100644 --- a/packages/cloud_firestore/cloud_firestore/CHANGELOG.md +++ b/packages/cloud_firestore/cloud_firestore/CHANGELOG.md @@ -1,3 +1,8 @@ +## 5.6.7 + + - **FIX**(firestore): Change asserts to throw argumentError ([#17302](https://github.com/firebase/flutterfire/issues/17302)). ([ec1e6a5e](https://github.com/firebase/flutterfire/commit/ec1e6a5eef149680b2750900d1f16d8074e09b38)) + - **FIX**(cloud_firestore): correct nanoseconds calculation for pre-1970 dates ([#17195](https://github.com/firebase/flutterfire/issues/17195)). ([a13deae3](https://github.com/firebase/flutterfire/commit/a13deae3334045fb1a48817ff9300cbe0696d177)) + ## 5.6.6 - Update a dependency to the latest release. diff --git a/packages/cloud_firestore/cloud_firestore/example/pubspec.yaml b/packages/cloud_firestore/cloud_firestore/example/pubspec.yaml index 49cd6cf1e876..ba3de1839893 100755 --- a/packages/cloud_firestore/cloud_firestore/example/pubspec.yaml +++ b/packages/cloud_firestore/cloud_firestore/example/pubspec.yaml @@ -5,7 +5,7 @@ environment: sdk: '>=3.2.0 <4.0.0' dependencies: - cloud_firestore: ^5.6.6 + cloud_firestore: ^5.6.7 firebase_core: ^3.13.0 flutter: sdk: flutter diff --git a/packages/cloud_firestore/cloud_firestore/pubspec.yaml b/packages/cloud_firestore/cloud_firestore/pubspec.yaml index a419c0b2340b..ba3616d41ce5 100755 --- a/packages/cloud_firestore/cloud_firestore/pubspec.yaml +++ b/packages/cloud_firestore/cloud_firestore/pubspec.yaml @@ -4,7 +4,7 @@ description: live synchronization and offline support on Android and iOS. homepage: https://firebase.google.com/docs/firestore repository: https://github.com/firebase/flutterfire/tree/main/packages/cloud_firestore/cloud_firestore -version: 5.6.6 +version: 5.6.7 topics: - firebase - firestore @@ -20,8 +20,8 @@ environment: flutter: '>=3.3.0' dependencies: - cloud_firestore_platform_interface: ^6.6.6 - cloud_firestore_web: ^4.4.6 + cloud_firestore_platform_interface: ^6.6.7 + cloud_firestore_web: ^4.4.7 collection: ^1.0.0 firebase_core: ^3.13.0 firebase_core_platform_interface: ^5.4.0 diff --git a/packages/cloud_firestore/cloud_firestore_platform_interface/CHANGELOG.md b/packages/cloud_firestore/cloud_firestore_platform_interface/CHANGELOG.md index cb53daeb6c44..5c2dad79a9e3 100644 --- a/packages/cloud_firestore/cloud_firestore_platform_interface/CHANGELOG.md +++ b/packages/cloud_firestore/cloud_firestore_platform_interface/CHANGELOG.md @@ -1,3 +1,7 @@ +## 6.6.7 + + - **FIX**(cloud_firestore): correct nanoseconds calculation for pre-1970 dates ([#17195](https://github.com/firebase/flutterfire/issues/17195)). ([a13deae3](https://github.com/firebase/flutterfire/commit/a13deae3334045fb1a48817ff9300cbe0696d177)) + ## 6.6.6 - Update a dependency to the latest release. diff --git a/packages/cloud_firestore/cloud_firestore_platform_interface/pubspec.yaml b/packages/cloud_firestore/cloud_firestore_platform_interface/pubspec.yaml index 6661f0986a24..95b967731fc5 100644 --- a/packages/cloud_firestore/cloud_firestore_platform_interface/pubspec.yaml +++ b/packages/cloud_firestore/cloud_firestore_platform_interface/pubspec.yaml @@ -1,6 +1,6 @@ name: cloud_firestore_platform_interface description: A common platform interface for the cloud_firestore plugin. -version: 6.6.6 +version: 6.6.7 homepage: https://github.com/firebase/flutterfire/tree/main/packages/cloud_firestore/cloud_firestore_platform_interface repository: https://github.com/firebase/flutterfire/tree/main/packages/cloud_firestore/cloud_firestore_platform_interface diff --git a/packages/cloud_firestore/cloud_firestore_web/CHANGELOG.md b/packages/cloud_firestore/cloud_firestore_web/CHANGELOG.md index 25400afa008a..b5e7fee0a32a 100644 --- a/packages/cloud_firestore/cloud_firestore_web/CHANGELOG.md +++ b/packages/cloud_firestore/cloud_firestore_web/CHANGELOG.md @@ -1,3 +1,7 @@ +## 4.4.7 + + - Update a dependency to the latest release. + ## 4.4.6 - Update a dependency to the latest release. diff --git a/packages/cloud_firestore/cloud_firestore_web/pubspec.yaml b/packages/cloud_firestore/cloud_firestore_web/pubspec.yaml index 84f131ad15a3..0f736d5071e9 100644 --- a/packages/cloud_firestore/cloud_firestore_web/pubspec.yaml +++ b/packages/cloud_firestore/cloud_firestore_web/pubspec.yaml @@ -3,7 +3,7 @@ description: The web implementation of cloud_firestore homepage: https://github.com/firebase/flutterfire/tree/main/packages/cloud_firestore/cloud_firestore_web repository: https://github.com/firebase/flutterfire/tree/main/packages/cloud_firestore/cloud_firestore_web -version: 4.4.6 +version: 4.4.7 environment: sdk: '>=3.4.0 <4.0.0' @@ -11,7 +11,7 @@ environment: dependencies: _flutterfire_internals: ^1.3.54 - cloud_firestore_platform_interface: ^6.6.6 + cloud_firestore_platform_interface: ^6.6.7 collection: ^1.0.0 firebase_core: ^3.13.0 firebase_core_web: ^2.22.0 diff --git a/packages/cloud_functions/cloud_functions/CHANGELOG.md b/packages/cloud_functions/cloud_functions/CHANGELOG.md index f05f0edb71bb..8d6b955a0e78 100644 --- a/packages/cloud_functions/cloud_functions/CHANGELOG.md +++ b/packages/cloud_functions/cloud_functions/CHANGELOG.md @@ -1,3 +1,7 @@ +## 5.5.0 + + - **FEAT**(cloud_functions): add support for cloud functions stream ([#17214](https://github.com/firebase/flutterfire/issues/17214)). ([509e0f3c](https://github.com/firebase/flutterfire/commit/509e0f3cc984a7b56a67979b4b27aff72defdd55)) + ## 5.4.0 - **FEAT**(functions): migrate cloud functions Apple implementation to Swift ([#17232](https://github.com/firebase/flutterfire/issues/17232)). ([9ebc7bc1](https://github.com/firebase/flutterfire/commit/9ebc7bc130757f918dfab9fbc583e5f6c5b3b565)) diff --git a/packages/cloud_functions/cloud_functions/android/build.gradle b/packages/cloud_functions/cloud_functions/android/build.gradle index 849cf1bec6c1..2e21f4ba4d89 100644 --- a/packages/cloud_functions/cloud_functions/android/build.gradle +++ b/packages/cloud_functions/cloud_functions/android/build.gradle @@ -64,6 +64,7 @@ android { implementation platform("com.google.firebase:firebase-bom:${getRootProjectExtOrCoreProperty("FirebaseSDKVersion", firebaseCoreProject)}") implementation 'com.google.firebase:firebase-functions' implementation 'androidx.annotation:annotation:1.7.0' + implementation 'org.reactivestreams:reactive-streams:1.0.4' } } diff --git a/packages/cloud_functions/cloud_functions/android/src/main/java/io/flutter/plugins/firebase/functions/FirebaseFunctionsStreamHandler.java b/packages/cloud_functions/cloud_functions/android/src/main/java/io/flutter/plugins/firebase/functions/FirebaseFunctionsStreamHandler.java new file mode 100644 index 000000000000..bd6b50f7bfe7 --- /dev/null +++ b/packages/cloud_functions/cloud_functions/android/src/main/java/io/flutter/plugins/firebase/functions/FirebaseFunctionsStreamHandler.java @@ -0,0 +1,85 @@ +// Copyright 2025 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package io.flutter.plugins.firebase.functions; + +import android.net.Uri; +import com.google.firebase.functions.FirebaseFunctions; +import com.google.firebase.functions.HttpsCallableOptions; +import com.google.firebase.functions.HttpsCallableReference; +import com.google.firebase.functions.StreamResponse; +import io.flutter.plugin.common.EventChannel; +import io.flutter.plugin.common.EventChannel.StreamHandler; +import java.net.URL; +import java.util.Map; +import java.util.Objects; +import java.util.concurrent.TimeUnit; +import org.reactivestreams.Publisher; + +public class FirebaseFunctionsStreamHandler implements StreamHandler { + + private final FirebaseFunctions firebaseFunctions; + + private StreamResponseSubscriber subscriber; + + public FirebaseFunctionsStreamHandler(FirebaseFunctions functions) { + this.firebaseFunctions = functions; + } + + @Override + public void onListen(Object arguments, EventChannel.EventSink events) { + @SuppressWarnings("unchecked") + Map argumentsMap = (Map) arguments; + httpsStreamCall(argumentsMap, events); + } + + @Override + public void onCancel(Object arguments) { + subscriber.cancel(); + } + + private void httpsStreamCall(Map arguments, EventChannel.EventSink events) { + try { + + String functionName = (String) arguments.get("functionName"); + String functionUri = (String) arguments.get("functionUri"); + String origin = (String) arguments.get("origin"); + Integer timeout = (Integer) arguments.get("timeout"); + Object parameters = arguments.get("parameters"); + boolean limitedUseAppCheckToken = + (boolean) Objects.requireNonNull(arguments.get("limitedUseAppCheckToken")); + + if (origin != null) { + Uri originUri = Uri.parse(origin); + firebaseFunctions.useEmulator(originUri.getHost(), originUri.getPort()); + } + + HttpsCallableReference httpsCallableReference; + HttpsCallableOptions options = + new HttpsCallableOptions.Builder() + .setLimitedUseAppCheckTokens(limitedUseAppCheckToken) + .build(); + + Publisher publisher; + if (functionName != null) { + httpsCallableReference = firebaseFunctions.getHttpsCallable(functionName, options); + publisher = httpsCallableReference.stream(parameters); + } else if (functionUri != null) { + httpsCallableReference = + firebaseFunctions.getHttpsCallableFromUrl(new URL(functionUri), options); + publisher = httpsCallableReference.stream(); + } else { + throw new IllegalArgumentException("Either functionName or functionUri must be set"); + } + + if (timeout != null) { + httpsCallableReference.setTimeout(timeout.longValue(), TimeUnit.MILLISECONDS); + } + subscriber = new StreamResponseSubscriber(events); + publisher.subscribe(subscriber); + } catch (Exception e) { + events.error("firebase_functions", e.getMessage(), null); + } + } +} diff --git a/packages/cloud_functions/cloud_functions/android/src/main/java/io/flutter/plugins/firebase/functions/FlutterFirebaseFunctionsPlugin.java b/packages/cloud_functions/cloud_functions/android/src/main/java/io/flutter/plugins/firebase/functions/FlutterFirebaseFunctionsPlugin.java index e93575011d84..7141fd4d7717 100644 --- a/packages/cloud_functions/cloud_functions/android/src/main/java/io/flutter/plugins/firebase/functions/FlutterFirebaseFunctionsPlugin.java +++ b/packages/cloud_functions/cloud_functions/android/src/main/java/io/flutter/plugins/firebase/functions/FlutterFirebaseFunctionsPlugin.java @@ -17,6 +17,7 @@ import com.google.firebase.functions.HttpsCallableReference; import com.google.firebase.functions.HttpsCallableResult; import io.flutter.embedding.engine.plugins.FlutterPlugin; +import io.flutter.plugin.common.EventChannel; import io.flutter.plugin.common.MethodCall; import io.flutter.plugin.common.MethodChannel; import io.flutter.plugin.common.MethodChannel.MethodCallHandler; @@ -35,6 +36,7 @@ public class FlutterFirebaseFunctionsPlugin private static final String METHOD_CHANNEL_NAME = "plugins.flutter.io/firebase_functions"; private MethodChannel channel; + private FlutterPluginBinding pluginBinding; /** * Default Constructor. @@ -45,6 +47,7 @@ public FlutterFirebaseFunctionsPlugin() {} @Override public void onAttachedToEngine(@NonNull FlutterPluginBinding binding) { + pluginBinding = binding; channel = new MethodChannel(binding.getBinaryMessenger(), METHOD_CHANNEL_NAME); channel.setMethodCallHandler(this); } @@ -55,6 +58,16 @@ public void onDetachedFromEngine(@NonNull FlutterPluginBinding binding) { channel = null; } + private void registerEventChannel(Map arguments) { + final String eventId = (String) Objects.requireNonNull(arguments.get("eventChannelId")); + final String eventChannelName = METHOD_CHANNEL_NAME + "/" + eventId; + final EventChannel eventChannel = + new EventChannel(pluginBinding.getBinaryMessenger(), eventChannelName); + FirebaseFunctions functions = getFunctions(arguments); + FirebaseFunctionsStreamHandler streamHandler = new FirebaseFunctionsStreamHandler(functions); + eventChannel.setStreamHandler(streamHandler); + } + private FirebaseFunctions getFunctions(Map arguments) { String appName = (String) Objects.requireNonNull(arguments.get("appName")); String region = (String) Objects.requireNonNull(arguments.get("region")); @@ -116,24 +129,26 @@ private Task httpsFunctionCall(Map arguments) { @Override public void onMethodCall(MethodCall call, @NonNull final Result result) { - if (!call.method.equals("FirebaseFunctions#call")) { + if (call.method.equals("FirebaseFunctions#registerEventChannel")) { + registerEventChannel(call.arguments()); + result.success(null); + } else if (call.method.equals("FirebaseFunctions#call")) { + httpsFunctionCall(call.arguments()) + .addOnCompleteListener( + task -> { + if (task.isSuccessful()) { + result.success(task.getResult()); + } else { + Exception exception = task.getException(); + result.error( + "firebase_functions", + exception != null ? exception.getMessage() : null, + getExceptionDetails(exception)); + } + }); + } else { result.notImplemented(); - return; } - - httpsFunctionCall(call.arguments()) - .addOnCompleteListener( - task -> { - if (task.isSuccessful()) { - result.success(task.getResult()); - } else { - Exception exception = task.getException(); - result.error( - "firebase_functions", - exception != null ? exception.getMessage() : null, - getExceptionDetails(exception)); - } - }); } private Map getExceptionDetails(@Nullable Exception exception) { diff --git a/packages/cloud_functions/cloud_functions/android/src/main/java/io/flutter/plugins/firebase/functions/StreamResponseSubscriber.java b/packages/cloud_functions/cloud_functions/android/src/main/java/io/flutter/plugins/firebase/functions/StreamResponseSubscriber.java new file mode 100644 index 000000000000..13dd5d8cacf8 --- /dev/null +++ b/packages/cloud_functions/cloud_functions/android/src/main/java/io/flutter/plugins/firebase/functions/StreamResponseSubscriber.java @@ -0,0 +1,65 @@ +// Copyright 2025 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package io.flutter.plugins.firebase.functions; + +import android.os.Handler; +import android.os.Looper; +import com.google.firebase.functions.StreamResponse; +import io.flutter.plugin.common.EventChannel; +import java.util.HashMap; +import java.util.Map; +import org.reactivestreams.Subscriber; +import org.reactivestreams.Subscription; + +public class StreamResponseSubscriber implements Subscriber { + private Subscription subscription; + private final EventChannel.EventSink eventSink; + + private final Handler mainThreadHandler = new Handler(Looper.getMainLooper()); + + public StreamResponseSubscriber(EventChannel.EventSink eventSink) { + this.eventSink = eventSink; + } + + @Override + public void onSubscribe(Subscription s) { + this.subscription = s; + subscription.request(Long.MAX_VALUE); + } + + @Override + public void onNext(StreamResponse streamResponse) { + Map responseMap = new HashMap<>(); + if (streamResponse instanceof StreamResponse.Message) { + Object message = ((StreamResponse.Message) streamResponse).getMessage().getData(); + responseMap.put("message", message); + mainThreadHandler.post(() -> eventSink.success(responseMap)); + } else { + Object result = ((StreamResponse.Result) streamResponse).getResult().getData(); + responseMap.put("result", result); + mainThreadHandler.post(() -> eventSink.success(responseMap)); + } + } + + @Override + public void onError(Throwable t) { + if (eventSink != null) { + mainThreadHandler.post(() -> eventSink.endOfStream()); + } + } + + @Override + public void onComplete() { + if (eventSink != null) { + mainThreadHandler.post(() -> eventSink.endOfStream()); + } + } + + public void cancel() { + if (subscription != null) { + subscription.cancel(); + } + } +} diff --git a/packages/cloud_functions/cloud_functions/example/android/app/src/main/AndroidManifest.xml b/packages/cloud_functions/cloud_functions/example/android/app/src/main/AndroidManifest.xml index 74a78b939e5e..a975611c0582 100644 --- a/packages/cloud_functions/cloud_functions/example/android/app/src/main/AndroidManifest.xml +++ b/packages/cloud_functions/cloud_functions/example/android/app/src/main/AndroidManifest.xml @@ -2,6 +2,7 @@ { List fruit = []; + List streamResult = []; + + @override + void initState() { + super.initState(); + streamFunction(); + } + + void streamFunction() { + fruit.clear(); + FirebaseFunctions.instance + .httpsCallable('testStreamResponse') + .stream() + .listen( + (data) { + if (data is Chunk) { + setState(() { + // adds individual stream values to list + fruit.add(data.partialData); + }); + } else if (data is Result) { + setState(() { + // stores complete stream result + streamResult = List.from(data.result.data); + }); + } + }, + onError: (e) { + debugPrint('Error: $e'); + }, + ); + } @override Widget build(BuildContext context) { @@ -44,15 +76,39 @@ class _MyAppState extends State { appBar: AppBar( title: const Text('Firebase Functions Example'), ), - body: Center( - child: ListView.builder( - itemCount: fruit.length, - itemBuilder: (context, index) { - return ListTile( - title: Text('${fruit[index]}'), - ); - }, - ), + body: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Expanded( + child: ListView.builder( + itemCount: fruit.length, + itemBuilder: (context, index) { + return ListTile( + title: Text('${fruit[index]}'), + ); + }, + ), + ), + Visibility( + visible: streamResult.isNotEmpty, + child: const Text( + "Stream's Complete Result: ", + style: TextStyle( + fontWeight: FontWeight.bold, + ), + ), + ), + Expanded( + child: ListView.builder( + itemCount: streamResult.length, + itemBuilder: (context, index) { + return ListTile( + title: Text('${streamResult[index]}'), + ); + }, + ), + ), + ], ), floatingActionButton: Builder( builder: (context) { @@ -60,6 +116,13 @@ class _MyAppState extends State { mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.end, children: [ + FloatingActionButton.extended( + onPressed: streamFunction, + label: const Text('Call Stream Function'), + icon: const Icon(Icons.cloud), + backgroundColor: Colors.deepOrange, + ), + const SizedBox(height: 10), FloatingActionButton.extended( onPressed: () async { // See .github/workflows/scripts/functions/src/index.ts for the example function we @@ -113,6 +176,7 @@ class _MyAppState extends State { final result = await callable(); setState(() { fruit.clear(); + streamResult.clear(); result.data.forEach((f) { fruit.add(f); }); diff --git a/packages/cloud_functions/cloud_functions/example/pubspec.yaml b/packages/cloud_functions/cloud_functions/example/pubspec.yaml index 147384c7dd17..84769f53f085 100644 --- a/packages/cloud_functions/cloud_functions/example/pubspec.yaml +++ b/packages/cloud_functions/cloud_functions/example/pubspec.yaml @@ -6,7 +6,7 @@ environment: flutter: '>=3.3.0' dependencies: - cloud_functions: ^5.4.0 + cloud_functions: ^5.5.0 firebase_core: ^3.13.0 flutter: sdk: flutter diff --git a/packages/cloud_functions/cloud_functions/ios/cloud_functions/Sources/cloud_functions/CodecUtility.swift b/packages/cloud_functions/cloud_functions/ios/cloud_functions/Sources/cloud_functions/CodecUtility.swift new file mode 100644 index 000000000000..1b8b7faed39a --- /dev/null +++ b/packages/cloud_functions/cloud_functions/ios/cloud_functions/Sources/cloud_functions/CodecUtility.swift @@ -0,0 +1,118 @@ +// Copyright 2025 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +import Foundation + +public struct AnyEncodable: Encodable { + private let value: Any? + + public init(_ value: Any?) { + self.value = value ?? NSNull() + } + + public func encode(to encoder: Encoder) throws { + var container = encoder.singleValueContainer() + + switch value { + case is NSNull: + try container.encodeNil() + case let stringValue as String: + try container.encode(stringValue) + case let boolValue as Bool: + try container.encode(boolValue) + case let intValue as Int: + try container.encode(intValue) + case let int8Value as Int8: + try container.encode(int8Value) + case let int16Value as Int16: + try container.encode(int16Value) + case let int32Value as Int32: + try container.encode(int32Value) + case let int64Value as Int64: + try container.encode(int64Value) + case let uintValue as UInt: + try container.encode(uintValue) + case let uint8Value as UInt8: + try container.encode(uint8Value) + case let uint16Value as UInt16: + try container.encode(uint16Value) + case let uint32Value as UInt32: + try container.encode(uint32Value) + case let uint64Value as UInt64: + try container.encode(uint64Value) + case let doubleValue as Double: + try container.encode(doubleValue) + case let floatValue as Float: + try container.encode(floatValue) + case let arrayValue as [Any]: + try container.encode(arrayValue.map { AnyEncodable($0) }) + case let dictionaryValue as [String: Any]: + try container.encode(dictionaryValue.mapValues { AnyEncodable($0) }) + default: + throw EncodingError.invalidValue( + value as Any, + EncodingError.Context( + codingPath: encoder.codingPath, + debugDescription: "Unsupported type: \(type(of: value))" + ) + ) + } + } +} + +public struct AnyDecodable: Decodable { + public let value: Any? + + public init(from decoder: Decoder) throws { + let container = try decoder.singleValueContainer() + + if container.decodeNil() { + value = NSNull() + return + } + + if let stringValue = try? container.decode(String.self) { + value = stringValue + } else if let intValue = try? container.decode(Int.self) { + value = intValue + } else if let int8Value = try? container.decode(Int8.self) { + value = int8Value + } else if let int16Value = try? container.decode(Int16.self) { + value = int16Value + } else if let int32Value = try? container.decode(Int32.self) { + value = int32Value + } else if let int64Value = try? container.decode(Int64.self) { + value = int64Value + } else if let uintValue = try? container.decode(UInt.self) { + value = uintValue + } else if let uint8Value = try? container.decode(UInt8.self) { + value = uint8Value + } else if let uint16Value = try? container.decode(UInt16.self) { + value = uint16Value + } else if let uint32Value = try? container.decode(UInt32.self) { + value = uint32Value + } else if let uint64Value = try? container.decode(UInt64.self) { + value = uint64Value + } else if let doubleValue = try? container.decode(Double.self) { + value = doubleValue + } else if let floatValue = try? container.decode(Float.self) { + value = floatValue + } else if let boolValue = try? container.decode(Bool.self) { + value = boolValue + } else if let arrayValue = try? container.decode([AnyDecodable].self) { + value = arrayValue.map(\.value) + } else if let dictionaryValue = try? container.decode([String: AnyDecodable].self) { + value = dictionaryValue.mapValues { $0.value } + + } else { + throw DecodingError.dataCorruptedError( + in: container, + debugDescription: "Unable to decode value of type: \(type(of: value))" + ) + } + } + + public init(_ value: Any?) { + self.value = value + } +} diff --git a/packages/cloud_functions/cloud_functions/ios/cloud_functions/Sources/cloud_functions/Constants.swift b/packages/cloud_functions/cloud_functions/ios/cloud_functions/Sources/cloud_functions/Constants.swift index e151ce718392..627273eab7a2 100644 --- a/packages/cloud_functions/cloud_functions/ios/cloud_functions/Sources/cloud_functions/Constants.swift +++ b/packages/cloud_functions/cloud_functions/ios/cloud_functions/Sources/cloud_functions/Constants.swift @@ -3,4 +3,4 @@ // found in the LICENSE file. // Auto-generated file. Do not edit. -public let versionNumber = "5.4.0" +public let versionNumber = "5.5.0" diff --git a/packages/cloud_functions/cloud_functions/ios/cloud_functions/Sources/cloud_functions/FirebaseFunctionsPlugin.swift b/packages/cloud_functions/cloud_functions/ios/cloud_functions/Sources/cloud_functions/FirebaseFunctionsPlugin.swift index 66766bec71b0..ec875e782abf 100644 --- a/packages/cloud_functions/cloud_functions/ios/cloud_functions/Sources/cloud_functions/FirebaseFunctionsPlugin.swift +++ b/packages/cloud_functions/cloud_functions/ios/cloud_functions/Sources/cloud_functions/FirebaseFunctionsPlugin.swift @@ -18,6 +18,12 @@ import FirebaseFunctions let kFLTFirebaseFunctionsChannelName = "plugins.flutter.io/firebase_functions" public class FirebaseFunctionsPlugin: NSObject, FLTFirebasePluginProtocol, FlutterPlugin { + private let binaryMessenger: FlutterBinaryMessenger + + init(binaryMessenger: FlutterBinaryMessenger) { + self.binaryMessenger = binaryMessenger + } + public func firebaseLibraryVersion() -> String { versionNumber } @@ -40,7 +46,6 @@ public class FirebaseFunctionsPlugin: NSObject, FLTFirebasePluginProtocol, Flutt public static func register(with registrar: FlutterPluginRegistrar) { let binaryMessenger: FlutterBinaryMessenger - #if os(macOS) binaryMessenger = registrar.messenger #elseif os(iOS) @@ -51,16 +56,20 @@ public class FirebaseFunctionsPlugin: NSObject, FLTFirebasePluginProtocol, Flutt name: kFLTFirebaseFunctionsChannelName, binaryMessenger: binaryMessenger ) - let instance = FirebaseFunctionsPlugin() + let instance = FirebaseFunctionsPlugin(binaryMessenger: binaryMessenger) registrar.addMethodCallDelegate(instance, channel: channel) } - public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) { - guard call.method == "FirebaseFunctions#call" else { - result(FlutterMethodNotImplemented) - return - } + private func registerEventChannel(arguments: [String: Any]) { + let eventChannelId = arguments["eventChannelId"]! + let eventChannelName = "\(kFLTFirebaseFunctionsChannelName)/\(eventChannelId)" + let eventChannel = FlutterEventChannel(name: eventChannelName, binaryMessenger: binaryMessenger) + let functions = getFunctions(arguments: arguments) + let streamHandler = FunctionsStreamHandler(functions: functions) + eventChannel.setStreamHandler(streamHandler) + } + public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) { guard let arguments = call.arguments as? [String: Any] else { result(FlutterError(code: "invalid_arguments", message: "Invalid arguments", @@ -68,12 +77,20 @@ public class FirebaseFunctionsPlugin: NSObject, FLTFirebasePluginProtocol, Flutt return } - httpsFunctionCall(arguments: arguments) { success, error in - if let error { - result(error) - } else { - result(success) + if call.method == "FirebaseFunctions#registerEventChannel" { + registerEventChannel(arguments: arguments) + result(nil) + } else if call.method == "FirebaseFunctions#call" { + httpsFunctionCall(arguments: arguments) { success, error in + if let error { + result(error) + } else { + result(success) + } } + } else { + result(FlutterMethodNotImplemented) + return } } @@ -132,6 +149,13 @@ public class FirebaseFunctionsPlugin: NSObject, FLTFirebasePluginProtocol, Flutt } } + private func getFunctions(arguments: [String: Any]) -> Functions { + let appName = arguments["appName"] as? String ?? "" + let region = arguments["region"] as? String + let app = FLTFirebasePlugin.firebaseAppNamed(appName)! + return Functions.functions(app: app, region: region ?? "") + } + private func createFlutterError(from error: Error) -> FlutterError { let nsError = error as NSError var errorCode = "unknown" diff --git a/packages/cloud_functions/cloud_functions/ios/cloud_functions/Sources/cloud_functions/FunctionsStreamHandler.swift b/packages/cloud_functions/cloud_functions/ios/cloud_functions/Sources/cloud_functions/FunctionsStreamHandler.swift new file mode 100644 index 000000000000..1e080691be6a --- /dev/null +++ b/packages/cloud_functions/cloud_functions/ios/cloud_functions/Sources/cloud_functions/FunctionsStreamHandler.swift @@ -0,0 +1,112 @@ +// Copyright 2025 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#if canImport(FlutterMacOS) + import FlutterMacOS +#else + import Flutter +#endif + +import FirebaseFunctions + +class FunctionsStreamHandler: NSObject, FlutterStreamHandler { + var functions: Functions + private var streamTask: Task? + + init(functions: Functions) { + self.functions = functions + super.init() + } + + func onListen(withArguments arguments: Any?, + eventSink events: @escaping FlutterEventSink) -> FlutterError? { + streamTask = Task { + await httpsStreamCall(arguments: arguments, events: events) + } + return nil + } + + func onCancel(withArguments arguments: Any?) -> FlutterError? { + streamTask?.cancel() + return nil + } + + private func httpsStreamCall(arguments: Any?, events: @escaping FlutterEventSink) async { + guard let arguments = arguments as? [String: Any] else { + await MainActor.run { + events(FlutterError(code: "invalid_arguments", + message: "Invalid arguments", + details: nil)) + } + return + } + let functionName = arguments["functionName"] as? String + let functionUri = arguments["functionUri"] as? String + let origin = arguments["origin"] as? String + let parameters = arguments["parameters"] + let timeout = arguments["timeout"] as? Double + let limitedUseAppCheckToken = arguments["limitedUseAppCheckToken"] as? Bool ?? false + + if let origin, + let url = URL(string: origin), + let host = url.host, + let port = url.port { + functions.useEmulator(withHost: host, port: port) + } + + let options = HTTPSCallableOptions(requireLimitedUseAppCheckTokens: limitedUseAppCheckToken) + + // Stream handling for iOS 15+ + if #available(iOS 15.0, macOS 12.0, *) { + var function: Callable> + + if let functionName { + function = self.functions.httpsCallable(functionName, options: options) + } else if let functionUri, let url = URL(string: functionUri) { + function = self.functions.httpsCallable(url, options: options) + } else { + await MainActor.run { + events(FlutterError(code: "IllegalArgumentException", + message: "Either functionName or functionUri must be set", + details: nil)) + } + return + } + + if let timeout { + function.timeoutInterval = timeout / 1000 + } + + do { + let encodedParameters = AnyEncodable(parameters) + + let stream = try function.stream(encodedParameters) + + for try await response in stream { + await MainActor.run { + switch response { + case let .message(message): + events(["message": message.value]) + case let .result(result): + events(["result": result.value]) + events(FlutterEndOfEventStream) + } + } + } + } catch { + await MainActor.run { + events(FlutterError(code: "unknown", + message: error.localizedDescription, + details: ["code": "unknown", "message": error.localizedDescription])) + } + } + } else { + await MainActor.run { + events(FlutterError(code: "unknown", + message: "Streaming requires iOS 15+ or macOS 12+", + details: nil)) + } + } + } +} diff --git a/packages/cloud_functions/cloud_functions/lib/cloud_functions.dart b/packages/cloud_functions/cloud_functions/lib/cloud_functions.dart index 5750bd226326..f95683cac2bd 100644 --- a/packages/cloud_functions/cloud_functions/lib/cloud_functions.dart +++ b/packages/cloud_functions/cloud_functions/lib/cloud_functions.dart @@ -15,8 +15,15 @@ import 'package:firebase_core_platform_interface/firebase_core_platform_interfac import 'package:flutter/foundation.dart'; export 'package:cloud_functions_platform_interface/cloud_functions_platform_interface.dart' - show HttpsCallableOptions, FirebaseFunctionsException; + show + HttpsCallableOptions, + FirebaseFunctionsException, + AbortSignal, + TimeLimit, + Abort, + Any; part 'src/firebase_functions.dart'; part 'src/https_callable.dart'; part 'src/https_callable_result.dart'; +part 'src/https_callable_stream_result.dart'; diff --git a/packages/cloud_functions/cloud_functions/lib/src/https_callable.dart b/packages/cloud_functions/cloud_functions/lib/src/https_callable.dart index 61e66c65b061..79cb5370efed 100644 --- a/packages/cloud_functions/cloud_functions/lib/src/https_callable.dart +++ b/packages/cloud_functions/cloud_functions/lib/src/https_callable.dart @@ -48,6 +48,32 @@ class HttpsCallable { } return HttpsCallableResult._(await delegate.call(updatedParameters)); } + + /// Streams data to the specified HTTPS endpoint. + /// + /// The data passed into the trigger can be any of the following types: + /// + /// `null` + /// `String` + /// `num` + /// [List], where the contained objects are also one of these types. + /// [Map], where the values are also one of these types. + /// + /// The request to the Cloud Functions backend made by this method + /// automatically includes a Firebase Instance ID token to identify the app + /// instance. If a user is logged in with Firebase Auth, an auth ID token for + /// the user is also automatically included. + Stream stream([Object? input]) async* { + await for (final value in delegate.stream(input).asBroadcastStream()) { + if (value is Map) { + if (value.containsKey('message')) { + yield Chunk(value['message'] as T); + } else if (value.containsKey('result')) { + yield Result(HttpsCallableResult._(value['result'] as R)); + } + } + } + } } dynamic _updateRawDataToList(dynamic value) { diff --git a/packages/cloud_functions/cloud_functions/lib/src/https_callable_stream_result.dart b/packages/cloud_functions/cloud_functions/lib/src/https_callable_stream_result.dart new file mode 100644 index 000000000000..6a377310fc30 --- /dev/null +++ b/packages/cloud_functions/cloud_functions/lib/src/https_callable_stream_result.dart @@ -0,0 +1,23 @@ +// ignore_for_file: require_trailing_commas +// Copyright 2025, the Chromium project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +part of '../cloud_functions.dart'; + +/// Represents a response from a Server-Sent Event (SSE) stream. +sealed class StreamResponse {} + +/// A chunk received during the stream. +class Chunk extends StreamResponse { + /// The intermediate data received from the server. + final T partialData; + Chunk(this.partialData); +} + +/// The final result of the computation, marking the end of the stream. +class Result extends StreamResponse { + /// The final computed result received from the server. + final HttpsCallableResult result; + Result(this.result); +} diff --git a/packages/cloud_functions/cloud_functions/macos/cloud_functions/Sources/cloud_functions/CodecUtility.swift b/packages/cloud_functions/cloud_functions/macos/cloud_functions/Sources/cloud_functions/CodecUtility.swift new file mode 120000 index 000000000000..4dd991ad2c6f --- /dev/null +++ b/packages/cloud_functions/cloud_functions/macos/cloud_functions/Sources/cloud_functions/CodecUtility.swift @@ -0,0 +1 @@ +../../../../ios/cloud_functions/Sources/cloud_functions/CodecUtility.swift \ No newline at end of file diff --git a/packages/cloud_functions/cloud_functions/macos/cloud_functions/Sources/cloud_functions/FunctionsStreamHandler.swift b/packages/cloud_functions/cloud_functions/macos/cloud_functions/Sources/cloud_functions/FunctionsStreamHandler.swift new file mode 120000 index 000000000000..f3d52d2d4e5e --- /dev/null +++ b/packages/cloud_functions/cloud_functions/macos/cloud_functions/Sources/cloud_functions/FunctionsStreamHandler.swift @@ -0,0 +1 @@ +../../../../ios/cloud_functions/Sources/cloud_functions/FunctionsStreamHandler.swift \ No newline at end of file diff --git a/packages/cloud_functions/cloud_functions/pubspec.yaml b/packages/cloud_functions/cloud_functions/pubspec.yaml index 8baea827b044..2ac27f36d73f 100644 --- a/packages/cloud_functions/cloud_functions/pubspec.yaml +++ b/packages/cloud_functions/cloud_functions/pubspec.yaml @@ -1,6 +1,6 @@ name: cloud_functions description: A Flutter plugin allowing you to use Firebase Cloud Functions. -version: 5.4.0 +version: 5.5.0 homepage: https://firebase.google.com/docs/functions repository: https://github.com/firebase/flutterfire/tree/main/packages/cloud_functions/cloud_functions topics: @@ -17,8 +17,8 @@ environment: flutter: '>=3.3.0' dependencies: - cloud_functions_platform_interface: ^5.6.5 - cloud_functions_web: ^4.10.11 + cloud_functions_platform_interface: ^5.7.0 + cloud_functions_web: ^4.11.0 firebase_core: ^3.13.0 firebase_core_platform_interface: ^5.3.1 flutter: diff --git a/packages/cloud_functions/cloud_functions_platform_interface/CHANGELOG.md b/packages/cloud_functions/cloud_functions_platform_interface/CHANGELOG.md index 6748cc86b58b..3c9519271aaf 100644 --- a/packages/cloud_functions/cloud_functions_platform_interface/CHANGELOG.md +++ b/packages/cloud_functions/cloud_functions_platform_interface/CHANGELOG.md @@ -1,3 +1,7 @@ +## 5.7.0 + + - **FEAT**(cloud_functions): add support for cloud functions stream ([#17214](https://github.com/firebase/flutterfire/issues/17214)). ([509e0f3c](https://github.com/firebase/flutterfire/commit/509e0f3cc984a7b56a67979b4b27aff72defdd55)) + ## 5.6.5 - Update a dependency to the latest release. diff --git a/packages/cloud_functions/cloud_functions_platform_interface/lib/src/https_callable_options.dart b/packages/cloud_functions/cloud_functions_platform_interface/lib/src/https_callable_options.dart index 37a240052a31..69e154f8b22e 100644 --- a/packages/cloud_functions/cloud_functions_platform_interface/lib/src/https_callable_options.dart +++ b/packages/cloud_functions/cloud_functions_platform_interface/lib/src/https_callable_options.dart @@ -10,11 +10,70 @@ class HttpsCallableOptions { /// Defaults [limitedUseAppCheckToken] to `false` HttpsCallableOptions( {this.timeout = const Duration(seconds: 60), - this.limitedUseAppCheckToken = false}); + this.limitedUseAppCheckToken = false, + this.webAbortSignal}); /// Returns the timeout for this instance Duration timeout; /// Sets whether or not to use limited-use App Check tokens when invoking the associated function. bool limitedUseAppCheckToken; + + /// An AbortSignal that can be used to cancel the streaming response. + /// When the signal is aborted, the underlying HTTP connection will be terminated. + AbortSignal? webAbortSignal; +} + +/// Represents a base class for encapsulating abort signals. +sealed class AbortSignal {} + +/// Creates an [AbortSignal] that will automatically abort after a specified [time]. +/// +/// This is equivalent to calling `AbortSignal.timeout(ms)` in the Web SDK. +/// +/// Typically used to cancel long-running operations after a timeout duration. +/// +/// Example: +/// ```dart +/// final signal = HttpsCallableOptions(webAbortSignal: TimeLimit(Duration(seconds: 10))); +/// ``` +class TimeLimit extends AbortSignal { + final Duration time; + TimeLimit(this.time); +} + +/// Creates an [AbortSignal] that is immediately aborted with an optional [reason]. +/// +/// This is equivalent to calling `AbortSignal.abort(reason)` in the Web SDK. +/// +/// Useful when you want to explicitly cancel a callable before it begins, or to provide +/// a specific reason for cancellation. +/// +/// Example: +/// ```dart +/// final signal = HttpsCallableOptions(webAbortSignal: Abort('User exited')); +/// ``` +class Abort extends AbortSignal { + final Object? reason; + Abort([this.reason]); +} + +/// Creates an [AbortSignal] that is aborted when **any** of the provided [signals] is aborted. +/// +/// This is equivalent to calling `AbortSignal.any([...])` in the Web SDK. +/// +/// Useful for combining multiple abort conditions. +/// +/// Example: +/// ```dart +/// final signal = HttpsCallableOptions( +/// webAbortSignal: Any([ +/// TimeLimit(Duration(seconds: 10)), +/// Abort('User cancelled'), +/// ]), +/// ); +/// ``` +class Any extends AbortSignal { + final List signals; + Any(this.signals); } diff --git a/packages/cloud_functions/cloud_functions_platform_interface/lib/src/method_channel/method_channel_https_callable.dart b/packages/cloud_functions/cloud_functions_platform_interface/lib/src/method_channel/method_channel_https_callable.dart index fb17e3e5b706..c4eddec24e03 100644 --- a/packages/cloud_functions/cloud_functions_platform_interface/lib/src/method_channel/method_channel_https_callable.dart +++ b/packages/cloud_functions/cloud_functions_platform_interface/lib/src/method_channel/method_channel_https_callable.dart @@ -5,6 +5,8 @@ import 'dart:async'; +import 'package:flutter/services.dart'; + import '../../cloud_functions_platform_interface.dart'; import 'method_channel_firebase_functions.dart'; import 'utils/exception.dart'; @@ -14,7 +16,16 @@ class MethodChannelHttpsCallable extends HttpsCallablePlatform { /// Creates a new [MethodChannelHttpsCallable] instance. MethodChannelHttpsCallable(FirebaseFunctionsPlatform functions, String? origin, String? name, HttpsCallableOptions options, Uri? uri) - : super(functions, origin, name, options, uri); + : _transformedUri = uri?.pathSegments.join('_').replaceAll('.', '_'), + super(functions, origin, name, options, uri) { + _eventChannelId = name ?? _transformedUri ?? ''; + _channel = + EventChannel('plugins.flutter.io/firebase_functions/$_eventChannelId'); + } + + late final EventChannel _channel; + final String? _transformedUri; + late String _eventChannelId; @override Future call([Object? parameters]) async { @@ -40,4 +51,36 @@ class MethodChannelHttpsCallable extends HttpsCallablePlatform { convertPlatformException(e, s); } } + + @override + Stream stream(Object? parameters) async* { + try { + await _registerEventChannelOnNative(); + final eventData = { + 'functionName': name, + 'functionUri': uri?.toString(), + 'origin': origin, + 'parameters': parameters, + 'limitedUseAppCheckToken': options.limitedUseAppCheckToken, + 'timeout': options.timeout.inMilliseconds, + }; + yield* _channel.receiveBroadcastStream(eventData).map((message) { + if (message is Map) { + return Map.from(message); + } + return message; + }); + } catch (e, s) { + convertPlatformException(e, s); + } + } + + Future _registerEventChannelOnNative() async { + await MethodChannelFirebaseFunctions.channel.invokeMethod( + 'FirebaseFunctions#registerEventChannel', { + 'eventChannelId': _eventChannelId, + 'appName': functions.app!.name, + 'region': functions.region, + }); + } } diff --git a/packages/cloud_functions/cloud_functions_platform_interface/lib/src/platform_interface/platform_interface_firebase_functions.dart b/packages/cloud_functions/cloud_functions_platform_interface/lib/src/platform_interface/platform_interface_firebase_functions.dart index f8339facf7ad..d9eac236d341 100644 --- a/packages/cloud_functions/cloud_functions_platform_interface/lib/src/platform_interface/platform_interface_firebase_functions.dart +++ b/packages/cloud_functions/cloud_functions_platform_interface/lib/src/platform_interface/platform_interface_firebase_functions.dart @@ -70,6 +70,6 @@ abstract class FirebaseFunctionsPlatform extends PlatformInterface { /// Creates a [HttpsCallablePlatform] instance from a [Uri] HttpsCallablePlatform httpsCallableWithUri( String? origin, Uri uri, HttpsCallableOptions options) { - throw UnimplementedError('httpsCallable() is not implemented'); + throw UnimplementedError('httpsCallableWithUri() is not implemented'); } } diff --git a/packages/cloud_functions/cloud_functions_platform_interface/lib/src/platform_interface/platform_interface_https_callable.dart b/packages/cloud_functions/cloud_functions_platform_interface/lib/src/platform_interface/platform_interface_https_callable.dart index ec5c2c22c9c1..be287c7a9571 100644 --- a/packages/cloud_functions/cloud_functions_platform_interface/lib/src/platform_interface/platform_interface_https_callable.dart +++ b/packages/cloud_functions/cloud_functions_platform_interface/lib/src/platform_interface/platform_interface_https_callable.dart @@ -67,4 +67,22 @@ abstract class HttpsCallablePlatform extends PlatformInterface { Future call([dynamic parameters]) { throw UnimplementedError('call() is not implemented'); } + + /// Streams data to the specified HTTPS endpoint. + /// + /// The data passed into the trigger can be any of the following types: + /// + /// `null` + /// `String` + /// `num` + /// [List], where the contained objects are also one of these types. + /// [Map], where the values are also one of these types. + /// + /// The request to the Cloud Functions backend made by this method + /// automatically includes a Firebase Instance ID token to identify the app + /// instance. If a user is logged in with Firebase Auth, an auth ID token for + /// the user is also automatically included. + Stream stream(Object? parameters) { + throw UnimplementedError('stream() is not implemented'); + } } diff --git a/packages/cloud_functions/cloud_functions_platform_interface/pubspec.yaml b/packages/cloud_functions/cloud_functions_platform_interface/pubspec.yaml index 7645c4625c14..fa0f16dbe31f 100644 --- a/packages/cloud_functions/cloud_functions_platform_interface/pubspec.yaml +++ b/packages/cloud_functions/cloud_functions_platform_interface/pubspec.yaml @@ -5,7 +5,7 @@ repository: https://github.com/firebase/flutterfire/tree/main/packages/cloud_fun # NOTE: We strongly prefer non-breaking changes, even at the expense of a # less-clean API. See https://flutter.dev/go/platform-interface-breaking-changes -version: 5.6.5 +version: 5.7.0 environment: sdk: '>=3.2.0 <4.0.0' diff --git a/packages/cloud_functions/cloud_functions_web/CHANGELOG.md b/packages/cloud_functions/cloud_functions_web/CHANGELOG.md index 2dbfe645265d..80bcdb95c396 100644 --- a/packages/cloud_functions/cloud_functions_web/CHANGELOG.md +++ b/packages/cloud_functions/cloud_functions_web/CHANGELOG.md @@ -1,3 +1,7 @@ +## 4.11.0 + + - **FEAT**(cloud_functions): add support for cloud functions stream ([#17214](https://github.com/firebase/flutterfire/issues/17214)). ([509e0f3c](https://github.com/firebase/flutterfire/commit/509e0f3cc984a7b56a67979b4b27aff72defdd55)) + ## 4.10.11 - Update a dependency to the latest release. diff --git a/packages/cloud_functions/cloud_functions_web/lib/https_callable_web.dart b/packages/cloud_functions/cloud_functions_web/lib/https_callable_web.dart index c85f7a17d564..31e30afc1859 100644 --- a/packages/cloud_functions/cloud_functions_web/lib/https_callable_web.dart +++ b/packages/cloud_functions/cloud_functions_web/lib/https_callable_web.dart @@ -7,9 +7,11 @@ import 'dart:async'; import 'dart:js_interop'; import 'package:cloud_functions_platform_interface/cloud_functions_platform_interface.dart'; +import 'package:cloud_functions_web/interop/functions_interop.dart' as interop; import 'interop/functions.dart' as functions_interop; import 'utils.dart'; +import 'package:web/web.dart' as web; /// A web specific implementation of [HttpsCallable]. class HttpsCallableWeb extends HttpsCallablePlatform { @@ -56,4 +58,57 @@ class HttpsCallableWeb extends HttpsCallablePlatform { return response.data; } + + @override + Stream stream(Object? parameters) async* { + if (origin != null) { + final uri = Uri.parse(origin!); + + _webFunctions.useFunctionsEmulator(uri.host, uri.port); + } + + late functions_interop.HttpsCallable callable; + + if (name != null) { + callable = _webFunctions.httpsCallable(name!); + } else if (uri != null) { + callable = _webFunctions.httpsCallableUri(uri!); + } else { + throw ArgumentError('Either name or uri must be provided'); + } + + final JSAny? parametersJS = parameters?.jsify(); + web.AbortSignal? signal; + if (options.webAbortSignal != null) { + signal = _createJsAbortSignal(options.webAbortSignal!); + } + interop.HttpsCallableStreamOptions callableStreamOptions = + interop.HttpsCallableStreamOptions( + limitedUseAppCheckTokens: options.limitedUseAppCheckToken.toJS, + signal: signal); + try { + await for (final value + in callable.stream(parametersJS, callableStreamOptions)) { + yield value; + } + } catch (e, s) { + throw convertFirebaseFunctionsException(e as JSObject, s); + } + } + + web.AbortSignal _createJsAbortSignal(AbortSignal signal) { + try { + switch (signal) { + case TimeLimit(:final time): + return web.AbortSignal.timeout(time.inMilliseconds); + case Abort(:final reason): + return web.AbortSignal.abort(reason.jsify()); + case Any(:final signals): + final jsSignals = signals.map(_createJsAbortSignal).toList().toJS; + return web.AbortSignal.any(jsSignals); + } + } catch (e, s) { + throw convertFirebaseFunctionsException(e as JSObject, s); + } + } } diff --git a/packages/cloud_functions/cloud_functions_web/lib/interop/functions.dart b/packages/cloud_functions/cloud_functions_web/lib/interop/functions.dart index 30319f68f5cb..0b548c34748f 100644 --- a/packages/cloud_functions/cloud_functions_web/lib/interop/functions.dart +++ b/packages/cloud_functions/cloud_functions_web/lib/interop/functions.dart @@ -6,7 +6,6 @@ // ignore_for_file: public_member_api_docs import 'dart:js_interop'; - import 'package:firebase_core_web/firebase_core_web_interop.dart'; import 'functions_interop.dart' as functions_interop; @@ -84,6 +83,28 @@ class HttpsCallable extends JsObjectWrapper { result! as functions_interop.HttpsCallableResultJsImpl, ); } + + Stream stream(JSAny? data, + functions_interop.HttpsCallableStreamOptions? options) async* { + final streamCallable = await (jsObject as functions_interop.HttpsCallable) + .stream(data, options) + .toDart; + final streamResult = + streamCallable! as functions_interop.HttpsCallableStreamResultJsImpl; + + await for (final value in streamResult.stream.asStream()) { + // ignore: invalid_runtime_check_with_js_interop_types + final message = value is JSObject + ? HttpsCallableStreamResult.getInstance( + value as functions_interop.HttpsStreamIterableResult, + ).data + : value; + yield {'message': message}; + } + + final result = await streamResult.data.toDart; + yield {'result': result}; + } } /// Returns Dart representation from JS Object. @@ -137,3 +158,25 @@ class HttpsCallableResult return _data; } } + +class HttpsCallableStreamResult + extends JsObjectWrapper { + HttpsCallableStreamResult._fromJsObject( + functions_interop.HttpsStreamIterableResult jsObject) + : _data = _dartify(jsObject.value), + super.fromJsObject(jsObject); + + static final _expando = Expando(); + final dynamic _data; + + /// Creates a new HttpsCallableResult from a [jsObject]. + static HttpsCallableStreamResult getInstance( + functions_interop.HttpsStreamIterableResult jsObject) { + return _expando[jsObject] ??= + HttpsCallableStreamResult._fromJsObject(jsObject); + } + + dynamic get data { + return _data; + } +} diff --git a/packages/cloud_functions/cloud_functions_web/lib/interop/functions_interop.dart b/packages/cloud_functions/cloud_functions_web/lib/interop/functions_interop.dart index ce70773e96a2..e6912f113b88 100644 --- a/packages/cloud_functions/cloud_functions_web/lib/interop/functions_interop.dart +++ b/packages/cloud_functions/cloud_functions_web/lib/interop/functions_interop.dart @@ -9,6 +9,8 @@ library; import 'dart:js_interop'; +import 'dart:js_interop_unsafe'; +import 'package:web/web.dart' as web; import 'package:firebase_core_web/firebase_core_web_interop.dart'; @@ -76,3 +78,66 @@ abstract class HttpsCallableResultJsImpl {} extension HttpsCallableResultJsImplExtension on HttpsCallableResultJsImpl { external JSAny? get data; } + +@JS('HttpsCallable') +@staticInterop +class HttpsCallable {} + +extension HttpsCallableExtension on HttpsCallable { + external JSPromise stream([JSAny? data, HttpsCallableStreamOptions? options]); +} + +@JS('HttpsCallableStreamResult') +@staticInterop +class HttpsCallableStreamResultJsImpl {} + +extension HttpsCallableStreamResultJsImplExtension + on HttpsCallableStreamResultJsImpl { + external JSPromise data; + external JsAsyncIterator stream; +} + +@JS('HttpsCallableStreamOptions') +@staticInterop +@anonymous +abstract class HttpsCallableStreamOptions { + external factory HttpsCallableStreamOptions( + {JSBoolean? limitedUseAppCheckTokens, web.AbortSignal? signal}); +} + +extension HttpsCallableStreamOptionsExtension on HttpsCallableStreamOptions { + external JSBoolean? get limitedUseAppCheckTokens; + external set limitedUseAppCheckTokens(JSBoolean? t); + external web.AbortSignal? signal; + external set siganl(web.AbortSignal? s); +} + +extension type JsAsyncIterator._(JSObject _) + implements JSObject { + Stream asStream() async* { + final symbolJS = web.window.getProperty('Symbol'.toJS)! as JSFunction; + final asyncIterator = symbolJS.getProperty('asyncIterator'.toJS); + final iterator = + (this as JSObject).getProperty(asyncIterator!)! as JsAsyncIterator; + final object = (iterator as JSFunction).callAsFunction()! as JSObject; + while (true) { + // Wait for the next iteration result. + final result = await ((object.getProperty('next'.toJS)! as JSFunction) + .callAsFunction()! as JSPromise) + .toDart; + final dartObject = (result.dartify()! as Map).cast(); + if (dartObject['done'] as bool) { + break; + } + yield result as JSObject; + } + } +} + +@JS() +@staticInterop +abstract class HttpsStreamIterableResult {} + +extension HttpsStreamIterableResultExtension on HttpsStreamIterableResult { + external JSAny? get value; +} diff --git a/packages/cloud_functions/cloud_functions_web/pubspec.yaml b/packages/cloud_functions/cloud_functions_web/pubspec.yaml index 57dad168943a..9e989d370d95 100644 --- a/packages/cloud_functions/cloud_functions_web/pubspec.yaml +++ b/packages/cloud_functions/cloud_functions_web/pubspec.yaml @@ -3,20 +3,21 @@ description: The web implementation of cloud_functions homepage: https://github.com/firebase/flutterfire/tree/main/packages/cloud_functions/cloud_functions_web repository: https://github.com/firebase/flutterfire/tree/main/packages/cloud_functions/cloud_functions_web -version: 4.10.11 +version: 4.11.0 environment: sdk: '>=3.4.0 <4.0.0' flutter: '>=3.22.0' dependencies: - cloud_functions_platform_interface: ^5.6.5 + cloud_functions_platform_interface: ^5.7.0 firebase_core: ^3.13.0 firebase_core_web: ^2.22.0 flutter: sdk: flutter flutter_web_plugins: sdk: flutter + web: ^1.1.1 dev_dependencies: firebase_core_platform_interface: ^5.3.1 diff --git a/packages/firebase_ai/firebase_ai/example/pubspec.yaml b/packages/firebase_ai/firebase_ai/example/pubspec.yaml index fe0fc37c6e25..430a5c2df7e2 100644 --- a/packages/firebase_ai/firebase_ai/example/pubspec.yaml +++ b/packages/firebase_ai/firebase_ai/example/pubspec.yaml @@ -45,9 +45,3 @@ flutter: - assets/images/ - assets/documents/ - assets/videos/ - -dependency_overrides: - firebase_ai: - path: ../../firebase_ai - firebase_vertexai: - path: ../../../firebase_vertexai/firebase_vertexai diff --git a/packages/firebase_ai/firebase_ai/lib/firebase_ai.dart b/packages/firebase_ai/firebase_ai/lib/firebase_ai.dart index aa5160ea03ca..dbc95e1bca24 100644 --- a/packages/firebase_ai/firebase_ai/lib/firebase_ai.dart +++ b/packages/firebase_ai/firebase_ai/lib/firebase_ai.dart @@ -27,6 +27,7 @@ export 'src/api.dart' HarmProbability, HarmBlockMethod, PromptFeedback, + ResponseModalities, SafetyRating, SafetySetting, UsageMetadata; @@ -70,7 +71,6 @@ export 'src/live_api.dart' show LiveGenerationConfig, SpeechConfig, - ResponseModalities, LiveServerMessage, LiveServerContent, LiveServerToolCall, diff --git a/packages/firebase_ai/firebase_ai/lib/src/api.dart b/packages/firebase_ai/firebase_ai/lib/src/api.dart index f42e57c86a5e..afe69f6dce52 100644 --- a/packages/firebase_ai/firebase_ai/lib/src/api.dart +++ b/packages/firebase_ai/firebase_ai/lib/src/api.dart @@ -109,6 +109,15 @@ final class GenerateContentResponse { Iterable get functionCalls => candidates.firstOrNull?.content.parts.whereType() ?? const []; + + /// The inline data parts of the first candidate in [candidates], if any. + /// + /// Returns an empty list if there are no candidates, or if the first + /// candidate has no [InlineDataPart] parts. There is no error thrown if the + /// prompt or response were blocked. + Iterable get inlineDataParts => + candidates.firstOrNull?.content.parts.whereType() ?? + const []; } /// Feedback metadata of a prompt specified in a [GenerativeModel] request. @@ -609,7 +618,12 @@ enum HarmBlockThreshold { high('BLOCK_ONLY_HIGH'), /// Always show regardless of probability of unsafe content. - none('BLOCK_NONE'); + none('BLOCK_NONE'), + + /// All content is allowed regardless of harm. + /// + /// metadata will not be included in the response. + off('OFF'); const HarmBlockThreshold(this._jsonString); @@ -620,6 +634,7 @@ enum HarmBlockThreshold { 'BLOCK_MEDIUM_AND_ABOVE' => HarmBlockThreshold.medium, 'BLOCK_ONLY_HIGH' => HarmBlockThreshold.high, 'BLOCK_NONE' => HarmBlockThreshold.none, + 'OFF' => HarmBlockThreshold.off, _ => throw FormatException( 'Unhandled HarmBlockThreshold format', jsonObject), }; @@ -668,6 +683,24 @@ enum HarmBlockMethod { Object toJson() => _jsonString; } +/// The available response modalities. +enum ResponseModalities { + /// Text response modality. + text('TEXT'), + + /// Image response modality. + image('IMAGE'), + + /// Audio response modality. + audio('AUDIO'); + + const ResponseModalities(this._jsonString); + final String _jsonString; + + /// Convert to json format + String toJson() => _jsonString; +} + /// Configuration options for model generation and outputs. abstract class BaseGenerationConfig { // ignore: public_member_api_docs @@ -679,6 +712,7 @@ abstract class BaseGenerationConfig { this.topK, this.presencePenalty, this.frequencyPenalty, + this.responseModalities, }); /// Number of generated responses to return. @@ -755,6 +789,9 @@ abstract class BaseGenerationConfig { /// for more details. final double? frequencyPenalty; + /// The list of desired response modalities. + final List? responseModalities; + // ignore: public_member_api_docs Map toJson() => { if (candidateCount case final candidateCount?) @@ -768,6 +805,9 @@ abstract class BaseGenerationConfig { 'presencePenalty': presencePenalty, if (frequencyPenalty case final frequencyPenalty?) 'frequencyPenalty': frequencyPenalty, + if (responseModalities case final responseModalities?) + 'responseModalities': + responseModalities.map((modality) => modality.toJson()).toList(), }; } @@ -783,6 +823,7 @@ final class GenerationConfig extends BaseGenerationConfig { super.topK, super.presencePenalty, super.frequencyPenalty, + super.responseModalities, this.responseMimeType, this.responseSchema, }); @@ -815,7 +856,7 @@ final class GenerationConfig extends BaseGenerationConfig { if (responseMimeType case final responseMimeType?) 'responseMimeType': responseMimeType, if (responseSchema case final responseSchema?) - 'responseSchema': responseSchema, + 'responseSchema': responseSchema.toJson(), }; } @@ -1071,14 +1112,22 @@ ModalityTokenCount _parseModalityTokenCount(Object? jsonObject) { if (jsonObject is! Map) { throw unhandledFormat('ModalityTokenCount', jsonObject); } - return ModalityTokenCount(ContentModality._parseValue(jsonObject['modality']), - jsonObject['tokenCount'] as int); + var modality = ContentModality._parseValue(jsonObject['modality']); + + if (jsonObject.containsKey('tokenCount')) { + return ModalityTokenCount(modality, jsonObject['tokenCount'] as int); + } else { + return ModalityTokenCount(modality, 0); + } } SafetyRating _parseSafetyRating(Object? jsonObject) { if (jsonObject is! Map) { throw unhandledFormat('SafetyRating', jsonObject); } + if (jsonObject.isEmpty) { + return SafetyRating(HarmCategory.unknown, HarmProbability.unknown); + } return SafetyRating(HarmCategory._parseValue(jsonObject['category']), HarmProbability._parseValue(jsonObject['probability']), probabilityScore: jsonObject['probabilityScore'] as double?, diff --git a/packages/firebase_ai/firebase_ai/lib/src/developer/api.dart b/packages/firebase_ai/firebase_ai/lib/src/developer/api.dart index 8bc1117fdbfa..e1a56f30a894 100644 --- a/packages/firebase_ai/firebase_ai/lib/src/developer/api.dart +++ b/packages/firebase_ai/firebase_ai/lib/src/developer/api.dart @@ -74,7 +74,8 @@ String _harmBlockThresholdtoJson(HarmBlockThreshold? threshold) => HarmBlockThreshold.low => 'BLOCK_LOW_AND_ABOVE', HarmBlockThreshold.medium => 'BLOCK_MEDIUM_AND_ABOVE', HarmBlockThreshold.high => 'BLOCK_ONLY_HIGH', - HarmBlockThreshold.none => 'BLOCK_NONE' + HarmBlockThreshold.none => 'BLOCK_NONE', + HarmBlockThreshold.off => 'OFF', }; String _harmCategoryToJson(HarmCategory harmCategory) => switch (harmCategory) { HarmCategory.unknown => 'HARM_CATEGORY_UNSPECIFIED', diff --git a/packages/firebase_ai/firebase_ai/lib/src/live_api.dart b/packages/firebase_ai/firebase_ai/lib/src/live_api.dart index d0480f2f7e22..8ae67a65051f 100644 --- a/packages/firebase_ai/firebase_ai/lib/src/live_api.dart +++ b/packages/firebase_ai/firebase_ai/lib/src/live_api.dart @@ -71,30 +71,12 @@ class SpeechConfig { }; } -/// The available response modalities. -enum ResponseModalities { - /// Text response modality. - text('TEXT'), - - /// Image response modality. - image('IMAGE'), - - /// Audio response modality. - audio('AUDIO'); - - const ResponseModalities(this._jsonString); - final String _jsonString; - - /// Convert to json format - String toJson() => _jsonString; -} - /// Configures live generation settings. final class LiveGenerationConfig extends BaseGenerationConfig { // ignore: public_member_api_docs LiveGenerationConfig({ this.speechConfig, - this.responseModalities, + super.responseModalities, super.candidateCount, super.maxOutputTokens, super.temperature, @@ -107,17 +89,11 @@ final class LiveGenerationConfig extends BaseGenerationConfig { /// The speech configuration. final SpeechConfig? speechConfig; - /// The list of desired response modalities. - final List? responseModalities; - @override Map toJson() => { ...super.toJson(), if (speechConfig case final speechConfig?) 'speechConfig': speechConfig.toJson(), - if (responseModalities case final responseModalities?) - 'responseModalities': - responseModalities.map((modality) => modality.toJson()).toList(), }; } diff --git a/packages/firebase_ai/firebase_ai/lib/src/schema.dart b/packages/firebase_ai/firebase_ai/lib/src/schema.dart index e73f44b355f3..44dc89e75a8b 100644 --- a/packages/firebase_ai/firebase_ai/lib/src/schema.dart +++ b/packages/firebase_ai/firebase_ai/lib/src/schema.dart @@ -23,24 +23,35 @@ final class Schema { this.type, { this.format, this.description, + this.title, this.nullable, this.enumValues, this.items, + this.minItems, + this.maxItems, + this.minimum, + this.maximum, this.properties, this.optionalProperties, + this.propertyOrdering, + this.anyOf, }); /// Construct a schema for an object with one or more properties. Schema.object({ required Map properties, List? optionalProperties, + List? propertyOrdering, String? description, + String? title, bool? nullable, }) : this( SchemaType.object, properties: properties, optionalProperties: optionalProperties, + propertyOrdering: propertyOrdering, description: description, + title: title, nullable: nullable, ); @@ -48,21 +59,29 @@ final class Schema { Schema.array({ required Schema items, String? description, + String? title, bool? nullable, + int? minItems, + int? maxItems, }) : this( SchemaType.array, description: description, + title: title, nullable: nullable, items: items, + minItems: minItems, + maxItems: maxItems, ); /// Construct a schema for bool value. Schema.boolean({ String? description, + String? title, bool? nullable, }) : this( SchemaType.boolean, description: description, + title: title, nullable: nullable, ); @@ -71,13 +90,19 @@ final class Schema { /// The [format] may be "int32" or "int64". Schema.integer({ String? description, + String? title, bool? nullable, String? format, + int? minimum, + int? maximum, }) : this( SchemaType.integer, description: description, + title: title, nullable: nullable, format: format, + minimum: minimum?.toDouble(), + maximum: maximum?.toDouble(), ); /// Construct a schema for a non-integer number. @@ -85,24 +110,32 @@ final class Schema { /// The [format] may be "float" or "double". Schema.number({ String? description, + String? title, bool? nullable, String? format, + double? minimum, + double? maximum, }) : this( SchemaType.number, description: description, + title: title, nullable: nullable, format: format, + minimum: minimum, + maximum: maximum, ); /// Construct a schema for String value with enumerated possible values. Schema.enumString({ required List enumValues, String? description, + String? title, bool? nullable, }) : this( SchemaType.string, enumValues: enumValues, description: description, + title: title, nullable: nullable, format: 'enum', ); @@ -110,10 +143,42 @@ final class Schema { /// Construct a schema for a String value. Schema.string({ String? description, + String? title, bool? nullable, String? format, - }) : this(SchemaType.string, - description: description, nullable: nullable, format: format); + }) : this( + SchemaType.string, + description: description, + title: title, + nullable: nullable, + format: format, + ); + + /// Construct a schema representing a value that must conform to + /// *any* (one or more) of the provided sub-schemas. + /// + /// This schema instructs the model to produce data that is valid against at + /// least one of the schemas listed in the `schemas` array. This is useful + /// when a field can accept multiple distinct types or structures. + /// + /// **Example:** A field that can hold either a simple user ID (integer) or a + /// detailed user object. + /// ``` + /// Schema.anyOf(anyOf: [ + /// .Schema.integer(description: "User ID"), + /// .Schema.object(properties: [ + /// "userId": Schema.integer(), + /// "userName": Schema.string() + /// ], description: "Detailed User Object") + /// ]) + /// ``` + /// The generated data could be decoded based on which schema it matches. + Schema.anyOf({ + required List schemas, + }) : this( + SchemaType.anyOf, // The type will be ignored in toJson + anyOf: schemas, + ); /// The type of this value. SchemaType type; @@ -134,6 +199,13 @@ final class Schema { /// Parameter description may be formatted as Markdown. String? description; + /// A human-readable name/summary for the schema or a specific property. + /// + /// This helps document the schema's purpose but doesn't typically constrain + /// the generated value. It can subtly guide the model by clarifying the + /// intent of a field. + String? title; + /// Whether the value mey be null. bool? nullable; @@ -143,6 +215,18 @@ final class Schema { /// Schema for the elements if this is a [SchemaType.array]. Schema? items; + /// An integer specifying the minimum number of items [SchemaType.array] must contain. + int? minItems; + + /// An integer specifying the maximum number of items [SchemaType.array] must contain. + int? maxItems; + + /// The minimum value of a numeric type. + double? minimum; + + /// The maximum value of a numeric type. + double? maximum; + /// Properties of this type if this is a [SchemaType.object]. Map? properties; @@ -153,14 +237,40 @@ final class Schema { /// treated as required properties List? optionalProperties; + /// Suggesting order of the properties. + /// + /// A specific hint provided to the Gemini model, suggesting the order in + /// which the keys should appear in the generated JSON string. + /// Important: Standard JSON objects are inherently unordered collections of + /// key-value pairs. While the model will try to respect PropertyOrdering in + /// its textual JSON output. + List? propertyOrdering; + + /// An array of [Schema] objects to validate generated content. + /// + /// The generated data must be valid against *any* (one or more) + /// of the schemas listed in this array. This allows specifying multiple + /// possible structures or types for a single field. + /// + /// For example, a value could be either a `String` or an `Int`: + /// ``` + /// Schema.anyOf(schemas: [Schema.string(), Schema.integer()]); + List? anyOf; + /// Convert to json object. Map toJson() => { - 'type': type.toJson(), + if (type != SchemaType.anyOf) + 'type': type.toJson(), // Omit the field while type is anyOf if (format case final format?) 'format': format, if (description case final description?) 'description': description, + if (title case final title?) 'title': title, if (nullable case final nullable?) 'nullable': nullable, if (enumValues case final enumValues?) 'enum': enumValues, if (items case final items?) 'items': items.toJson(), + if (minItems case final minItems?) 'minItems': minItems, + if (maxItems case final maxItems?) 'maxItems': maxItems, + if (minimum case final minimum?) 'minimum': minimum, + if (maximum case final maximum?) 'maximum': maximum, if (properties case final properties?) 'properties': { for (final MapEntry(:key, :value) in properties.entries) @@ -173,6 +283,10 @@ final class Schema { .where((key) => !optionalProperties!.contains(key)) .toList() : properties!.keys.toList(), + if (propertyOrdering case final propertyOrdering?) + 'propertyOrdering': propertyOrdering, + if (anyOf case final anyOf?) + 'anyOf': anyOf.map((e) => e.toJson()).toList(), }; } @@ -194,7 +308,10 @@ enum SchemaType { array, /// object type - object; + object, + + /// This schema is anyOf type. + anyOf; /// Convert to json object. String toJson() => switch (this) { @@ -204,5 +321,6 @@ enum SchemaType { boolean => 'BOOLEAN', array => 'ARRAY', object => 'OBJECT', + anyOf => 'null', }; } diff --git a/packages/firebase_ai/firebase_ai/lib/src/vertex_version.dart b/packages/firebase_ai/firebase_ai/lib/src/vertex_version.dart index 810214ad9044..62736fe73501 100644 --- a/packages/firebase_ai/firebase_ai/lib/src/vertex_version.dart +++ b/packages/firebase_ai/firebase_ai/lib/src/vertex_version.dart @@ -13,4 +13,4 @@ // limitations under the License. /// generated version number for the package, do not manually edit -const packageVersion = '1.5.0'; +const packageVersion = '1.6.0'; diff --git a/packages/firebase_ai/firebase_ai/test/live_test.dart b/packages/firebase_ai/firebase_ai/test/live_test.dart index b215c6e4ca08..090a2cbda469 100644 --- a/packages/firebase_ai/firebase_ai/test/live_test.dart +++ b/packages/firebase_ai/firebase_ai/test/live_test.dart @@ -13,6 +13,7 @@ // limitations under the License. import 'dart:typed_data'; +import 'package:firebase_ai/src/api.dart'; import 'package:firebase_ai/src/content.dart'; import 'package:firebase_ai/src/error.dart'; import 'package:firebase_ai/src/live_api.dart'; diff --git a/packages/firebase_app_check/firebase_app_check/example/pubspec.yaml b/packages/firebase_app_check/firebase_app_check/example/pubspec.yaml index c137df8df46e..59ae9e3b32fa 100644 --- a/packages/firebase_app_check/firebase_app_check/example/pubspec.yaml +++ b/packages/firebase_app_check/firebase_app_check/example/pubspec.yaml @@ -9,7 +9,7 @@ environment: sdk: '>=3.2.0 <4.0.0' dependencies: - cloud_firestore: ^5.6.6 + cloud_firestore: ^5.6.7 firebase_app_check: ^0.3.2+5 firebase_core: ^3.13.0 flutter: diff --git a/packages/firebase_auth/firebase_auth/CHANGELOG.md b/packages/firebase_auth/firebase_auth/CHANGELOG.md index 86644d16c79d..ce59d027844f 100644 --- a/packages/firebase_auth/firebase_auth/CHANGELOG.md +++ b/packages/firebase_auth/firebase_auth/CHANGELOG.md @@ -1,3 +1,7 @@ +## 5.5.3 + + - **FIX**(auth,iOS): include missing email and credential in account-exists-with-different-credential error ([#17180](https://github.com/firebase/flutterfire/issues/17180)). ([2a0bdc64](https://github.com/firebase/flutterfire/commit/2a0bdc64086e99f8a98bd18b472b36bcfe05a9a4)) + ## 5.5.2 - Update a dependency to the latest release. diff --git a/packages/firebase_auth/firebase_auth/example/pubspec.yaml b/packages/firebase_auth/firebase_auth/example/pubspec.yaml index e50716ae6535..16f84105f041 100644 --- a/packages/firebase_auth/firebase_auth/example/pubspec.yaml +++ b/packages/firebase_auth/firebase_auth/example/pubspec.yaml @@ -6,7 +6,7 @@ environment: dependencies: barcode_widget: ^2.0.4 - firebase_auth: ^5.5.2 + firebase_auth: ^5.5.3 firebase_core: ^3.13.0 firebase_messaging: ^15.2.5 flutter: diff --git a/packages/firebase_auth/firebase_auth/ios/firebase_auth/Sources/firebase_auth/FLTFirebaseAuthPlugin.m b/packages/firebase_auth/firebase_auth/ios/firebase_auth/Sources/firebase_auth/FLTFirebaseAuthPlugin.m index 7e7da1784579..558937778f4a 100644 --- a/packages/firebase_auth/firebase_auth/ios/firebase_auth/Sources/firebase_auth/FLTFirebaseAuthPlugin.m +++ b/packages/firebase_auth/firebase_auth/ios/firebase_auth/Sources/firebase_auth/FLTFirebaseAuthPlugin.m @@ -370,19 +370,21 @@ - (NSString *)stringBySha256HashingString:(NSString *)input { static void handleSignInWithApple(FLTFirebaseAuthPlugin *object, FIRAuthDataResult *authResult, NSString *authorizationCode, NSError *error) { + void (^completion)(PigeonUserCredential *_Nullable, FlutterError *_Nullable) = + object.appleCompletion; + if (completion == nil) return; + if (error != nil) { if (error.code == FIRAuthErrorCodeSecondFactorRequired) { - [object handleMultiFactorError:object.appleArguments - completion:object.appleCompletion - withError:error]; + [object handleMultiFactorError:object.appleArguments completion:completion withError:error]; } else { - object.appleCompletion(nil, [FLTFirebaseAuthPlugin convertToFlutterError:error]); + completion(nil, [FLTFirebaseAuthPlugin convertToFlutterError:error]); } return; } - object.appleCompletion([PigeonParser getPigeonUserCredentialFromAuthResult:authResult - authorizationCode:authorizationCode], - nil); + completion([PigeonParser getPigeonUserCredentialFromAuthResult:authResult + authorizationCode:authorizationCode], + nil); } - (void)authorizationController:(ASAuthorizationController *)controller @@ -418,6 +420,8 @@ - (void)authorizationController:(ASAuthorizationController *)controller if (self.isReauthenticatingWithApple == YES) { self.isReauthenticatingWithApple = NO; + void (^capturedCompletion)(PigeonUserCredential *_Nullable, FlutterError *_Nullable) = + self.appleCompletion; [[FIRAuth.auth currentUser] reauthenticateWithCredential:credential completion:^(FIRAuthDataResult *_Nullable authResult, @@ -426,16 +430,20 @@ - (void)authorizationController:(ASAuthorizationController *)controller }]; } else if (self.linkWithAppleUser != nil) { - [self.linkWithAppleUser - linkWithCredential:credential - completion:^(FIRAuthDataResult *authResult, NSError *error) { - self.linkWithAppleUser = nil; - handleSignInWithApple(self, authResult, authorizationCode, error); - }]; + FIRUser *userToLink = self.linkWithAppleUser; + void (^capturedCompletion)(PigeonUserCredential *_Nullable, FlutterError *_Nullable) = + self.appleCompletion; + [userToLink linkWithCredential:credential + completion:^(FIRAuthDataResult *authResult, NSError *error) { + self.linkWithAppleUser = nil; + handleSignInWithApple(self, authResult, authorizationCode, error); + }]; } else { FIRAuth *signInAuth = self.signInWithAppleAuth != nil ? self.signInWithAppleAuth : FIRAuth.auth; + void (^capturedCompletion)(PigeonUserCredential *_Nullable, FlutterError *_Nullable) = + self.appleCompletion; [signInAuth signInWithCredential:credential completion:^(FIRAuthDataResult *_Nullable authResult, NSError *_Nullable error) { diff --git a/packages/firebase_auth/firebase_auth/pubspec.yaml b/packages/firebase_auth/firebase_auth/pubspec.yaml index 6f244f1d033b..b7c06e06a95b 100755 --- a/packages/firebase_auth/firebase_auth/pubspec.yaml +++ b/packages/firebase_auth/firebase_auth/pubspec.yaml @@ -4,7 +4,7 @@ description: Flutter plugin for Firebase Auth, enabling like Google, Facebook and Twitter. homepage: https://firebase.google.com/docs/auth repository: https://github.com/firebase/flutterfire/tree/main/packages/firebase_auth/firebase_auth -version: 5.5.2 +version: 5.5.3 topics: - firebase - authentication diff --git a/packages/firebase_data_connect/firebase_data_connect/CHANGELOG.md b/packages/firebase_data_connect/firebase_data_connect/CHANGELOG.md index 87af3e2cd9da..0592f6d04adf 100644 --- a/packages/firebase_data_connect/firebase_data_connect/CHANGELOG.md +++ b/packages/firebase_data_connect/firebase_data_connect/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.1.4+1 + + - Update a dependency to the latest release. + ## 0.1.4 - **FEAT**(fdc): Implemented partial errors ([#17148](https://github.com/firebase/flutterfire/issues/17148)). ([e97eb0b2](https://github.com/firebase/flutterfire/commit/e97eb0b229390afa01e61b9e7bfbd496b51cc80a)) diff --git a/packages/firebase_data_connect/firebase_data_connect/example/pubspec.yaml b/packages/firebase_data_connect/firebase_data_connect/example/pubspec.yaml index 61df43721048..0c1d69e02afa 100644 --- a/packages/firebase_data_connect/firebase_data_connect/example/pubspec.yaml +++ b/packages/firebase_data_connect/firebase_data_connect/example/pubspec.yaml @@ -13,7 +13,7 @@ dependencies: sdk: flutter firebase_core: ^3.13.0 google_sign_in: ^6.1.0 - firebase_auth: ^5.5.2 + firebase_auth: ^5.5.3 firebase_data_connect: path: ../ diff --git a/packages/firebase_data_connect/firebase_data_connect/lib/src/common/common_library.dart b/packages/firebase_data_connect/firebase_data_connect/lib/src/common/common_library.dart index c44dbf6eb97c..72d30afc87c0 100644 --- a/packages/firebase_data_connect/firebase_data_connect/lib/src/common/common_library.dart +++ b/packages/firebase_data_connect/firebase_data_connect/lib/src/common/common_library.dart @@ -16,6 +16,10 @@ import 'dart:convert'; import 'package:firebase_app_check/firebase_app_check.dart'; +import 'dart:io' show Platform; + +import 'package:flutter/foundation.dart'; + part 'dataconnect_error.dart'; part 'dataconnect_options.dart'; @@ -26,7 +30,7 @@ String getGoogApiVal(CallerSDKType sdkType, String packageVersion) { if (sdkType == CallerSDKType.generated) { apiClientValue += ' dart/gen'; } - return apiClientValue; + return '$apiClientValue gl-${kIsWeb ? 'web' : Platform.operatingSystem}'; } String getFirebaseClientVal(String packageVersion) { diff --git a/packages/firebase_data_connect/firebase_data_connect/lib/src/dataconnect_version.dart b/packages/firebase_data_connect/firebase_data_connect/lib/src/dataconnect_version.dart index b2328cec5ac5..8b8ef9b567c4 100644 --- a/packages/firebase_data_connect/firebase_data_connect/lib/src/dataconnect_version.dart +++ b/packages/firebase_data_connect/firebase_data_connect/lib/src/dataconnect_version.dart @@ -13,4 +13,4 @@ // limitations under the License. /// version number for the package, should be align with pubspec.yaml. -const packageVersion = '0.1.4'; +const packageVersion = '0.1.4+1'; diff --git a/packages/firebase_data_connect/firebase_data_connect/pubspec.yaml b/packages/firebase_data_connect/firebase_data_connect/pubspec.yaml index ad50376b5126..4cb149787e11 100644 --- a/packages/firebase_data_connect/firebase_data_connect/pubspec.yaml +++ b/packages/firebase_data_connect/firebase_data_connect/pubspec.yaml @@ -1,6 +1,6 @@ name: firebase_data_connect description: 'Flutter plugin for Firebase Data Connect, a relational database service that lets you build and scale using a fully-managed PostgreSQL database powered by Cloud SQL.' -version: 0.1.4 +version: 0.1.4+1 homepage: https://firebase.google.com/docs/data-connect/quickstart?platform=flutter false_secrets: - example/** @@ -12,7 +12,7 @@ environment: dependencies: firebase_app_check: ^0.3.2+5 - firebase_auth: ^5.5.2 + firebase_auth: ^5.5.3 firebase_core: ^3.13.0 firebase_core_platform_interface: ^5.3.1 flutter: diff --git a/packages/firebase_data_connect/firebase_data_connect/test/src/common/common_library_test.dart b/packages/firebase_data_connect/firebase_data_connect/test/src/common/common_library_test.dart index d87e02fd8ef3..5ab20c284909 100644 --- a/packages/firebase_data_connect/firebase_data_connect/test/src/common/common_library_test.dart +++ b/packages/firebase_data_connect/firebase_data_connect/test/src/common/common_library_test.dart @@ -17,6 +17,7 @@ import 'package:firebase_data_connect/firebase_data_connect.dart'; import 'package:firebase_data_connect/src/common/common_library.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:mockito/mockito.dart'; +import 'dart:io' show Platform; // Mock classes for Firebase dependencies @@ -28,14 +29,14 @@ void main() { const packageVersion = '1.0.0'; expect( getGoogApiVal(CallerSDKType.core, packageVersion), - 'gl-dart/$packageVersion fire/$packageVersion', + 'gl-dart/$packageVersion fire/$packageVersion gl-${Platform.operatingSystem}', ); }); test('should return codegen suffix if using gen sdk', () { const packageVersion = '1.0.0'; expect( getGoogApiVal(CallerSDKType.generated, packageVersion), - 'gl-dart/$packageVersion fire/$packageVersion dart/gen', + 'gl-dart/$packageVersion fire/$packageVersion dart/gen gl-${Platform.operatingSystem}', ); }); }); diff --git a/packages/firebase_vertexai/firebase_vertexai/CHANGELOG.md b/packages/firebase_vertexai/firebase_vertexai/CHANGELOG.md index d90cb2e2d8c0..518200a09631 100644 --- a/packages/firebase_vertexai/firebase_vertexai/CHANGELOG.md +++ b/packages/firebase_vertexai/firebase_vertexai/CHANGELOG.md @@ -1,3 +1,8 @@ +## 1.6.0 + + - **FIX**(vertexai): add missing HarmBlockThreshold to exported APIs ([#17249](https://github.com/firebase/flutterfire/issues/17249)). ([59d902c6](https://github.com/firebase/flutterfire/commit/59d902c63bd1bd040f5357cb6a341db446429430)) + - **FEAT**(vertexai): Live API breaking changes ([#17299](https://github.com/firebase/flutterfire/issues/17299)). ([69cd2a64](https://github.com/firebase/flutterfire/commit/69cd2a640d25e0f2b623f2e631d090ead8af140d)) + ## 1.5.0 - **FIX**(vertex_ai): handle null predictions ([#17211](https://github.com/firebase/flutterfire/issues/17211)). ([d559703d](https://github.com/firebase/flutterfire/commit/d559703d71904918fc5c0e8ad02b86313738d263)) diff --git a/packages/firebase_vertexai/firebase_vertexai/example/lib/pages/chat_page.dart b/packages/firebase_vertexai/firebase_vertexai/example/lib/pages/chat_page.dart index 33b6e1141b72..489fccafa577 100644 --- a/packages/firebase_vertexai/firebase_vertexai/example/lib/pages/chat_page.dart +++ b/packages/firebase_vertexai/firebase_vertexai/example/lib/pages/chat_page.dart @@ -95,6 +95,17 @@ class _ChatPageState extends State { const SizedBox.square( dimension: 15, ), + if (!_loading) + IconButton( + onPressed: () async { + await _imageResponse(_textController.text); + }, + icon: Icon( + Icons.image, + color: Theme.of(context).colorScheme.primary, + ), + tooltip: 'Image response', + ), if (!_loading) IconButton( onPressed: () async { @@ -152,6 +163,58 @@ class _ChatPageState extends State { } } + Future _imageResponse(String message) async { + setState(() { + _loading = true; + }); + + try { + _messages.add(MessageData(text: message, fromUser: true)); + var response = await widget.model.generateContent( + [Content.text(message)], + generationConfig: GenerationConfig( + responseModalities: [ + ResponseModalities.text, + ResponseModalities.image, + ], + ), + ); + var inlineDatas = response.inlineDataParts.toList(); + + if (inlineDatas.isEmpty) { + _showError('No response from API.'); + return; + } else { + for (final inlineData in inlineDatas) { + if (inlineData.mimeType.contains('image')) { + _messages.add( + MessageData( + text: response.text, + image: Image.memory(inlineData.bytes), + fromUser: false, + ), + ); + } + } + setState(() { + _loading = false; + _scrollDown(); + }); + } + } catch (e) { + _showError(e.toString()); + setState(() { + _loading = false; + }); + } finally { + _textController.clear(); + setState(() { + _loading = false; + }); + _textFieldFocus.requestFocus(); + } + } + void _showError(String message) { showDialog( context: context, diff --git a/packages/firebase_vertexai/firebase_vertexai/example/pubspec.yaml b/packages/firebase_vertexai/firebase_vertexai/example/pubspec.yaml index 759e375e2812..6506bf944d74 100644 --- a/packages/firebase_vertexai/firebase_vertexai/example/pubspec.yaml +++ b/packages/firebase_vertexai/firebase_vertexai/example/pubspec.yaml @@ -22,7 +22,7 @@ dependencies: cupertino_icons: ^1.0.6 firebase_core: ^3.13.0 firebase_storage: ^12.4.5 - firebase_vertexai: ^1.5.0 + firebase_vertexai: ^1.6.0 flutter: sdk: flutter flutter_markdown: ^0.6.20 @@ -45,9 +45,3 @@ flutter: - assets/images/ - assets/documents/ - assets/videos/ - -dependency_overrides: - firebase_ai: - path: ../../../firebase_ai/firebase_ai - firebase_vertexai: - path: ../../firebase_vertexai diff --git a/packages/firebase_vertexai/firebase_vertexai/lib/firebase_vertexai.dart b/packages/firebase_vertexai/firebase_vertexai/lib/firebase_vertexai.dart index 1ff7f50478f7..d0580c4928e5 100644 --- a/packages/firebase_vertexai/firebase_vertexai/lib/firebase_vertexai.dart +++ b/packages/firebase_vertexai/firebase_vertexai/lib/firebase_vertexai.dart @@ -30,6 +30,7 @@ export 'package:firebase_ai/firebase_ai.dart' HarmProbability, HarmBlockMethod, PromptFeedback, + ResponseModalities, SafetyRating, SafetySetting, UsageMetadata, @@ -62,7 +63,6 @@ export 'package:firebase_ai/firebase_ai.dart' ImagenInlineImage, LiveGenerationConfig, SpeechConfig, - ResponseModalities, LiveServerMessage, LiveServerContent, LiveServerToolCall, diff --git a/packages/firebase_vertexai/firebase_vertexai/pubspec.yaml b/packages/firebase_vertexai/firebase_vertexai/pubspec.yaml index 1d7b89e5d3c0..dd2fa0a4239b 100644 --- a/packages/firebase_vertexai/firebase_vertexai/pubspec.yaml +++ b/packages/firebase_vertexai/firebase_vertexai/pubspec.yaml @@ -1,6 +1,6 @@ name: firebase_vertexai description: "Firebase Vertex AI SDK." -version: 1.5.0 +version: 1.6.0 homepage: https://firebase.google.com/docs/vertex-ai/get-started?platform=flutter topics: - firebase @@ -22,7 +22,7 @@ environment: dependencies: firebase_ai: ^0.1.0 firebase_app_check: ^0.3.2+5 - firebase_auth: ^5.5.2 + firebase_auth: ^5.5.3 firebase_core: ^3.13.0 firebase_core_platform_interface: ^5.3.1 flutter: @@ -38,7 +38,3 @@ dev_dependencies: matcher: ^0.12.16 mockito: ^5.0.0 plugin_platform_interface: ^2.1.3 - -dependency_overrides: - firebase_ai: - path: ../../firebase_ai/firebase_ai diff --git a/packages/firebase_vertexai/firebase_vertexai/test/api_test.dart b/packages/firebase_vertexai/firebase_vertexai/test/api_test.dart new file mode 100644 index 000000000000..e00b8090325a --- /dev/null +++ b/packages/firebase_vertexai/firebase_vertexai/test/api_test.dart @@ -0,0 +1,819 @@ +// Copyright 2025 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import 'package:firebase_ai/firebase_ai.dart'; +import 'package:firebase_ai/src/api.dart'; + +import 'package:flutter_test/flutter_test.dart'; + +// --- Mock/Helper Implementations --- +// Minimal implementations or mocks for classes from imported files +// to make tests self-contained and focused on the target file's logic. + +void main() { + group('CountTokensResponse', () { + test('constructor initializes fields correctly', () { + final details = [ModalityTokenCount(ContentModality.text, 10)]; + final response = CountTokensResponse(100, + totalBillableCharacters: 50, promptTokensDetails: details); + expect(response.totalTokens, 100); + expect(response.totalBillableCharacters, 50); + expect(response.promptTokensDetails, same(details)); + }); + + test('constructor with null optional fields', () { + final response = CountTokensResponse(100); + expect(response.totalTokens, 100); + expect(response.totalBillableCharacters, isNull); + expect(response.promptTokensDetails, isNull); + }); + }); + + group('GenerateContentResponse', () { + // Mock candidates + + final textContent = Content.text('Hello'); + + final candidateWithText = + Candidate(textContent, null, null, FinishReason.stop, null); + final candidateWithMultipleTextParts = Candidate( + Content('model', [TextPart('Hello'), TextPart(' World')]), + null, + null, + FinishReason.stop, + null); + + final candidateFinishedSafety = Candidate( + textContent, null, null, FinishReason.safety, 'Safety concern'); + final candidateFinishedRecitation = Candidate( + textContent, null, null, FinishReason.recitation, 'Recited content'); + + group('.text getter', () { + test('returns null if no candidates and no prompt feedback', () { + final response = GenerateContentResponse([], null); + expect(response.text, isNull); + }); + + test( + 'throws FirebaseAIException if prompt was blocked without message or reason', + () { + final feedback = PromptFeedback(BlockReason.safety, null, []); + final response = GenerateContentResponse([], feedback); + expect( + () => response.text, + throwsA(isA().having((e) => e.message, + 'message', 'Response was blocked due to safety'))); + }); + + test( + 'throws FirebaseAIException if prompt was blocked with reason and message', + () { + final feedback = + PromptFeedback(BlockReason.other, 'Custom block message', []); + final response = GenerateContentResponse([], feedback); + expect( + () => response.text, + throwsA(isA().having( + (e) => e.message, + 'message', + 'Response was blocked due to other: Custom block message'))); + }); + + test( + 'throws FirebaseAIException if first candidate finished due to safety', + () { + final response = + GenerateContentResponse([candidateFinishedSafety], null); + expect( + () => response.text, + throwsA(isA().having( + (e) => e.message, + 'message', + 'Candidate was blocked due to safety: Safety concern'))); + }); + test( + 'throws FirebaseAIException if first candidate finished due to safety without message', + () { + final candidateFinishedSafetyNoMsg = + Candidate(textContent, null, null, FinishReason.safety, ''); + final response = + GenerateContentResponse([candidateFinishedSafetyNoMsg], null); + expect( + () => response.text, + throwsA(isA().having((e) => e.message, + 'message', 'Candidate was blocked due to safety'))); + }); + + test( + 'throws FirebaseAIException if first candidate finished due to recitation', + () { + final response = + GenerateContentResponse([candidateFinishedRecitation], null); + expect( + () => response.text, + throwsA(isA().having( + (e) => e.message, + 'message', + 'Candidate was blocked due to recitation: Recited content'))); + }); + + test('returns text from single TextPart in first candidate', () { + final response = GenerateContentResponse([candidateWithText], null); + expect(response.text, 'Hello'); + }); + + test('concatenates text from multiple TextParts in first candidate', () { + final response = + GenerateContentResponse([candidateWithMultipleTextParts], null); + expect(response.text, 'Hello World'); + }); + }); + + group('.functionCalls getter', () { + test('returns empty list if no candidates', () { + final response = GenerateContentResponse([], null); + expect(response.functionCalls, isEmpty); + }); + + test('returns empty list if first candidate has no FunctionCall parts', + () { + final response = GenerateContentResponse([candidateWithText], null); + expect(response.functionCalls, isEmpty); + }); + }); + test('constructor initializes fields correctly', () { + final candidates = [candidateWithText]; + final feedback = PromptFeedback(null, null, []); + + final response = GenerateContentResponse( + candidates, + feedback, + ); + + expect(response.candidates, same(candidates)); + expect(response.promptFeedback, same(feedback)); + }); + }); + + group('PromptFeedback', () { + test('constructor initializes fields correctly', () { + final ratings = [ + SafetyRating(HarmCategory.dangerousContent, HarmProbability.high) + ]; + final feedback = PromptFeedback(BlockReason.safety, 'Blocked', ratings); + expect(feedback.blockReason, BlockReason.safety); + expect(feedback.blockReasonMessage, 'Blocked'); + expect(feedback.safetyRatings, same(ratings)); + }); + }); + + group('Candidate', () { + final textContent = Content.text('Test text'); + group('.text getter', () { + test('throws FirebaseAIException if finishReason is safety with message', + () { + final candidate = Candidate(textContent, null, null, + FinishReason.safety, 'Safety block message'); + expect( + () => candidate.text, + throwsA(isA().having( + (e) => e.message, + 'message', + 'Candidate was blocked due to safety: Safety block message'))); + }); + test( + 'throws FirebaseAIException if finishReason is safety without message', + () { + final candidate = Candidate( + textContent, null, null, FinishReason.safety, ''); // Empty message + expect( + () => candidate.text, + throwsA(isA().having((e) => e.message, + 'message', 'Candidate was blocked due to safety'))); + }); + + test( + 'throws FirebaseAIException if finishReason is recitation with message', + () { + final candidate = Candidate(textContent, null, null, + FinishReason.recitation, 'Recitation block message'); + expect( + () => candidate.text, + throwsA(isA().having( + (e) => e.message, + 'message', + 'Candidate was blocked due to recitation: Recitation block message'))); + }); + + test('returns text from single TextPart', () { + final candidate = + Candidate(textContent, null, null, FinishReason.stop, null); + expect(candidate.text, 'Test text'); + }); + + test('concatenates text from multiple TextParts', () { + final multiPartContent = + Content('model', [TextPart('Part 1'), TextPart('. Part 2')]); + final candidate = + Candidate(multiPartContent, null, null, FinishReason.stop, null); + expect(candidate.text, 'Part 1. Part 2'); + }); + + test('returns text if finishReason is other non-blocking reason', () { + final candidate = + Candidate(textContent, null, null, FinishReason.maxTokens, null); + expect(candidate.text, 'Test text'); + }); + }); + test('constructor initializes fields correctly', () { + final content = Content.text('Hello'); + final ratings = [ + SafetyRating(HarmCategory.harassment, HarmProbability.low) + ]; + final citationMeta = CitationMetadata([]); + final candidate = Candidate( + content, ratings, citationMeta, FinishReason.stop, 'Finished'); + + expect(candidate.content, same(content)); + expect(candidate.safetyRatings, same(ratings)); + expect(candidate.citationMetadata, same(citationMeta)); + expect(candidate.finishReason, FinishReason.stop); + expect(candidate.finishMessage, 'Finished'); + }); + }); + + group('SafetyRating', () { + test('constructor initializes fields correctly', () { + final rating = SafetyRating( + HarmCategory.hateSpeech, HarmProbability.medium, + probabilityScore: 0.6, + isBlocked: true, + severity: HarmSeverity.high, + severityScore: 0.9); + expect(rating.category, HarmCategory.hateSpeech); + expect(rating.probability, HarmProbability.medium); + expect(rating.probabilityScore, 0.6); + expect(rating.isBlocked, true); + expect(rating.severity, HarmSeverity.high); + expect(rating.severityScore, 0.9); + }); + }); + + group('Enums', () { + test('BlockReason toJson and toString', () { + expect(BlockReason.unknown.toJson(), 'UNKNOWN'); + expect(BlockReason.safety.toJson(), 'SAFETY'); + expect(BlockReason.other.toJson(), 'OTHER'); + }); + + test('HarmCategory toJson and toString', () { + expect(HarmCategory.unknown.toJson(), 'UNKNOWN'); + expect(HarmCategory.harassment.toJson(), 'HARM_CATEGORY_HARASSMENT'); + expect(HarmCategory.hateSpeech.toJson(), 'HARM_CATEGORY_HATE_SPEECH'); + expect(HarmCategory.sexuallyExplicit.toJson(), + 'HARM_CATEGORY_SEXUALLY_EXPLICIT'); + expect(HarmCategory.dangerousContent.toJson(), + 'HARM_CATEGORY_DANGEROUS_CONTENT'); + }); + + test('HarmProbability toJson and toString', () { + expect(HarmProbability.unknown.toJson(), 'UNKNOWN'); + expect(HarmProbability.negligible.toJson(), 'NEGLIGIBLE'); + expect(HarmProbability.low.toJson(), 'LOW'); + expect(HarmProbability.medium.toJson(), 'MEDIUM'); + expect(HarmProbability.high.toJson(), 'HIGH'); + }); + + test('HarmSeverity toJson and toString', () { + expect(HarmSeverity.unknown.toJson(), 'UNKNOWN'); + expect(HarmSeverity.negligible.toJson(), 'NEGLIGIBLE'); + expect(HarmSeverity.low.toJson(), 'LOW'); + expect(HarmSeverity.medium.toJson(), 'MEDIUM'); + expect(HarmSeverity.high.toJson(), 'HIGH'); + }); + + test('FinishReason toJson and toString', () { + expect(FinishReason.unknown.toJson(), 'UNKNOWN'); + expect(FinishReason.stop.toJson(), 'STOP'); + expect(FinishReason.maxTokens.toJson(), 'MAX_TOKENS'); + expect(FinishReason.safety.toJson(), 'SAFETY'); + expect(FinishReason.recitation.toJson(), 'RECITATION'); + expect(FinishReason.other.toJson(), 'OTHER'); + }); + + test('ContentModality toJson and toString', () { + expect(ContentModality.unspecified.toJson(), 'MODALITY_UNSPECIFIED'); + expect(ContentModality.text.toJson(), 'TEXT'); + expect(ContentModality.image.toJson(), 'IMAGE'); + expect(ContentModality.video.toJson(), 'VIDEO'); + expect(ContentModality.audio.toJson(), 'AUDIO'); + expect(ContentModality.document.toJson(), 'DOCUMENT'); + }); + + test('HarmBlockThreshold toJson and toString', () { + expect(HarmBlockThreshold.low.toJson(), 'BLOCK_LOW_AND_ABOVE'); + expect(HarmBlockThreshold.medium.toJson(), 'BLOCK_MEDIUM_AND_ABOVE'); + expect(HarmBlockThreshold.high.toJson(), 'BLOCK_ONLY_HIGH'); + expect(HarmBlockThreshold.none.toJson(), 'BLOCK_NONE'); + expect(HarmBlockThreshold.off.toJson(), 'OFF'); + }); + + test('HarmBlockMethod toJson and toString', () { + expect(HarmBlockMethod.severity.toJson(), 'SEVERITY'); + expect(HarmBlockMethod.probability.toJson(), 'PROBABILITY'); + expect(HarmBlockMethod.unspecified.toJson(), + 'HARM_BLOCK_METHOD_UNSPECIFIED'); + }); + + test('TaskType toJson and toString', () { + expect(TaskType.unspecified.toJson(), 'TASK_TYPE_UNSPECIFIED'); + expect(TaskType.retrievalQuery.toJson(), 'RETRIEVAL_QUERY'); + expect(TaskType.retrievalDocument.toJson(), 'RETRIEVAL_DOCUMENT'); + expect(TaskType.semanticSimilarity.toJson(), 'SEMANTIC_SIMILARITY'); + expect(TaskType.classification.toJson(), 'CLASSIFICATION'); + expect(TaskType.clustering.toJson(), 'CLUSTERING'); + }); + }); + + group('CitationMetadata and Citation', () { + test('Citation constructor', () { + final uri = Uri.parse('http://example.com'); + final citation = Citation(0, 10, uri, 'Apache-2.0'); + expect(citation.startIndex, 0); + expect(citation.endIndex, 10); + expect(citation.uri, uri); + expect(citation.license, 'Apache-2.0'); + }); + test('CitationMetadata constructor', () { + final citation = Citation(0, 5, Uri.parse('a.com'), 'MIT'); + final metadata = CitationMetadata([citation]); + expect(metadata.citations, hasLength(1)); + expect(metadata.citations.first, same(citation)); + }); + }); + + group('ModalityTokenCount', () { + test('constructor initializes fields correctly', () { + final mtc = ModalityTokenCount(ContentModality.image, 150); + expect(mtc.modality, ContentModality.image); + expect(mtc.tokenCount, 150); + }); + }); + + group('SafetySetting', () { + test('toJson with all fields', () { + final setting = SafetySetting(HarmCategory.dangerousContent, + HarmBlockThreshold.medium, HarmBlockMethod.severity); + expect(setting.toJson(), { + 'category': 'HARM_CATEGORY_DANGEROUS_CONTENT', + 'threshold': 'BLOCK_MEDIUM_AND_ABOVE', + 'method': 'SEVERITY', + }); + }); + + test('toJson with method null (default to probability in spirit)', () { + // The toJson implementation will omit method if null + final setting = + SafetySetting(HarmCategory.harassment, HarmBlockThreshold.low, null); + expect(setting.toJson(), { + 'category': 'HARM_CATEGORY_HARASSMENT', + 'threshold': 'BLOCK_LOW_AND_ABOVE', + }); + }); + }); + + group('GenerationConfig & BaseGenerationConfig', () { + test('GenerationConfig toJson with all fields', () { + final schema = Schema.object(properties: {}); + final config = GenerationConfig( + candidateCount: 1, + stopSequences: ['\n', 'stop'], + maxOutputTokens: 200, + temperature: 0.7, + topP: 0.95, + topK: 50, + presencePenalty: 0.3, + frequencyPenalty: 0.4, + responseMimeType: 'application/json', + responseSchema: schema, + ); + expect(config.toJson(), { + 'candidateCount': 1, + 'maxOutputTokens': 200, + 'temperature': 0.7, + 'topP': 0.95, + 'topK': 50, + 'presencePenalty': 0.3, + 'frequencyPenalty': 0.4, + 'stopSequences': ['\n', 'stop'], + 'responseMimeType': 'application/json', + 'responseSchema': schema + .toJson(), // Schema itself not schema.toJson() in the provided code + }); + }); + + test('GenerationConfig toJson with empty stopSequences (omitted)', () { + final config = GenerationConfig(stopSequences: []); + expect(config.toJson(), {}); // Empty list for stopSequences is omitted + }); + + test('GenerationConfig toJson with some fields null', () { + final config = GenerationConfig( + temperature: 0.7, + responseMimeType: 'text/plain', + ); + expect(config.toJson(), { + 'temperature': 0.7, + 'responseMimeType': 'text/plain', + }); + }); + }); + + group('Parsing Functions', () { + group('parseCountTokensResponse', () { + test('parses valid full JSON correctly', () { + final json = { + 'totalTokens': 120, + 'totalBillableCharacters': 240, + 'promptTokensDetails': [ + { + 'modality': 'TEXT', + }, + {'modality': 'IMAGE', 'tokenCount': 20} + ] + }; + final response = VertexSerialization().parseCountTokensResponse(json); + expect(response.totalTokens, 120); + expect(response.totalBillableCharacters, 240); + expect(response.promptTokensDetails, isNotNull); + expect(response.promptTokensDetails, hasLength(2)); + expect(response.promptTokensDetails![0].modality, ContentModality.text); + expect(response.promptTokensDetails![0].tokenCount, 0); + expect( + response.promptTokensDetails![1].modality, ContentModality.image); + expect(response.promptTokensDetails![1].tokenCount, 20); + }); + + test('parses valid JSON with minimal fields (only totalTokens)', () { + final json = {'totalTokens': 50}; + final response = VertexSerialization().parseCountTokensResponse(json); + expect(response.totalTokens, 50); + expect(response.totalBillableCharacters, isNull); + expect(response.promptTokensDetails, isNull); + }); + + test('throws FirebaseAIException if JSON contains error field', () { + final json = { + 'error': {'code': 400, 'message': 'Invalid request'} + }; + expect(() => VertexSerialization().parseCountTokensResponse(json), + throwsA(isA())); + }); + + test('throws FormatException for invalid JSON structure (not a Map)', () { + const json = 'not_a_map'; + expect( + () => VertexSerialization().parseCountTokensResponse(json), + throwsA(isA().having( + (e) => e.message, 'message', contains('CountTokensResponse')))); + }); + + test('throws if totalTokens is missing', () { + final json = {'totalBillableCharacters': 100}; + expect(() => VertexSerialization().parseCountTokensResponse(json), + throwsA(anything)); // More specific error expected + }); + }); + + group('parseGenerateContentResponse', () { + final basicCandidateJson = { + 'content': { + 'role': 'model', + 'parts': [ + {'text': 'Hello world'} + ] + }, + 'finishReason': 'STOP', + 'safetyRatings': [ + { + 'category': 'HARM_CATEGORY_SEXUALLY_EXPLICIT', + 'probability': 'NEGLIGIBLE' + } + ] + }; + + test('parses valid JSON with candidates and promptFeedback', () { + final json = { + 'candidates': [basicCandidateJson], + 'promptFeedback': { + 'blockReason': 'SAFETY', + 'blockReasonMessage': 'Prompt was too spicy.', + 'safetyRatings': [ + { + 'category': 'HARM_CATEGORY_DANGEROUS_CONTENT', + 'probability': 'HIGH', + 'blocked': true, + 'severity': 'HARM_SEVERITY_HIGH', + 'severityScore': 0.95 + } + ] + }, + 'usageMetadata': { + 'promptTokenCount': 10, + 'candidatesTokenCount': 20, + 'totalTokenCount': 30, + 'promptTokensDetails': [ + {'modality': 'TEXT', 'tokenCount': 10} + ], + 'candidatesTokensDetails': [ + {'modality': 'TEXT', 'tokenCount': 20} + ], + } + }; + final response = + VertexSerialization().parseGenerateContentResponse(json); + expect(response.candidates, hasLength(1)); + expect(response.candidates.first.text, 'Hello world'); + expect(response.candidates.first.finishReason, FinishReason.stop); + expect(response.candidates.first.safetyRatings, isNotNull); + expect(response.candidates.first.safetyRatings, hasLength(1)); + + expect(response.promptFeedback, isNotNull); + expect(response.promptFeedback!.blockReason, BlockReason.safety); + expect(response.promptFeedback!.blockReasonMessage, + 'Prompt was too spicy.'); + expect(response.promptFeedback!.safetyRatings, hasLength(1)); + expect(response.promptFeedback!.safetyRatings.first.category, + HarmCategory.dangerousContent); + expect(response.promptFeedback!.safetyRatings.first.probability, + HarmProbability.high); + expect(response.promptFeedback!.safetyRatings.first.isBlocked, true); + expect(response.promptFeedback!.safetyRatings.first.severity, + HarmSeverity.high); + expect( + response.promptFeedback!.safetyRatings.first.severityScore, 0.95); + + expect(response.usageMetadata, isNotNull); + expect(response.usageMetadata!.promptTokenCount, 10); + expect(response.usageMetadata!.candidatesTokenCount, 20); + expect(response.usageMetadata!.totalTokenCount, 30); + expect(response.usageMetadata!.promptTokensDetails, hasLength(1)); + expect(response.usageMetadata!.candidatesTokensDetails, hasLength(1)); + }); + + test('parses JSON with no candidates (empty list)', () { + final json = {'candidates': []}; + final response = + VertexSerialization().parseGenerateContentResponse(json); + expect(response.candidates, isEmpty); + expect(response.promptFeedback, isNull); + expect(response.usageMetadata, isNull); + }); + + test('parses JSON with null candidates (treated as empty)', () { + // The code defaults to [] if 'candidates' key is missing + final json = {'promptFeedback': null}; + final response = + VertexSerialization().parseGenerateContentResponse(json); + expect(response.candidates, isEmpty); + expect(response.promptFeedback, isNull); + }); + + test('parses JSON with missing optional fields in candidate', () { + final json = { + 'candidates': [ + { + 'content': { + 'parts': [ + {'text': 'Minimal'} + ] + } + // Missing finishReason, safetyRatings, citationMetadata, finishMessage + } + ] + }; + final response = + VertexSerialization().parseGenerateContentResponse(json); + expect(response.candidates, hasLength(1)); + expect(response.candidates.first.text, 'Minimal'); + expect(response.candidates.first.finishReason, isNull); + expect(response.candidates.first.safetyRatings, isNull); + expect(response.candidates.first.citationMetadata, isNull); + expect(response.candidates.first.finishMessage, isNull); + }); + + test('parses usageMetadata for no tokenCount', () { + final json = { + 'candidates': [basicCandidateJson], + 'usageMetadata': { + 'promptTokenCount': 10, + 'candidatesTokenCount': 20, + 'totalTokenCount': 30, + 'promptTokensDetails': [ + {'modality': 'TEXT', 'tokenCount': 10} + ], + 'candidatesTokensDetails': [ + { + 'modality': 'TEXT', + } + ], + } + }; + final response = + VertexSerialization().parseGenerateContentResponse(json); + expect(response.candidates, hasLength(1)); + expect(response.candidates.first.text, 'Hello world'); + expect(response.candidates.first.finishReason, FinishReason.stop); + expect(response.candidates.first.safetyRatings, isNotNull); + expect(response.candidates.first.safetyRatings, hasLength(1)); + + expect(response.usageMetadata, isNotNull); + expect(response.usageMetadata!.promptTokenCount, 10); + expect(response.usageMetadata!.candidatesTokenCount, 20); + expect(response.usageMetadata!.totalTokenCount, 30); + expect(response.usageMetadata!.promptTokensDetails, hasLength(1)); + expect(response.usageMetadata!.promptTokensDetails!.first.modality, + ContentModality.text); + expect( + response.usageMetadata!.promptTokensDetails!.first.tokenCount, 10); + expect(response.usageMetadata!.candidatesTokensDetails, hasLength(1)); + expect(response.usageMetadata!.candidatesTokensDetails!.first.modality, + ContentModality.text); + expect( + response.usageMetadata!.candidatesTokensDetails!.first.tokenCount, + 0); + }); + + test('parses citationMetadata with "citationSources"', () { + final json = { + 'candidates': [ + { + 'content': { + 'parts': [ + {'text': 'Cited text'} + ] + }, + 'citationMetadata': { + 'citationSources': [ + { + 'startIndex': 0, + 'endIndex': 5, + 'uri': 'http://example.com/source1', + 'license': 'CC-BY' + } + ] + } + } + ] + }; + final response = + VertexSerialization().parseGenerateContentResponse(json); + final candidate = response.candidates.first; + expect(candidate.citationMetadata, isNotNull); + expect(candidate.citationMetadata!.citations, hasLength(1)); + expect(candidate.citationMetadata!.citations.first.uri.toString(), + 'http://example.com/source1'); + }); + test('parses citationMetadata with "citations" (Vertex SDK format)', () { + final json = { + 'candidates': [ + { + 'content': { + 'parts': [ + {'text': 'Cited text'} + ] + }, + 'citationMetadata': { + 'citations': [ + // Vertex SDK uses 'citations' + { + 'startIndex': 0, + 'endIndex': 5, + 'uri': 'http://example.com/source2', + 'license': 'MIT' + } + ] + } + } + ] + }; + final response = + VertexSerialization().parseGenerateContentResponse(json); + final candidate = response.candidates.first; + expect(candidate.citationMetadata, isNotNull); + expect(candidate.citationMetadata!.citations, hasLength(1)); + expect(candidate.citationMetadata!.citations.first.uri.toString(), + 'http://example.com/source2'); + expect(candidate.citationMetadata!.citations.first.license, 'MIT'); + }); + + test('throws FirebaseAIException if JSON contains error field', () { + final json = { + 'error': {'code': 500, 'message': 'Internal server error'} + }; + expect(() => VertexSerialization().parseGenerateContentResponse(json), + throwsA(isA())); + }); + + test('handles missing content in candidate gracefully (empty content)', + () { + final json = { + 'candidates': [ + { + // No 'content' field + 'finishReason': 'STOP', + } + ] + }; + final response = + VertexSerialization().parseGenerateContentResponse(json); + expect(response.candidates, hasLength(1)); + expect(response.candidates.first.content.parts, isEmpty); + expect(response.candidates.first.text, isNull); + }); + test('throws FormatException for invalid candidate structure (not a Map)', + () { + final jsonResponse = { + 'candidates': ['not_a_map_candidate'] + }; + expect( + () => VertexSerialization() + .parseGenerateContentResponse(jsonResponse), + throwsA(isA() + .having((e) => e.message, 'message', contains('Candidate')))); + }); + + test('throws FormatException for invalid safety rating structure', () { + final jsonResponse = { + 'candidates': [ + { + 'content': {'parts': []}, + 'safetyRatings': ['not_a_map_rating'] + } + ] + }; + expect( + () => VertexSerialization() + .parseGenerateContentResponse(jsonResponse), + throwsA(isA().having( + (e) => e.message, 'message', contains('SafetyRating')))); + }); + test('throws FormatException for invalid citation metadata structure', + () { + final jsonResponse = { + 'candidates': [ + { + 'content': {'parts': []}, + 'citationMetadata': 'not_a_map_citation' + } + ] + }; + expect( + () => VertexSerialization() + .parseGenerateContentResponse(jsonResponse), + throwsA(isA().having( + (e) => e.message, 'message', contains('CitationMetadata')))); + }); + test('throws FormatException for invalid prompt feedback structure', () { + final jsonResponse = {'promptFeedback': 'not_a_map_feedback'}; + expect( + () => VertexSerialization() + .parseGenerateContentResponse(jsonResponse), + throwsA(isA().having( + (e) => e.message, 'message', contains('PromptFeedback')))); + }); + test('throws FormatException for invalid usage metadata structure', () { + final jsonResponse = {'usageMetadata': 'not_a_map_usage'}; + expect( + () => VertexSerialization() + .parseGenerateContentResponse(jsonResponse), + throwsA(isA().having( + (e) => e.message, 'message', contains('UsageMetadata')))); + }); + test('throws FormatException for invalid modality token count structure', + () { + final jsonResponse = { + 'usageMetadata': { + 'promptTokensDetails': ['not_a_map_modality'] + } + }; + expect( + () => VertexSerialization() + .parseGenerateContentResponse(jsonResponse), + throwsA(isA().having( + (e) => e.message, 'message', contains('ModalityTokenCount')))); + }); + }); + }); +} diff --git a/packages/firebase_vertexai/firebase_vertexai/test/live_test.dart b/packages/firebase_vertexai/firebase_vertexai/test/live_test.dart index 4852b52adf4b..14909bcbc0eb 100644 --- a/packages/firebase_vertexai/firebase_vertexai/test/live_test.dart +++ b/packages/firebase_vertexai/firebase_vertexai/test/live_test.dart @@ -13,6 +13,7 @@ // limitations under the License. import 'dart:typed_data'; +import 'package:firebase_ai/src/api.dart'; import 'package:firebase_ai/src/content.dart'; import 'package:firebase_ai/src/live_api.dart'; import 'package:firebase_vertexai/firebase_vertexai.dart' diff --git a/packages/firebase_vertexai/firebase_vertexai/test/schema_test.dart b/packages/firebase_vertexai/firebase_vertexai/test/schema_test.dart index b6c691e0f97e..e4b47be4be94 100644 --- a/packages/firebase_vertexai/firebase_vertexai/test/schema_test.dart +++ b/packages/firebase_vertexai/firebase_vertexai/test/schema_test.dart @@ -19,67 +19,98 @@ void main() { group('Schema Tests', () { // Test basic constructors and toJson() for primitive types test('Schema.boolean', () { - final schema = - Schema.boolean(description: 'A boolean value', nullable: true); + final schema = Schema.boolean( + description: 'A boolean value', nullable: true, title: 'Is Active'); expect(schema.type, SchemaType.boolean); expect(schema.description, 'A boolean value'); expect(schema.nullable, true); + expect(schema.title, 'Is Active'); expect(schema.toJson(), { 'type': 'BOOLEAN', 'description': 'A boolean value', 'nullable': true, + 'title': 'Is Active', }); }); test('Schema.integer', () { - final schema = Schema.integer(format: 'int32'); + final schema = Schema.integer( + format: 'int32', minimum: 0, maximum: 100, title: 'Count'); expect(schema.type, SchemaType.integer); expect(schema.format, 'int32'); + expect(schema.minimum, 0); + expect(schema.maximum, 100); + expect(schema.title, 'Count'); expect(schema.toJson(), { 'type': 'INTEGER', 'format': 'int32', + 'minimum': 0.0, // Ensure double conversion + 'maximum': 100.0, // Ensure double conversion + 'title': 'Count', }); }); test('Schema.number', () { - final schema = Schema.number(format: 'double', nullable: false); + final schema = Schema.number( + format: 'double', + nullable: false, + minimum: 0.5, + maximum: 99.5, + title: 'Percentage'); expect(schema.type, SchemaType.number); expect(schema.format, 'double'); expect(schema.nullable, false); + expect(schema.minimum, 0.5); + expect(schema.maximum, 99.5); + expect(schema.title, 'Percentage'); expect(schema.toJson(), { 'type': 'NUMBER', 'format': 'double', 'nullable': false, + 'minimum': 0.5, + 'maximum': 99.5, + 'title': 'Percentage', }); }); test('Schema.string', () { - final schema = Schema.string(); + final schema = Schema.string(title: 'User Name'); expect(schema.type, SchemaType.string); - expect(schema.toJson(), {'type': 'STRING'}); + expect(schema.title, 'User Name'); + expect(schema.toJson(), {'type': 'STRING', 'title': 'User Name'}); }); test('Schema.enumString', () { - final schema = Schema.enumString(enumValues: ['value1', 'value2']); + final schema = + Schema.enumString(enumValues: ['value1', 'value2'], title: 'Status'); expect(schema.type, SchemaType.string); expect(schema.format, 'enum'); expect(schema.enumValues, ['value1', 'value2']); + expect(schema.title, 'Status'); expect(schema.toJson(), { 'type': 'STRING', 'format': 'enum', 'enum': ['value1', 'value2'], + 'title': 'Status', }); }); // Test constructors and toJson() for complex types test('Schema.array', () { final itemSchema = Schema.string(); - final schema = Schema.array(items: itemSchema); + final schema = Schema.array( + items: itemSchema, minItems: 1, maxItems: 5, title: 'Tags'); expect(schema.type, SchemaType.array); expect(schema.items, itemSchema); + expect(schema.minItems, 1); + expect(schema.maxItems, 5); + expect(schema.title, 'Tags'); expect(schema.toJson(), { 'type': 'ARRAY', 'items': {'type': 'STRING'}, + 'minItems': 1, + 'maxItems': 5, + 'title': 'Tags', }); }); @@ -87,21 +118,32 @@ void main() { final properties = { 'name': Schema.string(), 'age': Schema.integer(), + 'city': Schema.string(description: 'City of residence'), }; final schema = Schema.object( properties: properties, optionalProperties: ['age'], + propertyOrdering: ['name', 'city', 'age'], + title: 'User Profile', + description: 'Represents a user profile', ); expect(schema.type, SchemaType.object); expect(schema.properties, properties); expect(schema.optionalProperties, ['age']); + expect(schema.propertyOrdering, ['name', 'city', 'age']); + expect(schema.title, 'User Profile'); + expect(schema.description, 'Represents a user profile'); expect(schema.toJson(), { 'type': 'OBJECT', 'properties': { 'name': {'type': 'STRING'}, 'age': {'type': 'INTEGER'}, + 'city': {'type': 'STRING', 'description': 'City of residence'}, }, - 'required': ['name'], + 'required': ['name', 'city'], + 'propertyOrdering': ['name', 'city', 'age'], + 'title': 'User Profile', + 'description': 'Represents a user profile', }); }); @@ -112,16 +154,94 @@ void main() { }; final schema = Schema.object( properties: properties, + // No optionalProperties, so all are required + ); + expect(schema.type, SchemaType.object); + expect(schema.properties, properties); + expect(schema.toJson(), { + 'type': 'OBJECT', + 'properties': { + 'name': {'type': 'STRING'}, + 'age': {'type': 'INTEGER'}, + }, + 'required': ['name', 'age'], // All keys from properties + }); + }); + + test('Schema.object with all properties optional', () { + final properties = { + 'name': Schema.string(), + 'age': Schema.integer(), + }; + final schema = Schema.object( + properties: properties, + optionalProperties: ['name', 'age'], ); expect(schema.type, SchemaType.object); expect(schema.properties, properties); + expect(schema.optionalProperties, ['name', 'age']); expect(schema.toJson(), { 'type': 'OBJECT', 'properties': { 'name': {'type': 'STRING'}, 'age': {'type': 'INTEGER'}, }, - 'required': ['name', 'age'], + 'required': [], // Empty list as all are optional + }); + }); + + // Test Schema.anyOf + test('Schema.anyOf', () { + final schema1 = Schema.string(description: 'A string value'); + final schema2 = Schema.integer(description: 'An integer value'); + final schema = Schema.anyOf(schemas: [schema1, schema2]); + + // The type field is SchemaType.anyOf internally for dispatching toJson + // but it should not be present in the final JSON for `anyOf`. + expect(schema.type, SchemaType.anyOf); + expect(schema.anyOf, [schema1, schema2]); + expect(schema.toJson(), { + 'anyOf': [ + {'type': 'STRING', 'description': 'A string value'}, + {'type': 'INTEGER', 'description': 'An integer value'}, + ], + }); + }); + + test('Schema.anyOf with complex types', () { + final userSchema = Schema.object(properties: { + 'id': Schema.integer(), + 'username': Schema.string(), + }, optionalProperties: [ + 'username' + ]); + final errorSchema = Schema.object(properties: { + 'errorCode': Schema.integer(), + 'errorMessage': Schema.string(), + }); + final schema = Schema.anyOf(schemas: [userSchema, errorSchema]); + + expect(schema.type, SchemaType.anyOf); + expect(schema.anyOf?.length, 2); + expect(schema.toJson(), { + 'anyOf': [ + { + 'type': 'OBJECT', + 'properties': { + 'id': {'type': 'INTEGER'}, + 'username': {'type': 'STRING'}, + }, + 'required': ['id'], + }, + { + 'type': 'OBJECT', + 'properties': { + 'errorCode': {'type': 'INTEGER'}, + 'errorMessage': {'type': 'STRING'}, + }, + 'required': ['errorCode', 'errorMessage'], + }, + ], }); }); @@ -133,8 +253,45 @@ void main() { expect(SchemaType.boolean.toJson(), 'BOOLEAN'); expect(SchemaType.array.toJson(), 'ARRAY'); expect(SchemaType.object.toJson(), 'OBJECT'); + expect(SchemaType.anyOf.toJson(), + 'null'); // As per implementation, 'null' string for anyOf }); - // Add more tests as needed to cover other scenarios and edge cases + // Test edge cases + test('Schema.object with no properties', () { + final schema = Schema.object(properties: {}); + expect(schema.type, SchemaType.object); + expect(schema.properties, {}); + expect(schema.toJson(), { + 'type': 'OBJECT', + 'properties': {}, + 'required': [], + }); + }); + + test('Schema.array with no items (should not happen with constructor)', () { + // This is more of a theoretical test as the constructor requires `items`. + // We construct it manually to test `toJson` robustness. + final schema = Schema(SchemaType.array); + expect(schema.type, SchemaType.array); + expect(schema.toJson(), { + 'type': 'ARRAY', + // 'items' field should be absent if items is null + }); + }); + + test('Schema with all optional fields null', () { + final schema = Schema(SchemaType.string); // Only type is provided + expect(schema.type, SchemaType.string); + expect(schema.format, isNull); + expect(schema.description, isNull); + expect(schema.nullable, isNull); + expect(schema.enumValues, isNull); + expect(schema.items, isNull); + expect(schema.properties, isNull); + expect(schema.optionalProperties, isNull); + expect(schema.anyOf, isNull); + expect(schema.toJson(), {'type': 'STRING'}); + }); }); } diff --git a/scripts/versions.json b/scripts/versions.json index f7a00065d899..80c5f56389ae 100644 --- a/scripts/versions.json +++ b/scripts/versions.json @@ -1,4 +1,33 @@ { + "3.10.0": { + "date": "2025-04-28", + "firebase_sdk": { + "android": "33.11.0", + "ios": "11.10.0", + "web": "11.5.0", + "windows": "12.7.0" + }, + "packages": { + "cloud_firestore": "5.6.7", + "cloud_functions": "5.5.0", + "firebase_analytics": "11.4.5", + "firebase_app_check": "0.3.2+5", + "firebase_app_installations": "0.3.2+5", + "firebase_auth": "5.5.3", + "firebase_core": "3.13.0", + "firebase_crashlytics": "4.3.5", + "firebase_data_connect": "0.1.4+1", + "firebase_database": "11.3.5", + "firebase_dynamic_links": "6.1.5", + "firebase_in_app_messaging": "0.8.1+5", + "firebase_messaging": "15.2.5", + "firebase_ml_model_downloader": "0.3.3+3", + "firebase_performance": "0.10.1+5", + "firebase_remote_config": "5.4.3", + "firebase_storage": "12.4.5", + "firebase_vertexai": "1.6.0" + } + }, "3.9.0": { "date": "2025-03-31", "firebase_sdk": { diff --git a/tests/integration_test/cloud_functions/cloud_functions_e2e_test.dart b/tests/integration_test/cloud_functions/cloud_functions_e2e_test.dart index aebaa0997442..f97c71cf737e 100644 --- a/tests/integration_test/cloud_functions/cloud_functions_e2e_test.dart +++ b/tests/integration_test/cloud_functions/cloud_functions_e2e_test.dart @@ -2,6 +2,7 @@ // for details. All rights reserved. Use of this source code is governed by a // BSD-style license that can be found in the LICENSE file. +import 'dart:async'; import 'dart:io'; import 'package:cloud_functions/cloud_functions.dart'; @@ -17,6 +18,7 @@ String kTestFunctionDefaultRegion = 'testFunctionDefaultRegion'; String kTestFunctionCustomRegion = 'testFunctionCustomRegion'; String kTestFunctionTimeout = 'testFunctionTimeout'; String kTestMapConvertType = 'testMapConvertType'; +String kTestStreamResponse = 'testStreamResponse'; void main() { IntegrationTestWidgetsFlutterBinding.ensureInitialized(); @@ -246,5 +248,210 @@ void main() { }, ); }); + + group('HttpsCallable Stream', () { + test('returns a [StreamResponse]', () { + final streamResponseCallable = + FirebaseFunctions.instance.httpsCallable(kTestStreamResponse); + final stream = streamResponseCallable.stream(); + expect(stream, emits(isA())); + }); + + test('accepts a string value', () async { + final stream = callable.stream('foo').where((event) => event is Chunk); + await expectLater( + stream, + emits( + isA() + .having((e) => e.partialData, 'partialData', equals('string')), + ), + ); + }); + + test('accepts a number value', () async { + final stream = callable + .stream(123) + .where((event) => event is Chunk) + .asBroadcastStream(); + await expectLater( + stream, + emits( + isA() + .having((e) => e.partialData, 'partialData', equals('number')), + ), + ); + }); + + test('accepts no arguments', () async { + final stream = callable + .stream() + .where((event) => event is Chunk) + .asBroadcastStream(); + await expectLater( + stream, + emits( + isA() + .having((e) => e.partialData, 'partialData', equals('null')), + ), + ); + }); + + test('accepts a false boolean value', () async { + final stream = callable.stream(false).where((event) => event is Chunk); + await expectLater( + stream, + emits( + isA() + .having((e) => e.partialData, 'partialData', equals('boolean')), + ), + ); + }); + + test('accepts a true boolean value', () async { + final stream = callable.stream(true).where((event) => event is Chunk); + await expectLater( + stream, + emits( + isA() + .having((e) => e.partialData, 'partialData', equals('boolean')), + ), + ); + }); + + test('can be called using an String url', () async { + final localhostMapped = + kIsWeb || !Platform.isAndroid ? 'localhost' : '10.0.2.2'; + + HttpsCallable callable = + FirebaseFunctions.instance.httpsCallableFromUrl( + 'http://$localhostMapped:5001/flutterfire-e2e-tests/us-central1/listfruits2ndgen', + ); + + final stream = callable.stream(); + await expectLater(stream, emits(isA())); + }); + + test('can be called using an Uri url', () async { + final localhostMapped = + kIsWeb || !Platform.isAndroid ? 'localhost' : '10.0.2.2'; + + HttpsCallable callable = + FirebaseFunctions.instance.httpsCallableFromUri( + Uri.parse( + 'http://$localhostMapped:5001/flutterfire-e2e-tests/us-central1/listfruits2ndgen', + ), + ); + + final stream = callable.stream(); + await expectLater(stream, emits(isA())); + }); + + test('should emit a [Result] as last value', () async { + final stream = await callable.stream().last; + expect( + stream, + isA(), + ); + }); + + test('accepts a [List]', () async { + final stream = + callable.stream(data.list).where((event) => event is Chunk); + await expectLater( + stream, + emits( + isA() + .having((e) => e.partialData, 'partialData', equals('array')), + ), + ); + }); + + test('accepts a deeply nested [Map]', () async { + final stream = callable.stream({ + 'type': 'deepMap', + 'inputData': data.deepMap, + }).where((event) => event is Chunk); + await expectLater( + stream, + emits( + isA().having( + (e) => e.partialData, + 'partialData', + equals(data.deepMap), + ), + ), + ); + }); + + test( + 'throws error when aborted with TimeLimit signal', + () async { + final instance = FirebaseFunctions.instance; + instance.useFunctionsEmulator('localhost', 5001); + + final completer = Completer(); + + final timeoutCallable = FirebaseFunctions.instance.httpsCallable( + kTestFunctionTimeout, + options: HttpsCallableOptions( + webAbortSignal: TimeLimit(const Duration(seconds: 3)), + ), + ); + + timeoutCallable.stream({ + 'testTimeout': const Duration(seconds: 6).inMilliseconds.toString(), + }).listen( + (data) { + completer.completeError('Should have thrown'); + }, + onError: (error) { + if (error is FirebaseFunctionsException) { + expect(error.code, equals('internal')); + completer.complete(); + } else { + completer.completeError('Unexpected error type: $error'); + } + }, + ); + await completer.future; + }, + skip: !kIsWeb, + ); + + test( + 'throws error when aborted with Abort signal', + () async { + final instance = FirebaseFunctions.instance; + instance.useFunctionsEmulator('localhost', 5001); + + final completer = Completer(); + + final timeoutCallable = FirebaseFunctions.instance.httpsCallable( + kTestFunctionTimeout, + options: HttpsCallableOptions( + webAbortSignal: Abort('aborted'), + ), + ); + + timeoutCallable.stream({ + 'testTimeout': const Duration(seconds: 6).inMilliseconds.toString(), + }).listen( + (data) { + completer.completeError('Should have thrown'); + }, + onError: (error) { + if (error is FirebaseFunctionsException) { + expect(error.code, equals('internal')); + completer.complete(); + } else { + completer.completeError('Unexpected error type: $error'); + } + }, + ); + await completer.future; + }, + skip: !kIsWeb, + ); + }); }); } diff --git a/tests/pubspec.yaml b/tests/pubspec.yaml index eb2707dbd8f4..31c69da039c2 100644 --- a/tests/pubspec.yaml +++ b/tests/pubspec.yaml @@ -9,9 +9,9 @@ environment: flutter: '>=3.22.0' dependencies: - cloud_functions: ^5.4.0 - cloud_functions_platform_interface: ^5.6.5 - cloud_functions_web: ^4.10.11 + cloud_functions: ^5.5.0 + cloud_functions_platform_interface: ^5.7.0 + cloud_functions_web: ^4.11.0 collection: ^1.15.0 firebase_analytics: ^11.4.5 firebase_analytics_platform_interface: ^4.3.5 @@ -22,7 +22,7 @@ dependencies: firebase_app_installations: ^0.3.2+5 firebase_app_installations_platform_interface: ^0.1.4+53 firebase_app_installations_web: ^0.1.6+11 - firebase_auth: ^5.5.2 + firebase_auth: ^5.5.3 firebase_auth_platform_interface: ^7.6.2 firebase_auth_web: ^5.14.2 firebase_core: ^3.13.0