From 127ed98c2b5decfb34ac428db12eb2b9b6b1d46b Mon Sep 17 00:00:00 2001 From: peterbom Date: Fri, 26 Apr 2024 15:50:37 +1200 Subject: [PATCH] Remove dependency on Azure Account extension (#551) * Use vscode authentication library instead of Azure Account extension * remove msal-node dependency * remove azure auth * remove duplication of getDefaultScope function and add error handling * auth fixes for switching between signed-in tenants * If no subscriptions are selected, display them all in the treeview * remove unused properties from jwt interface * fix URLs in select-subscriptions command * get tenant id from auth session and new filter option for listing subs * avoid passing treenodes to cluster library functions * avoid exposing ISubscriptionContext from tree nodes * handle session changes when tenants change and not when we triggered the change, and get session silently whenever possible * Select a tenant by default rather than forcing user to do that * list clusters using resource management client (as we were before) * dedicated command for tenant selection, and abstract session provider with interface --- package-lock.json | 6075 +---------------- package.json | 27 +- resources/azure.svg | 25 + resources/azureSubscription.svg | 16 + src/auth/azureAuth.ts | 136 + src/auth/azureSessionProvider.ts | 292 + src/auth/types.ts | 37 + src/azure-api-utils.ts | 10 +- src/commands/aksAccount/aksAccount.ts | 99 + .../aksClusterProperties.ts | 12 +- .../aksCompareCluster/aksCompareCluster.ts | 28 +- .../aksCreateCluster/aksCreateCluster.ts | 17 +- .../aksDeleteCluster/aksDeleteCluster.ts | 14 +- src/commands/aksEraserTool/erasertool.ts | 24 +- .../aksInspektorGadget/aksInspektorGadget.ts | 9 +- .../aksKubectlCommands/aksKubectlCommands.ts | 9 +- src/commands/aksNavToPortal/aksNavToPortal.ts | 3 +- .../aksReconcileCluster.ts | 13 +- .../aksRetinaCapture/aksRetinaCapture.ts | 44 +- .../aksRotateClusterCert.ts | 14 +- .../aksTCPCollection/tcpDumpCollection.ts | 8 +- .../installAzureServiceOperator.ts | 18 +- src/commands/detectors/detectors.ts | 17 +- .../periscope/helpers/periscopehelper.ts | 21 +- src/commands/periscope/periscope.ts | 38 +- src/commands/selectSubscriptions.ts | 15 - src/commands/utils/arm.ts | 54 + src/commands/utils/authProvider.ts | 55 - src/commands/utils/azureAccount.ts | 112 +- src/commands/utils/azureResources.ts | 38 + src/commands/utils/clusters.ts | 232 +- src/commands/utils/config.ts | 76 + src/commands/utils/detectors.ts | 21 +- src/commands/utils/resourceGroups.ts | 22 + src/commands/utils/subscriptions.ts | 43 + src/extension.ts | 34 +- src/panels/AzureServiceOperatorPanel.ts | 7 +- src/panels/ClusterPropertiesPanel.ts | 17 +- src/panels/CreateClusterPanel.ts | 61 +- src/tree/aksClusterTreeItem.ts | 42 +- src/tree/azureAccountTreeItem.ts | 193 +- src/tree/subscriptionTreeItem.ts | 76 +- webpack.config.js | 27 - 43 files changed, 1648 insertions(+), 6483 deletions(-) create mode 100644 resources/azure.svg create mode 100644 resources/azureSubscription.svg create mode 100644 src/auth/azureAuth.ts create mode 100644 src/auth/azureSessionProvider.ts create mode 100644 src/auth/types.ts create mode 100644 src/commands/aksAccount/aksAccount.ts delete mode 100644 src/commands/selectSubscriptions.ts create mode 100644 src/commands/utils/arm.ts delete mode 100644 src/commands/utils/authProvider.ts create mode 100644 src/commands/utils/azureResources.ts create mode 100644 src/commands/utils/resourceGroups.ts create mode 100644 src/commands/utils/subscriptions.ts diff --git a/package-lock.json b/package-lock.json index 23869409..a14efb8e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,7 +1,7 @@ { "name": "vscode-aks-tools", "version": "1.4.3", - "lockfileVersion": 2, + "lockfileVersion": 3, "requires": true, "packages": { "": { @@ -13,15 +13,14 @@ "@azure/arm-containerservice": "^19.7.0", "@azure/arm-monitor": "^7.0.0", "@azure/arm-resources": "^5.2.0", + "@azure/arm-resources-subscriptions": "^2.1.0", "@azure/arm-storage": "^18.2.0", "@azure/arm-subscriptions": "^5.1.0", "@azure/core-auth": "^1.7.2", "@azure/identity": "^4.1.0", "@azure/ms-rest-azure-env": "^2.0.0", - "@azure/msal-node": "^2.6.6", "@azure/storage-blob": "^12.17.0", "@microsoft/microsoft-graph-client": "^3.0.7", - "@microsoft/vscode-azext-azureutils": "^3.0.1", "@microsoft/vscode-azext-utils": "^2.4.0", "@vscode/extension-telemetry": "^0.9.6", "cross-fetch": "^4.0.0", @@ -53,7 +52,6 @@ "chai": "^5.1.0", "eslint": "^8.57.0", "eslint-webpack-plugin": "^4.1.0", - "filemanager-webpack-plugin": "^8.0.0", "glob": "^10.3.12", "mocha": "^10.4.0", "prettier": "^3.2.5", @@ -77,16 +75,16 @@ } }, "node_modules/@azure/abort-controller": { - "version": "1.0.1", - "license": "MIT", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@azure/abort-controller/-/abort-controller-1.1.0.tgz", + "integrity": "sha512-TrRLIoSQVzfAJX9H1JeFjzAoDGcoK1IYX1UImfceTZpsyYfWr09Ss1aHW1y5TrrR3iq6RZLBwJ3E24uwPhwahw==", "dependencies": { - "tslib": "^1.9.3" + "tslib": "^2.2.0" + }, + "engines": { + "node": ">=12.0.0" } }, - "node_modules/@azure/abort-controller/node_modules/tslib": { - "version": "1.14.1", - "license": "0BSD" - }, "node_modules/@azure/arm-authorization": { "version": "9.0.0", "resolved": "https://registry.npmjs.org/@azure/arm-authorization/-/arm-authorization-9.0.0.tgz", @@ -153,23 +151,6 @@ "node": ">=14.0.0" } }, - "node_modules/@azure/arm-resources-profile-2020-09-01-hybrid": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@azure/arm-resources-profile-2020-09-01-hybrid/-/arm-resources-profile-2020-09-01-hybrid-2.1.0.tgz", - "integrity": "sha512-7sNMfaf8agfQmExgtlvXzTooxoXPl2wJelSB2hQCG2BPZ37Oi24kxeECia+lXiZKfXAkiPSHxgdgECGjDQaV+Q==", - "dependencies": { - "@azure/abort-controller": "^1.0.0", - "@azure/core-auth": "^1.3.0", - "@azure/core-client": "^1.6.1", - "@azure/core-lro": "^2.2.0", - "@azure/core-paging": "^1.2.0", - "@azure/core-rest-pipeline": "^1.8.0", - "tslib": "^2.2.0" - }, - "engines": { - "node": ">=14.0.0" - } - }, "node_modules/@azure/arm-resources-subscriptions": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/@azure/arm-resources-subscriptions/-/arm-resources-subscriptions-2.1.0.tgz", @@ -202,23 +183,6 @@ "node": ">=14.0.0" } }, - "node_modules/@azure/arm-storage-profile-2020-09-01-hybrid": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@azure/arm-storage-profile-2020-09-01-hybrid/-/arm-storage-profile-2020-09-01-hybrid-2.1.0.tgz", - "integrity": "sha512-XZYoBWQP9BkQPde5DA7xIiOJVE+6Eeo755VfRqymN42gRn/X6GOcZ0X5x0qvLVxXZcwpFRKblRpkmxGi0FpIxg==", - "dependencies": { - "@azure/abort-controller": "^1.0.0", - "@azure/core-auth": "^1.3.0", - "@azure/core-client": "^1.6.1", - "@azure/core-lro": "^2.2.0", - "@azure/core-paging": "^1.2.0", - "@azure/core-rest-pipeline": "^1.8.0", - "tslib": "^2.2.0" - }, - "engines": { - "node": ">=14.0.0" - } - }, "node_modules/@azure/arm-subscriptions": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/@azure/arm-subscriptions/-/arm-subscriptions-5.1.0.tgz", @@ -959,39 +923,6 @@ } } }, - "node_modules/@microsoft/vscode-azext-azureutils": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@microsoft/vscode-azext-azureutils/-/vscode-azext-azureutils-3.0.1.tgz", - "integrity": "sha512-zNNhCoh6vKoImPxsxUTIP+311TBeIW1GL/EVq5LBWYhnN1v8jmhtltIJuWkmOOq52DQGWRe99Lkj3Qzh1mGZcw==", - "dependencies": { - "@azure/arm-resources": "^5.0.0", - "@azure/arm-resources-profile-2020-09-01-hybrid": "^2.0.0", - "@azure/arm-resources-subscriptions": "^2.0.0", - "@azure/arm-storage": "^18.2.0", - "@azure/arm-storage-profile-2020-09-01-hybrid": "^2.0.0", - "@azure/core-client": "^1.6.0", - "@azure/core-rest-pipeline": "^1.9.0", - "@azure/logger": "^1.0.4", - "@microsoft/vscode-azext-utils": "^2.2.0", - "semver": "^7.3.7", - "uuid": "^9.0.0" - }, - "peerDependencies": { - "@azure/ms-rest-azure-env": "^2.0.0" - } - }, - "node_modules/@microsoft/vscode-azext-azureutils/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/@microsoft/vscode-azext-utils": { "version": "2.4.0", "resolved": "https://registry.npmjs.org/@microsoft/vscode-azext-utils/-/vscode-azext-utils-2.4.0.tgz", @@ -1171,14 +1102,6 @@ "node": ">= 6" } }, - "node_modules/@types/archiver": { - "version": "5.3.1", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/glob": "*" - } - }, "node_modules/@types/chai": { "version": "4.3.14", "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.3.14.tgz", @@ -1186,9 +1109,9 @@ "dev": true }, "node_modules/@types/decompress": { - "version": "4.2.6", - "resolved": "https://registry.npmjs.org/@types/decompress/-/decompress-4.2.6.tgz", - "integrity": "sha512-ULmsMkKxU7aIGbnxP4Rz28hLdRZ4q0cdy6kcb8dx+UgDGOn+id5fibvoeTnjuolhrRM7f7TOtGADeKEk60SSsQ==", + "version": "4.2.7", + "resolved": "https://registry.npmjs.org/@types/decompress/-/decompress-4.2.7.tgz", + "integrity": "sha512-9z+8yjKr5Wn73Pt17/ldnmQToaFHZxK0N1GHysuk/JIPT8RIdQeoInM01wWPgypRcvb6VH1drjuFpQ4zmY437g==", "dev": true, "dependencies": { "@types/node": "*" @@ -1357,9 +1280,9 @@ "dev": true }, "node_modules/@types/tough-cookie": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-4.0.4.tgz", - "integrity": "sha512-95Sfz4nvMAb0Nl9DTxN3j64adfwfbBPEYq14VN7zT5J5O2M9V6iZMIIQU1U+pJyl9agHYHNCqhCXgyEtIRRa5A==", + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-4.0.5.tgz", + "integrity": "sha512-/Ad8+nIOV7Rl++6f1BdKxFSMgmoqEoYbHRpPcx3JEfv8VRsQe9Z4mCXeJBzxs7mbHY/XOZZuXlRNfhpVPbs6ZA==", "dev": true }, "node_modules/@types/tunnel": { @@ -1640,11 +1563,12 @@ } }, "node_modules/@vscode/vsce": { - "version": "2.25.0", - "resolved": "https://registry.npmjs.org/@vscode/vsce/-/vsce-2.25.0.tgz", - "integrity": "sha512-VXMCGUaP6wKBadA7vFQdsksxkBAMoh4ecZgXBwauZMASAgnwYesHyLnqIyWYeRwjy2uEpitHvz/1w5ENnR30pg==", + "version": "2.26.0", + "resolved": "https://registry.npmjs.org/@vscode/vsce/-/vsce-2.26.0.tgz", + "integrity": "sha512-v54ltgMzUG8lGY0kAgaOlry57xse1RlWzes9FotfGEx+Fr05KeR8rZicQzEMDmi9QnOgVWHuiEq+xA2HWkAz+Q==", "dev": true, "dependencies": { + "@azure/identity": "^4.1.0", "azure-devops-node-api": "^12.5.0", "chalk": "^2.4.2", "cheerio": "^1.0.0-rc.9", @@ -2025,19 +1949,6 @@ "node": ">= 6.0.0" } }, - "node_modules/aggregate-error": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", - "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", - "dev": true, - "dependencies": { - "clean-stack": "^2.0.0", - "indent-string": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/ajv": { "version": "6.12.6", "dev": true, @@ -2141,89 +2052,6 @@ "node": ">= 8" } }, - "node_modules/archiver": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/archiver/-/archiver-5.3.2.tgz", - "integrity": "sha512-+25nxyyznAXF7Nef3y0EbBeqmGZgeN/BxHX29Rs39djAfaFalmQ89SE6CWyDCHzGL0yt/ycBtNOmGTW0FyGWNw==", - "dev": true, - "dependencies": { - "archiver-utils": "^2.1.0", - "async": "^3.2.4", - "buffer-crc32": "^0.2.1", - "readable-stream": "^3.6.0", - "readdir-glob": "^1.1.2", - "tar-stream": "^2.2.0", - "zip-stream": "^4.1.0" - }, - "engines": { - "node": ">= 10" - } - }, - "node_modules/archiver-utils": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/archiver-utils/-/archiver-utils-2.1.0.tgz", - "integrity": "sha512-bEL/yUb/fNNiNTuUz979Z0Yg5L+LzLxGJz8x79lYmR54fmTIb6ob/hNQgkQnIUDWIFjZVQwl9Xs356I6BAMHfw==", - "dev": true, - "dependencies": { - "glob": "^7.1.4", - "graceful-fs": "^4.2.0", - "lazystream": "^1.0.0", - "lodash.defaults": "^4.2.0", - "lodash.difference": "^4.5.0", - "lodash.flatten": "^4.4.0", - "lodash.isplainobject": "^4.0.6", - "lodash.union": "^4.6.0", - "normalize-path": "^3.0.0", - "readable-stream": "^2.0.0" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/archiver-utils/node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "dev": 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_modules/archiver-utils/node_modules/readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", - "dev": true, - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "node_modules/archiver-utils/node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dev": true, - "dependencies": { - "safe-buffer": "~5.1.0" - } - }, "node_modules/argparse": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", @@ -2247,12 +2075,6 @@ "node": ">=12" } }, - "node_modules/async": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/async/-/async-3.2.4.tgz", - "integrity": "sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ==", - "dev": true - }, "node_modules/asynckit": { "version": "0.4.0", "license": "MIT" @@ -2326,6 +2148,7 @@ "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", "dev": true, + "optional": true, "dependencies": { "buffer": "^5.5.0", "inherits": "^2.0.4", @@ -2781,15 +2604,6 @@ "node": ">=8" } }, - "node_modules/clean-stack": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", - "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", - "dev": true, - "engines": { - "node": ">=6" - } - }, "node_modules/cliui": { "version": "7.0.4", "dev": true, @@ -2861,21 +2675,6 @@ "version": "2.20.3", "license": "MIT" }, - "node_modules/compress-commons": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/compress-commons/-/compress-commons-4.1.2.tgz", - "integrity": "sha512-D3uMHtGc/fcO1Gt1/L7i1e33VOvD4A9hfQLP+6ewd+BvG/gQ84Yh4oftEhAdjSMgBgwGL+jsppT7JYNpo6MHHg==", - "dev": true, - "dependencies": { - "buffer-crc32": "^0.2.13", - "crc32-stream": "^4.0.2", - "normalize-path": "^3.0.0", - "readable-stream": "^3.6.0" - }, - "engines": { - "node": ">= 10" - } - }, "node_modules/concat-map": { "version": "0.0.1", "dev": true, @@ -2885,31 +2684,6 @@ "version": "1.0.2", "license": "MIT" }, - "node_modules/crc-32": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/crc-32/-/crc-32-1.2.2.tgz", - "integrity": "sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==", - "dev": true, - "bin": { - "crc32": "bin/crc32.njs" - }, - "engines": { - "node": ">=0.8" - } - }, - "node_modules/crc32-stream": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/crc32-stream/-/crc32-stream-4.0.3.tgz", - "integrity": "sha512-NT7w2JVU7DFroFdYkeq8cywxrgjPHWkdX1wjpRQXPX5Asews3tA+Ght6lddQO5Mkumffp3X7GEqku3epj2toIw==", - "dev": true, - "dependencies": { - "crc-32": "^1.2.0", - "readable-stream": "^3.4.0" - }, - "engines": { - "node": ">= 10" - } - }, "node_modules/cross-fetch": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-4.0.0.tgz", @@ -3325,28 +3099,6 @@ "node": ">=8" } }, - "node_modules/del": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/del/-/del-6.1.1.tgz", - "integrity": "sha512-ua8BhapfP0JUJKC/zV9yHHDW/rDoDxP4Zhn3AkA6/xT6gY7jYXJiaeyBZznYVujhZZET+UgcbZiQ7sN3WqcImg==", - "dev": true, - "dependencies": { - "globby": "^11.0.1", - "graceful-fs": "^4.2.4", - "is-glob": "^4.0.1", - "is-path-cwd": "^2.2.0", - "is-path-inside": "^3.0.2", - "p-map": "^4.0.0", - "rimraf": "^3.0.2", - "slash": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/delayed-stream": { "version": "1.0.0", "license": "MIT", @@ -3948,9 +3700,9 @@ "license": "MIT" }, "node_modules/fast-glob": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.1.tgz", - "integrity": "sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==", + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", + "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", "dev": true, "dependencies": { "@nodelib/fs.stat": "^2.0.2", @@ -4009,175 +3761,72 @@ "node": "^10.12.0 || >=12.0.0" } }, - "node_modules/filemanager-webpack-plugin": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/filemanager-webpack-plugin/-/filemanager-webpack-plugin-8.0.0.tgz", - "integrity": "sha512-TYwu62wgq2O2c3K80Sfj8vEys/tP5wdgYoySHgUwWoc2hPbQY3Mq3ahcAW634JvHCTcSV7IAfRxMI3wTXRt2Vw==", + "node_modules/fill-range": { + "version": "7.0.1", "dev": true, + "license": "MIT", "dependencies": { - "@types/archiver": "^5.3.1", - "archiver": "^5.3.1", - "del": "^6.1.1", - "fast-glob": "^3.2.12", - "fs-extra": "^10.1.0", - "is-glob": "^4.0.3", - "normalize-path": "^3.0.0", - "schema-utils": "^4.0.0" + "to-regex-range": "^5.0.1" }, "engines": { - "node": "^14.13.1 || >=16.0.0" - }, - "peerDependencies": { - "webpack": "^5.0.0" + "node": ">=8" } }, - "node_modules/filemanager-webpack-plugin/node_modules/ajv": { - "version": "8.11.0", + "node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", "dev": true, - "license": "MIT", "dependencies": { - "fast-deep-equal": "^3.1.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" + "engines": { + "node": ">=8" } }, - "node_modules/filemanager-webpack-plugin/node_modules/ajv-keywords": { - "version": "5.1.0", + "node_modules/flat": { + "version": "5.0.2", "dev": true, - "license": "MIT", - "dependencies": { - "fast-deep-equal": "^3.1.3" - }, - "peerDependencies": { - "ajv": "^8.8.2" + "license": "BSD-3-Clause", + "bin": { + "flat": "cli.js" } }, - "node_modules/filemanager-webpack-plugin/node_modules/fs-extra": { - "version": "10.1.0", + "node_modules/flat-cache": { + "version": "3.0.4", "dev": true, "license": "MIT", "dependencies": { - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" + "flatted": "^3.1.0", + "rimraf": "^3.0.2" }, "engines": { - "node": ">=12" + "node": "^10.12.0 || >=12.0.0" } }, - "node_modules/filemanager-webpack-plugin/node_modules/json-schema-traverse": { - "version": "1.0.0", + "node_modules/flatted": { + "version": "3.2.7", "dev": true, - "license": "MIT" + "license": "ISC" }, - "node_modules/filemanager-webpack-plugin/node_modules/jsonfile": { - "version": "6.1.0", - "dev": true, - "license": "MIT", - "dependencies": { - "universalify": "^2.0.0" + "node_modules/follow-redirects": { + "version": "1.15.6", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz", + "integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "engines": { + "node": ">=4.0" }, - "optionalDependencies": { - "graceful-fs": "^4.1.6" - } - }, - "node_modules/filemanager-webpack-plugin/node_modules/schema-utils": { - "version": "4.0.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/json-schema": "^7.0.9", - "ajv": "^8.8.0", - "ajv-formats": "^2.1.1", - "ajv-keywords": "^5.0.0" - }, - "engines": { - "node": ">= 12.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - } - }, - "node_modules/filemanager-webpack-plugin/node_modules/universalify": { - "version": "2.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 10.0.0" - } - }, - "node_modules/fill-range": { - "version": "7.0.1", - "dev": true, - "license": "MIT", - "dependencies": { - "to-regex-range": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, - "dependencies": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/flat": { - "version": "5.0.2", - "dev": true, - "license": "BSD-3-Clause", - "bin": { - "flat": "cli.js" - } - }, - "node_modules/flat-cache": { - "version": "3.0.4", - "dev": true, - "license": "MIT", - "dependencies": { - "flatted": "^3.1.0", - "rimraf": "^3.0.2" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - } - }, - "node_modules/flatted": { - "version": "3.2.7", - "dev": true, - "license": "ISC" - }, - "node_modules/follow-redirects": { - "version": "1.15.6", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz", - "integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==", - "funding": [ - { - "type": "individual", - "url": "https://github.com/sponsors/RubenVerborgh" - } - ], - "engines": { - "node": ">=4.0" - }, - "peerDependenciesMeta": { - "debug": { - "optional": true - } + "peerDependenciesMeta": { + "debug": { + "optional": true + } } }, "node_modules/foreground-child": { @@ -4198,8 +3847,9 @@ }, "node_modules/form-data": { "version": "2.5.1", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.5.1.tgz", + "integrity": "sha512-m21N3WOmEEURgk6B9GLOE4RuWOFf28Lhh9qGYeNlGq4VDXUlJy2th2slBNU8Gp8EzloYZOibZJ7t5ecIrFSjVA==", "dev": true, - "license": "MIT", "dependencies": { "asynckit": "^0.4.0", "combined-stream": "^1.0.6", @@ -4615,15 +4265,6 @@ "node": ">=0.8.19" } }, - "node_modules/indent-string": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", - "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", @@ -4730,15 +4371,6 @@ "node": ">=0.12.0" } }, - "node_modules/is-path-cwd": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-2.2.0.tgz", - "integrity": "sha512-w942bTcih8fdJPJmQHFzkS76NEP8Kzzvmw92cXsazb8intwLqPibPPdXf4ANdKV3rYMuuQYGIWtvz9JilB3NFQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, "node_modules/is-path-inside": { "version": "3.0.3", "dev": true, @@ -5012,42 +4644,6 @@ "node": ">=0.10.0" } }, - "node_modules/lazystream": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/lazystream/-/lazystream-1.0.1.tgz", - "integrity": "sha512-b94GiNHQNy6JNTrt5w6zNyffMrNkXZb3KTkCZJb2V1xaEGCk093vkZ2jk3tpaeP33/OiXC+WvK9AxUebnf5nbw==", - "dev": true, - "dependencies": { - "readable-stream": "^2.0.5" - }, - "engines": { - "node": ">= 0.6.3" - } - }, - "node_modules/lazystream/node_modules/readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", - "dev": true, - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "node_modules/lazystream/node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dev": true, - "dependencies": { - "safe-buffer": "~5.1.0" - } - }, "node_modules/leven": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", @@ -5108,24 +4704,6 @@ "node": ">=8" } }, - "node_modules/lodash.defaults": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz", - "integrity": "sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ==", - "dev": true - }, - "node_modules/lodash.difference": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.difference/-/lodash.difference-4.5.0.tgz", - "integrity": "sha512-dS2j+W26TQ7taQBGN8Lbbq04ssV3emRw4NY58WErlTO29pIqS0HmoT5aJ9+TUQ1N3G+JOZSji4eugsWwGp9yPA==", - "dev": true - }, - "node_modules/lodash.flatten": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/lodash.flatten/-/lodash.flatten-4.4.0.tgz", - "integrity": "sha512-C5N2Z3DgnnKr0LOpv/hKCgKdb7ZZwafIrsesve6lmzvZIRZRGaZ/l6Q8+2W7NaT+ZwO3fFlSCzCzrDCFdJfZ4g==", - "dev": true - }, "node_modules/lodash.get": { "version": "4.4.2", "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", @@ -5171,12 +4749,6 @@ "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", "integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==" }, - "node_modules/lodash.union": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/lodash.union/-/lodash.union-4.6.0.tgz", - "integrity": "sha512-c4pB2CdGrGdjMKYLA+XiRDO7Y0PRQbm/Gzg8qMj+QH+pFVAoTp5sBpO0odL3FjoPCGjK96p6qsP+yQoiLoOBcw==", - "dev": true - }, "node_modules/log-symbols": { "version": "4.1.0", "dev": true, @@ -5776,21 +5348,6 @@ "node": ">=8" } }, - "node_modules/p-map": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", - "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", - "dev": true, - "dependencies": { - "aggregate-error": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/p-try": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", @@ -6233,6 +5790,7 @@ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", "dev": true, + "optional": true, "dependencies": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", @@ -6242,36 +5800,6 @@ "node": ">= 6" } }, - "node_modules/readdir-glob": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/readdir-glob/-/readdir-glob-1.1.3.tgz", - "integrity": "sha512-v05I2k7xN8zXvPD9N+z/uhXPaj0sUFCe2rcWZIpBsqxfP7xXFQ0tipAd/wjj1YxWyWtUS5IDJpOG82JKt2EAVA==", - "dev": true, - "dependencies": { - "minimatch": "^5.1.0" - } - }, - "node_modules/readdir-glob/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/readdir-glob/node_modules/minimatch": { - "version": "5.1.6", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", - "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", - "dev": true, - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/readdirp": { "version": "3.6.0", "dev": true, @@ -6694,6 +6222,7 @@ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", "dev": true, + "optional": true, "dependencies": { "safe-buffer": "~5.2.0" } @@ -6716,7 +6245,8 @@ "type": "consulting", "url": "https://feross.org/support" } - ] + ], + "optional": true }, "node_modules/string-width": { "version": "4.2.3", @@ -6838,6 +6368,7 @@ "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", "dev": true, + "optional": true, "dependencies": { "bl": "^4.0.3", "end-of-stream": "^1.4.1", @@ -7525,5468 +7056,6 @@ "funding": { "url": "https://github.com/sponsors/sindresorhus" } - }, - "node_modules/zip-stream": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/zip-stream/-/zip-stream-4.1.1.tgz", - "integrity": "sha512-9qv4rlDiopXg4E69k+vMHjNN63YFMe9sZMrdlvKnCjlCRWeCBswPPMPUfx+ipsAWq1LXHe70RcbaHdJJpS6hyQ==", - "dev": true, - "dependencies": { - "archiver-utils": "^3.0.4", - "compress-commons": "^4.1.2", - "readable-stream": "^3.6.0" - }, - "engines": { - "node": ">= 10" - } - }, - "node_modules/zip-stream/node_modules/archiver-utils": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/archiver-utils/-/archiver-utils-3.0.4.tgz", - "integrity": "sha512-KVgf4XQVrTjhyWmx6cte4RxonPLR9onExufI1jhvw/MQ4BB6IsZD5gT8Lq+u/+pRkWna/6JoHpiQioaqFP5Rzw==", - "dev": true, - "dependencies": { - "glob": "^7.2.3", - "graceful-fs": "^4.2.0", - "lazystream": "^1.0.0", - "lodash.defaults": "^4.2.0", - "lodash.difference": "^4.5.0", - "lodash.flatten": "^4.4.0", - "lodash.isplainobject": "^4.0.6", - "lodash.union": "^4.6.0", - "normalize-path": "^3.0.0", - "readable-stream": "^3.6.0" - }, - "engines": { - "node": ">= 10" - } - }, - "node_modules/zip-stream/node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "dev": 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" - } - } - }, - "dependencies": { - "@aashutoshrathi/word-wrap": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz", - "integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==", - "dev": true - }, - "@azure/abort-controller": { - "version": "1.0.1", - "requires": { - "tslib": "^1.9.3" - }, - "dependencies": { - "tslib": { - "version": "1.14.1" - } - } - }, - "@azure/arm-authorization": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/@azure/arm-authorization/-/arm-authorization-9.0.0.tgz", - "integrity": "sha512-GdiCA8IA1gO+qcCbFEPj+iLC4+3ByjfKzmeAnkP7MdlL84Yo30Huo/EwbZzwRjYybXYUBuFxGPBB+yeTT4Ebxg==", - "requires": { - "@azure/core-auth": "^1.3.0", - "@azure/core-client": "^1.7.0", - "@azure/core-paging": "^1.2.0", - "@azure/core-rest-pipeline": "^1.8.0", - "tslib": "^2.2.0" - } - }, - "@azure/arm-containerservice": { - "version": "19.7.0", - "resolved": "https://registry.npmjs.org/@azure/arm-containerservice/-/arm-containerservice-19.7.0.tgz", - "integrity": "sha512-AAxG+rT9DGJaokuFcZ+p0KIDAxgFTEuGerPRLilKvs9nYT5yjdojG2NIQ85gx1xeYAPFcQZ8FUo77gbA/+oNfw==", - "requires": { - "@azure/abort-controller": "^1.0.0", - "@azure/core-auth": "^1.3.0", - "@azure/core-client": "^1.7.0", - "@azure/core-lro": "^2.5.4", - "@azure/core-paging": "^1.2.0", - "@azure/core-rest-pipeline": "^1.12.0", - "tslib": "^2.2.0" - } - }, - "@azure/arm-monitor": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@azure/arm-monitor/-/arm-monitor-7.0.0.tgz", - "integrity": "sha512-RtCLRc/29bqaaf5iuUOmJvc5XDolN/icFhlKC/rXXKTtmwB3sKymaOZbNHnOM4P0nJYpS5QIo7Nzvh4M3Wj+FA==", - "requires": { - "@azure/abort-controller": "^1.0.0", - "@azure/core-auth": "^1.3.0", - "@azure/core-client": "^1.0.0", - "@azure/core-lro": "^2.2.0", - "@azure/core-paging": "^1.2.0", - "@azure/core-rest-pipeline": "^1.1.0", - "tslib": "^2.2.0" - } - }, - "@azure/arm-resources": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/@azure/arm-resources/-/arm-resources-5.2.0.tgz", - "integrity": "sha512-wQyuhL8WQsLkW/KMdik8bLJIJCz3Z6mg/+AKm0KedgK73SKhicSqYP+ed3t+43tLlRFltcrmGKMcHLQ+Jhv/6A==", - "requires": { - "@azure/abort-controller": "^1.0.0", - "@azure/core-auth": "^1.3.0", - "@azure/core-client": "^1.7.0", - "@azure/core-lro": "^2.5.0", - "@azure/core-paging": "^1.2.0", - "@azure/core-rest-pipeline": "^1.8.0", - "tslib": "^2.2.0" - } - }, - "@azure/arm-resources-profile-2020-09-01-hybrid": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@azure/arm-resources-profile-2020-09-01-hybrid/-/arm-resources-profile-2020-09-01-hybrid-2.1.0.tgz", - "integrity": "sha512-7sNMfaf8agfQmExgtlvXzTooxoXPl2wJelSB2hQCG2BPZ37Oi24kxeECia+lXiZKfXAkiPSHxgdgECGjDQaV+Q==", - "requires": { - "@azure/abort-controller": "^1.0.0", - "@azure/core-auth": "^1.3.0", - "@azure/core-client": "^1.6.1", - "@azure/core-lro": "^2.2.0", - "@azure/core-paging": "^1.2.0", - "@azure/core-rest-pipeline": "^1.8.0", - "tslib": "^2.2.0" - } - }, - "@azure/arm-resources-subscriptions": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@azure/arm-resources-subscriptions/-/arm-resources-subscriptions-2.1.0.tgz", - "integrity": "sha512-vKiu/3Yh84IV3IuJJ+0Fgs/ZQpvuGzoZ3dAoBksIV++Uu/Qz9RcQVz7pj+APWYIuODuR9I0eGKswZvzynzekug==", - "requires": { - "@azure/core-auth": "^1.3.0", - "@azure/core-client": "^1.7.0", - "@azure/core-paging": "^1.2.0", - "@azure/core-rest-pipeline": "^1.8.0", - "tslib": "^2.2.0" - } - }, - "@azure/arm-storage": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/@azure/arm-storage/-/arm-storage-18.2.0.tgz", - "integrity": "sha512-jLUsAVFq5YBOYQfhE6L+KaUs+lntctKVafPz50FFScfzPMHYT/SptQGZ7BKzAJBBE/evdt8afmt2NSdl8Szomg==", - "requires": { - "@azure/abort-controller": "^1.0.0", - "@azure/core-auth": "^1.3.0", - "@azure/core-client": "^1.7.0", - "@azure/core-lro": "^2.5.3", - "@azure/core-paging": "^1.2.0", - "@azure/core-rest-pipeline": "^1.8.0", - "tslib": "^2.2.0" - } - }, - "@azure/arm-storage-profile-2020-09-01-hybrid": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@azure/arm-storage-profile-2020-09-01-hybrid/-/arm-storage-profile-2020-09-01-hybrid-2.1.0.tgz", - "integrity": "sha512-XZYoBWQP9BkQPde5DA7xIiOJVE+6Eeo755VfRqymN42gRn/X6GOcZ0X5x0qvLVxXZcwpFRKblRpkmxGi0FpIxg==", - "requires": { - "@azure/abort-controller": "^1.0.0", - "@azure/core-auth": "^1.3.0", - "@azure/core-client": "^1.6.1", - "@azure/core-lro": "^2.2.0", - "@azure/core-paging": "^1.2.0", - "@azure/core-rest-pipeline": "^1.8.0", - "tslib": "^2.2.0" - } - }, - "@azure/arm-subscriptions": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/@azure/arm-subscriptions/-/arm-subscriptions-5.1.0.tgz", - "integrity": "sha512-6BeOF2eQWNLq22ch7xP9RxYnPjtGev54OUCGggKOWoOvmesK7jUZbIyLk8JeXDT21PEl7iyYnxw78gxJ7zBxQw==", - "requires": { - "@azure/abort-controller": "^1.0.0", - "@azure/core-auth": "^1.3.0", - "@azure/core-client": "^1.6.1", - "@azure/core-lro": "^2.2.0", - "@azure/core-paging": "^1.2.0", - "@azure/core-rest-pipeline": "^1.8.0", - "tslib": "^2.2.0" - } - }, - "@azure/core-auth": { - "version": "1.7.2", - "resolved": "https://registry.npmjs.org/@azure/core-auth/-/core-auth-1.7.2.tgz", - "integrity": "sha512-Igm/S3fDYmnMq1uKS38Ae1/m37B3zigdlZw+kocwEhh5GjyKjPrXKO2J6rzpC1wAxrNil/jX9BJRqBshyjnF3g==", - "requires": { - "@azure/abort-controller": "^2.0.0", - "@azure/core-util": "^1.1.0", - "tslib": "^2.6.2" - }, - "dependencies": { - "@azure/abort-controller": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@azure/abort-controller/-/abort-controller-2.0.0.tgz", - "integrity": "sha512-RP/mR/WJchR+g+nQFJGOec+nzeN/VvjlwbinccoqfhTsTHbb8X5+mLDp48kHT0ueyum0BNSwGm0kX0UZuIqTGg==", - "requires": { - "tslib": "^2.2.0" - } - } - } - }, - "@azure/core-client": { - "version": "1.7.3", - "resolved": "https://registry.npmjs.org/@azure/core-client/-/core-client-1.7.3.tgz", - "integrity": "sha512-kleJ1iUTxcO32Y06dH9Pfi9K4U+Tlb111WXEnbt7R/ne+NLRwppZiTGJuTD5VVoxTMK5NTbEtm5t2vcdNCFe2g==", - "requires": { - "@azure/abort-controller": "^1.0.0", - "@azure/core-auth": "^1.4.0", - "@azure/core-rest-pipeline": "^1.9.1", - "@azure/core-tracing": "^1.0.0", - "@azure/core-util": "^1.0.0", - "@azure/logger": "^1.0.0", - "tslib": "^2.2.0" - }, - "dependencies": { - "@azure/core-tracing": { - "version": "1.0.1", - "requires": { - "tslib": "^2.2.0" - } - } - } - }, - "@azure/core-http": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/@azure/core-http/-/core-http-3.0.4.tgz", - "integrity": "sha512-Fok9VVhMdxAFOtqiiAtg74fL0UJkt0z3D+ouUUxcRLzZNBioPRAMJFVxiWoJljYpXsRi4GDQHzQHDc9AiYaIUQ==", - "requires": { - "@azure/abort-controller": "^1.0.0", - "@azure/core-auth": "^1.3.0", - "@azure/core-tracing": "1.0.0-preview.13", - "@azure/core-util": "^1.1.1", - "@azure/logger": "^1.0.0", - "@types/node-fetch": "^2.5.0", - "@types/tunnel": "^0.0.3", - "form-data": "^4.0.0", - "node-fetch": "^2.6.7", - "process": "^0.11.10", - "tslib": "^2.2.0", - "tunnel": "^0.0.6", - "uuid": "^8.3.0", - "xml2js": "^0.5.0" - }, - "dependencies": { - "form-data": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", - "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", - "requires": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "mime-types": "^2.1.12" - } - } - } - }, - "@azure/core-lro": { - "version": "2.5.4", - "resolved": "https://registry.npmjs.org/@azure/core-lro/-/core-lro-2.5.4.tgz", - "integrity": "sha512-3GJiMVH7/10bulzOKGrrLeG/uCBH/9VtxqaMcB9lIqAeamI/xYQSHJL/KcsLDuH+yTjYpro/u6D/MuRe4dN70Q==", - "requires": { - "@azure/abort-controller": "^1.0.0", - "@azure/core-util": "^1.2.0", - "@azure/logger": "^1.0.0", - "tslib": "^2.2.0" - } - }, - "@azure/core-paging": { - "version": "1.3.0", - "requires": { - "tslib": "^2.2.0" - } - }, - "@azure/core-rest-pipeline": { - "version": "1.12.1", - "resolved": "https://registry.npmjs.org/@azure/core-rest-pipeline/-/core-rest-pipeline-1.12.1.tgz", - "integrity": "sha512-SsyWQ+T5MFQRX+M8H/66AlaI6HyCbQStGfFngx2fuiW+vKI2DkhtOvbYodPyf9fOe/ARLWWc3ohX54lQ5Kmaog==", - "requires": { - "@azure/abort-controller": "^1.0.0", - "@azure/core-auth": "^1.4.0", - "@azure/core-tracing": "^1.0.1", - "@azure/core-util": "^1.3.0", - "@azure/logger": "^1.0.0", - "form-data": "^4.0.0", - "http-proxy-agent": "^5.0.0", - "https-proxy-agent": "^5.0.0", - "tslib": "^2.2.0" - }, - "dependencies": { - "@azure/core-tracing": { - "version": "1.0.1", - "requires": { - "tslib": "^2.2.0" - } - }, - "@tootallnate/once": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz", - "integrity": "sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==" - }, - "form-data": { - "version": "4.0.0", - "requires": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "mime-types": "^2.1.12" - } - }, - "http-proxy-agent": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz", - "integrity": "sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==", - "requires": { - "@tootallnate/once": "2", - "agent-base": "6", - "debug": "4" - } - } - } - }, - "@azure/core-tracing": { - "version": "1.0.0-preview.13", - "resolved": "https://registry.npmjs.org/@azure/core-tracing/-/core-tracing-1.0.0-preview.13.tgz", - "integrity": "sha512-KxDlhXyMlh2Jhj2ykX6vNEU0Vou4nHr025KoSEiz7cS3BNiHNaZcdECk/DmLkEB0as5T7b/TpRcehJ5yV6NeXQ==", - "requires": { - "@opentelemetry/api": "^1.0.1", - "tslib": "^2.2.0" - } - }, - "@azure/core-util": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/@azure/core-util/-/core-util-1.3.2.tgz", - "integrity": "sha512-2bECOUh88RvL1pMZTcc6OzfobBeWDBf5oBbhjIhT1MV9otMVWCzpOJkkiKtrnO88y5GGBelgY8At73KGAdbkeQ==", - "requires": { - "@azure/abort-controller": "^1.0.0", - "tslib": "^2.2.0" - } - }, - "@azure/identity": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/@azure/identity/-/identity-4.1.0.tgz", - "integrity": "sha512-BhYkF8Xr2gXjyDxocm0pc9RI5J5a1jw8iW0dw6Bx95OGdYbuMyFZrrwNw4eYSqQ2BB6FZOqpJP3vjsAqRcvDhw==", - "requires": { - "@azure/abort-controller": "^1.0.0", - "@azure/core-auth": "^1.5.0", - "@azure/core-client": "^1.4.0", - "@azure/core-rest-pipeline": "^1.1.0", - "@azure/core-tracing": "^1.0.0", - "@azure/core-util": "^1.3.0", - "@azure/logger": "^1.0.0", - "@azure/msal-browser": "^3.11.1", - "@azure/msal-node": "^2.6.6", - "events": "^3.0.0", - "jws": "^4.0.0", - "open": "^8.0.0", - "stoppable": "^1.1.0", - "tslib": "^2.2.0" - }, - "dependencies": { - "@azure/core-tracing": { - "version": "1.0.1", - "requires": { - "tslib": "^2.2.0" - } - } - } - }, - "@azure/logger": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@azure/logger/-/logger-1.0.4.tgz", - "integrity": "sha512-ustrPY8MryhloQj7OWGe+HrYx+aoiOxzbXTtgblbV3xwCqpzUK36phH3XNHQKj3EPonyFUuDTfR3qFhTEAuZEg==", - "requires": { - "tslib": "^2.2.0" - } - }, - "@azure/ms-rest-azure-env": { - "version": "2.0.0" - }, - "@azure/msal-browser": { - "version": "3.13.0", - "resolved": "https://registry.npmjs.org/@azure/msal-browser/-/msal-browser-3.13.0.tgz", - "integrity": "sha512-fD906nmJei3yE7la6DZTdUtXKvpwzJURkfsiz9747Icv4pit77cegSm6prJTKLQ1fw4iiZzrrWwxnhMLrTf5gQ==", - "requires": { - "@azure/msal-common": "14.9.0" - } - }, - "@azure/msal-common": { - "version": "14.9.0", - "resolved": "https://registry.npmjs.org/@azure/msal-common/-/msal-common-14.9.0.tgz", - "integrity": "sha512-yzBPRlWPnTBeixxLNI3BBIgF5/bHpbhoRVuuDBnYjCyWRavaPUsKAHUDYLqpGkBLDciA6TCc6GOxN4/S3WiSxg==" - }, - "@azure/msal-node": { - "version": "2.6.6", - "resolved": "https://registry.npmjs.org/@azure/msal-node/-/msal-node-2.6.6.tgz", - "integrity": "sha512-j+1hW81ccglIYWukXufzRA4O71BCmpbmCO66ECDyE9FuPno6SjiR+K+mIk4tg6aQ7/UO2QA/EnRmT6YN0EF1Hw==", - "requires": { - "@azure/msal-common": "14.8.1", - "jsonwebtoken": "^9.0.0", - "uuid": "^8.3.0" - }, - "dependencies": { - "@azure/msal-common": { - "version": "14.8.1", - "resolved": "https://registry.npmjs.org/@azure/msal-common/-/msal-common-14.8.1.tgz", - "integrity": "sha512-9HfBMDTIgtFFkils+o6gO/aGEoLLuc4z+QLLfhy/T1bTNPiVsX/9CjaBPMZGnMltN/IlMkU5SGGNggGh55p5xA==" - } - } - }, - "@azure/storage-blob": { - "version": "12.17.0", - "resolved": "https://registry.npmjs.org/@azure/storage-blob/-/storage-blob-12.17.0.tgz", - "integrity": "sha512-sM4vpsCpcCApagRW5UIjQNlNylo02my2opgp0Emi8x888hZUvJ3dN69Oq20cEGXkMUWnoCrBaB0zyS3yeB87sQ==", - "requires": { - "@azure/abort-controller": "^1.0.0", - "@azure/core-http": "^3.0.0", - "@azure/core-lro": "^2.2.0", - "@azure/core-paging": "^1.1.1", - "@azure/core-tracing": "1.0.0-preview.13", - "@azure/logger": "^1.0.0", - "events": "^3.0.0", - "tslib": "^2.2.0" - } - }, - "@babel/runtime": { - "version": "7.20.6", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.20.6.tgz", - "integrity": "sha512-Q+8MqP7TiHMWzSfwiJwXCjyf4GYA4Dgw3emg/7xmwsdLJOZUp+nMqcOwOzzYheuM1rhDu8FSj2l0aoMygEuXuA==", - "requires": { - "regenerator-runtime": "^0.13.11" - } - }, - "@discoveryjs/json-ext": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz", - "integrity": "sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==", - "dev": true - }, - "@eslint-community/eslint-utils": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", - "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", - "dev": true, - "requires": { - "eslint-visitor-keys": "^3.3.0" - } - }, - "@eslint-community/regexpp": { - "version": "4.10.0", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.10.0.tgz", - "integrity": "sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA==", - "dev": true - }, - "@eslint/eslintrc": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", - "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", - "dev": true, - "requires": { - "ajv": "^6.12.4", - "debug": "^4.3.2", - "espree": "^9.6.0", - "globals": "^13.19.0", - "ignore": "^5.2.0", - "import-fresh": "^3.2.1", - "js-yaml": "^4.1.0", - "minimatch": "^3.1.2", - "strip-json-comments": "^3.1.1" - } - }, - "@eslint/js": { - "version": "8.57.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.0.tgz", - "integrity": "sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==", - "dev": true - }, - "@humanwhocodes/config-array": { - "version": "0.11.14", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz", - "integrity": "sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==", - "dev": true, - "requires": { - "@humanwhocodes/object-schema": "^2.0.2", - "debug": "^4.3.1", - "minimatch": "^3.0.5" - } - }, - "@humanwhocodes/module-importer": { - "version": "1.0.1", - "dev": true - }, - "@humanwhocodes/object-schema": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.2.tgz", - "integrity": "sha512-6EwiSjwWYP7pTckG6I5eyFANjPhmPjUX9JRLUSfNPC7FX7zK9gyZAfUEaECL6ALTpGX5AjnBq3C9XmVWPitNpw==", - "dev": true - }, - "@isaacs/cliui": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", - "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", - "dev": true, - "requires": { - "string-width": "^5.1.2", - "string-width-cjs": "npm:string-width@^4.2.0", - "strip-ansi": "^7.0.1", - "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", - "wrap-ansi": "^8.1.0", - "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" - }, - "dependencies": { - "ansi-regex": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", - "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", - "dev": true - }, - "ansi-styles": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", - "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", - "dev": true - }, - "emoji-regex": { - "version": "9.2.2", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", - "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", - "dev": true - }, - "string-width": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", - "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", - "dev": true, - "requires": { - "eastasianwidth": "^0.2.0", - "emoji-regex": "^9.2.2", - "strip-ansi": "^7.0.1" - } - }, - "strip-ansi": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", - "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", - "dev": true, - "requires": { - "ansi-regex": "^6.0.1" - } - }, - "wrap-ansi": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", - "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", - "dev": true, - "requires": { - "ansi-styles": "^6.1.0", - "string-width": "^5.0.1", - "strip-ansi": "^7.0.1" - } - } - } - }, - "@jest/schemas": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz", - "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==", - "dev": true, - "requires": { - "@sinclair/typebox": "^0.27.8" - } - }, - "@jest/types": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", - "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", - "dev": true, - "requires": { - "@jest/schemas": "^29.6.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" - } - }, - "@jridgewell/gen-mapping": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", - "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==", - "dev": true, - "requires": { - "@jridgewell/set-array": "^1.0.1", - "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.9" - } - }, - "@jridgewell/resolve-uri": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz", - "integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==", - "dev": true - }, - "@jridgewell/set-array": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", - "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", - "dev": true - }, - "@jridgewell/source-map": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.5.tgz", - "integrity": "sha512-UTYAUj/wviwdsMfzoSJspJxbkH5o1snzwX0//0ENX1u/55kkZZkcTZP6u9bwKGkv+dkk9at4m1Cpt0uY80kcpQ==", - "dev": true, - "requires": { - "@jridgewell/gen-mapping": "^0.3.0", - "@jridgewell/trace-mapping": "^0.3.9" - } - }, - "@jridgewell/sourcemap-codec": { - "version": "1.4.15", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", - "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", - "dev": true - }, - "@jridgewell/trace-mapping": { - "version": "0.3.22", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.22.tgz", - "integrity": "sha512-Wf963MzWtA2sjrNt+g18IAln9lKnlRp+K2eH4jjIoF1wYeq3aMREpG09xhlhdzS0EjwU7qmUJYangWa+151vZw==", - "dev": true, - "requires": { - "@jridgewell/resolve-uri": "^3.1.0", - "@jridgewell/sourcemap-codec": "^1.4.14" - } - }, - "@microsoft/1ds-core-js": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/@microsoft/1ds-core-js/-/1ds-core-js-4.1.2.tgz", - "integrity": "sha512-m1MeUdPtDqq4D7qmirMBgiHQNQs8wkUoTxA44RTtki6kup8cF1c4WYXsxvHJ8R4C/wbm+HRM9PxBqI5JH3d58Q==", - "requires": { - "@microsoft/applicationinsights-core-js": "3.1.2", - "@microsoft/applicationinsights-shims": "3.0.1", - "@microsoft/dynamicproto-js": "^2.0.3", - "@nevware21/ts-async": ">= 0.3.0 < 2.x", - "@nevware21/ts-utils": ">= 0.11.0 < 2.x" - } - }, - "@microsoft/1ds-post-js": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/@microsoft/1ds-post-js/-/1ds-post-js-4.1.2.tgz", - "integrity": "sha512-rfuILnEZqXtZaPQf+WRF/zYZ6V0Dxh0W9lWiVM9aY2Enuh8fEvbjeeXGk0n/jGXeko/bLXevmOaMrZw9x1pIVw==", - "requires": { - "@microsoft/1ds-core-js": "4.1.2", - "@microsoft/applicationinsights-shims": "3.0.1", - "@microsoft/dynamicproto-js": "^2.0.3", - "@nevware21/ts-async": ">= 0.3.0 < 2.x", - "@nevware21/ts-utils": ">= 0.11.0 < 2.x" - } - }, - "@microsoft/applicationinsights-channel-js": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/@microsoft/applicationinsights-channel-js/-/applicationinsights-channel-js-3.1.2.tgz", - "integrity": "sha512-QyPxpOOhtohFzcl4tzfWp4seN6JaToF66DZ1qjsYkUmEyHAackWSsv9m7qvuaAcCB9WrUzW9y0mRXgGKsEJcAg==", - "requires": { - "@microsoft/applicationinsights-common": "3.1.2", - "@microsoft/applicationinsights-core-js": "3.1.2", - "@microsoft/applicationinsights-shims": "3.0.1", - "@microsoft/dynamicproto-js": "^2.0.3", - "@nevware21/ts-async": ">= 0.3.0 < 2.x", - "@nevware21/ts-utils": ">= 0.11.0 < 2.x" - } - }, - "@microsoft/applicationinsights-common": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/@microsoft/applicationinsights-common/-/applicationinsights-common-3.1.2.tgz", - "integrity": "sha512-ivu3s73xt6Owakepnx2mbrMCry1mVHrA/2TL4nKCRLad6O3IBK3MkruMoeb3hoWpECBhErFRVj+/b0Kh7dl/Lw==", - "requires": { - "@microsoft/applicationinsights-core-js": "3.1.2", - "@microsoft/applicationinsights-shims": "3.0.1", - "@microsoft/dynamicproto-js": "^2.0.3", - "@nevware21/ts-utils": ">= 0.11.0 < 2.x" - } - }, - "@microsoft/applicationinsights-core-js": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/@microsoft/applicationinsights-core-js/-/applicationinsights-core-js-3.1.2.tgz", - "integrity": "sha512-xsJAm52tV355S/MogTunV/m1wg6P6tFg9Yhi4AC2OE9p2aa0k/FYHzWmrCrsEAVimCd8n/iTXmMRSrQk5QpxiA==", - "requires": { - "@microsoft/applicationinsights-shims": "3.0.1", - "@microsoft/dynamicproto-js": "^2.0.3", - "@nevware21/ts-async": ">= 0.3.0 < 2.x", - "@nevware21/ts-utils": ">= 0.11.0 < 2.x" - } - }, - "@microsoft/applicationinsights-shims": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@microsoft/applicationinsights-shims/-/applicationinsights-shims-3.0.1.tgz", - "integrity": "sha512-DKwboF47H1nb33rSUfjqI6ryX29v+2QWcTrRvcQDA32AZr5Ilkr7whOOSsD1aBzwqX0RJEIP1Z81jfE3NBm/Lg==", - "requires": { - "@nevware21/ts-utils": ">= 0.9.4 < 2.x" - } - }, - "@microsoft/applicationinsights-web-basic": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/@microsoft/applicationinsights-web-basic/-/applicationinsights-web-basic-3.1.2.tgz", - "integrity": "sha512-NUnAk/ML9ClnmiQQRo3Fq2obzJVZAfGTgkQOwobZMvNhBVK5IPuv/ROEEAVbl02Go9AjV5uCZ+QoRhTfWrIumQ==", - "requires": { - "@microsoft/applicationinsights-channel-js": "3.1.2", - "@microsoft/applicationinsights-common": "3.1.2", - "@microsoft/applicationinsights-core-js": "3.1.2", - "@microsoft/applicationinsights-shims": "3.0.1", - "@microsoft/dynamicproto-js": "^2.0.3", - "@nevware21/ts-async": ">= 0.3.0 < 2.x", - "@nevware21/ts-utils": ">= 0.11.0 < 2.x" - } - }, - "@microsoft/dynamicproto-js": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@microsoft/dynamicproto-js/-/dynamicproto-js-2.0.3.tgz", - "integrity": "sha512-JTWTU80rMy3mdxOjjpaiDQsTLZ6YSGGqsjURsY6AUQtIj0udlF/jYmhdLZu8693ZIC0T1IwYnFa0+QeiMnziBA==", - "requires": { - "@nevware21/ts-utils": ">= 0.10.4 < 2.x" - } - }, - "@microsoft/microsoft-graph-client": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/@microsoft/microsoft-graph-client/-/microsoft-graph-client-3.0.7.tgz", - "integrity": "sha512-/AazAV/F+HK4LIywF9C+NYHcJo038zEnWkteilcxC1FM/uK/4NVGDKGrxx7nNq1ybspAroRKT4I1FHfxQzxkUw==", - "requires": { - "@babel/runtime": "^7.12.5", - "tslib": "^2.2.0" - } - }, - "@microsoft/vscode-azext-azureutils": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@microsoft/vscode-azext-azureutils/-/vscode-azext-azureutils-3.0.1.tgz", - "integrity": "sha512-zNNhCoh6vKoImPxsxUTIP+311TBeIW1GL/EVq5LBWYhnN1v8jmhtltIJuWkmOOq52DQGWRe99Lkj3Qzh1mGZcw==", - "requires": { - "@azure/arm-resources": "^5.0.0", - "@azure/arm-resources-profile-2020-09-01-hybrid": "^2.0.0", - "@azure/arm-resources-subscriptions": "^2.0.0", - "@azure/arm-storage": "^18.2.0", - "@azure/arm-storage-profile-2020-09-01-hybrid": "^2.0.0", - "@azure/core-client": "^1.6.0", - "@azure/core-rest-pipeline": "^1.9.0", - "@azure/logger": "^1.0.4", - "@microsoft/vscode-azext-utils": "^2.2.0", - "semver": "^7.3.7", - "uuid": "^9.0.0" - }, - "dependencies": { - "uuid": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", - "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==" - } - } - }, - "@microsoft/vscode-azext-utils": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/@microsoft/vscode-azext-utils/-/vscode-azext-utils-2.4.0.tgz", - "integrity": "sha512-xWZiB1md9zdKsljyaTftj2EK+xJGynzRoMGT0MoMARewJ+xRDlS/xKUlguUoAzWoMFtS4COuEPoY6KYBgICOog==", - "requires": { - "@microsoft/vscode-azureresources-api": "^2.0.4", - "@vscode/extension-telemetry": "^0.9.0", - "dayjs": "^1.11.2", - "escape-string-regexp": "^2.0.0", - "html-to-text": "^8.2.0", - "semver": "^7.3.7", - "uuid": "^9.0.0", - "vscode-tas-client": "^0.1.47", - "vscode-uri": "^3.0.6" - }, - "dependencies": { - "escape-string-regexp": { - "version": "2.0.0" - }, - "uuid": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", - "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==" - } - } - }, - "@microsoft/vscode-azureresources-api": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@microsoft/vscode-azureresources-api/-/vscode-azureresources-api-2.1.0.tgz", - "integrity": "sha512-dqjLyHl0OJgnjEtMtZEDvA9YovszWnE2k3ktEcHiTHWZ62luYrhOQhMzJjGArSFH3ANRCWgS6A1q4OTjZoBrKQ==", - "requires": {} - }, - "@nevware21/ts-async": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/@nevware21/ts-async/-/ts-async-0.5.0.tgz", - "integrity": "sha512-fJ2wSl5fd4UWoWbnXpPVKRg2Uw6u4+o9RsBHb35tiaOajVxJ97LrKAtrCGi6E19GpgfQbAWRFvz/iDXe3XCjWQ==", - "requires": { - "@nevware21/ts-utils": ">= 0.11.0 < 2.x" - } - }, - "@nevware21/ts-utils": { - "version": "0.11.1", - "resolved": "https://registry.npmjs.org/@nevware21/ts-utils/-/ts-utils-0.11.1.tgz", - "integrity": "sha512-1QZSZ39UzjC8MR0+LRO2l8ITFHYdCZeHfBG9p3XUCz0hQ22I0Pf/XE5EF+TPSJK3LLME3pUNx2MCQ4XEtOHv+g==" - }, - "@nodelib/fs.scandir": { - "version": "2.1.5", - "dev": true, - "requires": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" - } - }, - "@nodelib/fs.stat": { - "version": "2.0.5", - "dev": true - }, - "@nodelib/fs.walk": { - "version": "1.2.8", - "dev": true, - "requires": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" - } - }, - "@opentelemetry/api": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/api/-/api-1.7.0.tgz", - "integrity": "sha512-AdY5wvN0P2vXBi3b29hxZgSFvdhdxPB9+f0B6s//P9Q8nibRWeA3cHm8UmLpio9ABigkVHJ5NMPk+Mz8VCCyrw==" - }, - "@pkgjs/parseargs": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", - "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", - "dev": true, - "optional": true - }, - "@selderee/plugin-htmlparser2": { - "version": "0.6.0", - "requires": { - "domhandler": "^4.2.0", - "selderee": "^0.6.0" - } - }, - "@sinclair/typebox": { - "version": "0.27.8", - "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", - "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==", - "dev": true - }, - "@sinonjs/commons": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.0.tgz", - "integrity": "sha512-jXBtWAF4vmdNmZgD5FoKsVLv3rPgDnLgPbU84LIJ3otV44vJlDRokVng5v8NFJdCf/da9legHcKaRuZs4L7faA==", - "dev": true, - "requires": { - "type-detect": "4.0.8" - } - }, - "@sinonjs/fake-timers": { - "version": "11.2.2", - "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-11.2.2.tgz", - "integrity": "sha512-G2piCSxQ7oWOxwGSAyFHfPIsyeJGXYtc6mFbnFA+kRXkiEnTl8c/8jul2S329iFBnDI9HGoeWWAZvuvOkZccgw==", - "dev": true, - "requires": { - "@sinonjs/commons": "^3.0.0" - } - }, - "@sinonjs/samsam": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-8.0.0.tgz", - "integrity": "sha512-Bp8KUVlLp8ibJZrnvq2foVhP0IVX2CIprMJPK0vqGqgrDa0OHVKeZyBykqskkrdxV6yKBPmGasO8LVjAKR3Gew==", - "dev": true, - "requires": { - "@sinonjs/commons": "^2.0.0", - "lodash.get": "^4.4.2", - "type-detect": "^4.0.8" - }, - "dependencies": { - "@sinonjs/commons": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-2.0.0.tgz", - "integrity": "sha512-uLa0j859mMrg2slwQYdO/AkrOfmH+X6LTVmNTS9CqexuE2IvVORIkSpJLqePAbEnKJ77aMmCwr1NUZ57120Xcg==", - "dev": true, - "requires": { - "type-detect": "4.0.8" - } - } - } - }, - "@sinonjs/text-encoding": { - "version": "0.7.2", - "resolved": "https://registry.npmjs.org/@sinonjs/text-encoding/-/text-encoding-0.7.2.tgz", - "integrity": "sha512-sXXKG+uL9IrKqViTtao2Ws6dy0znu9sOaP1di/jKGW1M6VssO8vlpXCQcpZ+jisQ1tTFAC5Jo/EOzFbggBagFQ==", - "dev": true - }, - "@tootallnate/once": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz", - "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==", - "dev": true - }, - "@types/archiver": { - "version": "5.3.1", - "dev": true, - "requires": { - "@types/glob": "*" - } - }, - "@types/chai": { - "version": "4.3.14", - "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.3.14.tgz", - "integrity": "sha512-Wj71sXE4Q4AkGdG9Tvq1u/fquNz9EdG4LIJMwVVII7ashjD/8cf8fyIfJAjRr6YcsXnSE8cOGQPq1gqeR8z+3w==", - "dev": true - }, - "@types/decompress": { - "version": "4.2.6", - "resolved": "https://registry.npmjs.org/@types/decompress/-/decompress-4.2.6.tgz", - "integrity": "sha512-ULmsMkKxU7aIGbnxP4Rz28hLdRZ4q0cdy6kcb8dx+UgDGOn+id5fibvoeTnjuolhrRM7f7TOtGADeKEk60SSsQ==", - "dev": true, - "requires": { - "@types/node": "*" - } - }, - "@types/download": { - "version": "8.0.5", - "resolved": "https://registry.npmjs.org/@types/download/-/download-8.0.5.tgz", - "integrity": "sha512-Ad68goc/BsL3atP3OP/lWKAKhiC6FduN1mC5yg9lZuGYmUY7vyoWBcXgt8GE9OzVWRq5IBXwm4o/QiE+gipZAg==", - "dev": true, - "requires": { - "@types/decompress": "*", - "@types/got": "^9", - "@types/node": "*" - } - }, - "@types/eslint": { - "version": "8.56.5", - "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.56.5.tgz", - "integrity": "sha512-u5/YPJHo1tvkSF2CE0USEkxon82Z5DBy2xR+qfyYNszpX9qcs4sT6uq2kBbj4BXY1+DBGDPnrhMZV3pKWGNukw==", - "dev": true, - "requires": { - "@types/estree": "*", - "@types/json-schema": "*" - } - }, - "@types/eslint-scope": { - "version": "3.7.4", - "dev": true, - "requires": { - "@types/eslint": "*", - "@types/estree": "*" - } - }, - "@types/estree": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", - "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==", - "dev": true - }, - "@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==", - "dev": true, - "requires": { - "@types/minimatch": "^5.1.2", - "@types/node": "*" - } - }, - "@types/got": { - "version": "9.6.12", - "resolved": "https://registry.npmjs.org/@types/got/-/got-9.6.12.tgz", - "integrity": "sha512-X4pj/HGHbXVLqTpKjA2ahI4rV/nNBc9mGO2I/0CgAra+F2dKgMXnENv2SRpemScBzBAI4vMelIVYViQxlSE6xA==", - "dev": true, - "requires": { - "@types/node": "*", - "@types/tough-cookie": "*", - "form-data": "^2.5.0" - } - }, - "@types/istanbul-lib-coverage": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz", - "integrity": "sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==", - "dev": true - }, - "@types/istanbul-lib-report": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.3.tgz", - "integrity": "sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "*" - } - }, - "@types/istanbul-reports": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.4.tgz", - "integrity": "sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==", - "dev": true, - "requires": { - "@types/istanbul-lib-report": "*" - } - }, - "@types/js-yaml": { - "version": "4.0.9", - "resolved": "https://registry.npmjs.org/@types/js-yaml/-/js-yaml-4.0.9.tgz", - "integrity": "sha512-k4MGaQl5TGo/iipqb2UDG2UwjXziSWkh0uysQelTlJpX1qGlpUZYm8PnO4DxG1qBomtJUdYJ6qR6xdIah10JLg==", - "dev": true - }, - "@types/json-schema": { - "version": "7.0.15", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", - "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", - "dev": true - }, - "@types/minimatch": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-5.1.2.tgz", - "integrity": "sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA==", - "dev": true - }, - "@types/mocha": { - "version": "10.0.6", - "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-10.0.6.tgz", - "integrity": "sha512-dJvrYWxP/UcXm36Qn36fxhUKu8A/xMRXVT2cliFF1Z7UA9liG5Psj3ezNSZw+5puH2czDXRLcXQxf8JbJt0ejg==", - "dev": true - }, - "@types/node": { - "version": "20.12.7", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.12.7.tgz", - "integrity": "sha512-wq0cICSkRLVaf3UGLMGItu/PtdY7oaXaI/RVU+xliKVOtRna3PRY57ZDfztpDL0n11vfymMUnXv8QwYCO7L1wg==", - "requires": { - "undici-types": "~5.26.4" - } - }, - "@types/node-fetch": { - "version": "2.6.11", - "resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.6.11.tgz", - "integrity": "sha512-24xFj9R5+rfQJLRyM56qh+wnVSYhyXC2tkoBndtY0U+vubqNsYXGjufB2nn8Q6gt0LrARwL6UBtMCSVCwl4B1g==", - "requires": { - "@types/node": "*", - "form-data": "^4.0.0" - }, - "dependencies": { - "form-data": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", - "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", - "requires": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "mime-types": "^2.1.12" - } - } - } - }, - "@types/semver": { - "version": "7.5.8", - "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.8.tgz", - "integrity": "sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==", - "dev": true - }, - "@types/sinon": { - "version": "17.0.3", - "resolved": "https://registry.npmjs.org/@types/sinon/-/sinon-17.0.3.tgz", - "integrity": "sha512-j3uovdn8ewky9kRBG19bOwaZbexJu/XjtkHyjvUgt4xfPFz18dcORIMqnYh66Fx3Powhcr85NT5+er3+oViapw==", - "dev": true, - "requires": { - "@types/sinonjs__fake-timers": "*" - } - }, - "@types/sinonjs__fake-timers": { - "version": "8.1.5", - "resolved": "https://registry.npmjs.org/@types/sinonjs__fake-timers/-/sinonjs__fake-timers-8.1.5.tgz", - "integrity": "sha512-mQkU2jY8jJEF7YHjHvsQO8+3ughTL1mcnn96igfhONmR+fUPSKIkefQYpSe8bsly2Ep7oQbn/6VG5/9/0qcArQ==", - "dev": true - }, - "@types/tmp": { - "version": "0.2.6", - "resolved": "https://registry.npmjs.org/@types/tmp/-/tmp-0.2.6.tgz", - "integrity": "sha512-chhaNf2oKHlRkDGt+tiKE2Z5aJ6qalm7Z9rlLdBwmOiAAf09YQvvoLXjWK4HWPF1xU/fqvMgfNfpVoBscA/tKA==", - "dev": true - }, - "@types/tough-cookie": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-4.0.4.tgz", - "integrity": "sha512-95Sfz4nvMAb0Nl9DTxN3j64adfwfbBPEYq14VN7zT5J5O2M9V6iZMIIQU1U+pJyl9agHYHNCqhCXgyEtIRRa5A==", - "dev": true - }, - "@types/tunnel": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/@types/tunnel/-/tunnel-0.0.3.tgz", - "integrity": "sha512-sOUTGn6h1SfQ+gbgqC364jLFBw2lnFqkgF3q0WovEHRLMrVD1sd5aufqi/aJObLekJO+Aq5z646U4Oxy6shXMA==", - "requires": { - "@types/node": "*" - } - }, - "@types/vscode": { - "version": "1.88.0", - "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.88.0.tgz", - "integrity": "sha512-rWY+Bs6j/f1lvr8jqZTyp5arRMfovdxolcqGi+//+cPDOh8SBvzXH90e7BiSXct5HJ9HGW6jATchbRTpTJpEkw==", - "dev": true - }, - "@types/yargs": { - "version": "17.0.32", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.32.tgz", - "integrity": "sha512-xQ67Yc/laOG5uMfX/093MRlGGCIBzZMarVa+gfNKJxWAIgykYpVGkBdbqEzGDDfCrVUj6Hiff4mTZ5BA6TmAog==", - "dev": true, - "requires": { - "@types/yargs-parser": "*" - } - }, - "@types/yargs-parser": { - "version": "21.0.3", - "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.3.tgz", - "integrity": "sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==", - "dev": true - }, - "@typescript-eslint/eslint-plugin": { - "version": "7.7.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.7.1.tgz", - "integrity": "sha512-KwfdWXJBOviaBVhxO3p5TJiLpNuh2iyXyjmWN0f1nU87pwyvfS0EmjC6ukQVYVFJd/K1+0NWGPDXiyEyQorn0Q==", - "dev": true, - "requires": { - "@eslint-community/regexpp": "^4.10.0", - "@typescript-eslint/scope-manager": "7.7.1", - "@typescript-eslint/type-utils": "7.7.1", - "@typescript-eslint/utils": "7.7.1", - "@typescript-eslint/visitor-keys": "7.7.1", - "debug": "^4.3.4", - "graphemer": "^1.4.0", - "ignore": "^5.3.1", - "natural-compare": "^1.4.0", - "semver": "^7.6.0", - "ts-api-utils": "^1.3.0" - } - }, - "@typescript-eslint/parser": { - "version": "7.7.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.7.1.tgz", - "integrity": "sha512-vmPzBOOtz48F6JAGVS/kZYk4EkXao6iGrD838sp1w3NQQC0W8ry/q641KU4PrG7AKNAf56NOcR8GOpH8l9FPCw==", - "dev": true, - "requires": { - "@typescript-eslint/scope-manager": "7.7.1", - "@typescript-eslint/types": "7.7.1", - "@typescript-eslint/typescript-estree": "7.7.1", - "@typescript-eslint/visitor-keys": "7.7.1", - "debug": "^4.3.4" - } - }, - "@typescript-eslint/scope-manager": { - "version": "7.7.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.7.1.tgz", - "integrity": "sha512-PytBif2SF+9SpEUKynYn5g1RHFddJUcyynGpztX3l/ik7KmZEv19WCMhUBkHXPU9es/VWGD3/zg3wg90+Dh2rA==", - "dev": true, - "requires": { - "@typescript-eslint/types": "7.7.1", - "@typescript-eslint/visitor-keys": "7.7.1" - } - }, - "@typescript-eslint/type-utils": { - "version": "7.7.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.7.1.tgz", - "integrity": "sha512-ZksJLW3WF7o75zaBPScdW1Gbkwhd/lyeXGf1kQCxJaOeITscoSl0MjynVvCzuV5boUz/3fOI06Lz8La55mu29Q==", - "dev": true, - "requires": { - "@typescript-eslint/typescript-estree": "7.7.1", - "@typescript-eslint/utils": "7.7.1", - "debug": "^4.3.4", - "ts-api-utils": "^1.3.0" - } - }, - "@typescript-eslint/types": { - "version": "7.7.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.7.1.tgz", - "integrity": "sha512-AmPmnGW1ZLTpWa+/2omPrPfR7BcbUU4oha5VIbSbS1a1Tv966bklvLNXxp3mrbc+P2j4MNOTfDffNsk4o0c6/w==", - "dev": true - }, - "@typescript-eslint/typescript-estree": { - "version": "7.7.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.7.1.tgz", - "integrity": "sha512-CXe0JHCXru8Fa36dteXqmH2YxngKJjkQLjxzoj6LYwzZ7qZvgsLSc+eqItCrqIop8Vl2UKoAi0StVWu97FQZIQ==", - "dev": true, - "requires": { - "@typescript-eslint/types": "7.7.1", - "@typescript-eslint/visitor-keys": "7.7.1", - "debug": "^4.3.4", - "globby": "^11.1.0", - "is-glob": "^4.0.3", - "minimatch": "^9.0.4", - "semver": "^7.6.0", - "ts-api-utils": "^1.3.0" - }, - "dependencies": { - "brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, - "requires": { - "balanced-match": "^1.0.0" - } - }, - "minimatch": { - "version": "9.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz", - "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==", - "dev": true, - "requires": { - "brace-expansion": "^2.0.1" - } - } - } - }, - "@typescript-eslint/utils": { - "version": "7.7.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.7.1.tgz", - "integrity": "sha512-QUvBxPEaBXf41ZBbaidKICgVL8Hin0p6prQDu6bbetWo39BKbWJxRsErOzMNT1rXvTll+J7ChrbmMCXM9rsvOQ==", - "dev": true, - "requires": { - "@eslint-community/eslint-utils": "^4.4.0", - "@types/json-schema": "^7.0.15", - "@types/semver": "^7.5.8", - "@typescript-eslint/scope-manager": "7.7.1", - "@typescript-eslint/types": "7.7.1", - "@typescript-eslint/typescript-estree": "7.7.1", - "semver": "^7.6.0" - } - }, - "@typescript-eslint/visitor-keys": { - "version": "7.7.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.7.1.tgz", - "integrity": "sha512-gBL3Eq25uADw1LQ9kVpf3hRM+DWzs0uZknHYK3hq4jcTPqVCClHGDnB6UUUV2SFeBeA4KWHWbbLqmbGcZ4FYbw==", - "dev": true, - "requires": { - "@typescript-eslint/types": "7.7.1", - "eslint-visitor-keys": "^3.4.3" - } - }, - "@ungap/structured-clone": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", - "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==", - "dev": true - }, - "@vscode/extension-telemetry": { - "version": "0.9.6", - "resolved": "https://registry.npmjs.org/@vscode/extension-telemetry/-/extension-telemetry-0.9.6.tgz", - "integrity": "sha512-qWK2GNw+b69QRYpjuNM9g3JKToMICoNIdc0rQMtvb4gIG9vKKCZCVCz+ZOx6XM/YlfWAyuPiyxcjIY0xyF+Djg==", - "requires": { - "@microsoft/1ds-core-js": "^4.1.2", - "@microsoft/1ds-post-js": "^4.1.2", - "@microsoft/applicationinsights-web-basic": "^3.1.2" - } - }, - "@vscode/test-electron": { - "version": "2.3.9", - "resolved": "https://registry.npmjs.org/@vscode/test-electron/-/test-electron-2.3.9.tgz", - "integrity": "sha512-z3eiChaCQXMqBnk2aHHSEkobmC2VRalFQN0ApOAtydL172zXGxTwGrRtviT5HnUB+Q+G3vtEYFtuQkYqBzYgMA==", - "dev": true, - "requires": { - "http-proxy-agent": "^4.0.1", - "https-proxy-agent": "^5.0.0", - "jszip": "^3.10.1", - "semver": "^7.5.2" - } - }, - "@vscode/vsce": { - "version": "2.25.0", - "resolved": "https://registry.npmjs.org/@vscode/vsce/-/vsce-2.25.0.tgz", - "integrity": "sha512-VXMCGUaP6wKBadA7vFQdsksxkBAMoh4ecZgXBwauZMASAgnwYesHyLnqIyWYeRwjy2uEpitHvz/1w5ENnR30pg==", - "dev": true, - "requires": { - "azure-devops-node-api": "^12.5.0", - "chalk": "^2.4.2", - "cheerio": "^1.0.0-rc.9", - "cockatiel": "^3.1.2", - "commander": "^6.2.1", - "form-data": "^4.0.0", - "glob": "^7.0.6", - "hosted-git-info": "^4.0.2", - "jsonc-parser": "^3.2.0", - "keytar": "^7.7.0", - "leven": "^3.1.0", - "markdown-it": "^12.3.2", - "mime": "^1.3.4", - "minimatch": "^3.0.3", - "parse-semver": "^1.1.1", - "read": "^1.0.7", - "semver": "^7.5.2", - "tmp": "^0.2.1", - "typed-rest-client": "^1.8.4", - "url-join": "^4.0.1", - "xml2js": "^0.5.0", - "yauzl": "^2.3.1", - "yazl": "^2.2.2" - }, - "dependencies": { - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "requires": { - "color-convert": "^1.9.0" - } - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "requires": { - "color-name": "1.1.3" - } - }, - "color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "dev": true - }, - "commander": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-6.2.1.tgz", - "integrity": "sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA==", - "dev": true - }, - "form-data": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", - "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", - "dev": true, - "requires": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "mime-types": "^2.1.12" - } - }, - "glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "dev": 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" - } - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "dev": true - }, - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "@webassemblyjs/ast": { - "version": "1.12.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.12.1.tgz", - "integrity": "sha512-EKfMUOPRRUTy5UII4qJDGPpqfwjOmZ5jeGFwid9mnoqIFK+e0vqoi1qH56JpmZSzEL53jKnNzScdmftJyG5xWg==", - "dev": true, - "requires": { - "@webassemblyjs/helper-numbers": "1.11.6", - "@webassemblyjs/helper-wasm-bytecode": "1.11.6" - } - }, - "@webassemblyjs/floating-point-hex-parser": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.6.tgz", - "integrity": "sha512-ejAj9hfRJ2XMsNHk/v6Fu2dGS+i4UaXBXGemOfQ/JfQ6mdQg/WXtwleQRLLS4OvfDhv8rYnVwH27YJLMyYsxhw==", - "dev": true - }, - "@webassemblyjs/helper-api-error": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.6.tgz", - "integrity": "sha512-o0YkoP4pVu4rN8aTJgAyj9hC2Sv5UlkzCHhxqWj8butaLvnpdc2jOwh4ewE6CX0txSfLn/UYaV/pheS2Txg//Q==", - "dev": true - }, - "@webassemblyjs/helper-buffer": { - "version": "1.12.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.12.1.tgz", - "integrity": "sha512-nzJwQw99DNDKr9BVCOZcLuJJUlqkJh+kVzVl6Fmq/tI5ZtEyWT1KZMyOXltXLZJmDtvLCDgwsyrkohEtopTXCw==", - "dev": true - }, - "@webassemblyjs/helper-numbers": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.6.tgz", - "integrity": "sha512-vUIhZ8LZoIWHBohiEObxVm6hwP034jwmc9kuq5GdHZH0wiLVLIPcMCdpJzG4C11cHoQ25TFIQj9kaVADVX7N3g==", - "dev": true, - "requires": { - "@webassemblyjs/floating-point-hex-parser": "1.11.6", - "@webassemblyjs/helper-api-error": "1.11.6", - "@xtuc/long": "4.2.2" - } - }, - "@webassemblyjs/helper-wasm-bytecode": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.6.tgz", - "integrity": "sha512-sFFHKwcmBprO9e7Icf0+gddyWYDViL8bpPjJJl0WHxCdETktXdmtWLGVzoHbqUcY4Be1LkNfwTmXOJUFZYSJdA==", - "dev": true - }, - "@webassemblyjs/helper-wasm-section": { - "version": "1.12.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.12.1.tgz", - "integrity": "sha512-Jif4vfB6FJlUlSbgEMHUyk1j234GTNG9dBJ4XJdOySoj518Xj0oGsNi59cUQF4RRMS9ouBUxDDdyBVfPTypa5g==", - "dev": true, - "requires": { - "@webassemblyjs/ast": "1.12.1", - "@webassemblyjs/helper-buffer": "1.12.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.6", - "@webassemblyjs/wasm-gen": "1.12.1" - } - }, - "@webassemblyjs/ieee754": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.6.tgz", - "integrity": "sha512-LM4p2csPNvbij6U1f19v6WR56QZ8JcHg3QIJTlSwzFcmx6WSORicYj6I63f9yU1kEUtrpG+kjkiIAkevHpDXrg==", - "dev": true, - "requires": { - "@xtuc/ieee754": "^1.2.0" - } - }, - "@webassemblyjs/leb128": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.6.tgz", - "integrity": "sha512-m7a0FhE67DQXgouf1tbN5XQcdWoNgaAuoULHIfGFIEVKA6tu/edls6XnIlkmS6FrXAquJRPni3ZZKjw6FSPjPQ==", - "dev": true, - "requires": { - "@xtuc/long": "4.2.2" - } - }, - "@webassemblyjs/utf8": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.6.tgz", - "integrity": "sha512-vtXf2wTQ3+up9Zsg8sa2yWiQpzSsMyXj0qViVP6xKGCUT8p8YJ6HqI7l5eCnWx1T/FYdsv07HQs2wTFbbof/RA==", - "dev": true - }, - "@webassemblyjs/wasm-edit": { - "version": "1.12.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.12.1.tgz", - "integrity": "sha512-1DuwbVvADvS5mGnXbE+c9NfA8QRcZ6iKquqjjmR10k6o+zzsRVesil54DKexiowcFCPdr/Q0qaMgB01+SQ1u6g==", - "dev": true, - "requires": { - "@webassemblyjs/ast": "1.12.1", - "@webassemblyjs/helper-buffer": "1.12.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.6", - "@webassemblyjs/helper-wasm-section": "1.12.1", - "@webassemblyjs/wasm-gen": "1.12.1", - "@webassemblyjs/wasm-opt": "1.12.1", - "@webassemblyjs/wasm-parser": "1.12.1", - "@webassemblyjs/wast-printer": "1.12.1" - } - }, - "@webassemblyjs/wasm-gen": { - "version": "1.12.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.12.1.tgz", - "integrity": "sha512-TDq4Ojh9fcohAw6OIMXqiIcTq5KUXTGRkVxbSo1hQnSy6lAM5GSdfwWeSxpAo0YzgsgF182E/U0mDNhuA0tW7w==", - "dev": true, - "requires": { - "@webassemblyjs/ast": "1.12.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.6", - "@webassemblyjs/ieee754": "1.11.6", - "@webassemblyjs/leb128": "1.11.6", - "@webassemblyjs/utf8": "1.11.6" - } - }, - "@webassemblyjs/wasm-opt": { - "version": "1.12.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.12.1.tgz", - "integrity": "sha512-Jg99j/2gG2iaz3hijw857AVYekZe2SAskcqlWIZXjji5WStnOpVoat3gQfT/Q5tb2djnCjBtMocY/Su1GfxPBg==", - "dev": true, - "requires": { - "@webassemblyjs/ast": "1.12.1", - "@webassemblyjs/helper-buffer": "1.12.1", - "@webassemblyjs/wasm-gen": "1.12.1", - "@webassemblyjs/wasm-parser": "1.12.1" - } - }, - "@webassemblyjs/wasm-parser": { - "version": "1.12.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.12.1.tgz", - "integrity": "sha512-xikIi7c2FHXysxXe3COrVUPSheuBtpcfhbpFj4gmu7KRLYOzANztwUU0IbsqvMqzuNK2+glRGWCEqZo1WCLyAQ==", - "dev": true, - "requires": { - "@webassemblyjs/ast": "1.12.1", - "@webassemblyjs/helper-api-error": "1.11.6", - "@webassemblyjs/helper-wasm-bytecode": "1.11.6", - "@webassemblyjs/ieee754": "1.11.6", - "@webassemblyjs/leb128": "1.11.6", - "@webassemblyjs/utf8": "1.11.6" - } - }, - "@webassemblyjs/wast-printer": { - "version": "1.12.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.12.1.tgz", - "integrity": "sha512-+X4WAlOisVWQMikjbcvY2e0rwPsKQ9F688lksZhBcPycBBuii3O7m8FACbDMWDojpAqvjIncrG8J0XHKyQfVeA==", - "dev": true, - "requires": { - "@webassemblyjs/ast": "1.12.1", - "@xtuc/long": "4.2.2" - } - }, - "@webpack-cli/configtest": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-2.1.1.tgz", - "integrity": "sha512-wy0mglZpDSiSS0XHrVR+BAdId2+yxPSoJW8fsna3ZpYSlufjvxnP4YbKTCBZnNIcGN4r6ZPXV55X4mYExOfLmw==", - "dev": true, - "requires": {} - }, - "@webpack-cli/info": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@webpack-cli/info/-/info-2.0.2.tgz", - "integrity": "sha512-zLHQdI/Qs1UyT5UBdWNqsARasIA+AaF8t+4u2aS2nEpBQh2mWIVb8qAklq0eUENnC5mOItrIB4LiS9xMtph18A==", - "dev": true, - "requires": {} - }, - "@webpack-cli/serve": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-2.0.5.tgz", - "integrity": "sha512-lqaoKnRYBdo1UgDX8uF24AfGMifWK19TxPmM5FHc2vAGxrJ/qtyUyFBWoY1tISZdelsQ5fBcOusifo5o5wSJxQ==", - "dev": true, - "requires": {} - }, - "@xtuc/ieee754": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", - "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==", - "dev": true - }, - "@xtuc/long": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", - "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", - "dev": true - }, - "acorn": { - "version": "8.11.2", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.2.tgz", - "integrity": "sha512-nc0Axzp/0FILLEVsm4fNwLCwMttvhEI263QtVPQcbpfZZ3ts0hLsZGOpE6czNlid7CJ9MlyH8reXkpsf3YUY4w==", - "dev": true - }, - "acorn-import-assertions": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.9.0.tgz", - "integrity": "sha512-cmMwop9x+8KFhxvKrKfPYmN6/pKTYYHBqLa0DfvVZcKMJWNyWLnaqND7dx/qn66R7ewM1UX5XMaDVP5wlVTaVA==", - "dev": true, - "requires": {} - }, - "acorn-jsx": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", - "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", - "dev": true, - "requires": {} - }, - "agent-base": { - "version": "6.0.2", - "requires": { - "debug": "4" - } - }, - "aggregate-error": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", - "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", - "dev": true, - "requires": { - "clean-stack": "^2.0.0", - "indent-string": "^4.0.0" - } - }, - "ajv": { - "version": "6.12.6", - "dev": true, - "requires": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - } - }, - "ajv-formats": { - "version": "2.1.1", - "dev": true, - "requires": { - "ajv": "^8.0.0" - }, - "dependencies": { - "ajv": { - "version": "8.11.0", - "dev": true, - "requires": { - "fast-deep-equal": "^3.1.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" - } - }, - "json-schema-traverse": { - "version": "1.0.0", - "dev": true - } - } - }, - "ajv-keywords": { - "version": "3.5.2", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", - "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", - "dev": true, - "requires": {} - }, - "ansi-colors": { - "version": "4.1.1", - "dev": true - }, - "ansi-regex": { - "version": "5.0.1", - "dev": true - }, - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "anymatch": { - "version": "3.1.2", - "dev": true, - "requires": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - } - }, - "archiver": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/archiver/-/archiver-5.3.2.tgz", - "integrity": "sha512-+25nxyyznAXF7Nef3y0EbBeqmGZgeN/BxHX29Rs39djAfaFalmQ89SE6CWyDCHzGL0yt/ycBtNOmGTW0FyGWNw==", - "dev": true, - "requires": { - "archiver-utils": "^2.1.0", - "async": "^3.2.4", - "buffer-crc32": "^0.2.1", - "readable-stream": "^3.6.0", - "readdir-glob": "^1.1.2", - "tar-stream": "^2.2.0", - "zip-stream": "^4.1.0" - } - }, - "archiver-utils": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/archiver-utils/-/archiver-utils-2.1.0.tgz", - "integrity": "sha512-bEL/yUb/fNNiNTuUz979Z0Yg5L+LzLxGJz8x79lYmR54fmTIb6ob/hNQgkQnIUDWIFjZVQwl9Xs356I6BAMHfw==", - "dev": true, - "requires": { - "glob": "^7.1.4", - "graceful-fs": "^4.2.0", - "lazystream": "^1.0.0", - "lodash.defaults": "^4.2.0", - "lodash.difference": "^4.5.0", - "lodash.flatten": "^4.4.0", - "lodash.isplainobject": "^4.0.6", - "lodash.union": "^4.6.0", - "normalize-path": "^3.0.0", - "readable-stream": "^2.0.0" - }, - "dependencies": { - "glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "dev": 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" - } - }, - "readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", - "dev": true, - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dev": true, - "requires": { - "safe-buffer": "~5.1.0" - } - } - } - }, - "argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" - }, - "array-union": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", - "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", - "dev": true - }, - "assertion-error": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz", - "integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==", - "dev": true - }, - "async": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/async/-/async-3.2.4.tgz", - "integrity": "sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ==", - "dev": true - }, - "asynckit": { - "version": "0.4.0" - }, - "axios": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.6.2.tgz", - "integrity": "sha512-7i24Ri4pmDRfJTR7LDBhsOTtcm+9kjX5WiY1X3wIisx6G9So3pfMkEiU7emUBe46oceVImccTEM3k6C5dbVW8A==", - "requires": { - "follow-redirects": "^1.15.0", - "form-data": "^4.0.0", - "proxy-from-env": "^1.1.0" - }, - "dependencies": { - "form-data": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", - "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", - "requires": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "mime-types": "^2.1.12" - } - } - } - }, - "azure-devops-node-api": { - "version": "12.5.0", - "resolved": "https://registry.npmjs.org/azure-devops-node-api/-/azure-devops-node-api-12.5.0.tgz", - "integrity": "sha512-R5eFskGvOm3U/GzeAuxRkUsAl0hrAwGgWn6zAd2KrZmrEhWZVqLew4OOupbQlXUuojUzpGtq62SmdhJ06N88og==", - "dev": true, - "requires": { - "tunnel": "0.0.6", - "typed-rest-client": "^1.8.4" - } - }, - "balanced-match": { - "version": "1.0.0", - "dev": true - }, - "base64-js": { - "version": "1.5.1" - }, - "binary-extensions": { - "version": "2.2.0", - "dev": true - }, - "bl": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", - "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", - "dev": true, - "requires": { - "buffer": "^5.5.0", - "inherits": "^2.0.4", - "readable-stream": "^3.4.0" - } - }, - "boolbase": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", - "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==", - "dev": true - }, - "brace-expansion": { - "version": "1.1.11", - "dev": true, - "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "braces": { - "version": "3.0.2", - "dev": true, - "requires": { - "fill-range": "^7.0.1" - } - }, - "browser-stdout": { - "version": "1.3.1", - "dev": true - }, - "browserslist": { - "version": "4.22.3", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.22.3.tgz", - "integrity": "sha512-UAp55yfwNv0klWNapjs/ktHoguxuQNGnOzxYmfnXIS+8AsRDZkSDxg7R1AX3GKzn078SBI5dzwzj/Yx0Or0e3A==", - "dev": true, - "requires": { - "caniuse-lite": "^1.0.30001580", - "electron-to-chromium": "^1.4.648", - "node-releases": "^2.0.14", - "update-browserslist-db": "^1.0.13" - } - }, - "buffer": { - "version": "5.7.1", - "requires": { - "base64-js": "^1.3.1", - "ieee754": "^1.1.13" - } - }, - "buffer-alloc": { - "version": "1.2.0", - "requires": { - "buffer-alloc-unsafe": "^1.1.0", - "buffer-fill": "^1.0.0" - } - }, - "buffer-alloc-unsafe": { - "version": "1.1.0" - }, - "buffer-crc32": { - "version": "0.2.13" - }, - "buffer-equal-constant-time": { - "version": "1.0.1" - }, - "buffer-fill": { - "version": "1.0.0" - }, - "buffer-from": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", - "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", - "dev": true - }, - "call-bind": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", - "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", - "dev": true, - "requires": { - "es-define-property": "^1.0.0", - "es-errors": "^1.3.0", - "function-bind": "^1.1.2", - "get-intrinsic": "^1.2.4", - "set-function-length": "^1.2.1" - } - }, - "callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "dev": true - }, - "camelcase": { - "version": "6.2.1", - "dev": true - }, - "caniuse-lite": { - "version": "1.0.30001581", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001581.tgz", - "integrity": "sha512-whlTkwhqV2tUmP3oYhtNfaWGYHDdS3JYFQBKXxcUR9qqPWsRhFHhoISO2Xnl/g0xyKzht9mI1LZpiNWfMzHixQ==", - "dev": true - }, - "chai": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/chai/-/chai-5.1.0.tgz", - "integrity": "sha512-kDZ7MZyM6Q1DhR9jy7dalKohXQ2yrlXkk59CR52aRKxJrobmlBNqnFQxX9xOX8w+4mz8SYlKJa/7D7ddltFXCw==", - "dev": true, - "requires": { - "assertion-error": "^2.0.1", - "check-error": "^2.0.0", - "deep-eql": "^5.0.1", - "loupe": "^3.1.0", - "pathval": "^2.0.0" - } - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "check-error": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/check-error/-/check-error-2.0.0.tgz", - "integrity": "sha512-tjLAOBHKVxtPoHe/SA7kNOMvhCRdCJ3vETdeY0RuAc9popf+hyaSV6ZEg9hr4cpWF7jmo/JSWEnLDrnijS9Tog==", - "dev": true - }, - "cheerio": { - "version": "1.0.0-rc.12", - "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0-rc.12.tgz", - "integrity": "sha512-VqR8m68vM46BNnuZ5NtnGBKIE/DfN0cRIzg9n40EIq9NOv90ayxLBXA8fXC5gquFRGJSTRqBq25Jt2ECLR431Q==", - "dev": true, - "requires": { - "cheerio-select": "^2.1.0", - "dom-serializer": "^2.0.0", - "domhandler": "^5.0.3", - "domutils": "^3.0.1", - "htmlparser2": "^8.0.1", - "parse5": "^7.0.0", - "parse5-htmlparser2-tree-adapter": "^7.0.0" - }, - "dependencies": { - "dom-serializer": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", - "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", - "dev": true, - "requires": { - "domelementtype": "^2.3.0", - "domhandler": "^5.0.2", - "entities": "^4.2.0" - } - }, - "domhandler": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", - "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", - "dev": true, - "requires": { - "domelementtype": "^2.3.0" - } - }, - "domutils": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.1.0.tgz", - "integrity": "sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==", - "dev": true, - "requires": { - "dom-serializer": "^2.0.0", - "domelementtype": "^2.3.0", - "domhandler": "^5.0.3" - } - }, - "entities": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", - "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", - "dev": true - }, - "htmlparser2": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-8.0.2.tgz", - "integrity": "sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==", - "dev": true, - "requires": { - "domelementtype": "^2.3.0", - "domhandler": "^5.0.3", - "domutils": "^3.0.1", - "entities": "^4.4.0" - } - } - } - }, - "cheerio-select": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/cheerio-select/-/cheerio-select-2.1.0.tgz", - "integrity": "sha512-9v9kG0LvzrlcungtnJtpGNxY+fzECQKhK4EGJX2vByejiMX84MFNQw4UxPJl3bFbTMw+Dfs37XaIkCwTZfLh4g==", - "dev": true, - "requires": { - "boolbase": "^1.0.0", - "css-select": "^5.1.0", - "css-what": "^6.1.0", - "domelementtype": "^2.3.0", - "domhandler": "^5.0.3", - "domutils": "^3.0.1" - }, - "dependencies": { - "dom-serializer": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", - "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", - "dev": true, - "requires": { - "domelementtype": "^2.3.0", - "domhandler": "^5.0.2", - "entities": "^4.2.0" - } - }, - "domhandler": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", - "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", - "dev": true, - "requires": { - "domelementtype": "^2.3.0" - } - }, - "domutils": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.1.0.tgz", - "integrity": "sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==", - "dev": true, - "requires": { - "dom-serializer": "^2.0.0", - "domelementtype": "^2.3.0", - "domhandler": "^5.0.3" - } - }, - "entities": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", - "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", - "dev": true - } - } - }, - "chokidar": { - "version": "3.5.3", - "dev": true, - "requires": { - "anymatch": "~3.1.2", - "braces": "~3.0.2", - "fsevents": "~2.3.2", - "glob-parent": "~5.1.2", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.6.0" - } - }, - "chownr": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", - "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==", - "dev": true, - "optional": true - }, - "chrome-trace-event": { - "version": "1.0.2", - "dev": true, - "requires": { - "tslib": "^1.9.0" - }, - "dependencies": { - "tslib": { - "version": "1.14.1", - "dev": true - } - } - }, - "ci-info": { - "version": "3.9.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz", - "integrity": "sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==", - "dev": true - }, - "clean-stack": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", - "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", - "dev": true - }, - "cliui": { - "version": "7.0.4", - "dev": true, - "requires": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^7.0.0" - } - }, - "clone-deep": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", - "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", - "dev": true, - "requires": { - "is-plain-object": "^2.0.4", - "kind-of": "^6.0.2", - "shallow-clone": "^3.0.0" - } - }, - "cockatiel": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/cockatiel/-/cockatiel-3.1.2.tgz", - "integrity": "sha512-5yARKww0dWyWg2/3xZeXgoxjHLwpVqFptj9Zy7qioJ6+/L0ARM184sgMUrQDjxw7ePJWlGhV998mKhzrxT0/Kg==", - "dev": true - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "colorette": { - "version": "2.0.20", - "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", - "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", - "dev": true - }, - "combined-stream": { - "version": "1.0.8", - "requires": { - "delayed-stream": "~1.0.0" - } - }, - "commander": { - "version": "2.20.3" - }, - "compress-commons": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/compress-commons/-/compress-commons-4.1.2.tgz", - "integrity": "sha512-D3uMHtGc/fcO1Gt1/L7i1e33VOvD4A9hfQLP+6ewd+BvG/gQ84Yh4oftEhAdjSMgBgwGL+jsppT7JYNpo6MHHg==", - "dev": true, - "requires": { - "buffer-crc32": "^0.2.13", - "crc32-stream": "^4.0.2", - "normalize-path": "^3.0.0", - "readable-stream": "^3.6.0" - } - }, - "concat-map": { - "version": "0.0.1", - "dev": true - }, - "core-util-is": { - "version": "1.0.2" - }, - "crc-32": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/crc-32/-/crc-32-1.2.2.tgz", - "integrity": "sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==", - "dev": true - }, - "crc32-stream": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/crc32-stream/-/crc32-stream-4.0.3.tgz", - "integrity": "sha512-NT7w2JVU7DFroFdYkeq8cywxrgjPHWkdX1wjpRQXPX5Asews3tA+Ght6lddQO5Mkumffp3X7GEqku3epj2toIw==", - "dev": true, - "requires": { - "crc-32": "^1.2.0", - "readable-stream": "^3.4.0" - } - }, - "cross-fetch": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-4.0.0.tgz", - "integrity": "sha512-e4a5N8lVvuLgAWgnCrLr2PP0YyDOTHa9H/Rj54dirp61qXnNq46m82bRhNqIA5VccJtWBvPTFRV3TtvHUKPB1g==", - "requires": { - "node-fetch": "^2.6.12" - }, - "dependencies": { - "node-fetch": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", - "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", - "requires": { - "whatwg-url": "^5.0.0" - } - } - } - }, - "cross-spawn": { - "version": "7.0.3", - "dev": true, - "requires": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - } - }, - "css-select": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.1.0.tgz", - "integrity": "sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==", - "dev": true, - "requires": { - "boolbase": "^1.0.0", - "css-what": "^6.1.0", - "domhandler": "^5.0.2", - "domutils": "^3.0.1", - "nth-check": "^2.0.1" - }, - "dependencies": { - "dom-serializer": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", - "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", - "dev": true, - "requires": { - "domelementtype": "^2.3.0", - "domhandler": "^5.0.2", - "entities": "^4.2.0" - } - }, - "domhandler": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", - "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", - "dev": true, - "requires": { - "domelementtype": "^2.3.0" - } - }, - "domutils": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.1.0.tgz", - "integrity": "sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==", - "dev": true, - "requires": { - "dom-serializer": "^2.0.0", - "domelementtype": "^2.3.0", - "domhandler": "^5.0.3" - } - }, - "entities": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", - "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", - "dev": true - } - } - }, - "css-what": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz", - "integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==", - "dev": true - }, - "dayjs": { - "version": "1.11.3" - }, - "debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "requires": { - "ms": "2.1.2" - } - }, - "decamelize": { - "version": "4.0.0", - "dev": true - }, - "decompress": { - "version": "4.2.1", - "requires": { - "decompress-tar": "^4.0.0", - "decompress-tarbz2": "^4.0.0", - "decompress-targz": "^4.0.0", - "decompress-unzip": "^4.0.1", - "graceful-fs": "^4.1.10", - "make-dir": "^1.0.0", - "pify": "^2.3.0", - "strip-dirs": "^2.0.0" - }, - "dependencies": { - "make-dir": { - "version": "1.3.0", - "requires": { - "pify": "^3.0.0" - }, - "dependencies": { - "pify": { - "version": "3.0.0" - } - } - } - } - }, - "decompress-response": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", - "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", - "dev": true, - "optional": true, - "requires": { - "mimic-response": "^3.1.0" - } - }, - "decompress-tar": { - "version": "4.1.1", - "requires": { - "file-type": "^5.2.0", - "is-stream": "^1.1.0", - "tar-stream": "^1.5.2" - }, - "dependencies": { - "bl": { - "version": "1.2.3", - "requires": { - "readable-stream": "^2.3.5", - "safe-buffer": "^5.1.1" - } - }, - "file-type": { - "version": "5.2.0" - }, - "is-stream": { - "version": "1.1.0" - }, - "readable-stream": { - "version": "2.3.7", - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "string_decoder": { - "version": "1.1.1", - "requires": { - "safe-buffer": "~5.1.0" - } - }, - "tar-stream": { - "version": "1.6.2", - "requires": { - "bl": "^1.0.0", - "buffer-alloc": "^1.2.0", - "end-of-stream": "^1.0.0", - "fs-constants": "^1.0.0", - "readable-stream": "^2.3.0", - "to-buffer": "^1.1.1", - "xtend": "^4.0.0" - } - } - } - }, - "decompress-tarbz2": { - "version": "4.1.1", - "requires": { - "decompress-tar": "^4.1.0", - "file-type": "^6.1.0", - "is-stream": "^1.1.0", - "seek-bzip": "^1.0.5", - "unbzip2-stream": "^1.0.9" - }, - "dependencies": { - "file-type": { - "version": "6.2.0" - }, - "is-stream": { - "version": "1.1.0" - } - } - }, - "decompress-targz": { - "version": "4.1.1", - "requires": { - "decompress-tar": "^4.1.1", - "file-type": "^5.2.0", - "is-stream": "^1.1.0" - }, - "dependencies": { - "file-type": { - "version": "5.2.0" - }, - "is-stream": { - "version": "1.1.0" - } - } - }, - "decompress-unzip": { - "version": "4.0.1", - "requires": { - "file-type": "^3.8.0", - "get-stream": "^2.2.0", - "pify": "^2.3.0", - "yauzl": "^2.4.2" - }, - "dependencies": { - "file-type": { - "version": "3.9.0" - }, - "get-stream": { - "version": "2.3.1", - "requires": { - "object-assign": "^4.0.1", - "pinkie-promise": "^2.0.0" - } - } - } - }, - "deep-eql": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-5.0.1.tgz", - "integrity": "sha512-nwQCf6ne2gez3o1MxWifqkciwt0zhl0LO1/UwVu4uMBuPmflWM4oQ70XMqHqnBJA+nhzncaqL9HVL6KkHJ28lw==", - "dev": true - }, - "deep-extend": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", - "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", - "dev": true, - "optional": true - }, - "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==", - "dev": true - }, - "deepmerge": { - "version": "4.2.2" - }, - "define-data-property": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", - "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", - "dev": true, - "requires": { - "es-define-property": "^1.0.0", - "es-errors": "^1.3.0", - "gopd": "^1.0.1" - } - }, - "define-lazy-prop": { - "version": "2.0.0" - }, - "del": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/del/-/del-6.1.1.tgz", - "integrity": "sha512-ua8BhapfP0JUJKC/zV9yHHDW/rDoDxP4Zhn3AkA6/xT6gY7jYXJiaeyBZznYVujhZZET+UgcbZiQ7sN3WqcImg==", - "dev": true, - "requires": { - "globby": "^11.0.1", - "graceful-fs": "^4.2.4", - "is-glob": "^4.0.1", - "is-path-cwd": "^2.2.0", - "is-path-inside": "^3.0.2", - "p-map": "^4.0.0", - "rimraf": "^3.0.2", - "slash": "^3.0.0" - } - }, - "delayed-stream": { - "version": "1.0.0" - }, - "detect-libc": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.3.tgz", - "integrity": "sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw==", - "dev": true, - "optional": true - }, - "diff": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-5.1.0.tgz", - "integrity": "sha512-D+mk+qE8VC/PAUrlAU34N+VfXev0ghe5ywmpqrawphmVZc1bEfn56uo9qpyGp1p4xpzOHkSW4ztBd6L7Xx4ACw==", - "dev": true - }, - "dir-glob": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", - "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", - "dev": true, - "requires": { - "path-type": "^4.0.0" - } - }, - "discontinuous-range": { - "version": "1.0.0" - }, - "doctrine": { - "version": "3.0.0", - "dev": true, - "requires": { - "esutils": "^2.0.2" - } - }, - "dom-serializer": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz", - "integrity": "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==", - "requires": { - "domelementtype": "^2.0.1", - "domhandler": "^4.2.0", - "entities": "^2.0.0" - } - }, - "domelementtype": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", - "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==" - }, - "domhandler": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz", - "integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==", - "requires": { - "domelementtype": "^2.2.0" - } - }, - "domutils": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz", - "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==", - "requires": { - "dom-serializer": "^1.0.1", - "domelementtype": "^2.2.0", - "domhandler": "^4.2.0" - } - }, - "eastasianwidth": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", - "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", - "dev": true - }, - "ecdsa-sig-formatter": { - "version": "1.0.11", - "requires": { - "safe-buffer": "^5.0.1" - } - }, - "electron-to-chromium": { - "version": "1.4.648", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.648.tgz", - "integrity": "sha512-EmFMarXeqJp9cUKu/QEciEApn0S/xRcpZWuAm32U7NgoZCimjsilKXHRO9saeEW55eHZagIDg6XTUOv32w9pjg==", - "dev": true - }, - "emoji-regex": { - "version": "8.0.0", - "dev": true - }, - "end-of-stream": { - "version": "1.4.4", - "requires": { - "once": "^1.4.0" - } - }, - "enhanced-resolve": { - "version": "5.16.0", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.16.0.tgz", - "integrity": "sha512-O+QWCviPNSSLAD9Ucn8Awv+poAkqn3T1XY5/N7kR7rQO9yfSGWkYZDwpJ+iKF7B8rxaQKWngSqACpgzeapSyoA==", - "dev": true, - "requires": { - "graceful-fs": "^4.2.4", - "tapable": "^2.2.0" - } - }, - "entities": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", - "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==" - }, - "envinfo": { - "version": "7.11.0", - "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.11.0.tgz", - "integrity": "sha512-G9/6xF1FPbIw0TtalAMaVPpiq2aDEuKLXM314jPVAO9r2fo2a4BLqMNkmRS7O/xPPZ+COAhGIz3ETvHEV3eUcg==", - "dev": 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==", - "dev": true, - "requires": { - "get-intrinsic": "^1.2.4" - } - }, - "es-errors": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", - "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", - "dev": true - }, - "es-module-lexer": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.4.1.tgz", - "integrity": "sha512-cXLGjP0c4T3flZJKQSuziYoq7MlT+rnvfZjfp7h+I7K9BNX54kP9nyWvdbwjQ4u1iWbOL4u96fgeZLToQlZC7w==", - "dev": true - }, - "escalade": { - "version": "3.1.1", - "dev": true - }, - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "dev": true - }, - "eslint": { - "version": "8.57.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.0.tgz", - "integrity": "sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==", - "dev": true, - "requires": { - "@eslint-community/eslint-utils": "^4.2.0", - "@eslint-community/regexpp": "^4.6.1", - "@eslint/eslintrc": "^2.1.4", - "@eslint/js": "8.57.0", - "@humanwhocodes/config-array": "^0.11.14", - "@humanwhocodes/module-importer": "^1.0.1", - "@nodelib/fs.walk": "^1.2.8", - "@ungap/structured-clone": "^1.2.0", - "ajv": "^6.12.4", - "chalk": "^4.0.0", - "cross-spawn": "^7.0.2", - "debug": "^4.3.2", - "doctrine": "^3.0.0", - "escape-string-regexp": "^4.0.0", - "eslint-scope": "^7.2.2", - "eslint-visitor-keys": "^3.4.3", - "espree": "^9.6.1", - "esquery": "^1.4.2", - "esutils": "^2.0.2", - "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^6.0.1", - "find-up": "^5.0.0", - "glob-parent": "^6.0.2", - "globals": "^13.19.0", - "graphemer": "^1.4.0", - "ignore": "^5.2.0", - "imurmurhash": "^0.1.4", - "is-glob": "^4.0.0", - "is-path-inside": "^3.0.3", - "js-yaml": "^4.1.0", - "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.4.1", - "lodash.merge": "^4.6.2", - "minimatch": "^3.1.2", - "natural-compare": "^1.4.0", - "optionator": "^0.9.3", - "strip-ansi": "^6.0.1", - "text-table": "^0.2.0" - }, - "dependencies": { - "escape-string-regexp": { - "version": "4.0.0", - "dev": true - }, - "eslint-scope": { - "version": "7.2.2", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", - "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", - "dev": true, - "requires": { - "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" - } - }, - "estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true - }, - "find-up": { - "version": "5.0.0", - "dev": true, - "requires": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" - } - }, - "glob-parent": { - "version": "6.0.2", - "dev": true, - "requires": { - "is-glob": "^4.0.3" - } - }, - "locate-path": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", - "dev": true, - "requires": { - "p-locate": "^5.0.0" - } - }, - "p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "dev": true, - "requires": { - "yocto-queue": "^0.1.0" - } - }, - "p-locate": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", - "dev": true, - "requires": { - "p-limit": "^3.0.2" - } - } - } - }, - "eslint-scope": { - "version": "5.1.1", - "dev": true, - "requires": { - "esrecurse": "^4.3.0", - "estraverse": "^4.1.1" - } - }, - "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==", - "dev": true - }, - "eslint-webpack-plugin": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/eslint-webpack-plugin/-/eslint-webpack-plugin-4.1.0.tgz", - "integrity": "sha512-C3wAG2jyockIhN0YRLuKieKj2nx/gnE/VHmoHemD5ifnAtY6ZU+jNPfzPoX4Zd6RIbUyWTiZUh/ofUlBhoAX7w==", - "dev": true, - "requires": { - "@types/eslint": "^8.56.5", - "jest-worker": "^29.7.0", - "micromatch": "^4.0.5", - "normalize-path": "^3.0.0", - "schema-utils": "^4.2.0" - }, - "dependencies": { - "ajv": { - "version": "8.12.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", - "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", - "dev": true, - "requires": { - "fast-deep-equal": "^3.1.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" - } - }, - "ajv-keywords": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", - "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", - "dev": true, - "requires": { - "fast-deep-equal": "^3.1.3" - } - }, - "jest-worker": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.7.0.tgz", - "integrity": "sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==", - "dev": true, - "requires": { - "@types/node": "*", - "jest-util": "^29.7.0", - "merge-stream": "^2.0.0", - "supports-color": "^8.0.0" - } - }, - "json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "dev": true - }, - "schema-utils": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.2.0.tgz", - "integrity": "sha512-L0jRsrPpjdckP3oPug3/VxNKt2trR8TcabrM6FOAAlvC/9Phcmm+cuAgTlxBqdBR1WJx7Naj9WHw+aOmheSVbw==", - "dev": true, - "requires": { - "@types/json-schema": "^7.0.9", - "ajv": "^8.9.0", - "ajv-formats": "^2.1.1", - "ajv-keywords": "^5.1.0" - } - }, - "supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "espree": { - "version": "9.6.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", - "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", - "dev": true, - "requires": { - "acorn": "^8.9.0", - "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^3.4.1" - } - }, - "esquery": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", - "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", - "dev": true, - "requires": { - "estraverse": "^5.1.0" - }, - "dependencies": { - "estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true - } - } - }, - "esrecurse": { - "version": "4.3.0", - "dev": true, - "requires": { - "estraverse": "^5.2.0" - }, - "dependencies": { - "estraverse": { - "version": "5.2.0", - "dev": true - } - } - }, - "estraverse": { - "version": "4.3.0", - "dev": true - }, - "esutils": { - "version": "2.0.3", - "dev": true - }, - "events": { - "version": "3.3.0" - }, - "expand-template": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz", - "integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==", - "dev": true, - "optional": true - }, - "fast-deep-equal": { - "version": "3.1.3", - "dev": true - }, - "fast-glob": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.1.tgz", - "integrity": "sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==", - "dev": true, - "requires": { - "@nodelib/fs.stat": "^2.0.2", - "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.2", - "merge2": "^1.3.0", - "micromatch": "^4.0.4" - } - }, - "fast-json-stable-stringify": { - "version": "2.0.0", - "dev": 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==", - "dev": true - }, - "fastest-levenshtein": { - "version": "1.0.16", - "resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz", - "integrity": "sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg==", - "dev": true - }, - "fastq": { - "version": "1.11.0", - "dev": true, - "requires": { - "reusify": "^1.0.4" - } - }, - "fd-slicer": { - "version": "1.1.0", - "requires": { - "pend": "~1.2.0" - } - }, - "file-entry-cache": { - "version": "6.0.1", - "dev": true, - "requires": { - "flat-cache": "^3.0.4" - } - }, - "filemanager-webpack-plugin": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/filemanager-webpack-plugin/-/filemanager-webpack-plugin-8.0.0.tgz", - "integrity": "sha512-TYwu62wgq2O2c3K80Sfj8vEys/tP5wdgYoySHgUwWoc2hPbQY3Mq3ahcAW634JvHCTcSV7IAfRxMI3wTXRt2Vw==", - "dev": true, - "requires": { - "@types/archiver": "^5.3.1", - "archiver": "^5.3.1", - "del": "^6.1.1", - "fast-glob": "^3.2.12", - "fs-extra": "^10.1.0", - "is-glob": "^4.0.3", - "normalize-path": "^3.0.0", - "schema-utils": "^4.0.0" - }, - "dependencies": { - "ajv": { - "version": "8.11.0", - "dev": true, - "requires": { - "fast-deep-equal": "^3.1.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" - } - }, - "ajv-keywords": { - "version": "5.1.0", - "dev": true, - "requires": { - "fast-deep-equal": "^3.1.3" - } - }, - "fs-extra": { - "version": "10.1.0", - "dev": true, - "requires": { - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - } - }, - "json-schema-traverse": { - "version": "1.0.0", - "dev": true - }, - "jsonfile": { - "version": "6.1.0", - "dev": true, - "requires": { - "graceful-fs": "^4.1.6", - "universalify": "^2.0.0" - } - }, - "schema-utils": { - "version": "4.0.0", - "dev": true, - "requires": { - "@types/json-schema": "^7.0.9", - "ajv": "^8.8.0", - "ajv-formats": "^2.1.1", - "ajv-keywords": "^5.0.0" - } - }, - "universalify": { - "version": "2.0.0", - "dev": true - } - } - }, - "fill-range": { - "version": "7.0.1", - "dev": true, - "requires": { - "to-regex-range": "^5.0.1" - } - }, - "find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, - "requires": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - } - }, - "flat": { - "version": "5.0.2", - "dev": true - }, - "flat-cache": { - "version": "3.0.4", - "dev": true, - "requires": { - "flatted": "^3.1.0", - "rimraf": "^3.0.2" - } - }, - "flatted": { - "version": "3.2.7", - "dev": true - }, - "follow-redirects": { - "version": "1.15.6", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz", - "integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==" - }, - "foreground-child": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.1.1.tgz", - "integrity": "sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==", - "dev": true, - "requires": { - "cross-spawn": "^7.0.0", - "signal-exit": "^4.0.1" - } - }, - "form-data": { - "version": "2.5.1", - "dev": true, - "requires": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.6", - "mime-types": "^2.1.12" - } - }, - "fs-constants": { - "version": "1.0.0" - }, - "fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", - "dev": true - }, - "function-bind": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", - "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", - "dev": true - }, - "get-caller-file": { - "version": "2.0.5", - "dev": true - }, - "get-func-name": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.2.tgz", - "integrity": "sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==", - "dev": 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==", - "dev": true, - "requires": { - "es-errors": "^1.3.0", - "function-bind": "^1.1.2", - "has-proto": "^1.0.1", - "has-symbols": "^1.0.3", - "hasown": "^2.0.0" - } - }, - "github-from-package": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz", - "integrity": "sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==", - "dev": true, - "optional": true - }, - "glob": { - "version": "10.3.12", - "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.12.tgz", - "integrity": "sha512-TCNv8vJ+xz4QiqTpfOJA7HvYv+tNIRHKfUWw/q+v2jdgN4ebz+KY9tGx5J4rHP0o84mNP+ApH66HRX8us3Khqg==", - "dev": true, - "requires": { - "foreground-child": "^3.1.0", - "jackspeak": "^2.3.6", - "minimatch": "^9.0.1", - "minipass": "^7.0.4", - "path-scurry": "^1.10.2" - }, - "dependencies": { - "brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, - "requires": { - "balanced-match": "^1.0.0" - } - }, - "minimatch": { - "version": "9.0.3", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", - "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", - "dev": true, - "requires": { - "brace-expansion": "^2.0.1" - } - } - } - }, - "glob-parent": { - "version": "5.1.2", - "dev": true, - "requires": { - "is-glob": "^4.0.1" - } - }, - "glob-to-regexp": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", - "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", - "dev": true - }, - "globals": { - "version": "13.24.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", - "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", - "dev": true, - "requires": { - "type-fest": "^0.20.2" - } - }, - "globby": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", - "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", - "dev": true, - "requires": { - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.2.9", - "ignore": "^5.2.0", - "merge2": "^1.4.1", - "slash": "^3.0.0" - } - }, - "gopd": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", - "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", - "dev": true, - "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==" - }, - "graphemer": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", - "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "has-property-descriptors": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", - "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", - "dev": true, - "requires": { - "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==", - "dev": true - }, - "has-symbols": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", - "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", - "dev": true - }, - "hasown": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.0.tgz", - "integrity": "sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==", - "dev": true, - "requires": { - "function-bind": "^1.1.2" - } - }, - "he": { - "version": "1.2.0" - }, - "hosted-git-info": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.1.0.tgz", - "integrity": "sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==", - "dev": true, - "requires": { - "lru-cache": "^6.0.0" - } - }, - "html-to-text": { - "version": "8.2.1", - "resolved": "https://registry.npmjs.org/html-to-text/-/html-to-text-8.2.1.tgz", - "integrity": "sha512-aN/3JvAk8qFsWVeE9InWAWueLXrbkoVZy0TkzaGhoRBC2gCFEeRLDDJN3/ijIGHohy6H+SZzUQWN/hcYtaPK8w==", - "requires": { - "@selderee/plugin-htmlparser2": "^0.6.0", - "deepmerge": "^4.2.2", - "he": "^1.2.0", - "htmlparser2": "^6.1.0", - "minimist": "^1.2.6", - "selderee": "^0.6.0" - } - }, - "htmlparser2": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-6.1.0.tgz", - "integrity": "sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A==", - "requires": { - "domelementtype": "^2.0.1", - "domhandler": "^4.0.0", - "domutils": "^2.5.2", - "entities": "^2.0.0" - } - }, - "http-proxy-agent": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz", - "integrity": "sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==", - "dev": true, - "requires": { - "@tootallnate/once": "1", - "agent-base": "6", - "debug": "4" - } - }, - "https-proxy-agent": { - "version": "5.0.0", - "requires": { - "agent-base": "6", - "debug": "4" - } - }, - "ieee754": { - "version": "1.2.1" - }, - "ignore": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz", - "integrity": "sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==", - "dev": true - }, - "immediate": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz", - "integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==", - "dev": true - }, - "import-fresh": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", - "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", - "dev": true, - "requires": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - }, - "dependencies": { - "resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true - } - } - }, - "import-local": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz", - "integrity": "sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==", - "dev": true, - "requires": { - "pkg-dir": "^4.2.0", - "resolve-cwd": "^3.0.0" - } - }, - "imurmurhash": { - "version": "0.1.4", - "dev": true - }, - "indent-string": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", - "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", - "dev": true - }, - "inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "dev": true, - "requires": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" - }, - "ini": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", - "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", - "dev": true, - "optional": true - }, - "interpret": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/interpret/-/interpret-3.1.1.tgz", - "integrity": "sha512-6xwYfHbajpoF0xLW+iwLkhwgvLoZDfjYfoFNu8ftMoXINzwuymNLd9u/KmwtdT2GbR+/Cz66otEGEVVUHX9QLQ==", - "dev": true - }, - "is-binary-path": { - "version": "2.1.0", - "dev": true, - "requires": { - "binary-extensions": "^2.0.0" - } - }, - "is-core-module": { - "version": "2.13.1", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz", - "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==", - "dev": true, - "requires": { - "hasown": "^2.0.0" - } - }, - "is-docker": { - "version": "2.2.1" - }, - "is-extglob": { - "version": "2.1.1", - "dev": true - }, - "is-fullwidth-code-point": { - "version": "3.0.0", - "dev": true - }, - "is-glob": { - "version": "4.0.3", - "dev": true, - "requires": { - "is-extglob": "^2.1.1" - } - }, - "is-natural-number": { - "version": "4.0.1" - }, - "is-number": { - "version": "7.0.0", - "dev": true - }, - "is-path-cwd": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-2.2.0.tgz", - "integrity": "sha512-w942bTcih8fdJPJmQHFzkS76NEP8Kzzvmw92cXsazb8intwLqPibPPdXf4ANdKV3rYMuuQYGIWtvz9JilB3NFQ==", - "dev": true - }, - "is-path-inside": { - "version": "3.0.3", - "dev": true - }, - "is-plain-obj": { - "version": "2.1.0", - "dev": true - }, - "is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", - "dev": true, - "requires": { - "isobject": "^3.0.1" - } - }, - "is-unicode-supported": { - "version": "0.1.0", - "dev": true - }, - "isarray": { - "version": "1.0.0" - }, - "isexe": { - "version": "2.0.0", - "dev": true - }, - "isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", - "dev": true - }, - "jackspeak": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-2.3.6.tgz", - "integrity": "sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ==", - "dev": true, - "requires": { - "@isaacs/cliui": "^8.0.2", - "@pkgjs/parseargs": "^0.11.0" - } - }, - "jest-util": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz", - "integrity": "sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==", - "dev": true, - "requires": { - "@jest/types": "^29.6.3", - "@types/node": "*", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "graceful-fs": "^4.2.9", - "picomatch": "^2.2.3" - } - }, - "jest-worker": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", - "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", - "dev": true, - "requires": { - "@types/node": "*", - "merge-stream": "^2.0.0", - "supports-color": "^8.0.0" - }, - "dependencies": { - "supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "requires": { - "argparse": "^2.0.1" - } - }, - "json-parse-even-better-errors": { - "version": "2.3.1", - "dev": true - }, - "json-schema-traverse": { - "version": "0.4.1", - "dev": true - }, - "json-stable-stringify-without-jsonify": { - "version": "1.0.1", - "dev": true - }, - "jsonc-parser": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.1.tgz", - "integrity": "sha512-AilxAyFOAcK5wA1+LeaySVBrHsGQvUFCDWXKpZjzaL0PqW+xfBOttn8GNtWKFWqneyMZj41MWF9Kl6iPWLwgOA==", - "dev": true - }, - "jsonwebtoken": { - "version": "9.0.2", - "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.2.tgz", - "integrity": "sha512-PRp66vJ865SSqOlgqS8hujT5U4AOgMfhrwYIuIhfKaoSCZcirrmASQr8CX7cUg+RMih+hgznrjp99o+W4pJLHQ==", - "requires": { - "jws": "^3.2.2", - "lodash.includes": "^4.3.0", - "lodash.isboolean": "^3.0.3", - "lodash.isinteger": "^4.0.4", - "lodash.isnumber": "^3.0.3", - "lodash.isplainobject": "^4.0.6", - "lodash.isstring": "^4.0.1", - "lodash.once": "^4.0.0", - "ms": "^2.1.1", - "semver": "^7.5.4" - }, - "dependencies": { - "jwa": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz", - "integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==", - "requires": { - "buffer-equal-constant-time": "1.0.1", - "ecdsa-sig-formatter": "1.0.11", - "safe-buffer": "^5.0.1" - } - }, - "jws": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz", - "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==", - "requires": { - "jwa": "^1.4.1", - "safe-buffer": "^5.0.1" - } - } - } - }, - "jszip": { - "version": "3.10.1", - "resolved": "https://registry.npmjs.org/jszip/-/jszip-3.10.1.tgz", - "integrity": "sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g==", - "dev": true, - "requires": { - "lie": "~3.3.0", - "pako": "~1.0.2", - "readable-stream": "~2.3.6", - "setimmediate": "^1.0.5" - }, - "dependencies": { - "readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", - "dev": true, - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dev": true, - "requires": { - "safe-buffer": "~5.1.0" - } - } - } - }, - "just-extend": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/just-extend/-/just-extend-4.2.1.tgz", - "integrity": "sha512-g3UB796vUFIY90VIv/WX3L2c8CS2MdWUww3CNrYmqza1Fg0DURc2K/O4YrnklBdQarSJ/y8JnJYDGc+1iumQjg==", - "dev": true - }, - "jwa": { - "version": "2.0.0", - "requires": { - "buffer-equal-constant-time": "1.0.1", - "ecdsa-sig-formatter": "1.0.11", - "safe-buffer": "^5.0.1" - } - }, - "jws": { - "version": "4.0.0", - "requires": { - "jwa": "^2.0.0", - "safe-buffer": "^5.0.1" - } - }, - "keytar": { - "version": "7.9.0", - "resolved": "https://registry.npmjs.org/keytar/-/keytar-7.9.0.tgz", - "integrity": "sha512-VPD8mtVtm5JNtA2AErl6Chp06JBfy7diFQ7TQQhdpWOl6MrCRB+eRbvAZUsbGQS9kiMq0coJsy0W0vHpDCkWsQ==", - "dev": true, - "optional": true, - "requires": { - "node-addon-api": "^4.3.0", - "prebuild-install": "^7.0.1" - } - }, - "kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", - "dev": true - }, - "lazystream": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/lazystream/-/lazystream-1.0.1.tgz", - "integrity": "sha512-b94GiNHQNy6JNTrt5w6zNyffMrNkXZb3KTkCZJb2V1xaEGCk093vkZ2jk3tpaeP33/OiXC+WvK9AxUebnf5nbw==", - "dev": true, - "requires": { - "readable-stream": "^2.0.5" - }, - "dependencies": { - "readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", - "dev": true, - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dev": true, - "requires": { - "safe-buffer": "~5.1.0" - } - } - } - }, - "leven": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", - "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", - "dev": true - }, - "levn": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", - "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", - "dev": true, - "requires": { - "prelude-ls": "^1.2.1", - "type-check": "~0.4.0" - } - }, - "lie": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz", - "integrity": "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==", - "dev": true, - "requires": { - "immediate": "~3.0.5" - } - }, - "linkify-it": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-3.0.3.tgz", - "integrity": "sha512-ynTsyrFSdE5oZ/O9GEf00kPngmOfVwazR5GKDq6EYfhlpFug3J2zybX56a2PRRpc9P+FuSoGNAwjlbDs9jJBPQ==", - "dev": true, - "requires": { - "uc.micro": "^1.0.1" - } - }, - "loader-runner": { - "version": "4.2.0", - "dev": true - }, - "locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, - "requires": { - "p-locate": "^4.1.0" - } - }, - "lodash.defaults": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz", - "integrity": "sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ==", - "dev": true - }, - "lodash.difference": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.difference/-/lodash.difference-4.5.0.tgz", - "integrity": "sha512-dS2j+W26TQ7taQBGN8Lbbq04ssV3emRw4NY58WErlTO29pIqS0HmoT5aJ9+TUQ1N3G+JOZSji4eugsWwGp9yPA==", - "dev": true - }, - "lodash.flatten": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/lodash.flatten/-/lodash.flatten-4.4.0.tgz", - "integrity": "sha512-C5N2Z3DgnnKr0LOpv/hKCgKdb7ZZwafIrsesve6lmzvZIRZRGaZ/l6Q8+2W7NaT+ZwO3fFlSCzCzrDCFdJfZ4g==", - "dev": true - }, - "lodash.get": { - "version": "4.4.2", - "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", - "integrity": "sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==", - "dev": true - }, - "lodash.includes": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", - "integrity": "sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==" - }, - "lodash.isboolean": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", - "integrity": "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==" - }, - "lodash.isinteger": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz", - "integrity": "sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==" - }, - "lodash.isnumber": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz", - "integrity": "sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==" - }, - "lodash.isplainobject": { - "version": "4.0.6" - }, - "lodash.isstring": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", - "integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==" - }, - "lodash.merge": { - "version": "4.6.2", - "dev": true - }, - "lodash.once": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", - "integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==" - }, - "lodash.union": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/lodash.union/-/lodash.union-4.6.0.tgz", - "integrity": "sha512-c4pB2CdGrGdjMKYLA+XiRDO7Y0PRQbm/Gzg8qMj+QH+pFVAoTp5sBpO0odL3FjoPCGjK96p6qsP+yQoiLoOBcw==", - "dev": true - }, - "log-symbols": { - "version": "4.1.0", - "dev": true, - "requires": { - "chalk": "^4.1.0", - "is-unicode-supported": "^0.1.0" - } - }, - "loupe": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/loupe/-/loupe-3.1.0.tgz", - "integrity": "sha512-qKl+FrLXUhFuHUoDJG7f8P8gEMHq9NFS0c6ghXG1J0rldmZFQZoNVv/vyirE9qwCIhWZDsvEFd1sbFu3GvRQFg==", - "dev": true, - "requires": { - "get-func-name": "^2.0.1" - } - }, - "lru-cache": { - "version": "6.0.0", - "requires": { - "yallist": "^4.0.0" - } - }, - "markdown-it": { - "version": "12.3.2", - "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-12.3.2.tgz", - "integrity": "sha512-TchMembfxfNVpHkbtriWltGWc+m3xszaRD0CZup7GFFhzIgQqxIfn3eGj1yZpfuflzPvfkt611B2Q/Bsk1YnGg==", - "dev": true, - "requires": { - "argparse": "^2.0.1", - "entities": "~2.1.0", - "linkify-it": "^3.0.1", - "mdurl": "^1.0.1", - "uc.micro": "^1.0.5" - }, - "dependencies": { - "entities": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-2.1.0.tgz", - "integrity": "sha512-hCx1oky9PFrJ611mf0ifBLBRW8lUUVRlFolb5gWRfIELabBlbp9xZvrqZLZAs+NxFnbfQoeGd8wDkygjg7U85w==", - "dev": true - } - } - }, - "mdurl": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz", - "integrity": "sha512-/sKlQJCBYVY9Ers9hqzKou4H6V5UWc/M59TH2dvkt+84itfnq7uFOMLpOiOS4ujvHP4etln18fmIxA5R5fll0g==", - "dev": true - }, - "merge-stream": { - "version": "2.0.0", - "dev": true - }, - "merge2": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", - "dev": true - }, - "micromatch": { - "version": "4.0.5", - "dev": true, - "requires": { - "braces": "^3.0.2", - "picomatch": "^2.3.1" - } - }, - "mime": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", - "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", - "dev": true - }, - "mime-db": { - "version": "1.38.0" - }, - "mime-types": { - "version": "2.1.22", - "requires": { - "mime-db": "~1.38.0" - } - }, - "mimic-response": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", - "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", - "dev": true, - "optional": true - }, - "minimatch": { - "version": "3.1.2", - "dev": true, - "requires": { - "brace-expansion": "^1.1.7" - } - }, - "minimist": { - "version": "1.2.6" - }, - "minipass": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.0.4.tgz", - "integrity": "sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==", - "dev": true - }, - "mkdirp-classic": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", - "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==", - "dev": true, - "optional": true - }, - "mocha": { - "version": "10.4.0", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.4.0.tgz", - "integrity": "sha512-eqhGB8JKapEYcC4ytX/xrzKforgEc3j1pGlAXVy3eRwrtAy5/nIfT1SvgGzfN0XZZxeLq0aQWkOUAmqIJiv+bA==", - "dev": true, - "requires": { - "ansi-colors": "4.1.1", - "browser-stdout": "1.3.1", - "chokidar": "3.5.3", - "debug": "4.3.4", - "diff": "5.0.0", - "escape-string-regexp": "4.0.0", - "find-up": "5.0.0", - "glob": "8.1.0", - "he": "1.2.0", - "js-yaml": "4.1.0", - "log-symbols": "4.1.0", - "minimatch": "5.0.1", - "ms": "2.1.3", - "serialize-javascript": "6.0.0", - "strip-json-comments": "3.1.1", - "supports-color": "8.1.1", - "workerpool": "6.2.1", - "yargs": "16.2.0", - "yargs-parser": "20.2.4", - "yargs-unparser": "2.0.0" - }, - "dependencies": { - "diff": { - "version": "5.0.0", - "dev": true - }, - "escape-string-regexp": { - "version": "4.0.0", - "dev": true - }, - "find-up": { - "version": "5.0.0", - "dev": true, - "requires": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" - } - }, - "glob": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", - "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", - "dev": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^5.0.1", - "once": "^1.3.0" - } - }, - "locate-path": { - "version": "6.0.0", - "dev": true, - "requires": { - "p-locate": "^5.0.0" - } - }, - "minimatch": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.0.1.tgz", - "integrity": "sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g==", - "dev": true, - "requires": { - "brace-expansion": "^2.0.1" - }, - "dependencies": { - "brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, - "requires": { - "balanced-match": "^1.0.0" - } - } - } - }, - "ms": { - "version": "2.1.3", - "dev": true - }, - "p-limit": { - "version": "3.1.0", - "dev": true, - "requires": { - "yocto-queue": "^0.1.0" - } - }, - "p-locate": { - "version": "5.0.0", - "dev": true, - "requires": { - "p-limit": "^3.0.2" - } - }, - "supports-color": { - "version": "8.1.1", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "moo": { - "version": "0.5.1" - }, - "move-file": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/move-file/-/move-file-3.1.0.tgz", - "integrity": "sha512-4aE3U7CCBWgrQlQDMq8da4woBWDGHioJFiOZ8Ie6Yq2uwYQ9V2kGhTz4x3u6Wc+OU17nw0yc3rJ/lQ4jIiPe3A==", - "requires": { - "path-exists": "^5.0.0" - }, - "dependencies": { - "path-exists": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-5.0.0.tgz", - "integrity": "sha512-RjhtfwJOxzcFmNOi6ltcbcu4Iu+FL3zEj83dk4kAS+fVpTxXLO1b38RvJgT/0QwvV/L3aY9TAnyv0EOqW4GoMQ==" - } - } - }, - "ms": { - "version": "2.1.2" - }, - "mute-stream": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", - "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", - "dev": true - }, - "napi-build-utils": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-1.0.2.tgz", - "integrity": "sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg==", - "dev": true, - "optional": true - }, - "natural-compare": { - "version": "1.4.0", - "dev": true - }, - "nearley": { - "version": "2.20.1", - "requires": { - "commander": "^2.19.0", - "moo": "^0.5.0", - "railroad-diagrams": "^1.0.0", - "randexp": "0.4.6" - } - }, - "nise": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/nise/-/nise-5.1.5.tgz", - "integrity": "sha512-VJuPIfUFaXNRzETTQEEItTOP8Y171ijr+JLq42wHes3DiryR8vT+1TXQW/Rx8JNUhyYYWyIvjXTU6dOhJcs9Nw==", - "dev": true, - "requires": { - "@sinonjs/commons": "^2.0.0", - "@sinonjs/fake-timers": "^10.0.2", - "@sinonjs/text-encoding": "^0.7.1", - "just-extend": "^4.0.2", - "path-to-regexp": "^1.7.0" - }, - "dependencies": { - "@sinonjs/commons": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-2.0.0.tgz", - "integrity": "sha512-uLa0j859mMrg2slwQYdO/AkrOfmH+X6LTVmNTS9CqexuE2IvVORIkSpJLqePAbEnKJ77aMmCwr1NUZ57120Xcg==", - "dev": true, - "requires": { - "type-detect": "4.0.8" - } - }, - "@sinonjs/fake-timers": { - "version": "10.3.0", - "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-10.3.0.tgz", - "integrity": "sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==", - "dev": true, - "requires": { - "@sinonjs/commons": "^3.0.0" - }, - "dependencies": { - "@sinonjs/commons": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.0.tgz", - "integrity": "sha512-jXBtWAF4vmdNmZgD5FoKsVLv3rPgDnLgPbU84LIJ3otV44vJlDRokVng5v8NFJdCf/da9legHcKaRuZs4L7faA==", - "dev": true, - "requires": { - "type-detect": "4.0.8" - } - } - } - } - } - }, - "node-abi": { - "version": "3.56.0", - "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.56.0.tgz", - "integrity": "sha512-fZjdhDOeRcaS+rcpve7XuwHBmktS1nS1gzgghwKUQQ8nTy2FdSDr6ZT8k6YhvlJeHmmQMYiT/IH9hfco5zeW2Q==", - "dev": true, - "optional": true, - "requires": { - "semver": "^7.3.5" - } - }, - "node-addon-api": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-4.3.0.tgz", - "integrity": "sha512-73sE9+3UaLYYFmDsFZnqCInzPyh3MqIwZO9cw58yIqAZhONrrabrYyYe3TuIqtIiOuTXVhsGau8hcrhhwSsDIQ==", - "dev": true, - "optional": true - }, - "node-fetch": { - "version": "2.6.7", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", - "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", - "requires": { - "whatwg-url": "^5.0.0" - } - }, - "node-releases": { - "version": "2.0.14", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.14.tgz", - "integrity": "sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==", - "dev": true - }, - "normalize-path": { - "version": "3.0.0", - "dev": true - }, - "nth-check": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", - "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", - "dev": true, - "requires": { - "boolbase": "^1.0.0" - } - }, - "object-assign": { - "version": "4.1.1" - }, - "object-inspect": { - "version": "1.13.1", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz", - "integrity": "sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==", - "dev": true - }, - "once": { - "version": "1.4.0", - "requires": { - "wrappy": "1" - } - }, - "open": { - "version": "8.4.0", - "requires": { - "define-lazy-prop": "^2.0.0", - "is-docker": "^2.1.1", - "is-wsl": "^2.2.0" - }, - "dependencies": { - "is-wsl": { - "version": "2.2.0", - "requires": { - "is-docker": "^2.0.0" - } - } - } - }, - "optionator": { - "version": "0.9.3", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz", - "integrity": "sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==", - "dev": true, - "requires": { - "@aashutoshrathi/word-wrap": "^1.2.3", - "deep-is": "^0.1.3", - "fast-levenshtein": "^2.0.6", - "levn": "^0.4.1", - "prelude-ls": "^1.2.1", - "type-check": "^0.4.0" - } - }, - "p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, - "requires": { - "p-try": "^2.0.0" - } - }, - "p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, - "requires": { - "p-limit": "^2.2.0" - } - }, - "p-map": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", - "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", - "dev": true, - "requires": { - "aggregate-error": "^3.0.0" - } - }, - "p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", - "dev": true - }, - "pako": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", - "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==", - "dev": true - }, - "parent-module": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", - "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", - "dev": true, - "requires": { - "callsites": "^3.0.0" - } - }, - "parse-semver": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/parse-semver/-/parse-semver-1.1.1.tgz", - "integrity": "sha512-Eg1OuNntBMH0ojvEKSrvDSnwLmvVuUOSdylH/pSCPNMIspLlweJyIWXCE+k/5hm3cj/EBUYwmWkjhBALNP4LXQ==", - "dev": true, - "requires": { - "semver": "^5.1.0" - }, - "dependencies": { - "semver": { - "version": "5.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", - "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", - "dev": true - } - } - }, - "parse5": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.2.tgz", - "integrity": "sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==", - "dev": true, - "requires": { - "entities": "^4.4.0" - }, - "dependencies": { - "entities": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", - "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", - "dev": true - } - } - }, - "parse5-htmlparser2-tree-adapter": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-7.0.0.tgz", - "integrity": "sha512-B77tOZrqqfUfnVcOrUvfdLbz4pu4RopLD/4vmu3HUPswwTA8OH0EMW9BlWR2B0RCoiZRAHEUu7IxeP1Pd1UU+g==", - "dev": true, - "requires": { - "domhandler": "^5.0.2", - "parse5": "^7.0.0" - }, - "dependencies": { - "domhandler": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", - "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", - "dev": true, - "requires": { - "domelementtype": "^2.3.0" - } - } - } - }, - "parseley": { - "version": "0.7.0", - "requires": { - "moo": "^0.5.1", - "nearley": "^2.20.1" - } - }, - "path-exists": { - "version": "4.0.0", - "dev": true - }, - "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==", - "dev": true - }, - "path-key": { - "version": "3.1.1", - "dev": true - }, - "path-parse": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "dev": true - }, - "path-scurry": { - "version": "1.10.2", - "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.10.2.tgz", - "integrity": "sha512-7xTavNy5RQXnsjANvVvMkEjvloOinkAjv/Z6Ildz9v2RinZ4SBKTWFOVRbaF8p0vpHnyjV/UwNDdKuUv6M5qcA==", - "dev": true, - "requires": { - "lru-cache": "^10.2.0", - "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" - }, - "dependencies": { - "lru-cache": { - "version": "10.2.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.0.tgz", - "integrity": "sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q==", - "dev": true - } - } - }, - "path-to-regexp": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.8.0.tgz", - "integrity": "sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA==", - "dev": true, - "requires": { - "isarray": "0.0.1" - }, - "dependencies": { - "isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==", - "dev": true - } - } - }, - "path-type": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", - "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", - "dev": true - }, - "pathval": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/pathval/-/pathval-2.0.0.tgz", - "integrity": "sha512-vE7JKRyES09KiunauX7nd2Q9/L7lhok4smP9RZTDeD4MVs72Dp2qNFVz39Nz5a0FVEW0BJR6C0DYrq6unoziZA==", - "dev": true - }, - "pend": { - "version": "1.2.0" - }, - "picocolors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", - "dev": true - }, - "picomatch": { - "version": "2.3.1", - "dev": true - }, - "pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==" - }, - "pinkie": { - "version": "2.0.4" - }, - "pinkie-promise": { - "version": "2.0.1", - "requires": { - "pinkie": "^2.0.0" - } - }, - "pkg-dir": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", - "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", - "dev": true, - "requires": { - "find-up": "^4.0.0" - } - }, - "prebuild-install": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-7.1.2.tgz", - "integrity": "sha512-UnNke3IQb6sgarcZIDU3gbMeTp/9SSU1DAIkil7PrqG1vZlBtY5msYccSKSHDqa3hNg436IXK+SNImReuA1wEQ==", - "dev": true, - "optional": true, - "requires": { - "detect-libc": "^2.0.0", - "expand-template": "^2.0.3", - "github-from-package": "0.0.0", - "minimist": "^1.2.3", - "mkdirp-classic": "^0.5.3", - "napi-build-utils": "^1.0.1", - "node-abi": "^3.3.0", - "pump": "^3.0.0", - "rc": "^1.2.7", - "simple-get": "^4.0.0", - "tar-fs": "^2.0.0", - "tunnel-agent": "^0.6.0" - } - }, - "prelude-ls": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", - "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", - "dev": true - }, - "prettier": { - "version": "3.2.5", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.2.5.tgz", - "integrity": "sha512-3/GWa9aOC0YeD7LUfvOG2NiDyhOWRvt1k+rcKhOuYnMY24iiCphgneUfJDyFXd6rZCAnuLBv6UeAULtrhT/F4A==", - "dev": true - }, - "process": { - "version": "0.11.10", - "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", - "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==" - }, - "process-nextick-args": { - "version": "2.0.1" - }, - "proxy-from-env": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", - "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" - }, - "pump": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", - "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", - "dev": true, - "optional": true, - "requires": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - }, - "punycode": { - "version": "2.1.1", - "dev": true - }, - "qs": { - "version": "6.12.1", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.12.1.tgz", - "integrity": "sha512-zWmv4RSuB9r2mYQw3zxQuHWeU+42aKi1wWig/j4ele4ygELZ7PEO6MM7rim9oAQH2A5MWfsAVf/jPvTPgCbvUQ==", - "dev": true, - "requires": { - "side-channel": "^1.0.6" - } - }, - "queue-microtask": { - "version": "1.2.3", - "dev": true - }, - "railroad-diagrams": { - "version": "1.0.0" - }, - "randexp": { - "version": "0.4.6", - "requires": { - "discontinuous-range": "1.0.0", - "ret": "~0.1.10" - } - }, - "randombytes": { - "version": "2.1.0", - "dev": true, - "requires": { - "safe-buffer": "^5.1.0" - } - }, - "rc": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", - "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", - "dev": true, - "optional": true, - "requires": { - "deep-extend": "^0.6.0", - "ini": "~1.3.0", - "minimist": "^1.2.0", - "strip-json-comments": "~2.0.1" - }, - "dependencies": { - "strip-json-comments": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", - "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", - "dev": true, - "optional": true - } - } - }, - "read": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/read/-/read-1.0.7.tgz", - "integrity": "sha512-rSOKNYUmaxy0om1BNjMN4ezNT6VKK+2xF4GBhc81mkH7L60i6dp8qPYrkndNLT3QPphoII3maL9PVC9XmhHwVQ==", - "dev": true, - "requires": { - "mute-stream": "~0.0.4" - } - }, - "readable-stream": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", - "dev": true, - "requires": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - } - }, - "readdir-glob": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/readdir-glob/-/readdir-glob-1.1.3.tgz", - "integrity": "sha512-v05I2k7xN8zXvPD9N+z/uhXPaj0sUFCe2rcWZIpBsqxfP7xXFQ0tipAd/wjj1YxWyWtUS5IDJpOG82JKt2EAVA==", - "dev": true, - "requires": { - "minimatch": "^5.1.0" - }, - "dependencies": { - "brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, - "requires": { - "balanced-match": "^1.0.0" - } - }, - "minimatch": { - "version": "5.1.6", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", - "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", - "dev": true, - "requires": { - "brace-expansion": "^2.0.1" - } - } - } - }, - "readdirp": { - "version": "3.6.0", - "dev": true, - "requires": { - "picomatch": "^2.2.1" - } - }, - "rechoir": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.8.0.tgz", - "integrity": "sha512-/vxpCXddiX8NGfGO/mTafwjq4aFa/71pvamip0++IQk3zG8cbCj0fifNPrjjF1XMXUne91jL9OoxmdykoEtifQ==", - "dev": true, - "requires": { - "resolve": "^1.20.0" - } - }, - "regenerator-runtime": { - "version": "0.13.11", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz", - "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==" - }, - "require-directory": { - "version": "2.1.1", - "dev": true - }, - "require-from-string": { - "version": "2.0.2", - "dev": true - }, - "resolve": { - "version": "1.22.8", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", - "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", - "dev": true, - "requires": { - "is-core-module": "^2.13.0", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - } - }, - "resolve-cwd": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", - "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", - "dev": true, - "requires": { - "resolve-from": "^5.0.0" - } - }, - "resolve-from": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", - "dev": true - }, - "ret": { - "version": "0.1.15" - }, - "reusify": { - "version": "1.0.4", - "dev": true - }, - "rimraf": { - "version": "3.0.2", - "dev": true, - "requires": { - "glob": "^7.1.3" - }, - "dependencies": { - "glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "dev": 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" - } - } - } - }, - "run-parallel": { - "version": "1.2.0", - "dev": true, - "requires": { - "queue-microtask": "^1.2.2" - } - }, - "rxjs": { - "version": "7.8.1", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", - "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", - "requires": { - "tslib": "^2.1.0" - } - }, - "safe-buffer": { - "version": "5.1.2" - }, - "sax": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/sax/-/sax-1.3.0.tgz", - "integrity": "sha512-0s+oAmw9zLl1V1cS9BtZN7JAd0cW5e0QH4W3LWEK6a4LaLEA2OTpGYWDY+6XasBLtz6wkm3u1xRw95mRuJ59WA==" - }, - "schema-utils": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", - "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", - "dev": true, - "requires": { - "@types/json-schema": "^7.0.8", - "ajv": "^6.12.5", - "ajv-keywords": "^3.5.2" - } - }, - "seek-bzip": { - "version": "1.0.6", - "requires": { - "commander": "^2.8.1" - } - }, - "selderee": { - "version": "0.6.0", - "requires": { - "parseley": "^0.7.0" - } - }, - "semver": { - "version": "7.6.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz", - "integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==", - "requires": { - "lru-cache": "^6.0.0" - } - }, - "serialize-javascript": { - "version": "6.0.0", - "dev": true, - "requires": { - "randombytes": "^2.1.0" - } - }, - "set-function-length": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", - "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", - "dev": true, - "requires": { - "define-data-property": "^1.1.4", - "es-errors": "^1.3.0", - "function-bind": "^1.1.2", - "get-intrinsic": "^1.2.4", - "gopd": "^1.0.1", - "has-property-descriptors": "^1.0.2" - } - }, - "setimmediate": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", - "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==", - "dev": true - }, - "shallow-clone": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", - "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", - "dev": true, - "requires": { - "kind-of": "^6.0.2" - } - }, - "shebang-command": { - "version": "2.0.0", - "dev": true, - "requires": { - "shebang-regex": "^3.0.0" - } - }, - "shebang-regex": { - "version": "3.0.0", - "dev": true - }, - "side-channel": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz", - "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==", - "dev": true, - "requires": { - "call-bind": "^1.0.7", - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.4", - "object-inspect": "^1.13.1" - } - }, - "signal-exit": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", - "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", - "dev": true - }, - "simple-concat": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz", - "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==", - "dev": true, - "optional": true - }, - "simple-get": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-4.0.1.tgz", - "integrity": "sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==", - "dev": true, - "optional": true, - "requires": { - "decompress-response": "^6.0.0", - "once": "^1.3.1", - "simple-concat": "^1.0.0" - } - }, - "sinon": { - "version": "17.0.1", - "resolved": "https://registry.npmjs.org/sinon/-/sinon-17.0.1.tgz", - "integrity": "sha512-wmwE19Lie0MLT+ZYNpDymasPHUKTaZHUH/pKEubRXIzySv9Atnlw+BUMGCzWgV7b7wO+Hw6f1TEOr0IUnmU8/g==", - "dev": true, - "requires": { - "@sinonjs/commons": "^3.0.0", - "@sinonjs/fake-timers": "^11.2.2", - "@sinonjs/samsam": "^8.0.0", - "diff": "^5.1.0", - "nise": "^5.1.5", - "supports-color": "^7.2.0" - } - }, - "slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true - }, - "source-map-support": { - "version": "0.5.21", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", - "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", - "dev": true, - "requires": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" - } - }, - "stoppable": { - "version": "1.1.0" - }, - "string_decoder": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", - "dev": true, - "requires": { - "safe-buffer": "~5.2.0" - }, - "dependencies": { - "safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "dev": true - } - } - }, - "string-width": { - "version": "4.2.3", - "dev": true, - "requires": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - } - }, - "string-width-cjs": { - "version": "npm:string-width@4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "requires": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - } - }, - "strip-ansi": { - "version": "6.0.1", - "dev": true, - "requires": { - "ansi-regex": "^5.0.1" - } - }, - "strip-ansi-cjs": { - "version": "npm:strip-ansi@6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "requires": { - "ansi-regex": "^5.0.1" - } - }, - "strip-dirs": { - "version": "2.1.0", - "requires": { - "is-natural-number": "^4.0.1" - } - }, - "strip-json-comments": { - "version": "3.1.1", - "dev": 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==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - }, - "supports-preserve-symlinks-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", - "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", - "dev": true - }, - "tapable": { - "version": "2.2.0", - "dev": true - }, - "tar-fs": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.1.tgz", - "integrity": "sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==", - "dev": true, - "optional": true, - "requires": { - "chownr": "^1.1.1", - "mkdirp-classic": "^0.5.2", - "pump": "^3.0.0", - "tar-stream": "^2.1.4" - } - }, - "tar-stream": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", - "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", - "dev": true, - "requires": { - "bl": "^4.0.3", - "end-of-stream": "^1.4.1", - "fs-constants": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^3.1.1" - } - }, - "tas-client": { - "version": "0.1.73", - "resolved": "https://registry.npmjs.org/tas-client/-/tas-client-0.1.73.tgz", - "integrity": "sha512-UDdUF9kV2hYdlv+7AgqP2kXarVSUhjK7tg1BUflIRGEgND0/QoNpN64rcEuhEcM8AIbW65yrCopJWqRhLZ3m8w==", - "requires": { - "axios": "^1.6.1" - } - }, - "terser": { - "version": "5.27.0", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.27.0.tgz", - "integrity": "sha512-bi1HRwVRskAjheeYl291n3JC4GgO/Ty4z1nVs5AAsmonJulGxpSektecnNedrwK9C7vpvVtcX3cw00VSLt7U2A==", - "dev": true, - "requires": { - "@jridgewell/source-map": "^0.3.3", - "acorn": "^8.8.2", - "commander": "^2.20.0", - "source-map-support": "~0.5.20" - } - }, - "terser-webpack-plugin": { - "version": "5.3.10", - "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.10.tgz", - "integrity": "sha512-BKFPWlPDndPs+NGGCr1U59t0XScL5317Y0UReNrHaw9/FwhPENlq6bfgs+4yPfyP51vqC1bQ4rp1EfXW5ZSH9w==", - "dev": true, - "requires": { - "@jridgewell/trace-mapping": "^0.3.20", - "jest-worker": "^27.4.5", - "schema-utils": "^3.1.1", - "serialize-javascript": "^6.0.1", - "terser": "^5.26.0" - }, - "dependencies": { - "serialize-javascript": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz", - "integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==", - "dev": true, - "requires": { - "randombytes": "^2.1.0" - } - } - } - }, - "text-table": { - "version": "0.2.0", - "dev": true - }, - "through": { - "version": "2.3.8" - }, - "tmp": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.3.tgz", - "integrity": "sha512-nZD7m9iCPC5g0pYmcaxogYKggSfLsdxl8of3Q/oIbqCqLLIO9IAF0GWjX1z9NZRHPiXv8Wex4yDCaZsgEw0Y8w==" - }, - "to-buffer": { - "version": "1.1.1" - }, - "to-regex-range": { - "version": "5.0.1", - "dev": true, - "requires": { - "is-number": "^7.0.0" - } - }, - "tr46": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" - }, - "ts-api-utils": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.3.0.tgz", - "integrity": "sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==", - "dev": true, - "requires": {} - }, - "ts-loader": { - "version": "9.5.1", - "resolved": "https://registry.npmjs.org/ts-loader/-/ts-loader-9.5.1.tgz", - "integrity": "sha512-rNH3sK9kGZcH9dYzC7CewQm4NtxJTjSEVRJ2DyBZR7f8/wcta+iV44UPCXc5+nzDzivKtlzV6c9P4e+oFhDLYg==", - "dev": true, - "requires": { - "chalk": "^4.1.0", - "enhanced-resolve": "^5.0.0", - "micromatch": "^4.0.0", - "semver": "^7.3.4", - "source-map": "^0.7.4" - }, - "dependencies": { - "source-map": { - "version": "0.7.4", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz", - "integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==", - "dev": true - } - } - }, - "tslib": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", - "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==" - }, - "tunnel": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz", - "integrity": "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==" - }, - "tunnel-agent": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", - "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", - "dev": true, - "optional": true, - "requires": { - "safe-buffer": "^5.0.1" - } - }, - "type-check": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", - "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", - "dev": true, - "requires": { - "prelude-ls": "^1.2.1" - } - }, - "type-detect": { - "version": "4.0.8", - "dev": true - }, - "type-fest": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", - "dev": true - }, - "typed-rest-client": { - "version": "1.8.11", - "resolved": "https://registry.npmjs.org/typed-rest-client/-/typed-rest-client-1.8.11.tgz", - "integrity": "sha512-5UvfMpd1oelmUPRbbaVnq+rHP7ng2cE4qoQkQeAqxRL6PklkxsM0g32/HL0yfvruK6ojQ5x8EE+HF4YV6DtuCA==", - "dev": true, - "requires": { - "qs": "^6.9.1", - "tunnel": "0.0.6", - "underscore": "^1.12.1" - } - }, - "typescript": { - "version": "5.4.5", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.5.tgz", - "integrity": "sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==", - "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==", - "dev": true - }, - "unbzip2-stream": { - "version": "1.4.3", - "requires": { - "buffer": "^5.2.1", - "through": "^2.3.8" - } - }, - "underscore": { - "version": "1.13.6", - "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.6.tgz", - "integrity": "sha512-+A5Sja4HP1M08MaXya7p5LvjuM7K6q/2EaC0+iovj/wOcMsTzMvDFbasi/oSapiwOlt252IqsKqPjCl7huKS0A==", - "dev": 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==" - }, - "update-browserslist-db": { - "version": "1.0.13", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz", - "integrity": "sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==", - "dev": true, - "requires": { - "escalade": "^3.1.1", - "picocolors": "^1.0.0" - } - }, - "uri-js": { - "version": "4.2.2", - "dev": true, - "requires": { - "punycode": "^2.1.0" - } - }, - "url-join": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/url-join/-/url-join-4.0.1.tgz", - "integrity": "sha512-jk1+QP6ZJqyOiuEI9AEWQfju/nB2Pw466kbA0LEZljHwKeMgd9WrAEgEGxjPDD2+TNbbb37rTyhEfrCXfuKXnA==", - "dev": true - }, - "util-deprecate": { - "version": "1.0.2" - }, - "uuid": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", - "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==" - }, - "vscode-kubernetes-tools-api": { - "version": "1.3.0" - }, - "vscode-tas-client": { - "version": "0.1.75", - "resolved": "https://registry.npmjs.org/vscode-tas-client/-/vscode-tas-client-0.1.75.tgz", - "integrity": "sha512-/+ALFWPI4U3obeRvLFSt39guT7P9bZQrkmcLoiS+2HtzJ/7iPKNt5Sj+XTiitGlPYVFGFc0plxX8AAp6Uxs0xQ==", - "requires": { - "tas-client": "0.1.73" - } - }, - "vscode-uri": { - "version": "3.0.8", - "resolved": "https://registry.npmjs.org/vscode-uri/-/vscode-uri-3.0.8.tgz", - "integrity": "sha512-AyFQ0EVmsOZOlAnxoFOGOq1SQDWAB7C6aqMGS23svWAllfOaxbuFvcT8D1i8z3Gyn8fraVeZNNmN6e9bxxXkKw==" - }, - "watchpack": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.1.tgz", - "integrity": "sha512-8wrBCMtVhqcXP2Sup1ctSkga6uc2Bx0IIvKyT7yTFier5AXHooSI+QyQQAtTb7+E0IUCCKyTFmXqdqgum2XWGg==", - "dev": true, - "requires": { - "glob-to-regexp": "^0.4.1", - "graceful-fs": "^4.1.2" - } - }, - "webidl-conversions": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" - }, - "webpack": { - "version": "5.91.0", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.91.0.tgz", - "integrity": "sha512-rzVwlLeBWHJbmgTC/8TvAcu5vpJNII+MelQpylD4jNERPwpBJOE2lEcko1zJX3QJeLjTTAnQxn/OJ8bjDzVQaw==", - "dev": true, - "requires": { - "@types/eslint-scope": "^3.7.3", - "@types/estree": "^1.0.5", - "@webassemblyjs/ast": "^1.12.1", - "@webassemblyjs/wasm-edit": "^1.12.1", - "@webassemblyjs/wasm-parser": "^1.12.1", - "acorn": "^8.7.1", - "acorn-import-assertions": "^1.9.0", - "browserslist": "^4.21.10", - "chrome-trace-event": "^1.0.2", - "enhanced-resolve": "^5.16.0", - "es-module-lexer": "^1.2.1", - "eslint-scope": "5.1.1", - "events": "^3.2.0", - "glob-to-regexp": "^0.4.1", - "graceful-fs": "^4.2.11", - "json-parse-even-better-errors": "^2.3.1", - "loader-runner": "^4.2.0", - "mime-types": "^2.1.27", - "neo-async": "^2.6.2", - "schema-utils": "^3.2.0", - "tapable": "^2.1.1", - "terser-webpack-plugin": "^5.3.10", - "watchpack": "^2.4.1", - "webpack-sources": "^3.2.3" - }, - "dependencies": { - "mime-db": { - "version": "1.46.0", - "dev": true - }, - "mime-types": { - "version": "2.1.29", - "dev": true, - "requires": { - "mime-db": "1.46.0" - } - }, - "neo-async": { - "version": "2.6.2", - "dev": true - } - } - }, - "webpack-cli": { - "version": "5.1.4", - "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-5.1.4.tgz", - "integrity": "sha512-pIDJHIEI9LR0yxHXQ+Qh95k2EvXpWzZ5l+d+jIo+RdSm9MiHfzazIxwwni/p7+x4eJZuvG1AJwgC4TNQ7NRgsg==", - "dev": true, - "requires": { - "@discoveryjs/json-ext": "^0.5.0", - "@webpack-cli/configtest": "^2.1.1", - "@webpack-cli/info": "^2.0.2", - "@webpack-cli/serve": "^2.0.5", - "colorette": "^2.0.14", - "commander": "^10.0.1", - "cross-spawn": "^7.0.3", - "envinfo": "^7.7.3", - "fastest-levenshtein": "^1.0.12", - "import-local": "^3.0.2", - "interpret": "^3.1.1", - "rechoir": "^0.8.0", - "webpack-merge": "^5.7.3" - }, - "dependencies": { - "commander": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz", - "integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==", - "dev": true - } - } - }, - "webpack-merge": { - "version": "5.10.0", - "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.10.0.tgz", - "integrity": "sha512-+4zXKdx7UnO+1jaN4l2lHVD+mFvnlZQP/6ljaJVb4SZiwIKeUnrT5l0gkT8z+n4hKpC+jpOv6O9R+gLtag7pSA==", - "dev": true, - "requires": { - "clone-deep": "^4.0.1", - "flat": "^5.0.2", - "wildcard": "^2.0.0" - } - }, - "webpack-sources": { - "version": "3.2.3", - "dev": true - }, - "whatwg-url": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", - "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", - "requires": { - "tr46": "~0.0.3", - "webidl-conversions": "^3.0.0" - } - }, - "which": { - "version": "2.0.2", - "dev": true, - "requires": { - "isexe": "^2.0.0" - } - }, - "wildcard": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.1.tgz", - "integrity": "sha512-CC1bOL87PIWSBhDcTrdeLo6eGT7mCFtrg0uIJtqJUFyK+eJnzl8A1niH56uu7KMa5XFrtiV+AQuHO3n7DsHnLQ==", - "dev": true - }, - "workerpool": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.1.tgz", - "integrity": "sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw==", - "dev": true - }, - "wrap-ansi": { - "version": "7.0.0", - "dev": true, - "requires": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - } - }, - "wrap-ansi-cjs": { - "version": "npm:wrap-ansi@7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dev": true, - "requires": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - } - }, - "wrappy": { - "version": "1.0.2" - }, - "xml2js": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.5.0.tgz", - "integrity": "sha512-drPFnkQJik/O+uPKpqSgr22mpuFHqKdbS835iAQrUC73L2F5WkboIRd63ai/2Yg6I1jzifPFKH2NTK+cfglkIA==", - "requires": { - "sax": ">=0.6.0", - "xmlbuilder": "~11.0.0" - } - }, - "xmlbuilder": { - "version": "11.0.1", - "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz", - "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==" - }, - "xtend": { - "version": "4.0.2" - }, - "y18n": { - "version": "5.0.8", - "dev": true - }, - "yallist": { - "version": "4.0.0" - }, - "yargs": { - "version": "16.2.0", - "dev": true, - "requires": { - "cliui": "^7.0.2", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.0", - "y18n": "^5.0.5", - "yargs-parser": "^20.2.2" - } - }, - "yargs-parser": { - "version": "20.2.4", - "dev": true - }, - "yargs-unparser": { - "version": "2.0.0", - "dev": true, - "requires": { - "camelcase": "^6.0.0", - "decamelize": "^4.0.0", - "flat": "^5.0.2", - "is-plain-obj": "^2.1.0" - } - }, - "yauzl": { - "version": "2.10.0", - "requires": { - "buffer-crc32": "~0.2.3", - "fd-slicer": "~1.1.0" - } - }, - "yazl": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/yazl/-/yazl-2.5.1.tgz", - "integrity": "sha512-phENi2PLiHnHb6QBVot+dJnaAZ0xosj7p3fWl+znIjBDlnMI2PsZCJZ306BPTFOaHf5qdDEI8x5qFrSOBN5vrw==", - "dev": true, - "requires": { - "buffer-crc32": "~0.2.3" - } - }, - "yocto-queue": { - "version": "0.1.0", - "dev": true - }, - "zip-stream": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/zip-stream/-/zip-stream-4.1.1.tgz", - "integrity": "sha512-9qv4rlDiopXg4E69k+vMHjNN63YFMe9sZMrdlvKnCjlCRWeCBswPPMPUfx+ipsAWq1LXHe70RcbaHdJJpS6hyQ==", - "dev": true, - "requires": { - "archiver-utils": "^3.0.4", - "compress-commons": "^4.1.2", - "readable-stream": "^3.6.0" - }, - "dependencies": { - "archiver-utils": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/archiver-utils/-/archiver-utils-3.0.4.tgz", - "integrity": "sha512-KVgf4XQVrTjhyWmx6cte4RxonPLR9onExufI1jhvw/MQ4BB6IsZD5gT8Lq+u/+pRkWna/6JoHpiQioaqFP5Rzw==", - "dev": true, - "requires": { - "glob": "^7.2.3", - "graceful-fs": "^4.2.0", - "lazystream": "^1.0.0", - "lodash.defaults": "^4.2.0", - "lodash.difference": "^4.5.0", - "lodash.flatten": "^4.4.0", - "lodash.isplainobject": "^4.0.6", - "lodash.union": "^4.6.0", - "normalize-path": "^3.0.0", - "readable-stream": "^3.6.0" - } - }, - "glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "dev": 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" - } - } - } } } } diff --git a/package.json b/package.json index 4a996a57..31bc5d2d 100644 --- a/package.json +++ b/package.json @@ -83,6 +83,13 @@ "configuration": { "title": "AKS", "properties": { + "aks.selectedSubscriptions": { + "type": "array", + "description": "Selected Azure subscriptions", + "items": { + "type": "string" + } + }, "aks.periscope.repoOrg": { "type": "string", "default": "azure", @@ -157,6 +164,7 @@ { "command": "aks.selectSubscriptions", "title": "Select subscriptions...", + "category": "AKS", "icon": { "dark": "resources/dark/filter.svg", "light": "resources/light/filter.svg" @@ -170,6 +178,16 @@ "light": "resources/light/refresh.svg" } }, + { + "command": "aks.signInToAzure", + "title": "Sign in to Azure...", + "category": "AKS" + }, + { + "command": "aks.selectTenant", + "title": "Select Tenant...", + "category": "AKS" + }, { "command": "aks.periscope", "title": "Run AKS Periscope" @@ -273,10 +291,6 @@ ], "menus": { "commandPalette": [ - { - "command": "aks.selectSubscriptions", - "when": "never" - }, { "command": "aks.refreshSubscription", "when": "never" @@ -477,7 +491,6 @@ "test": "npm run test-compile && node ./out/src/tests/runTests.js" }, "extensionDependencies": [ - "ms-vscode.azure-account", "ms-kubernetes-tools.vscode-kubernetes-tools" ], "devDependencies": { @@ -499,7 +512,6 @@ "chai": "^5.1.0", "eslint": "^8.57.0", "eslint-webpack-plugin": "^4.1.0", - "filemanager-webpack-plugin": "^8.0.0", "glob": "^10.3.12", "mocha": "^10.4.0", "prettier": "^3.2.5", @@ -514,15 +526,14 @@ "@azure/arm-containerservice": "^19.7.0", "@azure/arm-monitor": "^7.0.0", "@azure/arm-resources": "^5.2.0", + "@azure/arm-resources-subscriptions": "^2.1.0", "@azure/arm-storage": "^18.2.0", "@azure/arm-subscriptions": "^5.1.0", "@azure/core-auth": "^1.7.2", "@azure/identity": "^4.1.0", "@azure/ms-rest-azure-env": "^2.0.0", - "@azure/msal-node": "^2.6.6", "@azure/storage-blob": "^12.17.0", "@microsoft/microsoft-graph-client": "^3.0.7", - "@microsoft/vscode-azext-azureutils": "^3.0.1", "@microsoft/vscode-azext-utils": "^2.4.0", "@vscode/extension-telemetry": "^0.9.6", "cross-fetch": "^4.0.0", diff --git a/resources/azure.svg b/resources/azure.svg new file mode 100644 index 00000000..010bd1e0 --- /dev/null +++ b/resources/azure.svg @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/azureSubscription.svg b/resources/azureSubscription.svg new file mode 100644 index 00000000..dbc6eb67 --- /dev/null +++ b/resources/azureSubscription.svg @@ -0,0 +1,16 @@ + + + + + + + + + + Icon-general-2 + + + + + \ No newline at end of file diff --git a/src/auth/azureAuth.ts b/src/auth/azureAuth.ts new file mode 100644 index 00000000..29451ea3 --- /dev/null +++ b/src/auth/azureAuth.ts @@ -0,0 +1,136 @@ +import { + AuthenticationSession, + Disposable as VsCodeDisposable, + ProgressLocation, + ProgressOptions, + QuickPickItem, + window, +} from "vscode"; +import { AzureSessionProvider, ReadyAzureSessionProvider, Tenant, TokenInfo, isReady } from "./types"; +import { Environment } from "@azure/ms-rest-azure-env"; +import { getConfiguredAzureEnv } from "../commands/utils/config"; +import { Errorable, failed } from "../commands/utils/errorable"; +import { TokenCredential } from "@azure/core-auth"; +import { parseJson } from "../commands/utils/json"; +import { getSessionProvider } from "./azureSessionProvider"; + +export function getEnvironment(): Environment { + return getConfiguredAzureEnv(); +} + +export async function getReadySessionProvider(): Promise> { + const sessionProvider = getSessionProvider(); + if (isReady(sessionProvider)) { + return { succeeded: true, result: sessionProvider }; + } + + switch (sessionProvider.signInStatus) { + case "Initializing": + case "SigningIn": + await waitForSignIn(sessionProvider); + break; + case "SignedOut": + await sessionProvider.signIn(); + break; + case "SignedIn": + break; + } + + // Get a session, which will prompt the user to select a tenant if necessary. + const session = await sessionProvider.getAuthSession(); + if (failed(session)) { + return { succeeded: false, error: `Failed to get authentication session: ${session.error}` }; + } + + if (!isReady(sessionProvider)) { + return { succeeded: false, error: "Not signed in." }; + } + + return { succeeded: true, result: sessionProvider }; +} + +async function waitForSignIn(sessionProvider: AzureSessionProvider): Promise { + const options: ProgressOptions = { + location: ProgressLocation.Notification, + title: "Waiting for sign-in", + cancellable: true, + }; + + await window.withProgress(options, (_, token) => { + let listener: VsCodeDisposable | undefined; + token.onCancellationRequested(listener?.dispose()); + return new Promise((resolve) => { + listener = sessionProvider.signInStatusChangeEvent((status) => { + if (status === "SignedIn") { + listener?.dispose(); + resolve(undefined); + } + }); + }); + }); +} + +export function getCredential(sessionProvider: ReadyAzureSessionProvider): TokenCredential { + return { + getToken: async () => { + const session = await sessionProvider.getAuthSession(); + if (failed(session)) { + throw new Error(`No Microsoft authentication session found: ${session.error}`); + } + + return { token: session.result.accessToken, expiresOnTimestamp: 0 }; + }, + }; +} + +export function getTokenInfo(session: AuthenticationSession): Errorable { + const tokenParts = session.accessToken.split("."); + if (tokenParts.length !== 3) { + return { succeeded: false, error: `Access token not a valid JWT: ${session.accessToken}` }; + } + + const body = tokenParts[1]; + let jsonBody: string; + try { + jsonBody = Buffer.from(body, "base64").toString(); + } catch (e) { + return { succeeded: false, error: `Failed to decode JWT token body: ${body}` }; + } + + const jwt = parseJson(jsonBody); + if (failed(jwt)) { + return jwt; + } + + const tokenInfo: TokenInfo = { + token: session.accessToken, + expiry: new Date(jwt.result.exp * 1000), + }; + + return { succeeded: true, result: tokenInfo }; +} + +export function getDefaultScope(endpointUrl: string): string { + // Endpoint URL is that of the audience, e.g. for ARM in the public cloud + // it would be "https://management.azure.com". + return endpointUrl.endsWith("/") ? `${endpointUrl}.default` : `${endpointUrl}/.default`; +} + +/** + * The type of a JSON-parsed JWT body. Right now we only make use of the 'exp' field, + * but other standard claims could be added here if needed. + */ +interface Jwt { + exp: number; +} + +export async function quickPickTenant(tenants: Tenant[]): Promise { + const items: (QuickPickItem & { tenant: Tenant })[] = tenants.map((t) => ({ + label: `${t.name} (${t.id})`, + tenant: t, + })); + const result = await window.showQuickPick(items, { + placeHolder: "Select a tenant", + }); + return result ? result.tenant : undefined; +} diff --git a/src/auth/azureSessionProvider.ts b/src/auth/azureSessionProvider.ts new file mode 100644 index 00000000..0ee17c3c --- /dev/null +++ b/src/auth/azureSessionProvider.ts @@ -0,0 +1,292 @@ +import { + Disposable as VsCodeDisposable, + Event, + ExtensionContext, + EventEmitter, + authentication, + AuthenticationGetSessionOptions, + AuthenticationSession, +} from "vscode"; +import { AzureAuthenticationSession, AzureSessionProvider, SignInStatus, Tenant } from "./types"; +import { Errorable, bindAsync, getErrorMessage, map as errmap, succeeded } from "../commands/utils/errorable"; +import { getDefaultScope, quickPickTenant } from "./azureAuth"; +import { getConfiguredAzureEnv } from "../commands/utils/config"; +import { Environment } from "@azure/ms-rest-azure-env"; +import { TokenCredential } from "@azure/core-auth"; +import { SubscriptionClient, TenantIdDescription } from "@azure/arm-resources-subscriptions"; +import { listAll } from "../commands/utils/arm"; + +type AuthProviderId = "microsoft" | "microsoft-sovereign-cloud"; + +enum AuthScenario { + Initialization, + SignIn, + GetSession, +} + +let sessionProvider: AzureSessionProvider; + +export function activateAzureSessionProvider(context: ExtensionContext) { + sessionProvider = new AzureSessionProviderImpl(); + context.subscriptions.push(sessionProvider); +} + +export function getSessionProvider(): AzureSessionProvider { + return sessionProvider; +} + +class AzureSessionProviderImpl extends VsCodeDisposable implements AzureSessionProvider { + private readonly initializePromise: Promise; + private handleSessionChanges: boolean = true; + private tenants: Tenant[] = []; + private selectedTenantValue: Tenant | null = null; + + public readonly onSignInStatusChangeEmitter = new EventEmitter(); + public signInStatusValue: SignInStatus = "Initializing"; + + public constructor() { + const disposable = authentication.onDidChangeSessions(async (e) => { + // Ignore events for non-microsoft providers + if (e.provider.id !== getConfiguredAuthProviderId()) { + return; + } + + // Ignore events that we triggered. + if (!this.handleSessionChanges) { + return; + } + + // Silently check authentication status and tenants + await this.signInAndUpdateTenants(AuthScenario.Initialization); + }); + + super(() => { + this.onSignInStatusChangeEmitter.dispose(); + disposable.dispose(); + }); + + this.initializePromise = this.initialize(); + } + + public get signInStatus(): SignInStatus { + return this.signInStatusValue; + } + + public get signInStatusChangeEvent(): Event { + return this.onSignInStatusChangeEmitter.event; + } + + public get availableTenants(): Tenant[] { + return [...this.tenants]; + } + + public get selectedTenant(): Tenant | null { + return this.selectedTenantValue; + } + + public set selectedTenant(tenant: Tenant | null) { + const isValid = tenant === null || this.tenants.some((t) => t.id === tenant.id); + const isChanged = this.selectedTenantValue !== tenant; + if (isValid && isChanged) { + this.selectedTenantValue = tenant; + this.onSignInStatusChangeEmitter.fire(this.signInStatusValue); + } + } + + private async initialize(): Promise { + await this.signInAndUpdateTenants(AuthScenario.Initialization); + } + + /** + * Sign in to Azure interactively, i.e. prompt the user to sign in even if they have an active session. + * This allows the user to choose a different account or tenant. + */ + public async signIn(): Promise { + await this.initializePromise; + + const newSignInStatus = "SigningIn"; + if (newSignInStatus !== this.signInStatusValue) { + this.signInStatusValue = newSignInStatus; + this.onSignInStatusChangeEmitter.fire(this.signInStatusValue); + } + + await this.signInAndUpdateTenants(AuthScenario.SignIn); + } + + private async signInAndUpdateTenants(authScenario: AuthScenario): Promise { + // Initially, try to get a session using the 'organizations' tenant/authority: + // https://learn.microsoft.com/en-us/entra/identity-platform/msal-client-application-configuration#authority + // This allows the user to sign in to the Microsoft provider and list tenants, + // but the resulting session will not allow tenant-level operations. For that, + // we need to get a session for a specific tenant. + const getSessionResult = await this.getArmSession("organizations", authScenario); + + // Get the tenants + const getTenantsResult = await bindAsync(getSessionResult, (session) => getTenants(session)); + const newTenants = succeeded(getTenantsResult) ? getTenantsResult.result : []; + const tenantsChanged = getIdString(newTenants) !== getIdString(this.tenants); + + // Determine which tenant should be selected. We can't force the user to choose at this stage, + // so this can be null, and will be set when the user tries to get a session. + const newSelectedTenant = await this.getNewSelectedTenant(newTenants, this.selectedTenantValue, authScenario); + const selectedTenantChanged = newSelectedTenant?.id !== this.selectedTenantValue?.id; + + // Get the overall sign-in status. If the user has access to any tenants they are signed in. + const newSignInStatus = newTenants.length > 0 ? "SignedIn" : "SignedOut"; + const signInStatusChanged = newSignInStatus !== this.signInStatusValue; + + // Update the state and fire event if anything has changed. + this.selectedTenantValue = newSelectedTenant; + this.tenants = newTenants; + this.signInStatusValue = newSignInStatus; + if (signInStatusChanged || tenantsChanged || selectedTenantChanged) { + this.onSignInStatusChangeEmitter.fire(this.signInStatusValue); + } + } + + /** + * Get the current Azure session, silently if possible. + * @returns The current Azure session, if available. If the user is not signed in, or there are no tenants, + * an error message is returned. + */ + public async getAuthSession(): Promise> { + await this.initializePromise; + if (this.signInStatusValue !== "SignedIn") { + return { succeeded: false, error: `Not signed in (${this.signInStatusValue}).` }; + } + + if (this.tenants.length === 0) { + return { succeeded: false, error: "No tenants found." }; + } + + if (!this.selectedTenantValue) { + if (this.tenants.length > 1) { + const selectedTenant = await quickPickTenant(this.tenants); + if (!selectedTenant) { + return { succeeded: false, error: "No tenant selected." }; + } + + this.selectedTenantValue = selectedTenant; + } else { + this.selectedTenantValue = this.tenants[0]; + } + } + + // Get a session for a specific tenant. + return await this.getArmSession(this.selectedTenantValue.id, AuthScenario.GetSession); + } + + private async getNewSelectedTenant( + newTenants: Tenant[], + currentSelectedTenant: Tenant | null, + authScenario: AuthScenario, + ): Promise { + // For sign-in we ignore the current selected tenant because the user must be able to change it. + // For all other scenarios, we prefer to retain the current selected tenant if it is still valid. + const ignoreCurrentSelection = authScenario === AuthScenario.SignIn; + if (!ignoreCurrentSelection && currentSelectedTenant !== null) { + const isCurrentSelectedTenantValid = newTenants.some((t) => t.id === currentSelectedTenant.id); + if (isCurrentSelectedTenantValid) { + return currentSelectedTenant; + } + } + + // For sign-in, if there are multiple tenants, we should prompt the user to select one. + if (authScenario === AuthScenario.SignIn && newTenants.length > 1) { + return null; + } + + // For all other (non-interactive) scenarios, see if we can determine a default tenant to use. + const defaultTenant = await this.getDefaultTenantId(newTenants); + return defaultTenant; + } + + private async getDefaultTenantId(tenants: Tenant[]): Promise { + // Use the 'Initialization' scenario to ensure this is silent (no user interaction). + const getSessionPromises = tenants.map((t) => this.getArmSession(t.id, AuthScenario.Initialization)); + const results = await Promise.all(getSessionPromises); + const accessibleTenants = results.filter(succeeded).map((r) => r.result); + return accessibleTenants.length === 1 ? findTenant(tenants, accessibleTenants[0].tenantId) : null; + } + + private async getArmSession( + tenantId: string, + authScenario: AuthScenario, + ): Promise> { + this.handleSessionChanges = false; + try { + const tenantScopes = tenantId ? [`VSCODE_TENANT:${tenantId}`] : []; + const scopes = [getDefaultScope(getConfiguredAzureEnv().resourceManagerEndpointUrl), ...tenantScopes]; + + let options: AuthenticationGetSessionOptions; + let silentFirst = false; + switch (authScenario) { + case AuthScenario.Initialization: + options = { createIfNone: false, clearSessionPreference: false, silent: true }; + break; + case AuthScenario.SignIn: + options = { createIfNone: true, clearSessionPreference: true, silent: false }; + break; + case AuthScenario.GetSession: + // the 'createIfNone' option cannot be used with 'silent', but really we want both + // flags here (i.e. create a session silently, but do create one if it doesn't exist). + // To allow this, we first try to get a session silently. + silentFirst = true; + options = { createIfNone: true, clearSessionPreference: false, silent: false }; + break; + } + + let session: AuthenticationSession | undefined; + if (silentFirst) { + // The 'silent' option is incompatible with most other options, so we completely replace the options object here. + session = await authentication.getSession(getConfiguredAuthProviderId(), scopes, { silent: true }); + } + + if (!session) { + session = await authentication.getSession(getConfiguredAuthProviderId(), scopes, options); + } + + if (!session) { + return { succeeded: false, error: "No Azure session found." }; + } + + return { succeeded: true, result: Object.assign(session, { tenantId }) }; + } catch (e) { + return { succeeded: false, error: `Failed to retrieve Azure session: ${getErrorMessage(e)}` }; + } finally { + this.handleSessionChanges = true; + } + } +} + +function getConfiguredAuthProviderId(): AuthProviderId { + return getConfiguredAzureEnv().name === Environment.AzureCloud.name ? "microsoft" : "microsoft-sovereign-cloud"; +} + +async function getTenants(session: AuthenticationSession): Promise> { + const armEndpoint = getConfiguredAzureEnv().resourceManagerEndpointUrl; + const credential: TokenCredential = { + getToken: async () => { + return { token: session.accessToken, expiresOnTimestamp: 0 }; + }, + }; + const subscriptionClient = new SubscriptionClient(credential, { endpoint: armEndpoint }); + + const tenantsResult = await listAll(subscriptionClient.tenants.list()); + return errmap(tenantsResult, (t) => t.filter(asTenant).map((t) => ({ name: t.displayName, id: t.tenantId }))); +} + +function findTenant(tenants: Tenant[], tenantId: string): Tenant | null { + return tenants.find((t) => t.id === tenantId) || null; +} + +function asTenant(tenant: TenantIdDescription): tenant is { tenantId: string; displayName: string } { + return tenant.tenantId !== undefined && tenant.displayName !== undefined; +} + +function getIdString(tenants: Tenant[]): string { + return tenants + .map((t) => t.id) + .sort() + .join(","); +} diff --git a/src/auth/types.ts b/src/auth/types.ts new file mode 100644 index 00000000..d7662bd4 --- /dev/null +++ b/src/auth/types.ts @@ -0,0 +1,37 @@ +import { AuthenticationSession, Event } from "vscode"; +import { Errorable } from "../commands/utils/errorable"; + +export type SignInStatus = "Initializing" | "SigningIn" | "SignedIn" | "SignedOut"; + +export type TokenInfo = { + token: string; + expiry: Date; +}; + +export type AzureAuthenticationSession = AuthenticationSession & { + tenantId: string; +}; + +export type Tenant = { + name: string; + id: string; +}; + +export type AzureSessionProvider = { + signIn(): Promise; + signInStatus: SignInStatus; + availableTenants: Tenant[]; + selectedTenant: Tenant | null; + signInStatusChangeEvent: Event; + getAuthSession(): Promise>; + dispose(): void; +}; + +export type ReadyAzureSessionProvider = AzureSessionProvider & { + signInStatus: "SignedIn"; + selectedTenant: Tenant; +}; + +export function isReady(provider: AzureSessionProvider): provider is ReadyAzureSessionProvider { + return provider.signInStatus === "SignedIn" && provider.selectedTenant !== null; +} diff --git a/src/azure-api-utils.ts b/src/azure-api-utils.ts index 3354aac5..75bc8801 100644 --- a/src/azure-api-utils.ts +++ b/src/azure-api-utils.ts @@ -1,11 +1,7 @@ export function parseResource(armId: string): { resourceGroupName: string | undefined; name: string | undefined } { - const bits = armId.split("/"); - const resourceGroupName = bitAfter(bits, "resourceGroups"); + // /subscriptions/{subid}/resourcegroups/{group}/providers/.../{name} + const bits = armId.split("/").filter((bit) => bit.length > 0); + const resourceGroupName = bits[3]; const name = bits[bits.length - 1]; return { resourceGroupName, name }; } - -function bitAfter(bits: string[], after: string): string | undefined { - const afterIndex = bits.indexOf(after); - return bits[afterIndex + 1]; -} diff --git a/src/commands/aksAccount/aksAccount.ts b/src/commands/aksAccount/aksAccount.ts new file mode 100644 index 00000000..1c7109c5 --- /dev/null +++ b/src/commands/aksAccount/aksAccount.ts @@ -0,0 +1,99 @@ +import { QuickPickItem, Uri, env, window } from "vscode"; +import { failed } from "../utils/errorable"; +import { SubscriptionFilter, getFilteredSubscriptions, setFilteredSubscriptions } from "../utils/config"; +import { getSessionProvider } from "../../auth/azureSessionProvider"; +import { SelectionType, getSubscriptions } from "../utils/subscriptions"; +import { getReadySessionProvider, quickPickTenant } from "../../auth/azureAuth"; + +export async function signInToAzure(): Promise { + await getSessionProvider().signIn(); +} + +export async function selectTenant(): Promise { + const sessionProvider = getSessionProvider(); + if (sessionProvider.signInStatus !== "SignedIn") { + window.showInformationMessage("You must sign in before selecting a tenant."); + return; + } + + if (sessionProvider.availableTenants.length === 1) { + window.showInformationMessage(`Only one tenant available (${sessionProvider.availableTenants[0].name}).`); + return; + } + + const selectedTenant = await quickPickTenant(sessionProvider.availableTenants); + if (!selectedTenant) { + window.showInformationMessage("No tenant selected."); + return; + } + + sessionProvider.selectedTenant = selectedTenant; +} + +type SubscriptionQuickPickItem = QuickPickItem & { subscription: SubscriptionFilter }; + +export async function selectSubscriptions(): Promise { + const sessionProvider = await getReadySessionProvider(); + if (failed(sessionProvider)) { + window.showErrorMessage(sessionProvider.error); + return; + } + + const allSubscriptions = await getSubscriptions(sessionProvider.result, SelectionType.All); + if (failed(allSubscriptions)) { + window.showErrorMessage(allSubscriptions.error); + return; + } + + if (allSubscriptions.result.length === 0) { + const noSubscriptionsFound = "No subscriptions were found. Set up your account if you have yet to do so."; + const setupAccount = "Set up Account"; + const response = await window.showInformationMessage(noSubscriptionsFound, setupAccount); + if (response === setupAccount) { + env.openExternal(Uri.parse("https://azure.microsoft.com/")); + } + + return; + } + + const session = await sessionProvider.result.getAuthSession(); + if (failed(session)) { + window.showErrorMessage(session.error); + return; + } + + const filteredSubscriptions = await getFilteredSubscriptions(); + + const subscriptionsInCurrentTenant = filteredSubscriptions.filter( + (sub) => sub.tenantId === session.result.tenantId, + ); + const subscriptionsInOtherTenants = filteredSubscriptions.filter((sub) => sub.tenantId !== session.result.tenantId); + + const quickPickItems: SubscriptionQuickPickItem[] = allSubscriptions.result.map((sub) => { + return { + label: sub.displayName || "", + description: sub.subscriptionId, + picked: subscriptionsInCurrentTenant.some((filtered) => filtered.subscriptionId === sub.subscriptionId), + subscription: { + subscriptionId: sub.subscriptionId || "", + tenantId: sub.tenantId || "", + }, + }; + }); + + const selectedItems = await window.showQuickPick(quickPickItems, { + canPickMany: true, + placeHolder: "Select Subscriptions", + }); + + if (!selectedItems) { + return; + } + + const newFilteredSubscriptions = [ + ...selectedItems.map((item) => item.subscription), + ...subscriptionsInOtherTenants, // Retain filters in any other tenants. + ]; + + await setFilteredSubscriptions(newFilteredSubscriptions); +} diff --git a/src/commands/aksClusterProperties/aksClusterProperties.ts b/src/commands/aksClusterProperties/aksClusterProperties.ts index f8c39b38..d5f4c0b8 100644 --- a/src/commands/aksClusterProperties/aksClusterProperties.ts +++ b/src/commands/aksClusterProperties/aksClusterProperties.ts @@ -1,13 +1,19 @@ import * as vscode from "vscode"; import * as k8s from "vscode-kubernetes-tools-api"; import { IActionContext } from "@microsoft/vscode-azext-utils"; -import { getAksClusterTreeNode, getContainerClient } from "../utils/clusters"; +import { getAksClusterTreeNode } from "../utils/clusters"; import { getExtension } from "../utils/host"; import { failed } from "../utils/errorable"; import { ClusterPropertiesDataProvider, ClusterPropertiesPanel } from "../../panels/ClusterPropertiesPanel"; +import { getReadySessionProvider } from "../../auth/azureAuth"; export default async function aksClusterProperties(_context: IActionContext, target: unknown): Promise { const cloudExplorer = await k8s.extension.cloudExplorer.v1; + const sessionProvider = await getReadySessionProvider(); + if (failed(sessionProvider)) { + vscode.window.showErrorMessage(sessionProvider.error); + return; + } const clusterNode = getAksClusterTreeNode(target, cloudExplorer); if (failed(clusterNode)) { @@ -21,9 +27,9 @@ export default async function aksClusterProperties(_context: IActionContext, tar return; } - const client = getContainerClient(clusterNode.result); const dataProvider = new ClusterPropertiesDataProvider( - client, + sessionProvider.result, + clusterNode.result.subscriptionId, clusterNode.result.resourceGroupName, clusterNode.result.name, ); diff --git a/src/commands/aksCompareCluster/aksCompareCluster.ts b/src/commands/aksCompareCluster/aksCompareCluster.ts index 78e365d2..f80f163a 100644 --- a/src/commands/aksCompareCluster/aksCompareCluster.ts +++ b/src/commands/aksCompareCluster/aksCompareCluster.ts @@ -1,7 +1,7 @@ import { QuickPickItem } from "vscode"; import { createQuickPickStep, runMultiStepInput } from "../utils/multiStepHelper"; import { IActionContext } from "@microsoft/vscode-azext-utils"; -import { getAksClusterSubscriptionNode, getContainerClient, getResourceManagementClient } from "../utils/clusters"; +import { getAksClusterSubscriptionNode } from "../utils/clusters"; import { failed } from "../utils/errorable"; import * as vscode from "vscode"; import * as k8s from "vscode-kubernetes-tools-api"; @@ -10,6 +10,9 @@ import { getExtension } from "../utils/host"; import * as tmpfile from "../utils/tempfile"; import { longRunning } from "../utils/host"; import { ManagedCluster } from "@azure/arm-containerservice"; +import { getAksClient, getResourceManagementClient } from "../utils/arm"; +import { ReadyAzureSessionProvider } from "../../auth/types"; +import { getReadySessionProvider } from "../../auth/azureAuth"; interface State { clusterGroupCompareFrom: ClusterNameItem; @@ -43,14 +46,23 @@ export default async function aksCompareCluster(_context: IActionContext, target vscode.window.showErrorMessage(extension.error); return; } - const containerServiceClient = getContainerClient(subscriptionNode.result); + + const sessionProvider = await getReadySessionProvider(); + if (failed(sessionProvider)) { + vscode.window.showErrorMessage(sessionProvider.error); + return; + } + + const containerServiceClient = getAksClient(sessionProvider.result, subscriptionNode.result.subscriptionId); const clusterList: ManagedCluster[] = []; await longRunning(`Getting AKS Cluster list for ${subscriptionNode.result.name}`, async () => { const iterator = containerServiceClient.managedClusters.list(); for await (const clusters of iterator.byPage()) { const validClusters = clusters.filter((c) => c.id && c.name); - clusterList.push(...validClusters.map((c) => ({ label: c.name!, name: c.name!, id: c.id!, location: c.location! }))); + clusterList.push( + ...validClusters.map((c) => ({ label: c.name!, name: c.name!, id: c.id!, location: c.location! })), + ); } }); @@ -73,7 +85,7 @@ export default async function aksCompareCluster(_context: IActionContext, target }); const initialState: Partial = { - subid: subscriptionNode.result.subscription.subscriptionId, + subid: subscriptionNode.result.subscriptionId, }; const state = await runMultiStepInput( @@ -88,17 +100,21 @@ export default async function aksCompareCluster(_context: IActionContext, target } // Call compare cluster at this instance - await compareManagedCluster(state, subscriptionNode.result); + await compareManagedCluster(sessionProvider.result, state, subscriptionNode.result); } async function compareManagedCluster( + sessionProvider: ReadyAzureSessionProvider, state: State, subscriptionNode: SubscriptionTreeNode, ) { await longRunning( `Comparing AKS Cluster ${state.clusterGroupCompareWith.name} with ${state.clusterGroupCompareFrom.name}`, async () => { - const resourceManagementClient = getResourceManagementClient(subscriptionNode); + const resourceManagementClient = getResourceManagementClient( + sessionProvider, + subscriptionNode.subscriptionId, + ); const resourceArmIDWith = state.clusterGroupCompareWith.armid; const resourceArmIDFrom = state.clusterGroupCompareFrom.armid; diff --git a/src/commands/aksCreateCluster/aksCreateCluster.ts b/src/commands/aksCreateCluster/aksCreateCluster.ts index 1890ab54..de310791 100644 --- a/src/commands/aksCreateCluster/aksCreateCluster.ts +++ b/src/commands/aksCreateCluster/aksCreateCluster.ts @@ -1,10 +1,11 @@ import { IActionContext } from "@microsoft/vscode-azext-utils"; -import { getAksClusterSubscriptionNode, getContainerClient, getResourceManagementClient } from "../utils/clusters"; +import { getAksClusterSubscriptionNode } from "../utils/clusters"; import { failed } from "../utils/errorable"; import * as vscode from "vscode"; import * as k8s from "vscode-kubernetes-tools-api"; import { getExtension } from "../utils/host"; import { CreateClusterDataProvider, CreateClusterPanel } from "../../panels/CreateClusterPanel"; +import { getReadySessionProvider } from "../../auth/azureAuth"; /** * A multi-step input using window.createQuickPick() and window.createInputBox(). @@ -14,6 +15,12 @@ import { CreateClusterDataProvider, CreateClusterPanel } from "../../panels/Crea export default async function aksCreateCluster(_context: IActionContext, target: unknown): Promise { const cloudExplorer = await k8s.extension.cloudExplorer.v1; + const sessionProvider = await getReadySessionProvider(); + if (failed(sessionProvider)) { + vscode.window.showErrorMessage(sessionProvider.error); + return; + } + const subscriptionNode = getAksClusterSubscriptionNode(target, cloudExplorer); if (failed(subscriptionNode)) { vscode.window.showErrorMessage(subscriptionNode.error); @@ -28,12 +35,10 @@ export default async function aksCreateCluster(_context: IActionContext, target: const panel = new CreateClusterPanel(extension.result.extensionUri); - const resourceManagementClient = getResourceManagementClient(subscriptionNode.result); - const containerServiceClient = getContainerClient(subscriptionNode.result); const dataProvider = new CreateClusterDataProvider( - resourceManagementClient, - containerServiceClient, - subscriptionNode.result.subscription, + sessionProvider.result, + subscriptionNode.result.subscriptionId, + subscriptionNode.result.name, () => vscode.commands.executeCommand("aks.refreshSubscription", target), ); diff --git a/src/commands/aksDeleteCluster/aksDeleteCluster.ts b/src/commands/aksDeleteCluster/aksDeleteCluster.ts index 30860d58..cf4b83f7 100644 --- a/src/commands/aksDeleteCluster/aksDeleteCluster.ts +++ b/src/commands/aksDeleteCluster/aksDeleteCluster.ts @@ -4,12 +4,19 @@ import { IActionContext } from "@microsoft/vscode-azext-utils"; import { deleteCluster, getAksClusterTreeNode } from "../utils/clusters"; import { failed, succeeded } from "../utils/errorable"; import { longRunning } from "../utils/host"; +import { getReadySessionProvider } from "../../auth/azureAuth"; const refreshIntervals = [1, 2, 5, 10, 30, 60, 120]; export default async function aksDeleteCluster(_context: IActionContext, target: unknown): Promise { const cloudExplorer = await k8s.extension.cloudExplorer.v1; + const sessionProvider = await getReadySessionProvider(); + if (failed(sessionProvider)) { + vscode.window.showErrorMessage(sessionProvider.error); + return; + } + const clusterNode = getAksClusterTreeNode(target, cloudExplorer); if (failed(clusterNode)) { vscode.window.showErrorMessage(clusterNode.error); @@ -26,7 +33,12 @@ export default async function aksDeleteCluster(_context: IActionContext, target: if (answer === "Yes") { const result = await longRunning(`Deleting cluster ${clusterName}.`, async () => { - return await deleteCluster(clusterNode.result, clusterName); + return await deleteCluster( + sessionProvider.result, + clusterNode.result.subscriptionId, + clusterNode.result.resourceGroupName, + clusterName, + ); }); if (failed(result)) { diff --git a/src/commands/aksEraserTool/erasertool.ts b/src/commands/aksEraserTool/erasertool.ts index 84168f55..3ce1d36b 100644 --- a/src/commands/aksEraserTool/erasertool.ts +++ b/src/commands/aksEraserTool/erasertool.ts @@ -6,13 +6,19 @@ import { Errorable, failed, succeeded } from "../utils/errorable"; import { longRunning } from "../utils/host"; import { invokeKubectlCommand } from "../utils/kubectl"; import * as tmpfile from "../utils/tempfile"; - +import { getReadySessionProvider } from "../../auth/azureAuth"; export default async function aksEraserTool(_context: IActionContext, target: unknown): Promise { const kubectl = await k8s.extension.kubectl.v1; const cloudExplorer = await k8s.extension.cloudExplorer.v1; const clusterExplorer = await k8s.extension.clusterExplorer.v1; + const sessionProvider = await getReadySessionProvider(); + if (failed(sessionProvider)) { + vscode.window.showErrorMessage(sessionProvider.error); + return; + } + if (!kubectl.available) { vscode.window.showWarningMessage(`Kubectl is unavailable.`); return; @@ -28,12 +34,12 @@ export default async function aksEraserTool(_context: IActionContext, target: un return; } - const clusterInfo = await getKubernetesClusterInfo(target, cloudExplorer, clusterExplorer); + const clusterInfo = await getKubernetesClusterInfo(sessionProvider.result, target, cloudExplorer, clusterExplorer); if (failed(clusterInfo)) { vscode.window.showErrorMessage(clusterInfo.error); return; } - + const clusterName = clusterInfo.result.name; const answer = await vscode.window.showInformationMessage( @@ -52,7 +58,9 @@ export default async function aksEraserTool(_context: IActionContext, target: un } if (succeeded(result)) { - vscode.window.showInformationMessage(`Eraser tool is successfully deployed into cluster ${clusterName}. \n Output: \n ${result.result.stdout}`); + vscode.window.showInformationMessage( + `Eraser tool is successfully deployed into cluster ${clusterName}. \n Output: \n ${result.result.stdout}`, + ); } } } @@ -74,10 +82,14 @@ async function deployEraserAutomaticInstallationScenario( if (failed(deleteResult)) return deleteResult; // Deploy eraser tool: https://eraser-dev.github.io/eraser/docs/installation - const applyResult = await invokeKubectlCommand(kubectl, kubeConfigFile, `apply -f https://raw.githubusercontent.com/eraser-dev/eraser/v1.2.0/deploy/eraser.yaml`); + const applyResult = await invokeKubectlCommand( + kubectl, + kubeConfigFile, + `apply -f https://raw.githubusercontent.com/eraser-dev/eraser/v1.2.0/deploy/eraser.yaml`, + ); if (failed(applyResult)) return applyResult; return applyResult; }, ); -} \ No newline at end of file +} diff --git a/src/commands/aksInspektorGadget/aksInspektorGadget.ts b/src/commands/aksInspektorGadget/aksInspektorGadget.ts index 81ef500e..a0c04470 100644 --- a/src/commands/aksInspektorGadget/aksInspektorGadget.ts +++ b/src/commands/aksInspektorGadget/aksInspektorGadget.ts @@ -11,12 +11,19 @@ import { InspektorGadgetDataProvider, InspektorGadgetPanel } from "../../panels/ import { KubectlClusterOperations } from "./clusterOperations"; import { TraceWatcher } from "./traceWatcher"; import { ensureDirectoryInPath } from "../utils/env"; +import { getReadySessionProvider } from "../../auth/azureAuth"; export async function aksInspektorGadgetShow(_context: IActionContext, target: unknown): Promise { const kubectl = await k8s.extension.kubectl.v1; const cloudExplorer = await k8s.extension.cloudExplorer.v1; const clusterExplorer = await k8s.extension.clusterExplorer.v1; + const sessionProvider = await getReadySessionProvider(); + if (failed(sessionProvider)) { + vscode.window.showErrorMessage(sessionProvider.error); + return; + } + if (!kubectl.available) { vscode.window.showWarningMessage(`Kubectl is unavailable.`); return; @@ -32,7 +39,7 @@ export async function aksInspektorGadgetShow(_context: IActionContext, target: u return; } - const clusterInfo = await getKubernetesClusterInfo(target, cloudExplorer, clusterExplorer); + const clusterInfo = await getKubernetesClusterInfo(sessionProvider.result, target, cloudExplorer, clusterExplorer); if (failed(clusterInfo)) { vscode.window.showErrorMessage(clusterInfo.error); return; diff --git a/src/commands/aksKubectlCommands/aksKubectlCommands.ts b/src/commands/aksKubectlCommands/aksKubectlCommands.ts index 971f50f1..c530f6ac 100644 --- a/src/commands/aksKubectlCommands/aksKubectlCommands.ts +++ b/src/commands/aksKubectlCommands/aksKubectlCommands.ts @@ -7,12 +7,19 @@ import { failed } from "../utils/errorable"; import * as tmpfile from "../utils/tempfile"; import { KubectlDataProvider, KubectlPanel } from "../../panels/KubectlPanel"; import { getKubectlCustomCommands } from "../utils/config"; +import { getReadySessionProvider } from "../../auth/azureAuth"; export async function aksRunKubectlCommands(_context: IActionContext, target: unknown) { const kubectl = await k8s.extension.kubectl.v1; const cloudExplorer = await k8s.extension.cloudExplorer.v1; const clusterExplorer = await k8s.extension.clusterExplorer.v1; + const sessionProvider = await getReadySessionProvider(); + if (failed(sessionProvider)) { + vscode.window.showErrorMessage(sessionProvider.error); + return; + } + if (!kubectl.available) { vscode.window.showWarningMessage(`Kubectl is unavailable.`); return; @@ -28,7 +35,7 @@ export async function aksRunKubectlCommands(_context: IActionContext, target: un return; } - const clusterInfo = await getKubernetesClusterInfo(target, cloudExplorer, clusterExplorer); + const clusterInfo = await getKubernetesClusterInfo(sessionProvider.result, target, cloudExplorer, clusterExplorer); if (failed(clusterInfo)) { vscode.window.showErrorMessage(clusterInfo.error); return; diff --git a/src/commands/aksNavToPortal/aksNavToPortal.ts b/src/commands/aksNavToPortal/aksNavToPortal.ts index 06e64bd1..8be53b80 100644 --- a/src/commands/aksNavToPortal/aksNavToPortal.ts +++ b/src/commands/aksNavToPortal/aksNavToPortal.ts @@ -5,6 +5,7 @@ import { getAksClusterTreeNode } from "../utils/clusters"; import { getExtensionPath } from "../utils/host"; import { failed } from "../utils/errorable"; import { getPortalResourceUrl } from "../utils/env"; +import { getEnvironment } from "../../auth/azureAuth"; export default async function aksNavToPortal(_context: IActionContext, target: unknown): Promise { const cloudExplorer = await k8s.extension.cloudExplorer.v1; @@ -22,6 +23,6 @@ export default async function aksNavToPortal(_context: IActionContext, target: u } // armid is in the format: /subscriptions//resourceGroups//providers//managedClusters/ - const resourceUrl = getPortalResourceUrl(clusterNode.result.subscription.environment, clusterNode.result.armId); + const resourceUrl = getPortalResourceUrl(getEnvironment(), clusterNode.result.armId); vscode.env.openExternal(vscode.Uri.parse(resourceUrl)); } diff --git a/src/commands/aksReconcileCluster/aksReconcileCluster.ts b/src/commands/aksReconcileCluster/aksReconcileCluster.ts index bd4735ff..0099a47a 100644 --- a/src/commands/aksReconcileCluster/aksReconcileCluster.ts +++ b/src/commands/aksReconcileCluster/aksReconcileCluster.ts @@ -4,10 +4,16 @@ import { IActionContext } from "@microsoft/vscode-azext-utils"; import { reconcileUsingUpdateInCluster, getAksClusterTreeNode } from "../utils/clusters"; import { failed, succeeded } from "../utils/errorable"; import { longRunning } from "../utils/host"; +import { getReadySessionProvider } from "../../auth/azureAuth"; export default async function aksReconcileCluster(_context: IActionContext, target: unknown): Promise { const cloudExplorer = await k8s.extension.cloudExplorer.v1; + const sessionProvider = await getReadySessionProvider(); + if (failed(sessionProvider)) { + vscode.window.showErrorMessage(sessionProvider.error); + return; + } const clusterNode = getAksClusterTreeNode(target, cloudExplorer); if (failed(clusterNode)) { vscode.window.showErrorMessage(clusterNode.error); @@ -24,7 +30,12 @@ export default async function aksReconcileCluster(_context: IActionContext, targ if (answer === "Yes") { const result = await longRunning(`Reconciling/update last cluster operation in ${clusterName}.`, async () => { - return await reconcileUsingUpdateInCluster(clusterNode.result); + return await reconcileUsingUpdateInCluster( + sessionProvider.result, + clusterNode.result.subscriptionId, + clusterNode.result.resourceGroupName, + clusterName, + ); }); if (failed(result)) { diff --git a/src/commands/aksRetinaCapture/aksRetinaCapture.ts b/src/commands/aksRetinaCapture/aksRetinaCapture.ts index 04dff657..4f1ab10f 100644 --- a/src/commands/aksRetinaCapture/aksRetinaCapture.ts +++ b/src/commands/aksRetinaCapture/aksRetinaCapture.ts @@ -11,12 +11,19 @@ import { getVersion, invokeKubectlCommand } from "../utils/kubectl"; import { RetinaCapturePanel, RetinaCaptureProvider } from "../../panels/RetinaCapturePanel"; import { failed } from "../utils/errorable"; import { getLinuxNodes } from "../../panels/utilities/KubectlNetworkHelper"; +import { getReadySessionProvider } from "../../auth/azureAuth"; export async function aksRetinaCapture(_context: IActionContext, target: unknown): Promise { const kubectl = await k8s.extension.kubectl.v1; const cloudExplorer = await k8s.extension.cloudExplorer.v1; const clusterExplorer = await k8s.extension.clusterExplorer.v1; + const sessionProvider = await getReadySessionProvider(); + if (failed(sessionProvider)) { + vscode.window.showErrorMessage(sessionProvider.error); + return; + } + if (!kubectl.available) { vscode.window.showWarningMessage(`Kubectl is unavailable.`); return; @@ -32,7 +39,7 @@ export async function aksRetinaCapture(_context: IActionContext, target: unknown return; } - const clusterInfo = await getKubernetesClusterInfo(target, cloudExplorer, clusterExplorer); + const clusterInfo = await getKubernetesClusterInfo(sessionProvider.result, target, cloudExplorer, clusterExplorer); if (failed(clusterInfo)) { vscode.window.showErrorMessage(clusterInfo.error); return; @@ -68,7 +75,7 @@ export async function aksRetinaCapture(_context: IActionContext, target: unknown }); if (!nodeNamesSelected) { - vscode.window.showErrorMessage('No nodes were selected to capture traffic.'); + vscode.window.showErrorMessage("No nodes were selected to capture traffic."); return; } @@ -80,13 +87,16 @@ export async function aksRetinaCapture(_context: IActionContext, target: unknown // Retina Run Capture const capturename = `retina-capture-${clusterInfo.result.name.toLowerCase()}`; - const retinaCaptureResult = await longRunning(`Retina Distributed Capture running for cluster ${clusterInfo.result.name}.`, async () => { - return await invokeKubectlCommand( - kubectl, - kubeConfigFile.filePath, - `retina capture create --namespace default --name ${capturename} --host-path /mnt/capture --node-selectors "kubernetes.io/os=linux" --node-names "${selectedNodes}" --no-wait=false`, - ) - }); + const retinaCaptureResult = await longRunning( + `Retina Distributed Capture running for cluster ${clusterInfo.result.name}.`, + async () => { + return await invokeKubectlCommand( + kubectl, + kubeConfigFile.filePath, + `retina capture create --namespace default --name ${capturename} --host-path /mnt/capture --node-selectors "kubernetes.io/os=linux" --node-names "${selectedNodes}" --no-wait=false`, + ); + }, + ); if (failed(retinaCaptureResult)) { vscode.window.showErrorMessage(`Failed to capture the cluster: ${retinaCaptureResult.error}`); @@ -94,7 +104,9 @@ export async function aksRetinaCapture(_context: IActionContext, target: unknown } if (retinaCaptureResult.result.stdout && retinaCaptureResult.result.code === 0) { - vscode.window.showInformationMessage(`Retina distributed capture is successfully completed for the cluster ${clusterInfo.result.name}`); + vscode.window.showInformationMessage( + `Retina distributed capture is successfully completed for the cluster ${clusterInfo.result.name}`, + ); } const kubectlVersion = await getVersion(kubectl, kubeConfigFile.filePath); @@ -103,9 +115,9 @@ export async function aksRetinaCapture(_context: IActionContext, target: unknown return; } - const foldername = `${capturename}_${(new Date().toJSON().replaceAll(":", ""))}`; + const foldername = `${capturename}_${new Date().toJSON().replaceAll(":", "")}`; - // find if node explorer pod is already exists + // find if node explorer pod is already exists let nodeExplorerPodExists = false; const nodeExplorerPod = await invokeKubectlCommand( kubectl, @@ -113,12 +125,14 @@ export async function aksRetinaCapture(_context: IActionContext, target: unknown `get pods -n default -l app=node-explorer`, ); - - if (nodeExplorerPod.succeeded && nodeExplorerPod.result.stdout && nodeExplorerPod.result.stdout.includes("node-explorer")) { + if ( + nodeExplorerPod.succeeded && + nodeExplorerPod.result.stdout && + nodeExplorerPod.result.stdout.includes("node-explorer") + ) { nodeExplorerPodExists = true; } - const dataProvider = new RetinaCaptureProvider( kubectl, kubectlVersion.result, diff --git a/src/commands/aksRotateClusterCert/aksRotateClusterCert.ts b/src/commands/aksRotateClusterCert/aksRotateClusterCert.ts index 490cb570..dc2b06d6 100644 --- a/src/commands/aksRotateClusterCert/aksRotateClusterCert.ts +++ b/src/commands/aksRotateClusterCert/aksRotateClusterCert.ts @@ -4,10 +4,17 @@ import { IActionContext } from "@microsoft/vscode-azext-utils"; import { getAksClusterTreeNode, rotateClusterCert } from "../utils/clusters"; import { failed, succeeded } from "../utils/errorable"; import { longRunning } from "../utils/host"; +import { getReadySessionProvider } from "../../auth/azureAuth"; export default async function aksRotateClusterCert(_context: IActionContext, target: unknown): Promise { const cloudExplorer = await k8s.extension.cloudExplorer.v1; + const sessionProvider = await getReadySessionProvider(); + if (failed(sessionProvider)) { + vscode.window.showErrorMessage(sessionProvider.error); + return; + } + const clusterNode = getAksClusterTreeNode(target, cloudExplorer); if (failed(clusterNode)) { vscode.window.showErrorMessage(clusterNode.error); @@ -28,7 +35,12 @@ export default async function aksRotateClusterCert(_context: IActionContext, tar if (answer === "Yes") { const result = await longRunning(`Rotating cluster certificate for ${clusterName}.`, async () => - rotateClusterCert(clusterNode.result), + rotateClusterCert( + sessionProvider.result, + clusterNode.result.subscriptionId, + clusterNode.result.resourceGroupName, + clusterName, + ), ); if (failed(result)) { diff --git a/src/commands/aksTCPCollection/tcpDumpCollection.ts b/src/commands/aksTCPCollection/tcpDumpCollection.ts index 063ca05c..cecb98df 100644 --- a/src/commands/aksTCPCollection/tcpDumpCollection.ts +++ b/src/commands/aksTCPCollection/tcpDumpCollection.ts @@ -8,12 +8,18 @@ import * as tmpfile from "../utils/tempfile"; import { TcpDumpDataProvider, TcpDumpPanel } from "../../panels/TcpDumpPanel"; import { getVersion } from "../utils/kubectl"; import { getLinuxNodes } from "../../panels/utilities/KubectlNetworkHelper"; +import { getReadySessionProvider } from "../../auth/azureAuth"; export async function aksTCPDump(_context: IActionContext, target: unknown) { const kubectl = await k8s.extension.kubectl.v1; const cloudExplorer = await k8s.extension.cloudExplorer.v1; const clusterExplorer = await k8s.extension.clusterExplorer.v1; + const sessionProvider = await getReadySessionProvider(); + if (failed(sessionProvider)) { + vscode.window.showErrorMessage(sessionProvider.error); + return; + } if (!kubectl.available) { vscode.window.showWarningMessage(`Kubectl is unavailable.`); return; @@ -29,7 +35,7 @@ export async function aksTCPDump(_context: IActionContext, target: unknown) { return; } - const clusterInfo = await getKubernetesClusterInfo(target, cloudExplorer, clusterExplorer); + const clusterInfo = await getKubernetesClusterInfo(sessionProvider.result, target, cloudExplorer, clusterExplorer); if (failed(clusterInfo)) { vscode.window.showErrorMessage(clusterInfo.error); return; diff --git a/src/commands/azureServiceOperators/installAzureServiceOperator.ts b/src/commands/azureServiceOperators/installAzureServiceOperator.ts index 3a3e6e1c..22756a24 100644 --- a/src/commands/azureServiceOperators/installAzureServiceOperator.ts +++ b/src/commands/azureServiceOperators/installAzureServiceOperator.ts @@ -4,15 +4,21 @@ import { IActionContext } from "@microsoft/vscode-azext-utils"; import { getKubernetesClusterInfo } from "../utils/clusters"; import { getExtension } from "../utils/host"; import { failed } from "../utils/errorable"; -import { getAzureAccountExtensionApi } from "../utils/azureAccount"; import { createTempFile } from "../utils/tempfile"; import { AzureServiceOperatorDataProvider, AzureServiceOperatorPanel } from "../../panels/AzureServiceOperatorPanel"; +import { getReadySessionProvider } from "../../auth/azureAuth"; export default async function installAzureServiceOperator(_context: IActionContext, target: unknown): Promise { const kubectl = await k8s.extension.kubectl.v1; const cloudExplorer = await k8s.extension.cloudExplorer.v1; const clusterExplorer = await k8s.extension.clusterExplorer.v1; + const sessionProvider = await getReadySessionProvider(); + if (failed(sessionProvider)) { + vscode.window.showErrorMessage(sessionProvider.error); + return; + } + if (!kubectl.available) { vscode.window.showWarningMessage(`Kubectl is unavailable.`); return undefined; @@ -28,13 +34,7 @@ export default async function installAzureServiceOperator(_context: IActionConte return undefined; } - const azureAccountApi = getAzureAccountExtensionApi(); - if (failed(azureAccountApi)) { - vscode.window.showErrorMessage(azureAccountApi.error); - return undefined; - } - - const clusterInfo = await getKubernetesClusterInfo(target, cloudExplorer, clusterExplorer); + const clusterInfo = await getKubernetesClusterInfo(sessionProvider.result, target, cloudExplorer, clusterExplorer); if (failed(clusterInfo)) { vscode.window.showErrorMessage(clusterInfo.error); return undefined; @@ -48,10 +48,10 @@ export default async function installAzureServiceOperator(_context: IActionConte const kubeConfigFile = await createTempFile(clusterInfo.result.kubeconfigYaml, "yaml"); const dataProvider = new AzureServiceOperatorDataProvider( + sessionProvider.result, extension.result, kubectl, kubeConfigFile.filePath, - azureAccountApi.result, clusterInfo.result.name, ); const panel = new AzureServiceOperatorPanel(extension.result.extensionUri); diff --git a/src/commands/detectors/detectors.ts b/src/commands/detectors/detectors.ts index 605e7486..255727bf 100644 --- a/src/commands/detectors/detectors.ts +++ b/src/commands/detectors/detectors.ts @@ -7,6 +7,8 @@ import { getDetectorInfo, getDetectorListData } from "../utils/detectors"; import { Errorable, failed } from "../utils/errorable"; import { AksClusterTreeNode } from "../../tree/aksClusterTreeItem"; import { DetectorDataProvider, DetectorPanel } from "../../panels/DetectorPanel"; +import { getEnvironment, getReadySessionProvider } from "../../auth/azureAuth"; +import { ReadyAzureSessionProvider } from "../../auth/types"; export function aksBestPracticesDiagnostics(_context: IActionContext, target: unknown): Promise { return runDetector(target, "aks-category-risk-assessment"); @@ -50,9 +52,15 @@ async function runDetector(commandTarget: unknown, categoryDetectorName: string) return; } + const sessionProvider = await getReadySessionProvider(); + if (failed(sessionProvider)) { + vscode.window.showErrorMessage(sessionProvider.error); + return; + } + const clustername = clusterNode.result.name; const dataProvider = await longRunning(`Loading ${clustername} diagnostics.`, () => - getDataProvider(clusterNode.result, categoryDetectorName), + getDataProvider(sessionProvider.result, clusterNode.result, categoryDetectorName), ); if (failed(dataProvider)) { @@ -65,21 +73,22 @@ async function runDetector(commandTarget: unknown, categoryDetectorName: string) } async function getDataProvider( + sessionProvider: ReadyAzureSessionProvider, clusterNode: AksClusterTreeNode, categoryDetectorName: string, ): Promise> { - const detectorInfo = await getDetectorInfo(clusterNode, categoryDetectorName); + const detectorInfo = await getDetectorInfo(sessionProvider, clusterNode, categoryDetectorName); if (failed(detectorInfo)) { return detectorInfo; } - const detectors = await getDetectorListData(clusterNode, detectorInfo.result); + const detectors = await getDetectorListData(sessionProvider, clusterNode, detectorInfo.result); if (failed(detectors)) { return detectors; } const dataProvider = new DetectorDataProvider( - clusterNode.subscription.environment, + getEnvironment(), clusterNode.name, detectorInfo.result, detectors.result, diff --git a/src/commands/periscope/helpers/periscopehelper.ts b/src/commands/periscope/helpers/periscopehelper.ts index c2d14c7c..4140baf2 100644 --- a/src/commands/periscope/helpers/periscopehelper.ts +++ b/src/commands/periscope/helpers/periscopehelper.ts @@ -2,9 +2,8 @@ import * as vscode from "vscode"; import * as k8s from "vscode-kubernetes-tools-api"; import { getSASKey, LinkDuration } from "../../utils/azurestorage"; import { parseResource } from "../../../azure-api-utils"; -import { StorageManagementClient } from "@azure/arm-storage"; import { PeriscopeStorage, PodLogs, UploadStatus } from "../models/storage"; -import { MonitorClient, DiagnosticSettingsResourceCollection } from "@azure/arm-monitor"; +import { DiagnosticSettingsResourceCollection } from "@azure/arm-monitor"; import * as path from "path"; import * as fs from "fs"; import * as semver from "semver"; @@ -18,17 +17,17 @@ import { ContainerServiceClient } from "@azure/arm-containerservice"; import { getWindowsNodePoolKubernetesVersions } from "../../utils/clusters"; import { BlobServiceClient, StorageSharedKeyCredential } from "@azure/storage-blob"; import { dirSync } from "tmp"; +import { getMonitorClient, getStorageManagementClient } from "../../utils/arm"; +import { ReadyAzureSessionProvider } from "../../../auth/types"; export async function getClusterDiagnosticSettings( + sessionProvider: ReadyAzureSessionProvider, clusterNode: AksClusterTreeNode, ): Promise { try { - // Get daignostic setting via diagnostic monitor - const diagnosticMonitor = new MonitorClient( - clusterNode.subscription.credentials, - clusterNode.subscription.subscriptionId, - ); - const diagnosticSettings = await diagnosticMonitor.diagnosticSettings.list(clusterNode.armId); + // Get diagnostic setting via diagnostic monitor + const client = getMonitorClient(sessionProvider, clusterNode.subscriptionId); + const diagnosticSettings = await client.diagnosticSettings.list(clusterNode.armId); return diagnosticSettings; } catch (e) { @@ -81,6 +80,7 @@ export async function chooseStorageAccount( } export async function getStorageInfo( + sessionProvider: ReadyAzureSessionProvider, kubectl: k8s.APIAvailable, clusterNode: AksClusterTreeNode, diagnosticStorageAccountId: string, @@ -97,10 +97,7 @@ export async function getStorageInfo( } // Get keys from storage client. - const storageClient = new StorageManagementClient( - clusterNode.subscription.credentials, - clusterNode.subscription.subscriptionId, - ); + const storageClient = getStorageManagementClient(sessionProvider, clusterNode.subscriptionId); const storageAccKeyList = await storageClient.storageAccounts.listKeys(resourceGroupName, accountName); if (storageAccKeyList.keys === undefined) { return { succeeded: false, error: "No keys found for storage account." }; diff --git a/src/commands/periscope/periscope.ts b/src/commands/periscope/periscope.ts index f09ca423..d811cd0e 100644 --- a/src/commands/periscope/periscope.ts +++ b/src/commands/periscope/periscope.ts @@ -2,7 +2,7 @@ import * as vscode from "vscode"; import * as k8s from "vscode-kubernetes-tools-api"; import { IActionContext } from "@microsoft/vscode-azext-utils"; import * as tmpfile from "../utils/tempfile"; -import { getAksClusterTreeNode, getClusterProperties, getContainerClient, getKubeconfigYaml } from "../utils/clusters"; +import { getAksClusterTreeNode, getKubeconfigYaml, getManagedCluster } from "../utils/clusters"; import { getKustomizeConfig } from "../utils/config"; import { getExtension, longRunning } from "../utils/host"; import { @@ -17,6 +17,8 @@ import { AksClusterTreeNode } from "../../tree/aksClusterTreeItem"; import { Errorable, failed } from "../utils/errorable"; import { invokeKubectlCommand } from "../utils/kubectl"; import { PeriscopeDataProvider, PeriscopePanel } from "../../panels/PeriscopePanel"; +import { getAksClient } from "../utils/arm"; +import { getEnvironment, getReadySessionProvider } from "../../auth/azureAuth"; export default async function periscope(_context: IActionContext, target: unknown): Promise { const kubectl = await k8s.extension.kubectl.v1; @@ -24,6 +26,12 @@ export default async function periscope(_context: IActionContext, target: unknow return; } + const sessionProvider = await getReadySessionProvider(); + if (failed(sessionProvider)) { + vscode.window.showErrorMessage(sessionProvider.error); + return; + } + const cloudExplorer = await k8s.extension.cloudExplorer.v1; const clusterNode = getAksClusterTreeNode(target, cloudExplorer); @@ -34,14 +42,19 @@ export default async function periscope(_context: IActionContext, target: unknow // Once Periscope will support usgov endpoints all we need is to remove this check. // I have done background plumbing for vscode to fetch downlodable link from correct endpoint. - const cloudName = clusterNode.result.subscription.environment.name; + const cloudName = getEnvironment().name; if (cloudName !== "AzureCloud") { vscode.window.showInformationMessage(`Periscope is not supported in ${cloudName} cloud.`); return; } const properties = await longRunning(`Getting properties for cluster ${clusterNode.result.name}.`, () => - getClusterProperties(clusterNode.result), + getManagedCluster( + sessionProvider.result, + clusterNode.result.subscriptionId, + clusterNode.result.resourceGroupName, + clusterNode.result.name, + ), ); if (failed(properties)) { vscode.window.showErrorMessage(properties.error); @@ -49,7 +62,12 @@ export default async function periscope(_context: IActionContext, target: unknow } const kubeconfig = await longRunning(`Retrieving kubeconfig for cluster ${clusterNode.result.name}.`, () => - getKubeconfigYaml(clusterNode.result, properties.result), + getKubeconfigYaml( + sessionProvider.result, + clusterNode.result.subscriptionId, + clusterNode.result.resourceGroupName, + properties.result, + ), ); if (failed(kubeconfig)) { vscode.window.showErrorMessage(kubeconfig.error); @@ -66,9 +84,15 @@ async function runAKSPeriscope( ): Promise { const clusterName = clusterNode.name; + const sessionProvider = await getReadySessionProvider(); + if (failed(sessionProvider)) { + vscode.window.showErrorMessage(sessionProvider.error); + return; + } + // Get Diagnostic settings for cluster and get associated storage account information. const clusterDiagnosticSettings = await longRunning(`Identifying cluster diagnostic settings.`, () => - getClusterDiagnosticSettings(clusterNode), + getClusterDiagnosticSettings(sessionProvider.result, clusterNode), ); const extension = getExtension(); @@ -93,7 +117,7 @@ async function runAKSPeriscope( // Generate storage sas keys, manage aks persicope run. const clusterStorageInfo = await longRunning(`Generating SAS for ${clusterName} cluster.`, () => - getStorageInfo(kubectl, clusterNode, clusterStorageAccountId, clusterKubeConfig), + getStorageInfo(sessionProvider.result, kubectl, clusterNode, clusterStorageAccountId, clusterKubeConfig), ); if (failed(clusterStorageInfo)) { @@ -107,7 +131,7 @@ async function runAKSPeriscope( return; } - const containerClient = getContainerClient(clusterNode); + const containerClient = getAksClient(sessionProvider.result, clusterNode.subscriptionId); // Get the features of the cluster that determine which optional kustomize components to deploy. const clusterFeatures = await getClusterFeatures(containerClient, clusterNode.resourceGroupName, clusterNode.name); diff --git a/src/commands/selectSubscriptions.ts b/src/commands/selectSubscriptions.ts deleted file mode 100644 index 37679b3e..00000000 --- a/src/commands/selectSubscriptions.ts +++ /dev/null @@ -1,15 +0,0 @@ -import * as vscode from "vscode"; -import * as k8s from "vscode-kubernetes-tools-api"; -import { IActionContext } from "@microsoft/vscode-azext-utils"; - -export default async function selectSubscriptions(_context: IActionContext, target: unknown): Promise { - const cloudExplorer = await k8s.extension.cloudExplorer.v1; - - if (cloudExplorer.available) { - const commandTarget = cloudExplorer.api.resolveCommandTarget(target); - - if (commandTarget && commandTarget.nodeType === "resource") { - vscode.commands.executeCommand("azure-account.selectSubscriptions"); - } - } -} diff --git a/src/commands/utils/arm.ts b/src/commands/utils/arm.ts new file mode 100644 index 00000000..25038ee8 --- /dev/null +++ b/src/commands/utils/arm.ts @@ -0,0 +1,54 @@ +import { SubscriptionClient } from "@azure/arm-resources-subscriptions"; +import { getCredential, getEnvironment } from "../../auth/azureAuth"; +import { PagedAsyncIterableIterator } from "@azure/core-paging"; +import { Errorable, getErrorMessage } from "./errorable"; +import { ResourceManagementClient } from "@azure/arm-resources"; +import { ContainerServiceClient } from "@azure/arm-containerservice"; +import { MonitorClient } from "@azure/arm-monitor"; +import { StorageManagementClient } from "@azure/arm-storage"; +import { ReadyAzureSessionProvider } from "../../auth/types"; + +export function getSubscriptionClient(sessionProvider: ReadyAzureSessionProvider): SubscriptionClient { + return new SubscriptionClient(getCredential(sessionProvider), { endpoint: getArmEndpoint() }); +} + +export function getResourceManagementClient( + sessionProvider: ReadyAzureSessionProvider, + subscriptionId: string, +): ResourceManagementClient { + return new ResourceManagementClient(getCredential(sessionProvider), subscriptionId, { endpoint: getArmEndpoint() }); +} + +export function getAksClient( + sessionProvider: ReadyAzureSessionProvider, + subscriptionId: string, +): ContainerServiceClient { + return new ContainerServiceClient(getCredential(sessionProvider), subscriptionId, { endpoint: getArmEndpoint() }); +} + +export function getMonitorClient(sessionProvider: ReadyAzureSessionProvider, subscriptionId: string): MonitorClient { + return new MonitorClient(getCredential(sessionProvider), subscriptionId, { endpoint: getArmEndpoint() }); +} + +export function getStorageManagementClient( + sessionProvider: ReadyAzureSessionProvider, + subscriptionId: string, +): StorageManagementClient { + return new StorageManagementClient(getCredential(sessionProvider), subscriptionId, { endpoint: getArmEndpoint() }); +} + +function getArmEndpoint(): string { + return getEnvironment().resourceManagerEndpointUrl; +} + +export async function listAll(iterator: PagedAsyncIterableIterator): Promise> { + const result: T[] = []; + try { + for await (const page of iterator.byPage()) { + result.push(...page); + } + return { succeeded: true, result }; + } catch (e) { + return { succeeded: false, error: `Failed to list resources: ${getErrorMessage(e)}` }; + } +} diff --git a/src/commands/utils/authProvider.ts b/src/commands/utils/authProvider.ts deleted file mode 100644 index db56b07b..00000000 --- a/src/commands/utils/authProvider.ts +++ /dev/null @@ -1,55 +0,0 @@ -import { Environment } from "@azure/ms-rest-azure-env"; -import { AuthenticationResult, Configuration, PublicClientApplication, RefreshTokenRequest } from "@azure/msal-node"; -import { URL } from "url"; -import { Errorable } from "./errorable"; - -// The AppId (ClientId) of VS Code -// https://github.com/Azure/azure-sdk-for-js/blob/5eb19b911388ec4ba830e36934bdb4840ec7977d/sdk/identity/identity/src/credentials/visualStudioCodeCredential.ts#L21 -const azureAccountClientId = "aebc6443-996d-45c2-90f0-388ff96faa56"; - -export async function getAksAadAccessToken( - environment: Environment, - serverId: string, - tenantId: string, - refreshToken: string, -): Promise> { - // The MSAL configuration is for the current application (i.e. VS Code), - // even though we will be requesting a token for a different application. - const clientConfig: Configuration = { - auth: { - clientId: azureAccountClientId, - authority: new URL(tenantId, environment.activeDirectoryEndpointUrl).href, - }, - }; - - const application = new PublicClientApplication(clientConfig); - - // The token needs to have an 'audience' claim whose value matches the 'serverId' value (i.e. the AKS AAD server). - // We request that by specifying the serverId value in the scope. See: https://stackoverflow.com/a/67737375 - const request: RefreshTokenRequest = { - scopes: [`${serverId}/.default`], - refreshToken, - }; - - // According to the MSAL docs, this method is intended for use in migration from an older AD API (ADAL), - // and the recommended alternative is to use `acquireTokenSilent`: - // https://learn.microsoft.com/en-us/azure/active-directory/develop/msal-node-migration - // https://github.com/AzureAD/microsoft-authentication-library-for-js/blob/f318796c278e39153e8cd9bf3ce03259cb80c8a6/lib/msal-node/src/client/ClientApplication.ts#L172-L178 - // However, there's no obvious way to use `acquireTokenSilent`, since it relies on a TokenCache structure - // (to retrieve the refresh token) that's very specific to MSAL, and not available to us here. - let tokenResponse: AuthenticationResult | null; - try { - tokenResponse = await application.acquireTokenByRefreshToken(request); - } catch (e) { - return { - succeeded: false, - error: `Failed to acquire AAD token for server ${serverId} from refresh token:\n${e}`, - }; - } - - if (!tokenResponse) { - return { succeeded: false, error: `Unable to acquire AAD token for server ${serverId} from refresh token.` }; - } - - return { succeeded: true, result: tokenResponse }; -} diff --git a/src/commands/utils/azureAccount.ts b/src/commands/utils/azureAccount.ts index 0caaa013..f50b5cf8 100644 --- a/src/commands/utils/azureAccount.ts +++ b/src/commands/utils/azureAccount.ts @@ -1,8 +1,5 @@ -import * as vscode from "vscode"; -import { Subscription } from "@azure/arm-subscriptions"; -import { Environment } from "@azure/ms-rest-azure-env"; import { TokenCredential } from "@azure/core-auth"; -import { combine, Errorable, failed, getErrorMessage, succeeded } from "./errorable"; +import { combine, Errorable, failed, getErrorMessage } from "./errorable"; import { ClientSecretCredential } from "@azure/identity"; import "cross-fetch/polyfill"; // Needed by the graph client: https://github.com/microsoftgraph/msgraph-sdk-javascript/blob/dev/README.md#via-npm import { Client as GraphClient } from "@microsoft/microsoft-graph-client"; @@ -12,29 +9,9 @@ import { } from "@microsoft/microsoft-graph-client/authProviders/azureTokenCredentials"; import { AuthorizationManagementClient } from "@azure/arm-authorization"; import { RoleAssignment } from "@azure/arm-authorization"; - -export interface AzureAccountExtensionApi { - readonly filters: AzureResourceFilter[]; - readonly sessions: AzureSession[]; - readonly subscriptions: AzureSubscription[]; -} - -export interface AzureResourceFilter { - readonly session: AzureSession; - readonly subscription: Subscription; -} - -export interface AzureSession { - readonly environment: Environment; - readonly userId: string; - readonly tenantId: string; - readonly credentials2?: TokenCredential; -} - -export interface AzureSubscription { - readonly session: AzureSession; - readonly subscription: Subscription; -} +import { getDefaultScope, getEnvironment } from "../../auth/azureAuth"; +import { DefinedSubscription, getSubscriptions, SelectionType } from "./subscriptions"; +import { ReadyAzureSessionProvider } from "../../auth/types"; export interface ServicePrincipalAccess { readonly cloudName: string; @@ -46,43 +23,42 @@ export interface ServicePrincipalAccess { } interface SubscriptionAccessResult { - readonly subscription: Subscription; + readonly subscription: DefinedSubscription; readonly hasRoleAssignment: boolean; } interface ServicePrincipalInfo { readonly id: string; readonly displayName: string; - readonly session: AzureSession; readonly credential: TokenCredential; -} - -export function getAzureAccountExtensionApi(): Errorable { - const azureAccountExtension = vscode.extensions.getExtension("ms-vscode.azure-account"); - if (!azureAccountExtension) { - return { succeeded: false, error: "Azure extension not found." }; - } - - return { succeeded: true, result: azureAccountExtension.exports.api }; + readonly tenantId: string; } export async function getServicePrincipalAccess( - apiAzureAccount: AzureAccountExtensionApi, + sessionProvider: ReadyAzureSessionProvider, appId: string, secret: string, ): Promise> { - const spInfo = await getServicePrincipalInfo(apiAzureAccount.sessions, appId, secret); + const cloudName = getEnvironment().name; + const filteredSubscriptions = await getSubscriptions(sessionProvider, SelectionType.Filtered); + if (failed(filteredSubscriptions)) { + return filteredSubscriptions; + } + + const session = await sessionProvider.getAuthSession(); + if (failed(session)) { + return session; + } + + const spInfo = await getServicePrincipalInfo(session.result.tenantId, appId, secret); if (failed(spInfo)) { return spInfo; } - const cloudName = spInfo.result.session.environment.name; - const tenantId = spInfo.result.session.tenantId; const promiseResults = await Promise.all( - apiAzureAccount.filters.map((f) => - getSubscriptionAccess(spInfo.result.credential, f.subscription, spInfo.result), - ), + filteredSubscriptions.result.map((s) => getSubscriptionAccess(spInfo.result.credential, s, spInfo.result)), ); + const ownershipResults = combine(promiseResults); if (failed(ownershipResults)) { return ownershipResults; @@ -91,34 +67,11 @@ export async function getServicePrincipalAccess( const subscriptions = ownershipResults.result .filter((r) => r.hasRoleAssignment) .map((r) => ({ - id: r.subscription.subscriptionId || "", - name: r.subscription.displayName || "", + id: r.subscription.subscriptionId, + name: r.subscription.displayName, })); - return { succeeded: true, result: { cloudName, tenantId, subscriptions } }; -} - -async function getServicePrincipalInfo( - sessions: AzureSession[], - appId: string, - appSecret: string, -): Promise> { - const spInfoResults = await Promise.all( - sessions.map((s) => getServicePrincipalInfoForSession(s, appId, appSecret)), - ); - for (const spInfoResult of spInfoResults) { - if (succeeded(spInfoResult)) { - return spInfoResult; - } - } - - const spInfosResult = combine(spInfoResults); - if (succeeded(spInfosResult)) { - // Can only happen if there were no sessions, otherwise we would've returned success above. - return { succeeded: false, error: "No Azure sessions found." }; - } - - return spInfosResult; + return { succeeded: true, result: { cloudName, tenantId: spInfo.result.tenantId, subscriptions } }; } type ServicePrincipalSearchResult = { @@ -128,19 +81,19 @@ type ServicePrincipalSearchResult = { }[]; }; -async function getServicePrincipalInfoForSession( - session: AzureSession, +async function getServicePrincipalInfo( + tenantId: string, appId: string, appSecret: string, ): Promise> { // Use the MS Graph API to retrieve the object ID and display name of the service principal, // using its own password as the credential. - const baseUrl = getMicrosoftGraphClientBaseUrl(session.environment); + const baseUrl = getMicrosoftGraphClientBaseUrl(); const graphClientOptions: TokenCredentialAuthenticationProviderOptions = { - scopes: [`${baseUrl}/.default`], + scopes: [getDefaultScope(baseUrl)], }; - const credential = new ClientSecretCredential(session.tenantId, appId, appSecret); + const credential = new ClientSecretCredential(tenantId, appId, appSecret); const graphClient = GraphClient.initWithMiddleware({ baseUrl, @@ -171,14 +124,15 @@ async function getServicePrincipalInfoForSession( const spInfo = { id: searchResult.id, displayName: searchResult.displayName, - session, credential, + tenantId, }; return { succeeded: true, result: spInfo }; } -function getMicrosoftGraphClientBaseUrl(environment: Environment): string { +function getMicrosoftGraphClientBaseUrl(): string { + const environment = getEnvironment(); // Environments are from here: https://github.com/Azure/ms-rest-azure-env/blob/6fa17ce7f36741af6ce64461735e6c7c0125f0ed/lib/azureEnvironment.ts#L266-L346 // They do not contain the MS Graph endpoints, whose values are here: // https://github.com/microsoftgraph/msgraph-sdk-javascript/blob/d365ab1d68f90f2c38c67a5a7c7fe54acfc2584e/src/Constants.ts#L28 @@ -196,7 +150,7 @@ function getMicrosoftGraphClientBaseUrl(environment: Environment): string { async function getSubscriptionAccess( credential: TokenCredential, - subscription: Subscription, + subscription: DefinedSubscription, spInfo: ServicePrincipalInfo, ): Promise> { if (!subscription.subscriptionId) { diff --git a/src/commands/utils/azureResources.ts b/src/commands/utils/azureResources.ts new file mode 100644 index 00000000..7af0d4ac --- /dev/null +++ b/src/commands/utils/azureResources.ts @@ -0,0 +1,38 @@ +import { GenericResourceExpanded } from "@azure/arm-resources"; +import { getResourceManagementClient, listAll } from "./arm"; +import { Errorable, map as errmap } from "./errorable"; +import { parseResource } from "../../azure-api-utils"; +import { ReadyAzureSessionProvider } from "../../auth/types"; + +export type ResourceType = "Microsoft.ContainerService/managedClusters" | "Microsoft.ContainerRegistry/registries"; + +/** + * A resource with the id and name properties guaranteed to be defined. + */ +export type DefinedResource = GenericResourceExpanded & Required>; + +export type DefinedResourceWithGroup = DefinedResource & { + resourceGroup: string; +}; + +export async function getResources( + sessionProvider: ReadyAzureSessionProvider, + subscriptionId: string, + resourceType: ResourceType, +): Promise> { + const client = getResourceManagementClient(sessionProvider, subscriptionId); + const list = await listAll(client.resources.list({ filter: `resourceType eq '${resourceType}'` })); + return errmap(list, (resources) => resources.filter(isDefinedResource).map(asResourceWithGroup)); +} + +function isDefinedResource(resource: GenericResourceExpanded): resource is DefinedResource { + return resource.id !== undefined && resource.name !== undefined; +} + +function asResourceWithGroup(resource: DefinedResource): DefinedResourceWithGroup { + return { ...resource, resourceGroup: getResourceGroup(resource) }; +} + +function getResourceGroup(resource: DefinedResource): string { + return parseResource(resource.id).resourceGroupName!; +} diff --git a/src/commands/utils/clusters.ts b/src/commands/utils/clusters.ts index 56c830dc..f143b449 100644 --- a/src/commands/utils/clusters.ts +++ b/src/commands/utils/clusters.ts @@ -9,23 +9,31 @@ import { import { AksClusterTreeNode } from "../../tree/aksClusterTreeItem"; import * as azcs from "@azure/arm-containerservice"; import { Errorable, failed, getErrorMessage, succeeded } from "./errorable"; -import { ResourceGroup, ResourceManagementClient } from "@azure/arm-resources"; import { SubscriptionTreeNode, isSubscriptionTreeNode } from "../../tree/subscriptionTreeItem"; -import { getAksAadAccessToken } from "./authProvider"; import * as yaml from "js-yaml"; import * as fs from "fs"; import * as path from "path"; -import { AuthenticationResult } from "@azure/msal-node"; import { getKubeloginBinaryPath } from "./helper/kubeloginDownload"; import { longRunning } from "./host"; import { dirSync } from "tmp"; +import { ReadyAzureSessionProvider, TokenInfo } from "../../auth/types"; +import { AuthenticationSession, authentication } from "vscode"; +import { getTokenInfo } from "../../auth/azureAuth"; +import { getAksClient } from "./arm"; export interface KubernetesClusterInfo { readonly name: string; readonly kubeconfigYaml: string; } +/** + * A managed cluster with the name and location properties guaranteed to be defined. + */ +export type DefinedManagedCluster = azcs.ManagedCluster & + Required>; + export async function getKubernetesClusterInfo( + sessionProvider: ReadyAzureSessionProvider, commandTarget: unknown, cloudExplorer: APIAvailable, clusterExplorer: APIAvailable, @@ -34,13 +42,23 @@ export async function getKubernetesClusterInfo( const clusterNode = getAksClusterTreeNode(commandTarget, cloudExplorer); if (succeeded(clusterNode)) { const properties = await longRunning(`Getting properties for cluster ${clusterNode.result.name}.`, () => - getClusterProperties(clusterNode.result), + getManagedCluster( + sessionProvider, + clusterNode.result.subscriptionId, + clusterNode.result.resourceGroupName, + clusterNode.result.name, + ), ); if (failed(properties)) { return properties; } - const kubeconfigYaml = await getKubeconfigYaml(clusterNode.result, properties.result); + const kubeconfigYaml = await getKubeconfigYaml( + sessionProvider, + clusterNode.result.subscriptionId, + clusterNode.result.resourceGroupName, + properties.result, + ); if (failed(kubeconfigYaml)) { return kubeconfigYaml; } @@ -139,32 +157,34 @@ export function getAksClusterSubscriptionNode( } export async function getKubeconfigYaml( - clusterNode: AksClusterTreeNode, - managedCluster: azcs.ManagedCluster, + sessionProvider: ReadyAzureSessionProvider, + subscriptionId: string, + resourceGroup: string, + managedCluster: DefinedManagedCluster, ): Promise> { - const client = getContainerClient(clusterNode); - return managedCluster.aadProfile ? getAadKubeconfig(clusterNode, client) : getNonAadKubeconfig(clusterNode, client); + const client = getAksClient(sessionProvider, subscriptionId); + return managedCluster.aadProfile + ? getAadKubeconfig(client, resourceGroup, managedCluster.name) + : getNonAadKubeconfig(client, resourceGroup, managedCluster.name); } async function getNonAadKubeconfig( - clusterNode: AksClusterTreeNode, client: azcs.ContainerServiceClient, + resourceGroup: string, + clusterName: string, ): Promise> { let clusterUserCredentials: azcs.CredentialResults; try { - clusterUserCredentials = await client.managedClusters.listClusterUserCredentials( - clusterNode.resourceGroupName, - clusterNode.name, - ); + clusterUserCredentials = await client.managedClusters.listClusterUserCredentials(resourceGroup, clusterName); } catch (e) { return { succeeded: false, - error: `Failed to retrieve user credentials for non-AAD cluster ${clusterNode.name}: ${e}`, + error: `Failed to retrieve user credentials for non-AAD cluster ${clusterName}: ${e}`, }; } - return getClusterUserKubeconfig(clusterUserCredentials, clusterNode.name); + return getClusterUserKubeconfig(clusterUserCredentials, clusterName); } type KubeConfigExecBlock = { @@ -183,27 +203,26 @@ type KubeConfig = { }; async function getAadKubeconfig( - clusterNode: AksClusterTreeNode, client: azcs.ContainerServiceClient, + resourceGroup: string, + clusterName: string, ): Promise> { let clusterUserCredentials: azcs.CredentialResults; try { // For AAD clusters, force the credentials to be in 'exec' format. - clusterUserCredentials = await client.managedClusters.listClusterUserCredentials( - clusterNode.resourceGroupName, - clusterNode.name, - { format: azcs.KnownFormat.Exec }, - ); + clusterUserCredentials = await client.managedClusters.listClusterUserCredentials(resourceGroup, clusterName, { + format: azcs.KnownFormat.Exec, + }); } catch (e) { return { succeeded: false, - error: `Failed to retrieve user credentials for AAD cluster ${clusterNode.name}: ${e}`, + error: `Failed to retrieve user credentials for AAD cluster ${clusterName}: ${e}`, }; } // The initial credentials contain an 'exec' section that calls kubelogin with devicecode authentication. - const unauthenticatedKubeconfig = getClusterUserKubeconfig(clusterUserCredentials, clusterNode.name); + const unauthenticatedKubeconfig = getClusterUserKubeconfig(clusterUserCredentials, clusterName); if (failed(unauthenticatedKubeconfig)) { return unauthenticatedKubeconfig; } @@ -213,32 +232,33 @@ async function getAadKubeconfig( try { kubeconfigYaml = yaml.load(unauthenticatedKubeconfig.result) as KubeConfig; } catch (e) { - return { succeeded: false, error: `Failed to parse kubeconfig YAML for ${clusterNode.name}: ${e}` }; + return { succeeded: false, error: `Failed to parse kubeconfig YAML for ${clusterName}: ${e}` }; } // We expect there will be just one user in the kubeconfig. Read the 'exec' arguments for it. const execBlock = kubeconfigYaml.users[0].user.exec; const execOptions = readExecOptions(execBlock.args); - // We need to supply an access token that grants the user access to the cluster. The user running this will be authenticated, - // and we have access to their credentials here... - const localToken = await clusterNode.subscription.credentials.getToken(); + // Get a token whose audience is the AKS server ID. + const scopes = [`${execOptions.serverId}/.default`, `VSCODE_TENANT:${execOptions.tenantId}`]; + let session: AuthenticationSession; + try { + session = await authentication.getSession("microsoft", scopes, { createIfNone: true }); + } catch (e) { + return { + succeeded: false, + error: `Failed to retrieve Microsoft authentication session for scopes [${scopes.join(",")}]: ${getErrorMessage(e)}`, + }; + } - // But, the user's token is for VS Code, and instead we need a token whose audience is the AKS server ID. - // This can be obtained by exchanging the user's refresh token for one with the new audience. - const aadAccessToken = await getAksAadAccessToken( - clusterNode.subscription.environment, - execOptions.serverId, - execOptions.tenantId, - localToken.refreshToken, - ); - if (failed(aadAccessToken)) { - return aadAccessToken; + const tokenInfo = getTokenInfo(session); + if (failed(tokenInfo)) { + return tokenInfo; } // Now we have a token the user can use to access their cluster, but kubelogin doesn't support that being passed as an // argument directly. Instead, we can save it to a temp directory and instruct kubelogin to use that as its cache directory. - const cacheDir = storeCachedAadToken(aadAccessToken.result, execOptions); + const cacheDir = storeCachedAadToken(tokenInfo.result, execOptions); if (failed(cacheDir)) { return cacheDir; } @@ -313,7 +333,7 @@ function buildExecOptionsWithCache(execOptions: ExecOptions, cacheDir: string) { ]; } -function storeCachedAadToken(aadAccessToken: AuthenticationResult, execOptions: ExecOptions): Errorable { +function storeCachedAadToken(tokenInfo: TokenInfo, execOptions: ExecOptions): Errorable { // kubelogin supports an extra option '--token-cache-dir' where it expects to find cached credentials. // If our credential is found in there, it won't initiate an interactive login. // It will look for a file with a specific name based on the options supplied: @@ -322,11 +342,9 @@ function storeCachedAadToken(aadAccessToken: AuthenticationResult, execOptions: const cacheFilePath = path.join(cacheDirObj.name, expectedFilename); const nowTimestamp = Math.floor(new Date().getTime() / 1000); - const expiryTimestamp = aadAccessToken.expiresOn - ? Math.floor(aadAccessToken.expiresOn.getTime() / 1000) - : nowTimestamp; + const expiryTimestamp = Math.floor(tokenInfo.expiry.getTime() / 1000); const cachedTokenData = { - access_token: aadAccessToken.accessToken, + access_token: tokenInfo.token, refresh_token: "", expires_in: expiryTimestamp - nowTimestamp, expires_on: expiryTimestamp, @@ -357,19 +375,22 @@ function getClusterUserKubeconfig(credentialResults: azcs.CredentialResults, clu return { succeeded: true, result: kubeconfig }; } -export function getClusterProperties(clusterNode: AksClusterTreeNode): Promise> { - const client = getContainerClient(clusterNode); - return getManagedCluster(client, clusterNode.resourceGroupName, clusterNode.name); -} - export async function getManagedCluster( - client: azcs.ContainerServiceClient, + sessionProvider: ReadyAzureSessionProvider, + subscriptionId: string, resourceGroup: string, clusterName: string, -): Promise> { +): Promise> { + const client = getAksClient(sessionProvider, subscriptionId); try { const managedCluster = await client.managedClusters.get(resourceGroup, clusterName); - return { succeeded: true, result: managedCluster }; + if (isDefinedManagedCluster(managedCluster)) { + return { succeeded: true, result: managedCluster }; + } + return { + succeeded: false, + error: `Failed to retrieve Cluster ${clusterName}`, + }; } catch (e) { return { succeeded: false, error: `Failed to retrieve cluster ${clusterName}: ${e}` }; } @@ -387,20 +408,6 @@ export async function getKubernetesVersionInfo( } } -export async function determineProvisioningState( - clusterNode: AksClusterTreeNode, - clusterName: string, -): Promise> { - try { - const containerClient = getContainerClient(clusterNode); - const clusterInfo = await containerClient.managedClusters.get(clusterNode.resourceGroupName, clusterName); - - return { succeeded: true, result: clusterInfo.provisioningState ?? "" }; - } catch (ex) { - return { succeeded: false, error: `Error invoking ${clusterName} managed cluster: ${ex}` }; - } -} - export async function getWindowsNodePoolKubernetesVersions( containerClient: azcs.ContainerServiceClient, resourceGroupName: string, @@ -439,40 +446,15 @@ export async function getWindowsNodePoolKubernetesVersions( } } -export function getContainerClient(treeNode: AksClusterTreeNode | SubscriptionTreeNode): azcs.ContainerServiceClient { - const environment = treeNode.subscription.environment; - return new azcs.ContainerServiceClient(treeNode.subscription.credentials, treeNode.subscription.subscriptionId, { - endpoint: environment.resourceManagerEndpointUrl, - }); -} - -export function getResourceManagementClient( - treeNode: AksClusterTreeNode | SubscriptionTreeNode, -): ResourceManagementClient { - const environment = treeNode.subscription.environment; - return new ResourceManagementClient(treeNode.subscription.credentials, treeNode.subscription.subscriptionId, { - endpoint: environment.resourceManagerEndpointUrl, - }); -} - -export async function getResourceGroupList(client: ResourceManagementClient): Promise> { - try { - const resourceGroups = []; - const result = client.resourceGroups.list(); - for await (const pageGroups of result.byPage()) { - resourceGroups.push(...pageGroups); - } - - return { succeeded: true, result: resourceGroups }; - } catch (ex) { - return { succeeded: false, error: `Error listing resource groups: ${getErrorMessage(ex)}` }; - } -} - -export async function deleteCluster(clusterNode: AksClusterTreeNode, clusterName: string): Promise> { +export async function deleteCluster( + sessionProvider: ReadyAzureSessionProvider, + subscriptionId: string, + resourceGroup: string, + clusterName: string, +): Promise> { try { - const containerClient = getContainerClient(clusterNode); - await containerClient.managedClusters.beginDeleteAndWait(clusterNode.resourceGroupName, clusterName); + const containerClient = getAksClient(sessionProvider, subscriptionId); + await containerClient.managedClusters.beginDeleteAndWait(resourceGroup, clusterName); return { succeeded: true, result: "Delete cluster succeeded." }; } catch (ex) { @@ -480,44 +462,52 @@ export async function deleteCluster(clusterNode: AksClusterTreeNode, clusterName } } -export async function reconcileUsingUpdateInCluster(clusterNode: AksClusterTreeNode): Promise> { +export async function reconcileUsingUpdateInCluster( + sessionProvider: ReadyAzureSessionProvider, + subscriptionId: string, + resourceGroup: string, + clusterName: string, +): Promise> { + const clusterInfo = await getManagedCluster(sessionProvider, subscriptionId, resourceGroup, clusterName); + if (failed(clusterInfo)) { + return clusterInfo; + } + try { // Pleaset note: here is in the only place this way of reconcile is documented: https://learn.microsoft.com/en-us/cli/azure/aks?view=azure-cli-latest#az-aks-update()-examples - const containerClient = getContainerClient(clusterNode); - const getClusterInfo = await containerClient.managedClusters.get( - clusterNode.resourceGroupName, - clusterNode.name, - ); - await containerClient.managedClusters.beginCreateOrUpdateAndWait( - clusterNode.resourceGroupName, - clusterNode.name, - { - location: getClusterInfo.location, - }, - ); + const containerClient = getAksClient(sessionProvider, subscriptionId); + await containerClient.managedClusters.beginCreateOrUpdateAndWait(resourceGroup, clusterName, { + location: clusterInfo.result.location, + }); return { succeeded: true, result: "Reconcile/Update cluster succeeded." }; } catch (ex) { return { succeeded: false, - error: `Error invoking ${clusterNode.name} managed cluster: ${getErrorMessage(ex)}`, + error: `Error invoking ${clusterName} managed cluster: ${getErrorMessage(ex)}`, }; } } -export async function rotateClusterCert(clusterNode: AksClusterTreeNode): Promise> { +export async function rotateClusterCert( + sessionProvider: ReadyAzureSessionProvider, + subscriptionId: string, + resourceGroup: string, + clusterName: string, +): Promise> { try { - const containerClient = getContainerClient(clusterNode); - await containerClient.managedClusters.beginRotateClusterCertificatesAndWait( - clusterNode.resourceGroupName, - clusterNode.name, - ); + const containerClient = getAksClient(sessionProvider, subscriptionId); + await containerClient.managedClusters.beginRotateClusterCertificatesAndWait(resourceGroup, clusterName); - return { succeeded: true, result: `Rotate cluster certificate for ${clusterNode.name} succeeded.` }; + return { succeeded: true, result: `Rotate cluster certificate for ${clusterName} succeeded.` }; } catch (ex) { return { succeeded: false, - error: `Error invoking ${clusterNode.name} managed cluster: ${getErrorMessage(ex)}`, + error: `Error invoking ${clusterName} managed cluster: ${getErrorMessage(ex)}`, }; } } + +function isDefinedManagedCluster(cluster: azcs.ManagedCluster): cluster is DefinedManagedCluster { + return cluster.id !== undefined && cluster.name !== undefined && cluster.location !== undefined; +} diff --git a/src/commands/utils/config.ts b/src/commands/utils/config.ts index e629e06a..5062fcf5 100644 --- a/src/commands/utils/config.ts +++ b/src/commands/utils/config.ts @@ -5,6 +5,82 @@ import * as semver from "semver"; import { CommandCategory, PresetCommand } from "../../webview-contract/webviewDefinitions/kubectl"; import { RetinaDownloadConfig } from "../periscope/models/RetinaDownloadConfig"; import { isObject } from "./runtimeTypes"; +import { Environment, EnvironmentParameters } from "@azure/ms-rest-azure-env"; + +export function getConfiguredAzureEnv(): Environment { + // See: + // https://github.com/microsoft/vscode/blob/eac16e9b63a11885b538db3e0b533a02a2fb8143/extensions/microsoft-authentication/package.json#L40-L99 + const section = "microsoft-sovereign-cloud"; + const settingName = "environment"; + const authProviderConfig = vscode.workspace.getConfiguration(section); + const environmentSettingValue = authProviderConfig.get(settingName); + + if (environmentSettingValue === "ChinaCloud") { + return Environment.ChinaCloud; + } else if (environmentSettingValue === "USGovernment") { + return Environment.USGovernment; + } else if (environmentSettingValue === "custom") { + const customCloud = authProviderConfig.get("customEnvironment"); + if (customCloud) { + return new Environment(customCloud); + } + + throw new Error( + `The custom cloud choice is not configured. Please configure the setting ${section}.${settingName}.`, + ); + } + + return Environment.get(Environment.AzureCloud.name); +} + +export interface SubscriptionFilter { + tenantId: string; + subscriptionId: string; +} + +const onFilteredSubscriptionsChangeEmitter = new vscode.EventEmitter(); + +export function getFilteredSubscriptionsChangeEvent() { + return onFilteredSubscriptionsChangeEmitter.event; +} + +export function getFilteredSubscriptions(): SubscriptionFilter[] { + try { + let values = vscode.workspace.getConfiguration("aks").get("selectedSubscriptions", []); + if (values.length === 0) { + // Get filters from the Azure Account extension if the AKS extension has none. + values = vscode.workspace.getConfiguration("azure").get("resourceFilter", []); + } + return values.map(asSubscriptionFilter).filter((v) => v !== null) as SubscriptionFilter[]; + } catch (e) { + return []; + } +} + +function asSubscriptionFilter(value: string): SubscriptionFilter | null { + try { + const parts = value.split("/"); + return { tenantId: parts[0], subscriptionId: parts[1] }; + } catch (e) { + return null; + } +} + +export async function setFilteredSubscriptions(filters: SubscriptionFilter[]): Promise { + const existingFilters = getFilteredSubscriptions(); + const filtersChanged = + existingFilters.length !== filters.length || + !filters.every((f) => existingFilters.some((ef) => ef.subscriptionId === f.subscriptionId)); + + const values = filters.map((f) => `${f.tenantId}/${f.subscriptionId}`).sort(); + + if (filtersChanged) { + await vscode.workspace + .getConfiguration("aks") + .update("selectedSubscriptions", values, vscode.ConfigurationTarget.Global, true); + onFilteredSubscriptionsChangeEmitter.fire(); + } +} export function getKustomizeConfig(): Errorable { const periscopeConfig = vscode.workspace.getConfiguration("aks.periscope"); diff --git a/src/commands/utils/detectors.ts b/src/commands/utils/detectors.ts index 8ff8234f..160ea694 100644 --- a/src/commands/utils/detectors.ts +++ b/src/commands/utils/detectors.ts @@ -8,19 +8,24 @@ import { SingleDetectorARMResponse, isCategoryDataset, } from "../../webview-contract/webviewDefinitions/detector"; -import { getResourceManagementClient } from "./clusters"; import { dirSync } from "tmp"; import { Environment } from "@azure/ms-rest-azure-env"; import { getPortalResourceUrl } from "./env"; +import { getResourceManagementClient } from "./arm"; +import { ReadyAzureSessionProvider } from "../../auth/types"; /** * Can be used to store the JSON responses for a collection of category detectors and all their child detectors. */ -export async function saveAllDetectorResponses(clusterNode: AksClusterTreeNode, categoryDetectorIds: string[]) { +export async function saveAllDetectorResponses( + sessionProvider: ReadyAzureSessionProvider, + clusterNode: AksClusterTreeNode, + categoryDetectorIds: string[], +) { const outputDirObj = dirSync(); for (const categoryDetectorId of categoryDetectorIds) { - const categoryDetector = await getDetectorInfo(clusterNode, categoryDetectorId); + const categoryDetector = await getDetectorInfo(sessionProvider, clusterNode, categoryDetectorId); if (failed(categoryDetector)) { throw new Error( `Error getting category detector ${categoryDetectorId}: ${getErrorMessage(categoryDetector.error)}`, @@ -29,7 +34,7 @@ export async function saveAllDetectorResponses(clusterNode: AksClusterTreeNode, saveDetector(outputDirObj.name, categoryDetector.result); - const singleDetectors = await getDetectorListData(clusterNode, categoryDetector.result); + const singleDetectors = await getDetectorListData(sessionProvider, clusterNode, categoryDetector.result); if (failed(singleDetectors)) { throw new Error( `Error getting single detectors for ${categoryDetectorId}: ${getErrorMessage(singleDetectors.error)}`, @@ -50,6 +55,7 @@ function saveDetector(outputDir: string, detector: CategoryDetectorARMResponse | } export async function getDetectorListData( + sessionProvider: ReadyAzureSessionProvider, clusterNode: AksClusterTreeNode, categoryDetector: CategoryDetectorARMResponse, ): Promise> { @@ -61,7 +67,9 @@ export async function getDetectorListData( let results: Errorable[] = []; try { - const promiseResults = await Promise.all(detectorIds.map((name) => getDetectorInfo(clusterNode, name))); + const promiseResults = await Promise.all( + detectorIds.map((name) => getDetectorInfo(sessionProvider, clusterNode, name)), + ); // Line below is added to handle edge case of applens detector list with missing implementation, // due to internal server error it causes rest of list to fail. results = promiseResults.filter((x) => x.succeeded); @@ -75,11 +83,12 @@ export async function getDetectorListData( } export async function getDetectorInfo( + sessionProvider: ReadyAzureSessionProvider, clusterNode: AksClusterTreeNode, detectorName: string, ): Promise> { try { - const client = getResourceManagementClient(clusterNode); + const client = getResourceManagementClient(sessionProvider, clusterNode.subscriptionId); const detectorInfo = await client.resources.get( clusterNode.resourceGroupName, clusterNode.resourceType, diff --git a/src/commands/utils/resourceGroups.ts b/src/commands/utils/resourceGroups.ts new file mode 100644 index 00000000..64b7e8f3 --- /dev/null +++ b/src/commands/utils/resourceGroups.ts @@ -0,0 +1,22 @@ +import { ResourceGroup } from "@azure/arm-resources"; +import { getResourceManagementClient, listAll } from "./arm"; +import { Errorable, map as errmap } from "./errorable"; +import { ReadyAzureSessionProvider } from "../../auth/types"; + +/** + * A resource group with the name and location properties guaranteed to be defined. + */ +export type DefinedResourceGroup = ResourceGroup & Required>; + +export async function getResourceGroups( + sessionProvider: ReadyAzureSessionProvider, + subscriptionId: string, +): Promise> { + const client = getResourceManagementClient(sessionProvider, subscriptionId); + const groupsResult = await listAll(client.resourceGroups.list()); + return errmap(groupsResult, (groups) => groups.filter(asDefinedResourceGroup)); +} + +function asDefinedResourceGroup(rg: ResourceGroup): rg is DefinedResourceGroup { + return rg.name !== undefined && rg.location !== undefined; +} diff --git a/src/commands/utils/subscriptions.ts b/src/commands/utils/subscriptions.ts new file mode 100644 index 00000000..664c553f --- /dev/null +++ b/src/commands/utils/subscriptions.ts @@ -0,0 +1,43 @@ +import { Subscription } from "@azure/arm-resources-subscriptions"; +import { getSubscriptionClient, listAll } from "./arm"; +import { Errorable, map as errmap } from "./errorable"; +import { getFilteredSubscriptions } from "./config"; +import { ReadyAzureSessionProvider } from "../../auth/types"; + +export enum SelectionType { + Filtered, + All, + AllIfNoFilters, +} + +/** + * A subscription with the subscriptionId and displayName properties guaranteed to be defined. + */ +export type DefinedSubscription = Subscription & Required>; + +export async function getSubscriptions( + sessionProvider: ReadyAzureSessionProvider, + selectionType: SelectionType, +): Promise> { + const client = getSubscriptionClient(sessionProvider); + const subsResult = await listAll(client.subscriptions.list()); + return errmap(subsResult, (subs) => sortAndFilter(subs.filter(asDefinedSubscription), selectionType)); +} + +function sortAndFilter(subscriptions: DefinedSubscription[], selectionType: SelectionType): DefinedSubscription[] { + const attemptFilter = selectionType === SelectionType.Filtered || selectionType === SelectionType.AllIfNoFilters; + if (attemptFilter) { + const filters = getFilteredSubscriptions(); + const filteredSubs = subscriptions.filter((s) => filters.some((f) => f.subscriptionId === s.subscriptionId)); + const returnAll = selectionType === SelectionType.AllIfNoFilters && filteredSubs.length === 0; + if (!returnAll) { + subscriptions = filteredSubs; + } + } + + return subscriptions.sort((a, b) => a.displayName.localeCompare(b.displayName)); +} + +function asDefinedSubscription(sub: Subscription): sub is DefinedSubscription { + return sub.subscriptionId !== undefined && sub.displayName !== undefined; +} diff --git a/src/extension.ts b/src/extension.ts index 827ceaac..47599216 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -7,8 +7,8 @@ import { AzExtTreeDataProvider, registerCommand, CommandCallback, + registerUIExtensionVariables, } from "@microsoft/vscode-azext-utils"; -import selectSubscriptions from "./commands/selectSubscriptions"; import periscope from "./commands/periscope/periscope"; import { Reporter, reporter } from "./commands/utils/reporter"; import installAzureServiceOperator from "./commands/azureServiceOperators/installAzureServiceOperator"; @@ -32,10 +32,9 @@ import { failed } from "./commands/utils/errorable"; import aksNavToPortal from "./commands/aksNavToPortal/aksNavToPortal"; import aksClusterProperties from "./commands/aksClusterProperties/aksClusterProperties"; import aksCreateClusterNavToAzurePortal from "./commands/aksCreateClusterNavToAzurePortal/aksCreateClusterNavToAzurePortal"; -import { registerAzureUtilsExtensionVariables } from "@microsoft/vscode-azext-azureutils"; import { aksRunKubectlCommands } from "./commands/aksKubectlCommands/aksKubectlCommands"; import { longRunning } from "./commands/utils/host"; -import { getClusterProperties, getKubeconfigYaml } from "./commands/utils/clusters"; +import { getKubeconfigYaml, getManagedCluster } from "./commands/utils/clusters"; import aksDeleteCluster from "./commands/aksDeleteCluster/aksDeleteCluster"; import aksRotateClusterCert from "./commands/aksRotateClusterCert/aksRotateClusterCert"; import { aksInspektorGadgetShow } from "./commands/aksInspektorGadget/aksInspektorGadget"; @@ -46,12 +45,19 @@ import aksCompareCluster from "./commands/aksCompareCluster/aksCompareCluster"; import refreshSubscription from "./commands/refreshSubscriptions"; import aksEraserTool from "./commands/aksEraserTool/erasertool"; import { aksRetinaCapture } from "./commands/aksRetinaCapture/aksRetinaCapture"; +import { signInToAzure, selectSubscriptions, selectTenant } from "./commands/aksAccount/aksAccount"; +import { activateAzureSessionProvider, getSessionProvider } from "./auth/azureSessionProvider"; +import { getReadySessionProvider } from "./auth/azureAuth"; export async function activate(context: vscode.ExtensionContext) { const cloudExplorer = await k8s.extension.cloudExplorer.v1; context.subscriptions.push(new Reporter()); setAssetContext(context); + // Create and register the Azure session provider before accessing it. + activateAzureSessionProvider(context); + const sessionProvider = getSessionProvider(); + if (cloudExplorer.available) { // NOTE: This is boilerplate configuration for the Azure UI extension on which this extension relies. const uiExtensionVariables = { @@ -63,10 +69,12 @@ export async function activate(context: vscode.ExtensionContext) { context.subscriptions.push(uiExtensionVariables.outputChannel); - registerAzureUtilsExtensionVariables(uiExtensionVariables); + registerUIExtensionVariables(uiExtensionVariables); vscode.commands.executeCommand("workbench.action.openWalkthrough", { category: "ms-kubernetes-tools.vscode-aks-tools#aksvscodewalkthrough", }); + registerCommandWithTelemetry("aks.signInToAzure", signInToAzure); + registerCommandWithTelemetry("aks.selectTenant", selectTenant); registerCommandWithTelemetry("aks.selectSubscriptions", selectSubscriptions); registerCommandWithTelemetry("aks.periscope", periscope); registerCommandWithTelemetry("aks.installAzureServiceOperator", installAzureServiceOperator); @@ -100,7 +108,7 @@ export async function activate(context: vscode.ExtensionContext) { await registerAzureServiceNodes(context); - const azureAccountTreeItem = createAzureAccountTreeItem(); + const azureAccountTreeItem = createAzureAccountTreeItem(sessionProvider); context.subscriptions.push(azureAccountTreeItem); const treeDataProvider = new AzExtTreeDataProvider(azureAccountTreeItem, "azureAks.loadMore"); @@ -135,8 +143,14 @@ export async function registerAzureServiceNodes(context: vscode.ExtensionContext } async function getClusterKubeconfig(treeNode: AksClusterTreeNode): Promise { + const sessionProvider = await getReadySessionProvider(); + if (failed(sessionProvider)) { + vscode.window.showErrorMessage(sessionProvider.error); + return; + } + const properties = await longRunning(`Getting properties for cluster ${treeNode.name}.`, () => - getClusterProperties(treeNode), + getManagedCluster(sessionProvider.result, treeNode.subscriptionId, treeNode.resourceGroupName, treeNode.name), ); if (failed(properties)) { vscode.window.showErrorMessage(properties.error); @@ -144,8 +158,14 @@ async function getClusterKubeconfig(treeNode: AksClusterTreeNode): Promise - getKubeconfigYaml(treeNode, properties.result), + getKubeconfigYaml( + sessionProvider.result, + treeNode.subscriptionId, + treeNode.resourceGroupName, + properties.result, + ), ); + if (failed(kubeconfig)) { vscode.window.showErrorMessage(kubeconfig.error); return undefined; diff --git a/src/panels/AzureServiceOperatorPanel.ts b/src/panels/AzureServiceOperatorPanel.ts index 417d55f5..0d2fb169 100644 --- a/src/panels/AzureServiceOperatorPanel.ts +++ b/src/panels/AzureServiceOperatorPanel.ts @@ -12,12 +12,13 @@ import { ToWebViewMsgDef, azureToASOCloudMap, } from "../webview-contract/webviewDefinitions/azureServiceOperator"; -import { AzureAccountExtensionApi, getServicePrincipalAccess } from "../commands/utils/azureAccount"; +import { getServicePrincipalAccess } from "../commands/utils/azureAccount"; import { NonZeroExitCodeBehaviour, invokeKubectlCommand } from "../commands/utils/kubectl"; import path from "path"; import * as fs from "fs/promises"; import { createTempFile } from "../commands/utils/tempfile"; import { TelemetryDefinition } from "../webview-contract/webviewTypes"; +import { ReadyAzureSessionProvider } from "../auth/types"; export class AzureServiceOperatorPanel extends BasePanel<"aso"> { constructor(extensionUri: vscode.Uri) { @@ -34,10 +35,10 @@ export class AzureServiceOperatorPanel extends BasePanel<"aso"> { export class AzureServiceOperatorDataProvider implements PanelDataProvider<"aso"> { constructor( + readonly sessionProvider: ReadyAzureSessionProvider, readonly extension: vscode.Extension, readonly kubectl: k8s.APIAvailable, readonly kubeConfigFilePath: string, - readonly azAccount: AzureAccountExtensionApi, readonly clusterName: string, ) {} @@ -86,7 +87,7 @@ export class AzureServiceOperatorDataProvider implements PanelDataProvider<"aso" appSecret: string, webview: MessageSink, ): Promise { - const servicePrincipalAccess = await getServicePrincipalAccess(this.azAccount, appId, appSecret); + const servicePrincipalAccess = await getServicePrincipalAccess(this.sessionProvider, appId, appSecret); if (failed(servicePrincipalAccess)) { webview.postCheckSPResponse({ succeeded: false, diff --git a/src/panels/ClusterPropertiesPanel.ts b/src/panels/ClusterPropertiesPanel.ts index 168c57b1..339d9086 100644 --- a/src/panels/ClusterPropertiesPanel.ts +++ b/src/panels/ClusterPropertiesPanel.ts @@ -19,6 +19,8 @@ import { } from "@azure/arm-containerservice"; import { getKubernetesVersionInfo, getManagedCluster } from "../commands/utils/clusters"; import { TelemetryDefinition } from "../webview-contract/webviewTypes"; +import { getAksClient } from "../commands/utils/arm"; +import { ReadyAzureSessionProvider } from "../auth/types"; export class ClusterPropertiesPanel extends BasePanel<"clusterProperties"> { constructor(extensionUri: Uri) { @@ -30,11 +32,15 @@ export class ClusterPropertiesPanel extends BasePanel<"clusterProperties"> { } export class ClusterPropertiesDataProvider implements PanelDataProvider<"clusterProperties"> { + private readonly client: ContainerServiceClient; constructor( - readonly client: ContainerServiceClient, + private readonly sessionProvider: ReadyAzureSessionProvider, + readonly subscriptionId: string, readonly resourceGroup: string, readonly clusterName: string, - ) {} + ) { + this.client = getAksClient(sessionProvider, subscriptionId); + } getTitle(): string { return `Cluster Properties for ${this.clusterName}`; @@ -205,7 +211,12 @@ export class ClusterPropertiesDataProvider implements PanelDataProvider<"cluster } private async readAndPostClusterProperties(webview: MessageSink) { - const cluster = await getManagedCluster(this.client, this.resourceGroup, this.clusterName); + const cluster = await getManagedCluster( + this.sessionProvider, + this.subscriptionId, + this.resourceGroup, + this.clusterName, + ); if (failed(cluster)) { webview.postErrorNotification(cluster.error); return; diff --git a/src/panels/CreateClusterPanel.ts b/src/panels/CreateClusterPanel.ts index 7bc4bd2a..37cf29d5 100644 --- a/src/panels/CreateClusterPanel.ts +++ b/src/panels/CreateClusterPanel.ts @@ -1,9 +1,7 @@ import { ContainerServiceClient, KubernetesVersion } from "@azure/arm-containerservice"; import { ResourceGroup as ARMResourceGroup, ResourceManagementClient } from "@azure/arm-resources"; import { RestError } from "@azure/storage-blob"; -import { ISubscriptionContext } from "@microsoft/vscode-azext-utils"; import { Uri, window } from "vscode"; -import { getResourceGroupList } from "../commands/utils/clusters"; import { failed, getErrorMessage } from "../commands/utils/errorable"; import { MessageHandler, MessageSink } from "../webview-contract/messaging"; import { @@ -18,6 +16,10 @@ import { BasePanel, PanelDataProvider } from "./BasePanel"; import { ClusterDeploymentBuilder, ClusterSpec } from "./utilities/ClusterSpecCreationBuilder"; import { getPortalResourceUrl } from "../commands/utils/env"; import { TelemetryDefinition } from "../webview-contract/webviewTypes"; +import { getResourceGroups } from "../commands/utils/resourceGroups"; +import { getAksClient, getResourceManagementClient } from "../commands/utils/arm"; +import { getEnvironment } from "../auth/azureAuth"; +import { ReadyAzureSessionProvider } from "../auth/types"; export class CreateClusterPanel extends BasePanel<"createCluster"> { constructor(extensionUri: Uri) { @@ -30,21 +32,27 @@ export class CreateClusterPanel extends BasePanel<"createCluster"> { } export class CreateClusterDataProvider implements PanelDataProvider<"createCluster"> { + private readonly resourceManagementClient: ResourceManagementClient; + private readonly containerServiceClient: ContainerServiceClient; + public constructor( - readonly resourceManagementClient: ResourceManagementClient, - readonly containerServiceClient: ContainerServiceClient, - readonly subscriptionContext: ISubscriptionContext, + readonly sessionProvider: ReadyAzureSessionProvider, + readonly subscriptionId: string, + readonly subscriptionName: string, readonly refreshTree: () => void, - ) {} + ) { + this.resourceManagementClient = getResourceManagementClient(sessionProvider, this.subscriptionId); + this.containerServiceClient = getAksClient(sessionProvider, this.subscriptionId); + } getTitle(): string { - return `Create Cluster in ${this.subscriptionContext.subscriptionDisplayName}`; + return `Create Cluster in ${this.subscriptionName}`; } getInitialState(): InitialState { return { - subscriptionId: this.subscriptionContext.subscriptionId, - subscriptionName: this.subscriptionContext.subscriptionDisplayName, + subscriptionId: this.subscriptionId, + subscriptionName: this.subscriptionName, }; } @@ -92,7 +100,7 @@ export class CreateClusterDataProvider implements PanelDataProvider<"createClust } private async handleGetResourceGroupsRequest(webview: MessageSink) { - const groups = await getResourceGroupList(this.resourceManagementClient); + const groups = await getResourceGroups(this.sessionProvider, this.subscriptionId); if (failed(groups)) { webview.postProgressUpdate({ event: ProgressEventType.Failed, @@ -133,6 +141,8 @@ export class CreateClusterDataProvider implements PanelDataProvider<"createClust } await createCluster( + this.sessionProvider, + this.subscriptionId, groupName, location, name, @@ -140,7 +150,6 @@ export class CreateClusterDataProvider implements PanelDataProvider<"createClust webview, this.containerServiceClient, this.resourceManagementClient, - this.subscriptionContext, ); this.refreshTree(); @@ -182,6 +191,8 @@ async function createResourceGroup( } async function createCluster( + sessionProvider: ReadyAzureSessionProvider, + subscriptionId: string, groupName: string, location: string, name: string, @@ -189,7 +200,6 @@ async function createCluster( webview: MessageSink, containerServiceClient: ContainerServiceClient, resourceManagementClient: ResourceManagementClient, - subscriptionContext: ISubscriptionContext, ) { const operationDescription = `Creating cluster ${name}`; webview.postProgressUpdate({ @@ -217,13 +227,26 @@ async function createCluster( return; } + const session = await sessionProvider.getAuthSession(); + if (failed(session)) { + window.showErrorMessage(`Error getting authentication session: ${session.error}`); + webview.postProgressUpdate({ + event: ProgressEventType.Failed, + operationDescription, + errorMessage: session.error, + deploymentPortalUrl: null, + createdCluster: null, + }); + return; + } + const clusterSpec: ClusterSpec = { location, name, resourceGroupName: groupName, - subscriptionId: subscriptionContext.subscriptionId, + subscriptionId: subscriptionId, kubernetesVersion: kubernetesVersion.version, - username: subscriptionContext.userId, + username: session.result.account.label, // Account label seems to be email address }; // Create a unique deployment name. @@ -233,14 +256,16 @@ async function createCluster( .buildTemplate(preset) .getDeployment(); + const environment = getEnvironment(); + try { const poller = await resourceManagementClient.deployments.beginCreateOrUpdate( groupName, deploymentName, deploymentSpec, ); - const deploymentArmId = `/subscriptions/${subscriptionContext.subscriptionId}/resourcegroups/${groupName}/providers/Microsoft.Resources/deployments/${deploymentName}`; - const deploymentPortalUrl = getPortalResourceUrl(subscriptionContext.environment, deploymentArmId); + const deploymentArmId = `/subscriptions/${subscriptionId}/resourcegroups/${groupName}/providers/Microsoft.Resources/deployments/${deploymentName}`; + const deploymentPortalUrl = getPortalResourceUrl(environment, deploymentArmId); webview.postProgressUpdate({ event: ProgressEventType.InProgress, operationDescription, @@ -270,14 +295,14 @@ async function createCluster( }); } else if (state.status === "succeeded") { window.showInformationMessage(`Successfully created AKS cluster ${name}.`); - const armId = `/subscriptions/${subscriptionContext.subscriptionId}/resourceGroups/${groupName}/providers/Microsoft.ContainerService/managedClusters/${name}`; + const armId = `/subscriptions/${subscriptionId}/resourceGroups/${groupName}/providers/Microsoft.ContainerService/managedClusters/${name}`; webview.postProgressUpdate({ event: ProgressEventType.Success, operationDescription, errorMessage: null, deploymentPortalUrl, createdCluster: { - portalUrl: getPortalResourceUrl(subscriptionContext.environment, armId), + portalUrl: getPortalResourceUrl(environment, armId), }, }); } diff --git a/src/tree/aksClusterTreeItem.ts b/src/tree/aksClusterTreeItem.ts index 919dab0b..51b77bb8 100644 --- a/src/tree/aksClusterTreeItem.ts +++ b/src/tree/aksClusterTreeItem.ts @@ -1,9 +1,7 @@ -import { AzExtParentTreeItem, AzExtTreeItem, ISubscriptionContext } from "@microsoft/vscode-azext-utils"; +import { AzExtParentTreeItem, AzExtTreeItem } from "@microsoft/vscode-azext-utils"; import { CloudExplorerV1 } from "vscode-kubernetes-tools-api"; import { assetUri } from "../assets"; -import { parseResource } from "../azure-api-utils"; -import { Resource } from "@azure/arm-resources"; -import { SubscriptionTreeItemBase } from "@microsoft/vscode-azext-azureutils"; +import { DefinedResourceWithGroup } from "../commands/utils/azureResources"; import { SubscriptionTreeNode } from "./subscriptionTreeItem"; // The de facto API of tree nodes that represent individual AKS clusters. @@ -14,30 +12,37 @@ export interface AksClusterTreeNode { readonly armId: string; readonly name: string; readonly subscriptionTreeNode: SubscriptionTreeNode; - readonly subscription: ISubscriptionContext; + readonly subscriptionId: string; readonly resourceGroupName: string; } -export function createChildClusterTreeNode( - parent: SubscriptionTreeItemBase & SubscriptionTreeNode, - clusterResource: Resource, +export function createClusterTreeNode( + parent: AzExtParentTreeItem & SubscriptionTreeNode, + subscriptionId: string, + clusterResource: DefinedResourceWithGroup, ): AzExtTreeItem { - return new AksClusterTreeItem(parent, clusterResource); + return new AksClusterTreeItem(parent, subscriptionId, clusterResource); } class AksClusterTreeItem extends AzExtTreeItem implements AksClusterTreeNode { - public readonly armId: string; public readonly subscriptionTreeNode: SubscriptionTreeNode; + public readonly armId: string; + public readonly resourceGroupName: string; + public readonly name: string; + constructor( parent: AzExtParentTreeItem & SubscriptionTreeNode, - readonly resource: Resource, + readonly subscriptionId: string, + readonly clusterResource: DefinedResourceWithGroup, ) { super(parent); this.iconPath = assetUri("resources/aks-tools.png"); - this.id = `${this.resource.name!} ${parseResource(this.resource.id!).resourceGroupName!}`; - this.armId = this.resource.id!; this.subscriptionTreeNode = parent; + this.id = `${this.clusterResource.name} ${clusterResource.resourceGroup}`; + this.armId = this.clusterResource.id; + this.resourceGroupName = clusterResource.resourceGroup; + this.name = this.clusterResource.name; } public readonly contextValue: string = `aks.cluster ${CloudExplorerV1.SHOW_KUBECONFIG_COMMANDS_CONTEXT}`; @@ -46,17 +51,8 @@ class AksClusterTreeItem extends AzExtTreeItem implements AksClusterTreeNode { return this.name; } - public get name(): string { - return this.resource.name!; - } - public get resourceType(): string { - return this.resource.type!; - } - - public get resourceGroupName(): string { - // armid is in the format: /subscriptions//resourceGroups//providers//managedClusters/ - return parseResource(this.armId).resourceGroupName!; + return "Microsoft.ContainerService/managedClusters"; } public get clusterTreeItem(): AzExtTreeItem { diff --git a/src/tree/azureAccountTreeItem.ts b/src/tree/azureAccountTreeItem.ts index cd6dfea8..3ae2865f 100644 --- a/src/tree/azureAccountTreeItem.ts +++ b/src/tree/azureAccountTreeItem.ts @@ -1,15 +1,53 @@ -import { ISubscriptionContext } from "@microsoft/vscode-azext-utils"; -import { AzureAccountTreeItemBase, SubscriptionTreeItemBase } from "@microsoft/vscode-azext-azureutils"; -import { createChildSubscriptionTreeItem } from "./subscriptionTreeItem"; +import { + AzExtParentTreeItem, + AzExtTreeItem, + GenericTreeItem, + ISubscriptionContext, + TreeItemIconPath, + registerEvent, +} from "@microsoft/vscode-azext-utils"; +import { AuthenticationSession, ThemeIcon } from "vscode"; +import { assetUri } from "../assets"; +import { failed } from "../commands/utils/errorable"; import * as k8s from "vscode-kubernetes-tools-api"; +import { createSubscriptionTreeItem } from "./subscriptionTreeItem"; +import { getFilteredSubscriptionsChangeEvent } from "../commands/utils/config"; +import { getCredential, getEnvironment } from "../auth/azureAuth"; +import { SelectionType, getSubscriptions } from "../commands/utils/subscriptions"; +import { Subscription } from "@azure/arm-resources-subscriptions"; +import { AzureSessionProvider, ReadyAzureSessionProvider, isReady } from "../auth/types"; -export function createAzureAccountTreeItem(): AzureAccountTreeItemBase { - return new AzureAccountTreeItem(); +export function createAzureAccountTreeItem( + sessionProvider: AzureSessionProvider, +): AzExtParentTreeItem & { dispose(): unknown } { + return new AzureAccountTreeItem(sessionProvider); } -class AzureAccountTreeItem extends AzureAccountTreeItemBase { - public createSubscriptionTreeItem(subscription: ISubscriptionContext): SubscriptionTreeItemBase { - return createChildSubscriptionTreeItem(this, subscription); +class AzureAccountTreeItem extends AzExtParentTreeItem { + private subscriptionTreeItems: AzExtTreeItem[] | undefined; + + constructor(private readonly sessionProvider: AzureSessionProvider) { + super(undefined); + this.autoSelectInTreeItemPicker = true; + + const onStatusChange = this.sessionProvider.signInStatusChangeEvent; + const onFilteredSubscriptionsChange = getFilteredSubscriptionsChangeEvent(); + registerEvent("azureAccountTreeItem.onSignInStatusChange", onStatusChange, (context) => this.refresh(context)); + registerEvent("azureAccountTreeItem.onSubscriptionFilterChange", onFilteredSubscriptionsChange, (context) => + this.refresh(context), + ); + } + + public override get label() { + return "Azure"; + } + + public override get contextValue() { + return "aks.azureAccount"; + } + + public override get iconPath(): TreeItemIconPath { + return assetUri("resources/azure.svg"); } public async refreshImpl?(): Promise { @@ -23,4 +61,143 @@ class AzureAccountTreeItem extends AzureAccountTreeItemBase { cloudExplorer.api.refresh(); } } + + public dispose(): void {} + + public hasMoreChildrenImpl(): boolean { + return false; + } + + public async loadMoreChildrenImpl(): Promise { + const existingSubscriptionTreeItems: AzExtTreeItem[] = this.subscriptionTreeItems || []; + this.subscriptionTreeItems = []; + + switch (this.sessionProvider.signInStatus) { + case "Initializing": + return [ + new GenericTreeItem(this, { + label: "Loading...", + contextValue: "azureCommand", + id: "aksAccountLoading", + iconPath: new ThemeIcon("loading~spin"), + }), + ]; + case "SignedOut": + return [ + new GenericTreeItem(this, { + label: "Sign in to Azure...", + commandId: "aks.signInToAzure", + contextValue: "azureCommand", + id: "aksAccountSignIn", + iconPath: new ThemeIcon("sign-in"), + includeInTreeItemPicker: true, + }), + ]; + case "SigningIn": + return [ + new GenericTreeItem(this, { + label: "Waiting for Azure sign-in...", + contextValue: "azureCommand", + id: "aksAccountSigningIn", + iconPath: new ThemeIcon("loading~spin"), + }), + ]; + } + + if (this.sessionProvider.selectedTenant === null) { + // Signed in, but maybe no tenant selected + return [ + new GenericTreeItem(this, { + label: "Select tenant...", + commandId: "aks.selectTenant", + contextValue: "azureCommand", + id: "aksAccountSelectTenant", + iconPath: new ThemeIcon("account"), + includeInTreeItemPicker: true, + }), + ]; + } + + // Check the session is ready and we can get an auth session + // (which will be used below for creating a subscription context). + const session = await this.sessionProvider.getAuthSession(); + if (failed(session) || !isReady(this.sessionProvider)) { + return [ + new GenericTreeItem(this, { + label: "Error authenticating", + contextValue: "azureCommand", + id: "aksAccountError", + iconPath: new ThemeIcon("error"), + }), + ]; + } + + const subscriptions = await getSubscriptions(this.sessionProvider, SelectionType.AllIfNoFilters); + if (failed(subscriptions)) { + return [ + new GenericTreeItem(this, { + label: "Error loading subscriptions", + contextValue: "azureCommand", + id: "aksAccountError", + iconPath: new ThemeIcon("error"), + description: subscriptions.error, + }), + ]; + } + + if (subscriptions.result.length === 0) { + return [ + new GenericTreeItem(this, { + label: "No subscriptions found", + contextValue: "azureCommand", + id: "aksAccountNoSubs", + iconPath: new ThemeIcon("info"), + }), + ]; + } + + // We've confirmed above that the provider is ready. + const readySessionProvider: ReadyAzureSessionProvider = this.sessionProvider; + + this.subscriptionTreeItems = await Promise.all( + subscriptions.result.map(async (subscription) => { + const existingTreeItem: AzExtTreeItem | undefined = existingSubscriptionTreeItems.find( + (ti) => ti.id === subscription.subscriptionId, + ); + if (existingTreeItem) { + // Return existing treeItem (which might have many 'cached' tree items underneath it) rather than creating a brand new tree item every time + return existingTreeItem; + } else { + const subscriptionContext = getSubscriptionContext( + readySessionProvider, + session.result, + subscription, + ); + return await createSubscriptionTreeItem(this, readySessionProvider, subscriptionContext); + } + }), + ); + + return this.subscriptionTreeItems; + } +} + +function getSubscriptionContext( + sessionProvider: ReadyAzureSessionProvider, + session: AuthenticationSession, + subscription: Subscription, +): ISubscriptionContext { + const credentials = getCredential(sessionProvider); + const environment = getEnvironment(); + + return { + credentials, + subscriptionDisplayName: subscription.displayName || "", + subscriptionId: subscription.subscriptionId || "", + subscriptionPath: `/subscriptions/${subscription.subscriptionId}`, + tenantId: subscription.tenantId || "", + userId: session.account.id, + environment, + isCustomCloud: environment.name === "AzureCustomCloud", + }; } diff --git a/src/tree/subscriptionTreeItem.ts b/src/tree/subscriptionTreeItem.ts index 38101942..26177b19 100644 --- a/src/tree/subscriptionTreeItem.ts +++ b/src/tree/subscriptionTreeItem.ts @@ -1,65 +1,91 @@ -import { AzureAccountTreeItemBase, SubscriptionTreeItemBase } from "@microsoft/vscode-azext-azureutils"; import { - AzExtTreeItem, AzExtParentTreeItem, - ISubscriptionContext, AzExtTreeDataProvider, + AzExtTreeItem, + ISubscriptionContext, } from "@microsoft/vscode-azext-utils"; -import { createChildClusterTreeNode } from "./aksClusterTreeItem"; -import { getResourceManagementClient } from "../commands/utils/clusters"; +import { createClusterTreeNode } from "./aksClusterTreeItem"; +import { assetUri } from "../assets"; import * as k8s from "vscode-kubernetes-tools-api"; -import { Resource } from "@azure/arm-resources"; +import { window } from "vscode"; +import { getResources } from "../commands/utils/azureResources"; +import { failed } from "../commands/utils/errorable"; +import { ReadyAzureSessionProvider } from "../auth/types"; // The de facto API of tree nodes that represent individual Azure subscriptions. // Tree items should implement this interface to maintain backward compatibility with previous versions of the extension. export interface SubscriptionTreeNode { readonly nodeType: "subscription"; readonly name: string; - readonly subscription: ISubscriptionContext; + readonly subscriptionId: string; readonly treeDataProvider: AzExtTreeDataProvider; readonly treeItem: AzExtTreeItem; } export function isSubscriptionTreeNode(node: unknown): node is SubscriptionTreeNode { - return node instanceof SubscriptionTreeItemBase; + return node instanceof SubscriptionTreeItem; } -export function createChildSubscriptionTreeItem( - parent: AzureAccountTreeItemBase, +export function createSubscriptionTreeItem( + parent: AzExtParentTreeItem, + sessionProvider: ReadyAzureSessionProvider, subscription: ISubscriptionContext, -): SubscriptionTreeItemBase { - return new SubscriptionTreeItem(parent, subscription); +): AzExtTreeItem { + return new SubscriptionTreeItem(parent, sessionProvider, subscription); } -class SubscriptionTreeItem extends SubscriptionTreeItemBase implements SubscriptionTreeNode { +class SubscriptionTreeItem extends AzExtParentTreeItem implements SubscriptionTreeNode { + private readonly sessionProvider: ReadyAzureSessionProvider; + public readonly subscriptionContext: ISubscriptionContext; + public readonly subscriptionId: string; public readonly name: string; + public readonly contextValue = "aks.subscription"; + public readonly label: string; - constructor(parent: AzExtParentTreeItem, root: ISubscriptionContext) { - super(parent, root); - this.name = root.subscriptionDisplayName || ""; + public constructor( + parent: AzExtParentTreeItem, + sessionProvider: ReadyAzureSessionProvider, + subscription: ISubscriptionContext, + ) { + super(parent); + this.sessionProvider = sessionProvider; + this.subscriptionContext = subscription; + this.subscriptionId = subscription.subscriptionId; + this.name = subscription.subscriptionDisplayName; + this.label = subscription.subscriptionDisplayName; + this.id = subscription.subscriptionPath; + this.iconPath = assetUri("resources/azureSubscription.svg"); } get treeItem(): AzExtTreeItem { return this; } - public readonly contextValue: string = "aks.subscription"; + /** + * Needed by parent class. + */ + get subscription(): ISubscriptionContext { + return this.subscriptionContext; + } public hasMoreChildrenImpl(): boolean { return false; } public async loadMoreChildrenImpl(): Promise { - const client = getResourceManagementClient(this); - const aksClusterResources: Resource[] = []; - const result = client.resources.list({ - filter: "resourceType eq 'Microsoft.ContainerService/managedClusters'", - }); - for await (const pageResources of result.byPage()) { - aksClusterResources.push(...pageResources); + const clusterResources = await getResources( + this.sessionProvider, + this.subscription.subscriptionId, + "Microsoft.ContainerService/managedClusters", + ); + if (failed(clusterResources)) { + window.showErrorMessage( + `Failed to list clusters in subscription ${this.subscription.subscriptionId}: ${clusterResources.error}`, + ); + return []; } - return aksClusterResources.map((aksClusterResource) => createChildClusterTreeNode(this, aksClusterResource)); + return clusterResources.result.map((r) => createClusterTreeNode(this, this.subscriptionId, r)); } public async refreshImpl(): Promise { diff --git a/webpack.config.js b/webpack.config.js index db4d2511..5f9536d2 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -2,7 +2,6 @@ const path = require("path"); const webpack = require("webpack"); -const FileManagerPlugin = require("filemanager-webpack-plugin"); const ESLintPlugin = require("eslint-webpack-plugin"); /**@type {import('webpack').Configuration}*/ @@ -35,32 +34,6 @@ const config = { // Prevent webpack from trying to bundle electron, or require it as a direct dependency: // https://github.com/sindresorhus/got/issues/345#issuecomment-329939488 new webpack.IgnorePlugin({ resourceRegExp: /^electron$/ }), - new FileManagerPlugin({ - events: { - onEnd: { - copy: [ - { - source: path.join( - __dirname, - "node_modules", - "@microsoft", - "vscode-azext-azureutils", - "resources", - "**", - ), - destination: path.join( - __dirname, - "dist", - "node_modules", - "@microsoft", - "vscode-azext-azureutils", - "resources", - ), - }, - ], - }, - }, - }), ], resolve: { extensions: [".ts", ".js", ".json"],