diff --git a/package-lock.json b/package-lock.json index a83fd56..8201f1a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "vibecheque", - "version": "0.0.1", + "version": "0.0.2", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "vibecheque", - "version": "0.0.1", + "version": "0.0.2", "license": "CC0-1.0", "dependencies": { "discord.js": "^14.16.3", @@ -54,9 +54,9 @@ } }, "node_modules/@babel/compat-data": { - "version": "7.26.2", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.26.2.tgz", - "integrity": "sha512-Z0WgzSEa+aUcdiJuCIqgujCshpMWgUpgOxXotrYPSA53hA3qopNaqcJpyr0hVb1FeWdnqFA35/fUtXgBK8srQg==", + "version": "7.26.8", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.26.8.tgz", + "integrity": "sha512-oH5UPLMWR3L2wEFLnFJ1TZXqHufiTKAiLfqw5zkhS4dKXLJ10yVztfil/twG8EDTA4F/tvVNw9nOl4ZMslB8rQ==", "dev": true, "license": "MIT", "engines": { @@ -64,22 +64,22 @@ } }, "node_modules/@babel/core": { - "version": "7.26.0", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.26.0.tgz", - "integrity": "sha512-i1SLeK+DzNnQ3LL/CswPCa/E5u4lh1k6IAEphON8F+cXt0t9euTshDru0q7/IqMa1PMPz5RnHuHscF8/ZJsStg==", + "version": "7.26.10", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.26.10.tgz", + "integrity": "sha512-vMqyb7XCDMPvJFFOaT9kxtiRh42GwlZEg1/uIgtZshS5a/8OaduUfCi7kynKgc3Tw/6Uo2D+db9qBttghhmxwQ==", "dev": true, "license": "MIT", "dependencies": { "@ampproject/remapping": "^2.2.0", - "@babel/code-frame": "^7.26.0", - "@babel/generator": "^7.26.0", - "@babel/helper-compilation-targets": "^7.25.9", + "@babel/code-frame": "^7.26.2", + "@babel/generator": "^7.26.10", + "@babel/helper-compilation-targets": "^7.26.5", "@babel/helper-module-transforms": "^7.26.0", - "@babel/helpers": "^7.26.0", - "@babel/parser": "^7.26.0", - "@babel/template": "^7.25.9", - "@babel/traverse": "^7.25.9", - "@babel/types": "^7.26.0", + "@babel/helpers": "^7.26.10", + "@babel/parser": "^7.26.10", + "@babel/template": "^7.26.9", + "@babel/traverse": "^7.26.10", + "@babel/types": "^7.26.10", "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", @@ -95,14 +95,14 @@ } }, "node_modules/@babel/generator": { - "version": "7.26.2", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.26.2.tgz", - "integrity": "sha512-zevQbhbau95nkoxSq3f/DC/SC+EEOUZd3DYqfSkMhY2/wfSeaHV1Ew4vk8e+x8lja31IbyuUa2uQ3JONqKbysw==", + "version": "7.26.10", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.26.10.tgz", + "integrity": "sha512-rRHT8siFIXQrAYOYqZQVsAr8vJ+cBNqcVAY6m5V8/4QqzaPl+zDBe6cLEPRDuNOUf3ww8RfJVlOyQMoSI+5Ang==", "dev": true, "license": "MIT", "dependencies": { - "@babel/parser": "^7.26.2", - "@babel/types": "^7.26.0", + "@babel/parser": "^7.26.10", + "@babel/types": "^7.26.10", "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.25", "jsesc": "^3.0.2" @@ -112,13 +112,13 @@ } }, "node_modules/@babel/helper-compilation-targets": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.25.9.tgz", - "integrity": "sha512-j9Db8Suy6yV/VHa4qzrj9yZfZxhLWQdVnRlXxmKLYlhWUVB1sB2G5sxuWYXk/whHD9iW76PmNzxZ4UCnTQTVEQ==", + "version": "7.26.5", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.26.5.tgz", + "integrity": "sha512-IXuyn5EkouFJscIDuFF5EsiSolseme1s0CZB+QxVugqJLYmKdxI1VfIBOst0SUu4rnk2Z7kqTwmoO1lp3HIfnA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/compat-data": "^7.25.9", + "@babel/compat-data": "^7.26.5", "@babel/helper-validator-option": "^7.25.9", "browserslist": "^4.24.0", "lru-cache": "^5.1.1", @@ -161,9 +161,9 @@ } }, "node_modules/@babel/helper-plugin-utils": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.25.9.tgz", - "integrity": "sha512-kSMlyUVdWe25rEsRGviIgOWnoT/nfABVWlqt9N19/dIPWViAOW2s9wznP5tURbs/IDuNk4gPy3YdYRgH3uxhBw==", + "version": "7.26.5", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.26.5.tgz", + "integrity": "sha512-RS+jZcRdZdRFzMyr+wcsaqOmld1/EqTghfaBGQQd/WnRdzdlvSZ//kF7U8VQTxf1ynZ4cjUcYgjVGx13ewNPMg==", "dev": true, "license": "MIT", "engines": { @@ -201,27 +201,27 @@ } }, "node_modules/@babel/helpers": { - "version": "7.26.0", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.26.0.tgz", - "integrity": "sha512-tbhNuIxNcVb21pInl3ZSjksLCvgdZy9KwJ8brv993QtIVKJBBkYXz4q4ZbAv31GdnC+R90np23L5FbEBlthAEw==", + "version": "7.26.10", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.26.10.tgz", + "integrity": "sha512-UPYc3SauzZ3JGgj87GgZ89JVdC5dj0AoetR5Bw6wj4niittNyFh6+eOGonYvJ1ao6B8lEa3Q3klS7ADZ53bc5g==", "dev": true, "license": "MIT", "dependencies": { - "@babel/template": "^7.25.9", - "@babel/types": "^7.26.0" + "@babel/template": "^7.26.9", + "@babel/types": "^7.26.10" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/parser": { - "version": "7.26.2", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.26.2.tgz", - "integrity": "sha512-DWMCZH9WA4Maitz2q21SRKHo9QXZxkDsbNZoVD62gusNtNBBqDg9i7uOhASfTfIGNzW+O+r7+jAlM8dwphcJKQ==", + "version": "7.26.10", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.26.10.tgz", + "integrity": "sha512-6aQR2zGE/QFi8JpDLjUZEPYOs7+mhKXm86VaKFiLP35JQwQb6bwUE+XbvkH0EptsYhbNBSUGaUBLKqxH1xSgsA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/types": "^7.26.0" + "@babel/types": "^7.26.10" }, "bin": { "parser": "bin/babel-parser.js" @@ -470,32 +470,32 @@ } }, "node_modules/@babel/template": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.25.9.tgz", - "integrity": "sha512-9DGttpmPvIxBb/2uwpVo3dqJ+O6RooAFOS+lB+xDqoE2PVCE8nfoHMdZLpfCQRLwvohzXISPZcgxt80xLfsuwg==", + "version": "7.26.9", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.26.9.tgz", + "integrity": "sha512-qyRplbeIpNZhmzOysF/wFMuP9sctmh2cFzRAZOn1YapxBsE1i9bJIY586R/WBLfLcmcBlM8ROBiQURnnNy+zfA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.25.9", - "@babel/parser": "^7.25.9", - "@babel/types": "^7.25.9" + "@babel/code-frame": "^7.26.2", + "@babel/parser": "^7.26.9", + "@babel/types": "^7.26.9" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/traverse": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.25.9.tgz", - "integrity": "sha512-ZCuvfwOwlz/bawvAuvcj8rrithP2/N55Tzz342AkTvq4qaWbGfmCk/tKhNaV2cthijKrPAA8SRJV5WWe7IBMJw==", + "version": "7.26.10", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.26.10.tgz", + "integrity": "sha512-k8NuDrxr0WrPH5Aupqb2LCVURP/S0vBEn5mK6iH+GIYob66U5EtoZvcdudR2jQ4cmTwhEwW1DLB+Yyas9zjF6A==", "dev": true, "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.25.9", - "@babel/generator": "^7.25.9", - "@babel/parser": "^7.25.9", - "@babel/template": "^7.25.9", - "@babel/types": "^7.25.9", + "@babel/code-frame": "^7.26.2", + "@babel/generator": "^7.26.10", + "@babel/parser": "^7.26.10", + "@babel/template": "^7.26.9", + "@babel/types": "^7.26.10", "debug": "^4.3.1", "globals": "^11.1.0" }, @@ -504,9 +504,9 @@ } }, "node_modules/@babel/types": { - "version": "7.26.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.26.0.tgz", - "integrity": "sha512-Z/yiTPj+lDVnF7lWeKCIJzaIkI0vYO87dMpZ4bg4TDrFe4XXLFWL1TbXU27gBP3QccxV9mZICCrnjnYlJjXHOA==", + "version": "7.26.10", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.26.10.tgz", + "integrity": "sha512-emqcG3vHrpxUKTrxcblR36dcrcoRDvKmnL/dCL6ZsHaShW80qxCAcNhzQZrpeM765VzEos+xOi4s+r4IXzTwdQ==", "dev": true, "license": "MIT", "dependencies": { @@ -549,32 +549,26 @@ } }, "node_modules/@discordjs/builders": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/@discordjs/builders/-/builders-1.9.0.tgz", - "integrity": "sha512-0zx8DePNVvQibh5ly5kCEei5wtPBIUbSoE9n+91Rlladz4tgtFbJ36PZMxxZrTEOQ7AHMZ/b0crT/0fCy6FTKg==", + "version": "1.10.1", + "resolved": "https://registry.npmjs.org/@discordjs/builders/-/builders-1.10.1.tgz", + "integrity": "sha512-OWo1fY4ztL1/M/DUyRPShB4d/EzVfuUvPTRRHRIt/YxBrUYSz0a+JicD5F5zHFoNs2oTuWavxCOVFV1UljHTng==", "license": "Apache-2.0", "dependencies": { - "@discordjs/formatters": "^0.5.0", + "@discordjs/formatters": "^0.6.0", "@discordjs/util": "^1.1.1", "@sapphire/shapeshift": "^4.0.0", - "discord-api-types": "0.37.97", + "discord-api-types": "^0.37.119", "fast-deep-equal": "^3.1.3", "ts-mixer": "^6.0.4", "tslib": "^2.6.3" }, "engines": { - "node": ">=18" + "node": ">=16.11.0" }, "funding": { "url": "https://github.com/discordjs/discord.js?sponsor" } }, - "node_modules/@discordjs/builders/node_modules/discord-api-types": { - "version": "0.37.97", - "resolved": "https://registry.npmjs.org/discord-api-types/-/discord-api-types-0.37.97.tgz", - "integrity": "sha512-No1BXPcVkyVD4ZVmbNgDKaBoqgeQ+FJpzZ8wqHkfmBnTZig1FcH3iPPersiK1TUIAzgClh2IvOuVUYfcWLQAOA==", - "license": "MIT" - }, "node_modules/@discordjs/collection": { "version": "1.5.3", "resolved": "https://registry.npmjs.org/@discordjs/collection/-/collection-1.5.3.tgz", @@ -585,30 +579,24 @@ } }, "node_modules/@discordjs/formatters": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/@discordjs/formatters/-/formatters-0.5.0.tgz", - "integrity": "sha512-98b3i+Y19RFq1Xke4NkVY46x8KjJQjldHUuEbCqMvp1F5Iq9HgnGpu91jOi/Ufazhty32eRsKnnzS8n4c+L93g==", + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/@discordjs/formatters/-/formatters-0.6.0.tgz", + "integrity": "sha512-YIruKw4UILt/ivO4uISmrGq2GdMY6EkoTtD0oS0GvkJFRZbTSdPhzYiUILbJ/QslsvC9H9nTgGgnarnIl4jMfw==", "license": "Apache-2.0", "dependencies": { - "discord-api-types": "0.37.97" + "discord-api-types": "^0.37.114" }, "engines": { - "node": ">=18" + "node": ">=16.11.0" }, "funding": { "url": "https://github.com/discordjs/discord.js?sponsor" } }, - "node_modules/@discordjs/formatters/node_modules/discord-api-types": { - "version": "0.37.97", - "resolved": "https://registry.npmjs.org/discord-api-types/-/discord-api-types-0.37.97.tgz", - "integrity": "sha512-No1BXPcVkyVD4ZVmbNgDKaBoqgeQ+FJpzZ8wqHkfmBnTZig1FcH3iPPersiK1TUIAzgClh2IvOuVUYfcWLQAOA==", - "license": "MIT" - }, "node_modules/@discordjs/rest": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/@discordjs/rest/-/rest-2.4.0.tgz", - "integrity": "sha512-Xb2irDqNcq+O8F0/k/NaDp7+t091p+acb51iA4bCKfIn+WFWd6HrNvcsSbMMxIR9NjcMZS6NReTKygqiQN+ntw==", + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/@discordjs/rest/-/rest-2.4.3.tgz", + "integrity": "sha512-+SO4RKvWsM+y8uFHgYQrcTl/3+cY02uQOH7/7bKbVZsTfrfpoE62o5p+mmV+s7FVhTX82/kQUGGbu4YlV60RtA==", "license": "Apache-2.0", "dependencies": { "@discordjs/collection": "^2.1.1", @@ -616,10 +604,10 @@ "@sapphire/async-queue": "^1.5.3", "@sapphire/snowflake": "^3.5.3", "@vladfrangu/async_event_emitter": "^2.4.6", - "discord-api-types": "0.37.97", + "discord-api-types": "^0.37.119", "magic-bytes.js": "^1.10.0", "tslib": "^2.6.3", - "undici": "6.19.8" + "undici": "6.21.1" }, "engines": { "node": ">=18" @@ -640,12 +628,6 @@ "url": "https://github.com/discordjs/discord.js?sponsor" } }, - "node_modules/@discordjs/rest/node_modules/discord-api-types": { - "version": "0.37.97", - "resolved": "https://registry.npmjs.org/discord-api-types/-/discord-api-types-0.37.97.tgz", - "integrity": "sha512-No1BXPcVkyVD4ZVmbNgDKaBoqgeQ+FJpzZ8wqHkfmBnTZig1FcH3iPPersiK1TUIAzgClh2IvOuVUYfcWLQAOA==", - "license": "MIT" - }, "node_modules/@discordjs/util": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/@discordjs/util/-/util-1.1.1.tgz", @@ -659,20 +641,20 @@ } }, "node_modules/@discordjs/ws": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@discordjs/ws/-/ws-1.1.1.tgz", - "integrity": "sha512-PZ+vLpxGCRtmr2RMkqh8Zp+BenUaJqlS6xhgWKEZcgC/vfHLEzpHtKkB0sl3nZWpwtcKk6YWy+pU3okL2I97FA==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@discordjs/ws/-/ws-1.2.1.tgz", + "integrity": "sha512-PBvenhZG56a6tMWF/f4P6f4GxZKJTBG95n7aiGSPTnodmz4N5g60t79rSIAq7ywMbv8A4jFtexMruH+oe51aQQ==", "license": "Apache-2.0", "dependencies": { "@discordjs/collection": "^2.1.0", - "@discordjs/rest": "^2.3.0", + "@discordjs/rest": "^2.4.3", "@discordjs/util": "^1.1.0", "@sapphire/async-queue": "^1.5.2", "@types/ws": "^8.5.10", "@vladfrangu/async_event_emitter": "^2.2.4", - "discord-api-types": "0.37.83", + "discord-api-types": "^0.37.119", "tslib": "^2.6.2", - "ws": "^8.16.0" + "ws": "^8.17.0" }, "engines": { "node": ">=16.11.0" @@ -693,22 +675,16 @@ "url": "https://github.com/discordjs/discord.js?sponsor" } }, - "node_modules/@discordjs/ws/node_modules/discord-api-types": { - "version": "0.37.83", - "resolved": "https://registry.npmjs.org/discord-api-types/-/discord-api-types-0.37.83.tgz", - "integrity": "sha512-urGGYeWtWNYMKnYlZnOnDHm8fVRffQs3U0SpE8RHeiuLKb/u92APS8HoQnPTFbnXmY1vVnXjXO4dOxcAn3J+DA==", - "license": "MIT" - }, "node_modules/@firebase/analytics": { - "version": "0.10.10", - "resolved": "https://registry.npmjs.org/@firebase/analytics/-/analytics-0.10.10.tgz", - "integrity": "sha512-Psdo7c9g2SLAYh6u1XRA+RZ7ab2JfBVuAt/kLzXkhKZL/gS2cQUCMsOW5p0RIlDPRKqpdNSmvujd2TeRWLKOkQ==", + "version": "0.10.12", + "resolved": "https://registry.npmjs.org/@firebase/analytics/-/analytics-0.10.12.tgz", + "integrity": "sha512-iDCGnw6qdFqwI5ywkgece99WADJNoymu+nLIQI4fZM/vCZ3bEo4wlpEetW71s1HqGpI0hQStiPhqVjFxDb2yyw==", "license": "Apache-2.0", "dependencies": { - "@firebase/component": "0.6.11", - "@firebase/installations": "0.6.11", + "@firebase/component": "0.6.13", + "@firebase/installations": "0.6.13", "@firebase/logger": "0.4.4", - "@firebase/util": "1.10.2", + "@firebase/util": "1.11.0", "tslib": "^2.1.0" }, "peerDependencies": { @@ -716,15 +692,15 @@ } }, "node_modules/@firebase/analytics-compat": { - "version": "0.2.16", - "resolved": "https://registry.npmjs.org/@firebase/analytics-compat/-/analytics-compat-0.2.16.tgz", - "integrity": "sha512-Q/s+u/TEMSb2EDJFQMGsOzpSosybBl8HuoSEMyGZ99+0Pu7SIR9MPDGUjc8PKiCFQWDJ3QXxgqh1d/rujyAMbA==", + "version": "0.2.18", + "resolved": "https://registry.npmjs.org/@firebase/analytics-compat/-/analytics-compat-0.2.18.tgz", + "integrity": "sha512-Hw9mzsSMZaQu6wrTbi3kYYwGw9nBqOHr47pVLxfr5v8CalsdrG5gfs9XUlPOZjHRVISp3oQrh1j7d3E+ulHPjQ==", "license": "Apache-2.0", "dependencies": { - "@firebase/analytics": "0.10.10", + "@firebase/analytics": "0.10.12", "@firebase/analytics-types": "0.8.3", - "@firebase/component": "0.6.11", - "@firebase/util": "1.10.2", + "@firebase/component": "0.6.13", + "@firebase/util": "1.11.0", "tslib": "^2.1.0" }, "peerDependencies": { @@ -738,14 +714,14 @@ "license": "Apache-2.0" }, "node_modules/@firebase/app": { - "version": "0.10.16", - "resolved": "https://registry.npmjs.org/@firebase/app/-/app-0.10.16.tgz", - "integrity": "sha512-SUati2qH48gvVGnSsqMkZr1Iq7No52a3tJQ4itboSTM89Erezmw3v1RsfVymrDze9+KiOLmBpvLNKSvheITFjg==", + "version": "0.11.2", + "resolved": "https://registry.npmjs.org/@firebase/app/-/app-0.11.2.tgz", + "integrity": "sha512-bFee0hPJZBzNtiizRxdgsu8C9DW3mn1y0OJJ4zHQsccjDYzGOfvN0G3CMGyBIiwNctsFpQa8orbp2IKywoUeqA==", "license": "Apache-2.0", "dependencies": { - "@firebase/component": "0.6.11", + "@firebase/component": "0.6.13", "@firebase/logger": "0.4.4", - "@firebase/util": "1.10.2", + "@firebase/util": "1.11.0", "idb": "7.1.1", "tslib": "^2.1.0" }, @@ -754,14 +730,14 @@ } }, "node_modules/@firebase/app-check": { - "version": "0.8.10", - "resolved": "https://registry.npmjs.org/@firebase/app-check/-/app-check-0.8.10.tgz", - "integrity": "sha512-DWFfxxif/t+Ow4MmRUevDX+A3hVxm1rUf6y5ZP4sIomfnVCO1NNahqtsv9rb1/tKGkTeoVT40weiTS/WjQG1mA==", + "version": "0.8.12", + "resolved": "https://registry.npmjs.org/@firebase/app-check/-/app-check-0.8.12.tgz", + "integrity": "sha512-LxjcoIFOU4sgK07ZWb8XDHxuVB+UKs41vPK+Sg9PeZMvEoz84fndFAx8Nz2nipiya2EmyxBgVhff8Hi6GBt+XA==", "license": "Apache-2.0", "dependencies": { - "@firebase/component": "0.6.11", + "@firebase/component": "0.6.13", "@firebase/logger": "0.4.4", - "@firebase/util": "1.10.2", + "@firebase/util": "1.11.0", "tslib": "^2.1.0" }, "engines": { @@ -772,16 +748,16 @@ } }, "node_modules/@firebase/app-check-compat": { - "version": "0.3.17", - "resolved": "https://registry.npmjs.org/@firebase/app-check-compat/-/app-check-compat-0.3.17.tgz", - "integrity": "sha512-a/eadrGsY0MVCBPhrNbKUhoYpms4UKTYLKO7nswwSFVsm3Rw6NslQQCNLfvljcDqP4E7alQDRGJXjkxd/5gJ+Q==", + "version": "0.3.19", + "resolved": "https://registry.npmjs.org/@firebase/app-check-compat/-/app-check-compat-0.3.19.tgz", + "integrity": "sha512-G8FMiqhrKc4gEEujrBDBBrbRav8MGqoLObWj1hy/riCSg4XlRYhpnq3ev8E9HTirqU1tAGH6oJl7vr+jfM7YNA==", "license": "Apache-2.0", "dependencies": { - "@firebase/app-check": "0.8.10", + "@firebase/app-check": "0.8.12", "@firebase/app-check-types": "0.5.3", - "@firebase/component": "0.6.11", + "@firebase/component": "0.6.13", "@firebase/logger": "0.4.4", - "@firebase/util": "1.10.2", + "@firebase/util": "1.11.0", "tslib": "^2.1.0" }, "engines": { @@ -804,15 +780,15 @@ "license": "Apache-2.0" }, "node_modules/@firebase/app-compat": { - "version": "0.2.46", - "resolved": "https://registry.npmjs.org/@firebase/app-compat/-/app-compat-0.2.46.tgz", - "integrity": "sha512-9hSHWE5LMqtKIm13CnH5OZeMPbkVV3y5vgNZ5EMFHcG2ceRrncyNjG9No5XfWQw8JponZdGs4HlE4aMD/jxcFA==", + "version": "0.2.51", + "resolved": "https://registry.npmjs.org/@firebase/app-compat/-/app-compat-0.2.51.tgz", + "integrity": "sha512-pxF1+coABt+ugqNI0YXDlmkKv4kh3pjI5BqIJJ1VXBo42OZbKMsQbFeos14YBrWwiqqSjUvQ70FBNsv5E2wuxg==", "license": "Apache-2.0", "dependencies": { - "@firebase/app": "0.10.16", - "@firebase/component": "0.6.11", + "@firebase/app": "0.11.2", + "@firebase/component": "0.6.13", "@firebase/logger": "0.4.4", - "@firebase/util": "1.10.2", + "@firebase/util": "1.11.0", "tslib": "^2.1.0" }, "engines": { @@ -826,14 +802,14 @@ "license": "Apache-2.0" }, "node_modules/@firebase/auth": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/@firebase/auth/-/auth-1.8.1.tgz", - "integrity": "sha512-LX9N/Cf5Z35r5yqm2+5M3+2bRRe/+RFaa/+u4HDni7TA27C/Xm4XHLKcWcLg1BzjrS4zngSaBEOSODvp6RFOqQ==", + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/@firebase/auth/-/auth-1.9.1.tgz", + "integrity": "sha512-9KKo5SNVkyJzftsW+daS+PGDbeJ+MFJWXQFHDqqPPH3acWHtiNnGHH5HGpIJErEELrsm9xMPie5zfZ0XpGU8+w==", "license": "Apache-2.0", "dependencies": { - "@firebase/component": "0.6.11", + "@firebase/component": "0.6.13", "@firebase/logger": "0.4.4", - "@firebase/util": "1.10.2", + "@firebase/util": "1.11.0", "tslib": "^2.1.0" }, "engines": { @@ -850,15 +826,15 @@ } }, "node_modules/@firebase/auth-compat": { - "version": "0.5.16", - "resolved": "https://registry.npmjs.org/@firebase/auth-compat/-/auth-compat-0.5.16.tgz", - "integrity": "sha512-YlYwJMBqAyv0ESy3jDUyshMhZlbUiwAm6B6+uUmigNDHU+uq7j4SFiDJEZlFFIz397yBzKn06SUdqutdQzGnCA==", + "version": "0.5.19", + "resolved": "https://registry.npmjs.org/@firebase/auth-compat/-/auth-compat-0.5.19.tgz", + "integrity": "sha512-v898POphOIBJliKF76SiGOXh4EdhO5fM6S9a2ZKf/8wHdBea/qwxwZoVVya4DW6Mi7vWyp1lIzHbFgwRz8G9TA==", "license": "Apache-2.0", "dependencies": { - "@firebase/auth": "1.8.1", - "@firebase/auth-types": "0.12.3", - "@firebase/component": "0.6.11", - "@firebase/util": "1.10.2", + "@firebase/auth": "1.9.1", + "@firebase/auth-types": "0.13.0", + "@firebase/component": "0.6.13", + "@firebase/util": "1.11.0", "tslib": "^2.1.0" }, "engines": { @@ -875,9 +851,9 @@ "license": "Apache-2.0" }, "node_modules/@firebase/auth-types": { - "version": "0.12.3", - "resolved": "https://registry.npmjs.org/@firebase/auth-types/-/auth-types-0.12.3.tgz", - "integrity": "sha512-Zq9zI0o5hqXDtKg6yDkSnvMCMuLU6qAVS51PANQx+ZZX5xnzyNLEBO3GZgBUPsV5qIMFhjhqmLDxUqCbnAYy2A==", + "version": "0.13.0", + "resolved": "https://registry.npmjs.org/@firebase/auth-types/-/auth-types-0.13.0.tgz", + "integrity": "sha512-S/PuIjni0AQRLF+l9ck0YpsMOdE8GO2KU6ubmBB7P+7TJUCQDa3R1dlgYm9UzGbbePMZsp0xzB93f2b/CgxMOg==", "license": "Apache-2.0", "peerDependencies": { "@firebase/app-types": "0.x", @@ -885,12 +861,12 @@ } }, "node_modules/@firebase/component": { - "version": "0.6.11", - "resolved": "https://registry.npmjs.org/@firebase/component/-/component-0.6.11.tgz", - "integrity": "sha512-eQbeCgPukLgsKD0Kw5wQgsMDX5LeoI1MIrziNDjmc6XDq5ZQnuUymANQgAb2wp1tSF9zDSXyxJmIUXaKgN58Ug==", + "version": "0.6.13", + "resolved": "https://registry.npmjs.org/@firebase/component/-/component-0.6.13.tgz", + "integrity": "sha512-I/Eg1NpAtZ8AAfq8mpdfXnuUpcLxIDdCDtTzWSh+FXnp/9eCKJ3SNbOCKrUCyhLzNa2SiPJYruei0sxVjaOTeg==", "license": "Apache-2.0", "dependencies": { - "@firebase/util": "1.10.2", + "@firebase/util": "1.11.0", "tslib": "^2.1.0" }, "engines": { @@ -898,15 +874,15 @@ } }, "node_modules/@firebase/data-connect": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/@firebase/data-connect/-/data-connect-0.1.2.tgz", - "integrity": "sha512-Bcf29mntFCt5V7aceMe36wnkHrG7cwbMlUVbDHOlh2foQKx9VtSXEONw9r6FtL1sFobHVYOM5L6umX35f59m5g==", + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@firebase/data-connect/-/data-connect-0.3.1.tgz", + "integrity": "sha512-PNlfAJ2mcbyRlWfm41nfk8EksTuvMFTFIX+puNzeUa6OTIDtyp1IX1NJVc7n6WpfbErN7tNqcOEMe6BMtpcjVA==", "license": "Apache-2.0", "dependencies": { "@firebase/auth-interop-types": "0.2.4", - "@firebase/component": "0.6.11", + "@firebase/component": "0.6.13", "@firebase/logger": "0.4.4", - "@firebase/util": "1.10.2", + "@firebase/util": "1.11.0", "tslib": "^2.1.0" }, "peerDependencies": { @@ -914,16 +890,16 @@ } }, "node_modules/@firebase/database": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/@firebase/database/-/database-1.0.10.tgz", - "integrity": "sha512-sWp2g92u7xT4BojGbTXZ80iaSIaL6GAL0pwvM0CO/hb0nHSnABAqsH7AhnWGsGvXuEvbPr7blZylPaR9J+GSuQ==", + "version": "1.0.13", + "resolved": "https://registry.npmjs.org/@firebase/database/-/database-1.0.13.tgz", + "integrity": "sha512-cdc+LuseKdJXzlrCx8ePMXyctSWtYS9SsP3y7EeA85GzNh/IL0b7HOq0eShridL935iQ0KScZCj5qJtKkGE53g==", "license": "Apache-2.0", "dependencies": { "@firebase/app-check-interop-types": "0.3.3", "@firebase/auth-interop-types": "0.2.4", - "@firebase/component": "0.6.11", + "@firebase/component": "0.6.13", "@firebase/logger": "0.4.4", - "@firebase/util": "1.10.2", + "@firebase/util": "1.11.0", "faye-websocket": "0.11.4", "tslib": "^2.1.0" }, @@ -932,16 +908,16 @@ } }, "node_modules/@firebase/database-compat": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@firebase/database-compat/-/database-compat-2.0.1.tgz", - "integrity": "sha512-IsFivOjdE1GrjTeKoBU/ZMenESKDXidFDzZzHBPQ/4P20ptGdrl3oLlWrV/QJqJ9lND4IidE3z4Xr5JyfUW1vg==", + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@firebase/database-compat/-/database-compat-2.0.4.tgz", + "integrity": "sha512-4qsptwZ3DTGNBje56ETItZQyA/HMalOelnLmkC3eR0M6+zkzOHjNHyWUWodW2mqxRKAM0sGkn+aIwYHKZFJXug==", "license": "Apache-2.0", "dependencies": { - "@firebase/component": "0.6.11", - "@firebase/database": "1.0.10", - "@firebase/database-types": "1.0.7", + "@firebase/component": "0.6.13", + "@firebase/database": "1.0.13", + "@firebase/database-types": "1.0.9", "@firebase/logger": "0.4.4", - "@firebase/util": "1.10.2", + "@firebase/util": "1.11.0", "tslib": "^2.1.0" }, "engines": { @@ -949,24 +925,24 @@ } }, "node_modules/@firebase/database-types": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/@firebase/database-types/-/database-types-1.0.7.tgz", - "integrity": "sha512-I7zcLfJXrM0WM+ksFmFdAMdlq/DFmpeMNa+/GNsLyFo5u/lX5zzkPzGe3srVWqaBQBY5KprylDGxOsP6ETfL0A==", + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@firebase/database-types/-/database-types-1.0.9.tgz", + "integrity": "sha512-uCntrxPbJHhZsNRpMhxNCm7GzhYWX+7J2e57wq1ZZ4NJrQw5DORgkAzJMByYZcVAjgADnCxxhK/GkoypH+XpvQ==", "license": "Apache-2.0", "dependencies": { "@firebase/app-types": "0.9.3", - "@firebase/util": "1.10.2" + "@firebase/util": "1.11.0" } }, "node_modules/@firebase/firestore": { - "version": "4.7.5", - "resolved": "https://registry.npmjs.org/@firebase/firestore/-/firestore-4.7.5.tgz", - "integrity": "sha512-OO3rHvjC07jL2ITN255xH/UzCVSvh6xG8oTzQdFScQvFbcm1fjCL1hgAdpDZcx3vVcKMV+6ktr8wbllkB8r+FQ==", + "version": "4.7.9", + "resolved": "https://registry.npmjs.org/@firebase/firestore/-/firestore-4.7.9.tgz", + "integrity": "sha512-uq/bUtHDqJ5ZqPHAJIlNzHpXUtcVYcASz2V6y7UmP1WLlRKEt1yf1OcQW5u8pY2yq7162OnCl5J5mkOdMTMLZw==", "license": "Apache-2.0", "dependencies": { - "@firebase/component": "0.6.11", + "@firebase/component": "0.6.13", "@firebase/logger": "0.4.4", - "@firebase/util": "1.10.2", + "@firebase/util": "1.11.0", "@firebase/webchannel-wrapper": "1.0.3", "@grpc/grpc-js": "~1.9.0", "@grpc/proto-loader": "^0.7.8", @@ -980,15 +956,15 @@ } }, "node_modules/@firebase/firestore-compat": { - "version": "0.3.40", - "resolved": "https://registry.npmjs.org/@firebase/firestore-compat/-/firestore-compat-0.3.40.tgz", - "integrity": "sha512-18HopMN811KYBc9Ptpr1Rewwio0XF09FF3jc5wtV6rGyAs815SlFFw5vW7ZeLd43zv9tlEc2FzM0H+5Vr9ZRxw==", + "version": "0.3.44", + "resolved": "https://registry.npmjs.org/@firebase/firestore-compat/-/firestore-compat-0.3.44.tgz", + "integrity": "sha512-4Lv2TyHEW+FugXPgmQ0ZylSbh9uFuKDP0lCL1hX9cbxXaafhC/Nww+DWokUQ2zZcynjc8fxFunw6Xbd3QHAlgA==", "license": "Apache-2.0", "dependencies": { - "@firebase/component": "0.6.11", - "@firebase/firestore": "4.7.5", + "@firebase/component": "0.6.13", + "@firebase/firestore": "4.7.9", "@firebase/firestore-types": "3.0.3", - "@firebase/util": "1.10.2", + "@firebase/util": "1.11.0", "tslib": "^2.1.0" }, "engines": { @@ -1009,16 +985,16 @@ } }, "node_modules/@firebase/functions": { - "version": "0.11.10", - "resolved": "https://registry.npmjs.org/@firebase/functions/-/functions-0.11.10.tgz", - "integrity": "sha512-TP+Dzebazhw6+GduBdWn1kOJRFH84G2z+BW3pNVfkpFRkc//+uT1Uw2+dLpMGSSBRG7FrcDG91vcPnOFCzr15w==", + "version": "0.12.3", + "resolved": "https://registry.npmjs.org/@firebase/functions/-/functions-0.12.3.tgz", + "integrity": "sha512-Wv7JZMUkKLb1goOWRtsu3t7m97uK6XQvjQLPvn8rncY91+VgdU72crqnaYCDI/ophNuBEmuK8mn0/pAnjUeA6A==", "license": "Apache-2.0", "dependencies": { "@firebase/app-check-interop-types": "0.3.3", "@firebase/auth-interop-types": "0.2.4", - "@firebase/component": "0.6.11", + "@firebase/component": "0.6.13", "@firebase/messaging-interop-types": "0.2.3", - "@firebase/util": "1.10.2", + "@firebase/util": "1.11.0", "tslib": "^2.1.0" }, "engines": { @@ -1029,15 +1005,15 @@ } }, "node_modules/@firebase/functions-compat": { - "version": "0.3.16", - "resolved": "https://registry.npmjs.org/@firebase/functions-compat/-/functions-compat-0.3.16.tgz", - "integrity": "sha512-FL7EXehiiBisNIR7mlb0i+moyWKLVfcEJgh/Wq6ZV6BdrCObpCTz7w5EvuRIEFX5e9cNL2oWInKg8S5X4HtINg==", + "version": "0.3.20", + "resolved": "https://registry.npmjs.org/@firebase/functions-compat/-/functions-compat-0.3.20.tgz", + "integrity": "sha512-iIudmYDAML6n3c7uXO2YTlzra2/J6lnMzmJTXNthvrKVMgNMaseNoQP1wKfchK84hMuSF8EkM4AvufwbJ+Juew==", "license": "Apache-2.0", "dependencies": { - "@firebase/component": "0.6.11", - "@firebase/functions": "0.11.10", + "@firebase/component": "0.6.13", + "@firebase/functions": "0.12.3", "@firebase/functions-types": "0.6.3", - "@firebase/util": "1.10.2", + "@firebase/util": "1.11.0", "tslib": "^2.1.0" }, "engines": { @@ -1054,13 +1030,13 @@ "license": "Apache-2.0" }, "node_modules/@firebase/installations": { - "version": "0.6.11", - "resolved": "https://registry.npmjs.org/@firebase/installations/-/installations-0.6.11.tgz", - "integrity": "sha512-w8fY8mw6fxJzsZM2ufmTtomopXl1+bn/syYon+Gpn+0p0nO1cIUEVEFrFazTLaaL9q1CaVhc3HmseRTsI3igAA==", + "version": "0.6.13", + "resolved": "https://registry.npmjs.org/@firebase/installations/-/installations-0.6.13.tgz", + "integrity": "sha512-6ZpkUiaygPFwgVneYxuuOuHnSPnTA4KefLEaw/sKk/rNYgC7X6twaGfYb0sYLpbi9xV4i5jXsqZ3WO+yaguNgg==", "license": "Apache-2.0", "dependencies": { - "@firebase/component": "0.6.11", - "@firebase/util": "1.10.2", + "@firebase/component": "0.6.13", + "@firebase/util": "1.11.0", "idb": "7.1.1", "tslib": "^2.1.0" }, @@ -1069,15 +1045,15 @@ } }, "node_modules/@firebase/installations-compat": { - "version": "0.2.11", - "resolved": "https://registry.npmjs.org/@firebase/installations-compat/-/installations-compat-0.2.11.tgz", - "integrity": "sha512-SHRgw5LTa6v8LubmJZxcOCwEd1MfWQPUtKdiuCx2VMWnapX54skZd1PkQg0K4l3k+4ujbI2cn7FE6Li9hbChBw==", + "version": "0.2.13", + "resolved": "https://registry.npmjs.org/@firebase/installations-compat/-/installations-compat-0.2.13.tgz", + "integrity": "sha512-f/o6MqCI7LD/ulY9gvgkv6w5k6diaReD8BFHd/y/fEdpsXmFWYS/g28GXCB72bRVBOgPpkOUNl+VsMvDwlRKmw==", "license": "Apache-2.0", "dependencies": { - "@firebase/component": "0.6.11", - "@firebase/installations": "0.6.11", + "@firebase/component": "0.6.13", + "@firebase/installations": "0.6.13", "@firebase/installations-types": "0.5.3", - "@firebase/util": "1.10.2", + "@firebase/util": "1.11.0", "tslib": "^2.1.0" }, "peerDependencies": { @@ -1106,15 +1082,15 @@ } }, "node_modules/@firebase/messaging": { - "version": "0.12.14", - "resolved": "https://registry.npmjs.org/@firebase/messaging/-/messaging-0.12.14.tgz", - "integrity": "sha512-cSGP34jJswFvME8tdMDkvJvW6T1jEekyMSyq84AMBZ0KEpJbDWuC9n4wKT2lxUm1jaL651iZnn6g51yCl77ICg==", + "version": "0.12.17", + "resolved": "https://registry.npmjs.org/@firebase/messaging/-/messaging-0.12.17.tgz", + "integrity": "sha512-W3CnGhTm6Nx8XGb6E5/+jZTuxX/EK8Vur4QXvO1DwZta/t0xqWMRgO9vNsZFMYBqFV4o3j4F9qK/iddGYwWS6g==", "license": "Apache-2.0", "dependencies": { - "@firebase/component": "0.6.11", - "@firebase/installations": "0.6.11", + "@firebase/component": "0.6.13", + "@firebase/installations": "0.6.13", "@firebase/messaging-interop-types": "0.2.3", - "@firebase/util": "1.10.2", + "@firebase/util": "1.11.0", "idb": "7.1.1", "tslib": "^2.1.0" }, @@ -1123,14 +1099,14 @@ } }, "node_modules/@firebase/messaging-compat": { - "version": "0.2.14", - "resolved": "https://registry.npmjs.org/@firebase/messaging-compat/-/messaging-compat-0.2.14.tgz", - "integrity": "sha512-r9weK8jTEA2aGiwy0IbMQPnzuJ0DHkOQaMxGJOlU2QZ1a7fh6RHpNtaoM+LKnn6u1NQgmAOWYNr9vezVQEm9zw==", + "version": "0.2.17", + "resolved": "https://registry.npmjs.org/@firebase/messaging-compat/-/messaging-compat-0.2.17.tgz", + "integrity": "sha512-5Q+9IG7FuedusdWHVQRjpA3OVD9KUWp/IPegcv0s5qSqRLBjib7FlAeWxN+VL0Ew43tuPJBY2HKhEecuizmO1Q==", "license": "Apache-2.0", "dependencies": { - "@firebase/component": "0.6.11", - "@firebase/messaging": "0.12.14", - "@firebase/util": "1.10.2", + "@firebase/component": "0.6.13", + "@firebase/messaging": "0.12.17", + "@firebase/util": "1.11.0", "tslib": "^2.1.0" }, "peerDependencies": { @@ -1144,32 +1120,33 @@ "license": "Apache-2.0" }, "node_modules/@firebase/performance": { - "version": "0.6.11", - "resolved": "https://registry.npmjs.org/@firebase/performance/-/performance-0.6.11.tgz", - "integrity": "sha512-FlkJFeqLlIeh5T4Am3uE38HVzggliDIEFy/fErEc1faINOUFCb6vQBEoNZGaXvRnTR8lh3X/hP7tv37C7BsK9g==", + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/@firebase/performance/-/performance-0.7.1.tgz", + "integrity": "sha512-SkEUurawojCjav2V2AXo6BQLDtv02NxgXPLCiAvrkn95IAKI4W/UbLKYQvMbEez/nqvmnucLyklcMlB0Q5a1iw==", "license": "Apache-2.0", "dependencies": { - "@firebase/component": "0.6.11", - "@firebase/installations": "0.6.11", + "@firebase/component": "0.6.13", + "@firebase/installations": "0.6.13", "@firebase/logger": "0.4.4", - "@firebase/util": "1.10.2", - "tslib": "^2.1.0" + "@firebase/util": "1.11.0", + "tslib": "^2.1.0", + "web-vitals": "^4.2.4" }, "peerDependencies": { "@firebase/app": "0.x" } }, "node_modules/@firebase/performance-compat": { - "version": "0.2.11", - "resolved": "https://registry.npmjs.org/@firebase/performance-compat/-/performance-compat-0.2.11.tgz", - "integrity": "sha512-DqeNBy51W2xzlklyC7Ht9JQ94HhTA08PCcM4MDeyG/ol3fqum/+YgtHWQ2IQuduqH9afETthZqLwCZiSgY7hiA==", + "version": "0.2.14", + "resolved": "https://registry.npmjs.org/@firebase/performance-compat/-/performance-compat-0.2.14.tgz", + "integrity": "sha512-/crPg0fDqHIx+FjFoEqWxNp+lJSF40ZG7x43AAJGRaUaWLJDncQm3UJB5/mABaRZb7obs1CQAcRtd4phZFkmZg==", "license": "Apache-2.0", "dependencies": { - "@firebase/component": "0.6.11", + "@firebase/component": "0.6.13", "@firebase/logger": "0.4.4", - "@firebase/performance": "0.6.11", + "@firebase/performance": "0.7.1", "@firebase/performance-types": "0.2.3", - "@firebase/util": "1.10.2", + "@firebase/util": "1.11.0", "tslib": "^2.1.0" }, "peerDependencies": { @@ -1183,15 +1160,15 @@ "license": "Apache-2.0" }, "node_modules/@firebase/remote-config": { - "version": "0.4.11", - "resolved": "https://registry.npmjs.org/@firebase/remote-config/-/remote-config-0.4.11.tgz", - "integrity": "sha512-9z0rgKuws2nj+7cdiqF+NY1QR4na6KnuOvP+jQvgilDOhGtKOcCMq5XHiu66i73A9kFhyU6QQ2pHXxcmaq1pBw==", + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/@firebase/remote-config/-/remote-config-0.6.0.tgz", + "integrity": "sha512-Yrk4l5+6FJLPHC6irNHMzgTtJ3NfHXlAXVChCBdNFtgmzyGmufNs/sr8oA0auEfIJ5VpXCaThRh3P4OdQxiAlQ==", "license": "Apache-2.0", "dependencies": { - "@firebase/component": "0.6.11", - "@firebase/installations": "0.6.11", + "@firebase/component": "0.6.13", + "@firebase/installations": "0.6.13", "@firebase/logger": "0.4.4", - "@firebase/util": "1.10.2", + "@firebase/util": "1.11.0", "tslib": "^2.1.0" }, "peerDependencies": { @@ -1199,16 +1176,16 @@ } }, "node_modules/@firebase/remote-config-compat": { - "version": "0.2.11", - "resolved": "https://registry.npmjs.org/@firebase/remote-config-compat/-/remote-config-compat-0.2.11.tgz", - "integrity": "sha512-zfIjpwPrGuIOZDmduukN086qjhZ1LnbJi/iYzgua+2qeTlO0XdlE1v66gJPwygGB3TOhT0yb9EiUZ3nBNttMqg==", + "version": "0.2.13", + "resolved": "https://registry.npmjs.org/@firebase/remote-config-compat/-/remote-config-compat-0.2.13.tgz", + "integrity": "sha512-UmHoO7TxAEJPIZf8e1Hy6CeFGMeyjqSCpgoBkQZYXFI2JHhzxIyDpr8jVKJJN1dmAePKZ5EX7dC13CmcdTOl7Q==", "license": "Apache-2.0", "dependencies": { - "@firebase/component": "0.6.11", + "@firebase/component": "0.6.13", "@firebase/logger": "0.4.4", - "@firebase/remote-config": "0.4.11", - "@firebase/remote-config-types": "0.3.3", - "@firebase/util": "1.10.2", + "@firebase/remote-config": "0.6.0", + "@firebase/remote-config-types": "0.4.0", + "@firebase/util": "1.11.0", "tslib": "^2.1.0" }, "peerDependencies": { @@ -1216,19 +1193,19 @@ } }, "node_modules/@firebase/remote-config-types": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/@firebase/remote-config-types/-/remote-config-types-0.3.3.tgz", - "integrity": "sha512-YlRI9CHxrk3lpQuFup9N1eohpwdWayKZUNZ/YeQ0PZoncJ66P32UsKUKqVXOaieTjJIOh7yH8JEzRdht5s+d6g==", + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/@firebase/remote-config-types/-/remote-config-types-0.4.0.tgz", + "integrity": "sha512-7p3mRE/ldCNYt8fmWMQ/MSGRmXYlJ15Rvs9Rk17t8p0WwZDbeK7eRmoI1tvCPaDzn9Oqh+yD6Lw+sGLsLg4kKg==", "license": "Apache-2.0" }, "node_modules/@firebase/storage": { - "version": "0.13.4", - "resolved": "https://registry.npmjs.org/@firebase/storage/-/storage-0.13.4.tgz", - "integrity": "sha512-b1KaTTRiMupFurIhpGIbReaWev0k5O3ouTHkAPcEssT+FvU3q/1JwzvkX4+ZdB60Fc43Mbp8qQ1gWfT0Z2FP9Q==", + "version": "0.13.7", + "resolved": "https://registry.npmjs.org/@firebase/storage/-/storage-0.13.7.tgz", + "integrity": "sha512-FkRyc24rK+Y6EaQ1tYFm3TevBnnfSNA0VyTfew2hrYyL/aYfatBg7HOgktUdB4kWMHNA9VoTotzZTGoLuK92wg==", "license": "Apache-2.0", "dependencies": { - "@firebase/component": "0.6.11", - "@firebase/util": "1.10.2", + "@firebase/component": "0.6.13", + "@firebase/util": "1.11.0", "tslib": "^2.1.0" }, "engines": { @@ -1239,15 +1216,15 @@ } }, "node_modules/@firebase/storage-compat": { - "version": "0.3.14", - "resolved": "https://registry.npmjs.org/@firebase/storage-compat/-/storage-compat-0.3.14.tgz", - "integrity": "sha512-Ok5FmXJiapaNAOQ8W8qppnfwgP8540jw2B8M0c4TFZqF4BD+CoKBxW0dRtOuLNGadLhzqqkDZZZtkexxrveQqA==", + "version": "0.3.17", + "resolved": "https://registry.npmjs.org/@firebase/storage-compat/-/storage-compat-0.3.17.tgz", + "integrity": "sha512-CBlODWEZ5b6MJWVh21VZioxwxNwVfPA9CAdsk+ZgVocJQQbE2oDW1XJoRcgthRY1HOitgbn4cVrM+NlQtuUYhw==", "license": "Apache-2.0", "dependencies": { - "@firebase/component": "0.6.11", - "@firebase/storage": "0.13.4", + "@firebase/component": "0.6.13", + "@firebase/storage": "0.13.7", "@firebase/storage-types": "0.8.3", - "@firebase/util": "1.10.2", + "@firebase/util": "1.11.0", "tslib": "^2.1.0" }, "engines": { @@ -1268,9 +1245,10 @@ } }, "node_modules/@firebase/util": { - "version": "1.10.2", - "resolved": "https://registry.npmjs.org/@firebase/util/-/util-1.10.2.tgz", - "integrity": "sha512-qnSHIoE9FK+HYnNhTI8q14evyqbc/vHRivfB4TgCIUOl4tosmKSQlp7ltymOlMP4xVIJTg5wrkfcZ60X4nUf7Q==", + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/@firebase/util/-/util-1.11.0.tgz", + "integrity": "sha512-PzSrhIr++KI6y4P6C/IdgBNMkEx0Ex6554/cYd0Hm+ovyFSJtJXqb/3OSIdnBoa2cpwZT1/GW56EmRc5qEc5fQ==", + "hasInstallScript": true, "license": "Apache-2.0", "dependencies": { "tslib": "^2.1.0" @@ -1280,15 +1258,15 @@ } }, "node_modules/@firebase/vertexai": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@firebase/vertexai/-/vertexai-1.0.1.tgz", - "integrity": "sha512-f48MGSofhaS05ebpN7zMIv4tBqYf19pXr5/4njKtNZVLbjxUswDma0SuFDoO+IwgbdkhFxgtNctM+C1zfI/O1Q==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@firebase/vertexai/-/vertexai-1.1.0.tgz", + "integrity": "sha512-K8CgIFKJrfrf5lYhKnDXOu08FEmIzVExK+ApUZx4Bw2GAmLEA3wDVrsjuupuvpXZSp8QlzvEiXwqshqqc4v0pA==", "license": "Apache-2.0", "dependencies": { "@firebase/app-check-interop-types": "0.3.3", - "@firebase/component": "0.6.11", + "@firebase/component": "0.6.13", "@firebase/logger": "0.4.4", - "@firebase/util": "1.10.2", + "@firebase/util": "1.11.0", "tslib": "^2.1.0" }, "engines": { @@ -1656,9 +1634,9 @@ } }, "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", - "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", + "version": "0.3.8", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.8.tgz", + "integrity": "sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA==", "dev": true, "license": "MIT", "dependencies": { @@ -1808,9 +1786,9 @@ "license": "BSD-3-Clause" }, "node_modules/@sapphire/async-queue": { - "version": "1.5.3", - "resolved": "https://registry.npmjs.org/@sapphire/async-queue/-/async-queue-1.5.3.tgz", - "integrity": "sha512-x7zadcfJGxFka1Q3f8gCts1F0xMwCKbZweM85xECGI0hBTeIZJGGCrHgLggihBoprlQ/hBmDR5LKfIPqnmHM3w==", + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@sapphire/async-queue/-/async-queue-1.5.5.tgz", + "integrity": "sha512-cvGzxbba6sav2zZkH8GPf2oGk9yYoD5qrNWdu9fRehifgnFZJMV+nuy2nON2roRO4yQQ+v7MK/Pktl/HgfsUXg==", "license": "MIT", "engines": { "node": ">=v14.0.0", @@ -1989,18 +1967,18 @@ } }, "node_modules/@types/node": { - "version": "22.7.6", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.7.6.tgz", - "integrity": "sha512-/d7Rnj0/ExXDMcioS78/kf1lMzYk4BZV8MZGTBKzTGZ6/406ukkbYlIsZmMPhcR5KlkunDHQLrtAVmSq7r+mSw==", + "version": "22.13.10", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.13.10.tgz", + "integrity": "sha512-I6LPUvlRH+O6VRUqYOcMudhaIdUVWfsjnZavnsraHvpBwaEyMN29ry+0UVJhImYL16xsscu0aske3yA+uPOWfw==", "license": "MIT", "dependencies": { - "undici-types": "~6.19.2" + "undici-types": "~6.20.0" } }, "node_modules/@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==", + "version": "2.6.12", + "resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.6.12.tgz", + "integrity": "sha512-8nneRWKCg3rMtF69nLQJnOYUcbafYeFSjqkw3jCRLsqkWFlHaoQrr5mXmofFGOx3DKn7UfmBMyov8ySvLRVldA==", "license": "MIT", "dependencies": { "@types/node": "*", @@ -2015,9 +1993,9 @@ "license": "MIT" }, "node_modules/@types/ws": { - "version": "8.5.12", - "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.12.tgz", - "integrity": "sha512-3tPRkv1EtkDpzlgyKyI8pGsGZAGPEaXeu0DOj5DI25Ja91bdAYddYHbADRYVrZMRbfW+1l5YwXVDKohDJNQxkQ==", + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.18.0.tgz", + "integrity": "sha512-8svvI3hMyvN0kKCJMvTJP/x6Y/EoQbepff882wL+Sn5QsXb3etnamgrJq4isrBxSJj5L2AuXcI0+bgkoAXGUJw==", "license": "MIT", "dependencies": { "@types/node": "*" @@ -2063,9 +2041,9 @@ } }, "node_modules/acorn": { - "version": "8.14.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.0.tgz", - "integrity": "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==", + "version": "8.14.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.1.tgz", + "integrity": "sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg==", "dev": true, "license": "MIT", "bin": { @@ -2089,9 +2067,9 @@ } }, "node_modules/agentkeepalive": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.5.0.tgz", - "integrity": "sha512-5GG/5IbQQpC9FpkRGsSvZI5QYeSCzlJHdpBQntCsuTOxhKD8lqKhrleg2Yi7yvMIf82Ycmmqln9U8V9qwEiJew==", + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.6.0.tgz", + "integrity": "sha512-kja8j7PjmncONqaTsB8fQ+wE2mSU2DJ9D4XKoJ5PFWIdRMa6SLSN1ff4mOr4jCbfRSsxR4keIiySJU0N9T5hIQ==", "license": "MIT", "dependencies": { "humanize-ms": "^1.2.1" @@ -2351,9 +2329,9 @@ } }, "node_modules/browserslist": { - "version": "4.24.2", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.24.2.tgz", - "integrity": "sha512-ZIc+Q62revdMcqC6aChtW4jz3My3klmCO1fEmINZY/8J3EpBg5/A/D0AKmBveUh6pgoeycoMkVMko84tuYS+Gg==", + "version": "4.24.4", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.24.4.tgz", + "integrity": "sha512-KDi1Ny1gSePi1vm0q4oxSF8b4DR44GF4BbmS2YdhPLOEqd8pDviZOGH/GsmRwoWJ2+5Lr085X7naowMwKHDG1A==", "dev": true, "funding": [ { @@ -2371,9 +2349,9 @@ ], "license": "MIT", "dependencies": { - "caniuse-lite": "^1.0.30001669", - "electron-to-chromium": "^1.5.41", - "node-releases": "^2.0.18", + "caniuse-lite": "^1.0.30001688", + "electron-to-chromium": "^1.5.73", + "node-releases": "^2.0.19", "update-browserslist-db": "^1.1.1" }, "bin": { @@ -2413,6 +2391,19 @@ "dev": true, "license": "MIT" }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/callsites": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", @@ -2434,9 +2425,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001677", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001677.tgz", - "integrity": "sha512-fmfjsOlJUpMWu+mAAtZZZHz7UEwsUxIIvu1TJfO1HqFQvB/B+ii0xr9B5HpbZY/mC4XZ8SvjHJqtAY6pDPQEog==", + "version": "1.0.30001706", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001706.tgz", + "integrity": "sha512-3ZczoTApMAZwPKYWmwVbQMFpXBDds3/0VciVoUwPUbldlYyVLmRVuRs/PcUZtHpbLRpzzDvrvnFuREsGt6lUug==", "dev": true, "funding": [ { @@ -2522,9 +2513,9 @@ } }, "node_modules/cjs-module-lexer": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.4.1.tgz", - "integrity": "sha512-cuSVIHi9/9E/+821Qjdvngor+xpnlwnuwIyZOaLmHBVdXL+gP+I6QQB9VkO7RI77YIcTV+S1W9AreJ5eN63JBA==", + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.4.3.tgz", + "integrity": "sha512-9z8TZaGM1pfswYeXrUpzPrkx8UnWYdhJclsiYMm6x/w5+nN+8Tf/LnAgfLGQCm59qAOxU8WwHEq2vNwF6i4j+Q==", "dev": true, "license": "MIT" }, @@ -2658,9 +2649,9 @@ } }, "node_modules/debug": { - "version": "4.3.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", - "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", + "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", "dev": true, "license": "MIT", "dependencies": { @@ -2752,29 +2743,29 @@ } }, "node_modules/discord-api-types": { - "version": "0.37.100", - "resolved": "https://registry.npmjs.org/discord-api-types/-/discord-api-types-0.37.100.tgz", - "integrity": "sha512-a8zvUI0GYYwDtScfRd/TtaNBDTXwP5DiDVX7K5OmE+DRT57gBqKnwtOC5Ol8z0mRW8KQfETIgiB8U0YZ9NXiCA==", + "version": "0.37.119", + "resolved": "https://registry.npmjs.org/discord-api-types/-/discord-api-types-0.37.119.tgz", + "integrity": "sha512-WasbGFXEB+VQWXlo6IpW3oUv73Yuau1Ig4AZF/m13tXcTKnMpc/mHjpztIlz4+BM9FG9BHQkEXiPto3bKduQUg==", "license": "MIT" }, "node_modules/discord.js": { - "version": "14.16.3", - "resolved": "https://registry.npmjs.org/discord.js/-/discord.js-14.16.3.tgz", - "integrity": "sha512-EPCWE9OkA9DnFFNrO7Kl1WHHDYFXu3CNVFJg63bfU7hVtjZGyhShwZtSBImINQRWxWP2tgo2XI+QhdXx28r0aA==", + "version": "14.18.0", + "resolved": "https://registry.npmjs.org/discord.js/-/discord.js-14.18.0.tgz", + "integrity": "sha512-SvU5kVUvwunQhN2/+0t55QW/1EHfB1lp0TtLZUSXVHDmyHTrdOj5LRKdR0zLcybaA15F+NtdWuWmGOX9lE+CAw==", "license": "Apache-2.0", "dependencies": { - "@discordjs/builders": "^1.9.0", + "@discordjs/builders": "^1.10.1", "@discordjs/collection": "1.5.3", - "@discordjs/formatters": "^0.5.0", - "@discordjs/rest": "^2.4.0", + "@discordjs/formatters": "^0.6.0", + "@discordjs/rest": "^2.4.3", "@discordjs/util": "^1.1.1", - "@discordjs/ws": "1.1.1", + "@discordjs/ws": "^1.2.1", "@sapphire/snowflake": "3.5.3", - "discord-api-types": "0.37.100", + "discord-api-types": "^0.37.119", "fast-deep-equal": "3.1.3", "lodash.snakecase": "4.1.1", "tslib": "^2.6.3", - "undici": "6.19.8" + "undici": "6.21.1" }, "engines": { "node": ">=18" @@ -2784,9 +2775,9 @@ } }, "node_modules/dotenv": { - "version": "16.4.5", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.5.tgz", - "integrity": "sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg==", + "version": "16.4.7", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.7.tgz", + "integrity": "sha512-47qPchRCykZC03FhkYAhrvwU4xDBFIj1QPqaarj6mdM/hgUzfPHcpkHJOn3mJAufFeeAxAzeGsr5X0M4k6fLZQ==", "license": "BSD-2-Clause", "engines": { "node": ">=12" @@ -2795,6 +2786,20 @@ "url": "https://dotenvx.com" } }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/ejs": { "version": "3.1.10", "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.10.tgz", @@ -2812,9 +2817,9 @@ } }, "node_modules/electron-to-chromium": { - "version": "1.5.52", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.52.tgz", - "integrity": "sha512-xtoijJTZ+qeucLBDNztDOuQBE1ksqjvNjvqFoST3nGC7fSpqJ+X6BdTBaY5BHG+IhWWmpc6b/KfpeuEDupEPOQ==", + "version": "1.5.120", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.120.tgz", + "integrity": "sha512-oTUp3gfX1gZI+xfD2djr2rzQdHCwHzPQrrK0CD7WpTdF0nPdQ/INcRVjWgLdCT4a9W3jFObR9DAfsuyFQnI8CQ==", "dev": true, "license": "ISC" }, @@ -2847,6 +2852,51 @@ "is-arrayish": "^0.2.1" } }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-object-atoms": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-set-tostringtag": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", + "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/escalade": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", @@ -2946,16 +2996,16 @@ "license": "MIT" }, "node_modules/fast-glob": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", - "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", + "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", "license": "MIT", "dependencies": { "@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" + "micromatch": "^4.0.8" }, "engines": { "node": ">=8.6.0" @@ -2969,9 +3019,9 @@ "license": "MIT" }, "node_modules/fastq": { - "version": "1.17.1", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", - "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==", + "version": "1.19.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.19.1.tgz", + "integrity": "sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==", "license": "ISC", "dependencies": { "reusify": "^1.0.4" @@ -3059,49 +3109,50 @@ } }, "node_modules/firebase": { - "version": "11.0.2", - "resolved": "https://registry.npmjs.org/firebase/-/firebase-11.0.2.tgz", - "integrity": "sha512-w4T8BSJpzdZA25QRch5ahLsgB6uRvg1LEic4BaC5rTD1YygroI1AXp+W+rbMnr8d8EjfAv6t4k8doULIjc1P8Q==", + "version": "11.4.0", + "resolved": "https://registry.npmjs.org/firebase/-/firebase-11.4.0.tgz", + "integrity": "sha512-Z6kwhWIPDgIm0+NUEQxwjH14hMP7t42WSFnf/78R0Vh59VovLYTOCTM3MIdY3jlSZ9uKz56FhXrvsNXNhAn/Xg==", "license": "Apache-2.0", "dependencies": { - "@firebase/analytics": "0.10.10", - "@firebase/analytics-compat": "0.2.16", - "@firebase/app": "0.10.16", - "@firebase/app-check": "0.8.10", - "@firebase/app-check-compat": "0.3.17", - "@firebase/app-compat": "0.2.46", + "@firebase/analytics": "0.10.12", + "@firebase/analytics-compat": "0.2.18", + "@firebase/app": "0.11.2", + "@firebase/app-check": "0.8.12", + "@firebase/app-check-compat": "0.3.19", + "@firebase/app-compat": "0.2.51", "@firebase/app-types": "0.9.3", - "@firebase/auth": "1.8.1", - "@firebase/auth-compat": "0.5.16", - "@firebase/data-connect": "0.1.2", - "@firebase/database": "1.0.10", - "@firebase/database-compat": "2.0.1", - "@firebase/firestore": "4.7.5", - "@firebase/firestore-compat": "0.3.40", - "@firebase/functions": "0.11.10", - "@firebase/functions-compat": "0.3.16", - "@firebase/installations": "0.6.11", - "@firebase/installations-compat": "0.2.11", - "@firebase/messaging": "0.12.14", - "@firebase/messaging-compat": "0.2.14", - "@firebase/performance": "0.6.11", - "@firebase/performance-compat": "0.2.11", - "@firebase/remote-config": "0.4.11", - "@firebase/remote-config-compat": "0.2.11", - "@firebase/storage": "0.13.4", - "@firebase/storage-compat": "0.3.14", - "@firebase/util": "1.10.2", - "@firebase/vertexai": "1.0.1" + "@firebase/auth": "1.9.1", + "@firebase/auth-compat": "0.5.19", + "@firebase/data-connect": "0.3.1", + "@firebase/database": "1.0.13", + "@firebase/database-compat": "2.0.4", + "@firebase/firestore": "4.7.9", + "@firebase/firestore-compat": "0.3.44", + "@firebase/functions": "0.12.3", + "@firebase/functions-compat": "0.3.20", + "@firebase/installations": "0.6.13", + "@firebase/installations-compat": "0.2.13", + "@firebase/messaging": "0.12.17", + "@firebase/messaging-compat": "0.2.17", + "@firebase/performance": "0.7.1", + "@firebase/performance-compat": "0.2.14", + "@firebase/remote-config": "0.6.0", + "@firebase/remote-config-compat": "0.2.13", + "@firebase/storage": "0.13.7", + "@firebase/storage-compat": "0.3.17", + "@firebase/util": "1.11.0", + "@firebase/vertexai": "1.1.0" } }, "node_modules/form-data": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.1.tgz", - "integrity": "sha512-tzN8e4TX8+kkxGPK8D5u0FNmjPUjw3lwC9lSLxxoB/+GtsJG91CO8bSWy73APlgAZzZbXEYZJuxjkHH2w+Ezhw==", + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.2.tgz", + "integrity": "sha512-hGfm/slu0ZabnNt4oaRZ6uREyfCj6P4fT/n6A1rGV+Z0VdGXjfOhVUpkn6qVQONHGIFwmveGXyDs75+nr6FM8w==", "license": "MIT", "dependencies": { "asynckit": "^0.4.0", "combined-stream": "^1.0.8", + "es-set-tostringtag": "^2.1.0", "mime-types": "^2.1.12" }, "engines": { @@ -3152,7 +3203,6 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", - "dev": true, "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" @@ -3177,6 +3227,30 @@ "node": "6.* || 8.* || >= 10.*" } }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/get-package-type": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", @@ -3187,6 +3261,19 @@ "node": ">=8.0.0" } }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/get-stream": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", @@ -3264,6 +3351,18 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/graceful-fs": { "version": "4.2.11", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", @@ -3281,11 +3380,37 @@ "node": ">=8" } }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "license": "MIT", + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/hasown": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", - "dev": true, "license": "MIT", "dependencies": { "function-bind": "^1.1.2" @@ -3302,9 +3427,9 @@ "license": "MIT" }, "node_modules/http-parser-js": { - "version": "0.5.8", - "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.8.tgz", - "integrity": "sha512-SGeBX54F94Wgu5RH3X5jsDtf4eHyRogWX1XGT3b4HuW3tQPM4AaBzoUji/4AAJNXCEOWZ5O0DgZmJw1947gD5Q==", + "version": "0.5.9", + "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.9.tgz", + "integrity": "sha512-n1XsPy3rXVxlqxVioEWdC+0+M+SQw0DpJynwtOPo1X+ZlvdzTLtDBIJJlDQTnwZIFJrZSzSGmIOUdP8tu+SgLw==", "license": "MIT" }, "node_modules/human-signals": { @@ -3410,9 +3535,9 @@ } }, "node_modules/is-core-module": { - "version": "2.15.1", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.15.1.tgz", - "integrity": "sha512-z0vtXSwucUJtANQWldhbtbt7BnL0vxiFjIdDLAatwhDYty2bad6s+rijD6Ri4YuYJubLzIJLUidCh09e1djEVQ==", + "version": "2.16.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", + "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", "dev": true, "license": "MIT", "dependencies": { @@ -3522,9 +3647,9 @@ } }, "node_modules/istanbul-lib-instrument/node_modules/semver": { - "version": "7.6.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", - "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "version": "7.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", + "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", "dev": true, "license": "ISC", "bin": { @@ -4080,9 +4205,9 @@ } }, "node_modules/jest-snapshot/node_modules/semver": { - "version": "7.6.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", - "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "version": "7.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", + "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", "dev": true, "license": "ISC", "bin": { @@ -4215,9 +4340,9 @@ } }, "node_modules/jsesc": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.0.2.tgz", - "integrity": "sha512-xKqzzWXDttJuOcawBt4KnKHHIf5oQ/Cxax+0PWFG+DFDgHNAdi+TXECADI+RYiFUMmx8792xsMbbgXj4CwnP4g==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", "dev": true, "license": "MIT", "bin": { @@ -4313,9 +4438,9 @@ "license": "MIT" }, "node_modules/long": { - "version": "5.2.3", - "resolved": "https://registry.npmjs.org/long/-/long-5.2.3.tgz", - "integrity": "sha512-lcHwpNoggQTObv5apGNCTdJrO69eHOZMi4BNC+rTLER8iHAqGrUVeLh/irVIM7zTw2bOXA8T6uNPeujwOLg/2Q==", + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/long/-/long-5.3.1.tgz", + "integrity": "sha512-ka87Jz3gcx/I7Hal94xaN2tZEOPoUOEVftkQqZx2EeQRN7LGdfLlI3FvZ+7WDplm+vK2Urx9ULrvSowtdCieng==", "license": "Apache-2.0" }, "node_modules/lru-cache": { @@ -4351,9 +4476,9 @@ } }, "node_modules/make-dir/node_modules/semver": { - "version": "7.6.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", - "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "version": "7.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", + "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", "dev": true, "license": "ISC", "bin": { @@ -4380,6 +4505,15 @@ "tmpl": "1.0.5" } }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, "node_modules/merge-stream": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", @@ -4526,9 +4660,9 @@ "license": "MIT" }, "node_modules/node-releases": { - "version": "2.0.18", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.18.tgz", - "integrity": "sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g==", + "version": "2.0.19", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.19.tgz", + "integrity": "sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==", "dev": true, "license": "MIT" }, @@ -4581,9 +4715,9 @@ } }, "node_modules/openai": { - "version": "4.68.1", - "resolved": "https://registry.npmjs.org/openai/-/openai-4.68.1.tgz", - "integrity": "sha512-C9XmYRHgra1U1G4GGFNqRHQEjxhoOWbQYR85IibfJ0jpHUhOm4/lARiKaC/h3zThvikwH9Dx/XOKWPNVygIS3g==", + "version": "4.88.0", + "resolved": "https://registry.npmjs.org/openai/-/openai-4.88.0.tgz", + "integrity": "sha512-Ll2ZJCdX/56WcCF/wLtAFou+zWRyLeneoXy+qya5T5/wm5LkIr6heJfSn53c5ujXWPB+24cgumiOetbFqcppFA==", "license": "Apache-2.0", "dependencies": { "@types/node": "^18.11.18", @@ -4598,18 +4732,22 @@ "openai": "bin/cli" }, "peerDependencies": { + "ws": "^8.18.0", "zod": "^3.23.8" }, "peerDependenciesMeta": { + "ws": { + "optional": true + }, "zod": { "optional": true } } }, "node_modules/openai/node_modules/@types/node": { - "version": "18.19.57", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.57.tgz", - "integrity": "sha512-I2ioBd/IPrYDMv9UNR5NlPElOZ68QB7yY5V2EsLtSrTO0LM0PnCEFF9biLWHf5k+sIy4ohueCV9t4gk1AEdlVA==", + "version": "18.19.80", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.80.tgz", + "integrity": "sha512-kEWeMwMeIvxYkeg1gTc01awpwLbfMRZXdIhwRcakd/KlK53jmRC26LqcbIt7fnAQTu5GzlnWmzA3H6+l1u6xxQ==", "license": "MIT", "dependencies": { "undici-types": "~5.26.4" @@ -4936,19 +5074,22 @@ } }, "node_modules/resolve": { - "version": "1.22.8", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", - "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", + "version": "1.22.10", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz", + "integrity": "sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==", "dev": true, "license": "MIT", "dependencies": { - "is-core-module": "^2.13.0", + "is-core-module": "^2.16.0", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, "bin": { "resolve": "bin/resolve" }, + "engines": { + "node": ">= 0.4" + }, "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -4977,9 +5118,9 @@ } }, "node_modules/resolve.exports": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-2.0.2.tgz", - "integrity": "sha512-X2UW6Nw3n/aMgDVy+0rSqgHlv39WZAlZrXCdnbyEiKm17DSqHX4MmQMaST3FbeWR5FTuRcUwYAziZajji0Y7mg==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-2.0.3.tgz", + "integrity": "sha512-OcXjMsGdhL4XnbShKpAcSqPMzQoYkYyhbEaeSko47MjRP9NfEQMhZkXL1DoFlt9LWQn4YttrdnV6X2OiyzBi+A==", "dev": true, "license": "MIT", "engines": { @@ -4987,9 +5128,9 @@ } }, "node_modules/reusify": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", - "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", + "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", "license": "MIT", "engines": { "iojs": ">=1.0.0", @@ -5276,9 +5417,9 @@ "license": "MIT" }, "node_modules/ts-jest": { - "version": "29.2.5", - "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.2.5.tgz", - "integrity": "sha512-KD8zB2aAZrcKIdGk4OwpJggeLcH1FgrICqDSROWqlnJXGCXK4Mn6FcdK2B6670Xr73lHMG1kHw8R87A0ecZ+vA==", + "version": "29.2.6", + "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.2.6.tgz", + "integrity": "sha512-yTNZVZqc8lSixm+QGVFcPe6+yj7+TWZwIesuOWvfcn4B9bz5x4NDzVCQQjOs7Hfouu36aEqfEbo9Qpo+gq8dDg==", "dev": true, "license": "MIT", "dependencies": { @@ -5289,7 +5430,7 @@ "json5": "^2.2.3", "lodash.memoize": "^4.1.2", "make-error": "^1.3.6", - "semver": "^7.6.3", + "semver": "^7.7.1", "yargs-parser": "^21.1.1" }, "bin": { @@ -5325,9 +5466,9 @@ } }, "node_modules/ts-jest/node_modules/semver": { - "version": "7.6.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", - "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "version": "7.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", + "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", "dev": true, "license": "ISC", "bin": { @@ -5388,9 +5529,9 @@ } }, "node_modules/tsc-alias": { - "version": "1.8.10", - "resolved": "https://registry.npmjs.org/tsc-alias/-/tsc-alias-1.8.10.tgz", - "integrity": "sha512-Ibv4KAWfFkFdKJxnWfVtdOmB0Zi1RJVxcbPGiCDsFpCQSsmpWyuzHG3rQyI5YkobWwxFPEyQfu1hdo4qLG2zPw==", + "version": "1.8.11", + "resolved": "https://registry.npmjs.org/tsc-alias/-/tsc-alias-1.8.11.tgz", + "integrity": "sha512-2DuEQ58A9Rj2NE2c1+/qaGKlshni9MCK95MJzRGhQG0CYLw0bE/ACgbhhTSf/p1svLelwqafOd8stQate2bYbg==", "license": "MIT", "dependencies": { "chokidar": "^3.5.3", @@ -5405,9 +5546,9 @@ } }, "node_modules/tslib": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.0.tgz", - "integrity": "sha512-jWVzBLplnCmoaTr13V9dYbiQ99wvZRd0vNWaDRg+aVYRcjDF3nDksxFDE/+fkXnKhpnUUkmx5pK/v8mCtLVqZA==", + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", "license": "0BSD" }, "node_modules/type-detect": { @@ -5434,9 +5575,9 @@ } }, "node_modules/typescript": { - "version": "5.6.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.6.3.tgz", - "integrity": "sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw==", + "version": "5.8.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.2.tgz", + "integrity": "sha512-aJn6wq13/afZp/jT9QZmwEjDqqvSGp1VT5GVg+f/t6/oVyrgXM6BY1h9BRh/O5p3PlUPAe+WuiEZOmb/49RqoQ==", "license": "Apache-2.0", "bin": { "tsc": "bin/tsc", @@ -5447,24 +5588,24 @@ } }, "node_modules/undici": { - "version": "6.19.8", - "resolved": "https://registry.npmjs.org/undici/-/undici-6.19.8.tgz", - "integrity": "sha512-U8uCCl2x9TK3WANvmBavymRzxbfFYG+tAu+fgx3zxQy3qdagQqBLwJVrdyO1TBfUXvfKveMKJZhpvUYoOjM+4g==", + "version": "6.21.1", + "resolved": "https://registry.npmjs.org/undici/-/undici-6.21.1.tgz", + "integrity": "sha512-q/1rj5D0/zayJB2FraXdaWxbhWiNKDvu8naDT2dl1yTlvJp4BLtOcp2a5BvgGNQpYYJzau7tf1WgKv3b+7mqpQ==", "license": "MIT", "engines": { "node": ">=18.17" } }, "node_modules/undici-types": { - "version": "6.19.8", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz", - "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==", + "version": "6.20.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz", + "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==", "license": "MIT" }, "node_modules/update-browserslist-db": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.1.tgz", - "integrity": "sha512-R8UzCaa9Az+38REPiJ1tXlImTJXlVfgHZsglwBD/k6nj76ctsH1E3q4doGrukiLQd3sGQYu56r5+lo5r94l29A==", + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.3.tgz", + "integrity": "sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw==", "dev": true, "funding": [ { @@ -5483,7 +5624,7 @@ "license": "MIT", "dependencies": { "escalade": "^3.2.0", - "picocolors": "^1.1.0" + "picocolors": "^1.1.1" }, "bin": { "update-browserslist-db": "cli.js" @@ -5533,6 +5674,12 @@ "node": ">= 14" } }, + "node_modules/web-vitals": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/web-vitals/-/web-vitals-4.2.4.tgz", + "integrity": "sha512-r4DIlprAGwJ7YM11VZp4R884m0Vmgr6EAKe3P+kO0PPj3Unqyvv59rczf6UiGcb9Z8QxZVcqKNwv/g0WNdWwsw==", + "license": "Apache-2.0" + }, "node_modules/webidl-conversions": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", @@ -5627,9 +5774,9 @@ } }, "node_modules/ws": { - "version": "8.18.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz", - "integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==", + "version": "8.18.1", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.1.tgz", + "integrity": "sha512-RKW2aJZMXeMxVpnZ6bck+RswznaxmzdULiBr6KY7XkTnW8uvt0iT9H5DkHUChXrc+uurzwa0rVI16n/Xzjdz1w==", "license": "MIT", "engines": { "node": ">=10.0.0" diff --git a/src/__mocks__/discord.js.ts b/src/__mocks__/discord.js.ts index 76df2f3..194202c 100644 --- a/src/__mocks__/discord.js.ts +++ b/src/__mocks__/discord.js.ts @@ -1,8 +1,9 @@ -import { Client, ClientOptions, RESTOptions, UserFlagsBitField } from "discord.js"; +import { Client, ClientOptions, GuildManager, RESTOptions, UserFlagsBitField } from "discord.js"; const discordJS = jest.requireActual("discord.js"); const mockDiscordJS = jest.createMockFromModule("discord.js"); +mockDiscordJS.MessageFlags = discordJS.MessageFlags; mockDiscordJS.EmbedBuilder = discordJS.EmbedBuilder; mockDiscordJS.ApplicationCommandOptionType = discordJS.ApplicationCommandOptionType; mockDiscordJS.GatewayIntentBits = discordJS.GatewayIntentBits; @@ -32,12 +33,29 @@ class MockREST extends discordJS.REST { } } + +class MockGuildManager { + create: jest.Mock; + fetch: jest.Mock; + setIncidentActions: jest.Mock; + widgetImageURL: jest.Mock; + + constructor() { + this.create = jest.fn().mockResolvedValue(null); + this.fetch = jest.fn().mockResolvedValue(new mockDiscordJS.Collection()); + this.setIncidentActions = jest.fn().mockResolvedValue(null); + this.widgetImageURL = jest.fn().mockResolvedValue(null); + } +} + // @ts-ignore class MockClient { _ready: true = true; on: jest.Mock; options: ClientOptions; token: string; + guilds: GuildManager; + constructor(options?: ClientOptions) { this.on = MockClient.prototype.on; this.login = MockClient.prototype.login; @@ -47,6 +65,7 @@ class MockClient { } as any } this.token = "test-token"; + this.guilds = new MockGuildManager() as unknown as GuildManager; } public login(token: string): Promise { @@ -98,5 +117,6 @@ class MockClientUser { mockDiscordJS.REST = MockREST; mockDiscordJS.Client = MockClient as unknown as typeof discordJS.Client; mockDiscordJS.ClientUser = MockClientUser as unknown as typeof discordJS.ClientUser; +mockDiscordJS.GuildManager = MockGuildManager as unknown as typeof discordJS.GuildManager; module.exports = mockDiscordJS; diff --git a/src/__mocks__/firebase/database.ts b/src/__mocks__/firebase/database.ts new file mode 100644 index 0000000..73ce908 --- /dev/null +++ b/src/__mocks__/firebase/database.ts @@ -0,0 +1,30 @@ +import { DatabaseReference, DataSnapshot } from "firebase/database"; + +const firebaseDatabase = jest.requireActual("firebase/database"); +const mockFirebaseDatabase = jest.createMockFromModule("firebase/database"); + +const mockSnapshot = { + exists: () => true, + val: () => ({ count: 2 }), + forEach: () => true +}; + +mockFirebaseDatabase.get = jest.fn().mockResolvedValue(mockSnapshot); + +mockFirebaseDatabase.child = jest.fn((_, path): DatabaseReference => { + return `${path}` as unknown as DatabaseReference; +}); +mockFirebaseDatabase.ref = jest.fn().mockReturnValue('mock-ref'); +mockFirebaseDatabase.set = jest.fn().mockResolvedValue(undefined); +mockFirebaseDatabase.remove = jest.fn().mockResolvedValue(undefined); + +class mockDataSnapshot { + forEach: jest.Mock; + constructor() { + this.forEach = jest.fn().mockReturnValue(true); + } +} + +mockFirebaseDatabase.DataSnapshot = mockDataSnapshot as unknown as typeof DataSnapshot; + +module.exports = mockFirebaseDatabase; diff --git a/src/__mocks__/helpers.ts b/src/__mocks__/helpers.ts new file mode 100644 index 0000000..e6138c2 --- /dev/null +++ b/src/__mocks__/helpers.ts @@ -0,0 +1,7 @@ +const helpers = jest.requireActual("../helpers"); +const mockHelpers = jest.createMockFromModule("../helpers"); + +module.exports = { + ...helpers, + MINIMUM_MOOD_LIFESPAN: 0 +}; \ No newline at end of file diff --git a/src/discordApp.ts b/src/discordApp.ts index d12f30c..9639c81 100644 --- a/src/discordApp.ts +++ b/src/discordApp.ts @@ -1,6 +1,7 @@ import "dotenv/config"; import { Client, GatewayIntentBits, Events } from "discord.js"; import { clarify, embed, ping, tone, requestAnonymousClarification, mood } from "./interactions" +import { cleanupMoods } from "./helpers"; export async function launchBot(): Promise { // the client has to declare the features it uses up front so discord.js kno9ws if it can @@ -9,7 +10,8 @@ export async function launchBot(): Promise { // discord API: https://discord.com/developers/docs/topics/gateway#list-of-intents const client = new Client({ intents: [ - GatewayIntentBits.GuildEmojisAndStickers, + GatewayIntentBits.GuildExpressions, + GatewayIntentBits.GuildMembers, GatewayIntentBits.GuildVoiceStates, GatewayIntentBits.Guilds, GatewayIntentBits.GuildMessages, @@ -25,6 +27,13 @@ export async function launchBot(): Promise { client.on(Events.ClientReady, () => { if (client.user) { console.log(`client "ready": Logged in as ${client.user.tag}!`); + + client.guilds.fetch().then(guilds => { + guilds.map((_, id) => { + console.log(`cleaning up roles in guild with id ${id}`); + cleanupMoods(client, id); + }) + }); } else { console.error(`client "ready": client.user is null!`); } diff --git a/src/gptRequests.ts b/src/gptRequests.ts index 575de37..113d724 100644 --- a/src/gptRequests.ts +++ b/src/gptRequests.ts @@ -72,7 +72,7 @@ export async function analyzeMoodColor(mood: string): Promise { "text": ` This text is supposed to show a text messaging app user's mood. The text might be an emotion, or a symbol for an emotion (such as a smiley) or it could be something arbitrary. Try to come up with a color hexcode that depicts the mood, and return that as hexcode without the pound (#) symbol - (example, 000000) Only return the 6 character hexcode that is appropriate for the mood, and nothing else. + (example, 000000) Only return the 6 character hexcode that is appropriate for the mood, and nothing else. Use saturated colors. ` } ] diff --git a/src/helpers.test.ts b/src/helpers.test.ts index 997aa77..d620830 100644 --- a/src/helpers.test.ts +++ b/src/helpers.test.ts @@ -1,237 +1,206 @@ import * as discordJS from "discord.js"; +import * as firebase from "firebase/database"; import { MockDiscord } from "./testing/mocks/mockDiscord"; -import { updateOldRoleInServer, removeOldRoleInServer, updateNewRoleInServer } from "./helpers"; +import { addRoleToDatabase, cleanupMoods, getTimestampFromSnowflake, MINIMUM_MOOD_LIFESPAN, removeRoleFromDatabase, removeRoleIfUnused, timestampToSnowflake } from "./helpers"; jest.mock("discord.js"); - -type MockDatabase = { - get: jest.Mock; - child: jest.Mock; - ref: jest.Mock; - set: jest.Mock; - remove: jest.Mock; - getDatabase: jest.Mock; -} - -jest.mock('firebase/database', (): MockDatabase => { - const mockSnapshot = { - exists: () => true, - val: () => ({ count: 2 }) - }; - - const mockGet = jest.fn().mockResolvedValue(mockSnapshot); - const mockChild = jest.fn((_, path) => { - return `servers/${path}`; - }); - const mockRef = jest.fn().mockReturnValue('mock-ref'); - const mockSet = jest.fn().mockResolvedValue(undefined); - const mockRemove = jest.fn().mockResolvedValue(undefined); - - return { - get: mockGet, - child: mockChild, - ref: mockRef, - set: mockSet, - remove: mockRemove, - getDatabase: jest.fn().mockReturnValue({ - ref: mockRef - }) - }; -}); +jest.mock("firebase/database"); describe("Testing helper functions", () => { beforeAll(()=>{ process.env.APP_ID = "TEST APP ID"; process.env.DISCORD_TOKEN = "TEST TOKEN"; - jest.spyOn(console, "log").mockImplementation(() => {}); + // jest.spyOn(console, "log").mockImplementation(() => {}); + // jest.spyOn(console, "error").mockImplementation(() => {}); }); - describe("Testing updateOldRoleInServer", () => { - test("returns 'No role specified' when roleName is empty, null, or undefined", async () => { - const discord = new MockDiscord({ command: "/mood" }); - const interaction = discord.getInteraction() as discordJS.ChatInputCommandInteraction; + describe("Testing getTimestampFromSnowflake", () => { + test("the snowflake '0' should return the Discord Epoch (1420070400000)", () => { + const inputSnowflake = "0"; + const outputTime = 1420070400000; + + const result = getTimestampFromSnowflake(inputSnowflake); - expect(await updateOldRoleInServer(interaction, "")).toBe("No role specified"); - expect(await updateOldRoleInServer(interaction, undefined)).toBe("No role specified"); + expect(result).toBe(outputTime); }); - test("returns 'No server found' when guild is null", async () => { - const discord = new MockDiscord({ command: "/mood" }); - const interaction = discord.getInteraction() as discordJS.ChatInputCommandInteraction; - Object.defineProperty(interaction, 'guild', { value: null }); + test("the snowflake '175928847299117063' should return 2016-04-30 11:18:25.796 UTC (1462015105796)", () => { + const inputSnowflake = "175928847299117063"; + const outputTime = 1462015105796; - expect(await updateOldRoleInServer(interaction, "test-role")).toBe("No server found"); + const result = getTimestampFromSnowflake(inputSnowflake); + + expect(result).toBe(outputTime); }); + }); - test("prints \"No data available when getting role\" when role does not exist", async () => { - const discord = new MockDiscord({ command: "/mood" }); - const interaction = discord.getInteraction() as discordJS.ChatInputCommandInteraction; + describe("Testing timestampToSnowflake", () => { + test("the Discord Epoch (1420070400000) should return the snowflake '0'", () => { + const inputTime = 1420070400000; + const outputSnowflake = "0"; - const { get: mockGet } = require('firebase/database') as MockDatabase; - mockGet.mockResolvedValueOnce({ - exists: () => false, - val: () => null - }); + const result = timestampToSnowflake(inputTime); - const spyConsole = jest.spyOn(console, "log"); + expect(result).toBe(outputSnowflake); + }); - await updateOldRoleInServer(interaction, "test-role"); + test("the time 2016-04-30 11:18:25.796 UTC (1462015105796) should return the snowflake '175928847298985984'", () => { + const inputTime = 1462015105796; + const outputSnowflake = "175928847298985984"; - expect(spyConsole).toHaveBeenCalledWith("No data available when getting role"); - }); + const result = timestampToSnowflake(inputTime); - test("prints error when getting role fails", async () => { - const discord = new MockDiscord({ command: "/mood" }); - const interaction = discord.getInteraction() as discordJS.ChatInputCommandInteraction; + expect(result).toBe(outputSnowflake); + }); + }); - const error = new Error("TEST ERROR"); + describe("Testing addRoleToDatabase", () => { + test("addRoleToDatabase should set servers/[guild id]/roles/[role name] to the role id", async () => { + const role = { name: "role-name", id: "role-id" } as unknown as discordJS.Role; + const guildId = "guild-id"; - const spyConsoleError = jest.spyOn(console, "error").mockImplementationOnce(() => {}); // Mock implementation to prevent actual error printing - - const { get: mockGet } = require('firebase/database') as MockDatabase; - mockGet.mockRejectedValueOnce(error); + const mockSet = jest.spyOn(firebase, "set"); + const result = await addRoleToDatabase(guildId, role); - await updateOldRoleInServer(interaction, "test-role"); + expect(mockSet).toHaveBeenCalled(); + expect(mockSet.mock.calls[0][0]).toBe(`servers/${guildId}/roles/${role.name}`); + expect(mockSet.mock.calls[0][1]).toBe(role.id); - expect(spyConsoleError).toHaveBeenCalledWith(error); + expect(result).toBe("role successfully set"); }); - test("decreases role count when count > 1", async () => { - const discord = new MockDiscord({ command: "/mood" }); - const interaction = discord.getInteraction() as discordJS.ChatInputCommandInteraction; - - const { set: mockSet } = require('firebase/database') as MockDatabase; + test("addRoleToDatabase should return \"something went wrong\" if `set` fails", async () => { + const role = { name: "role-name", id: "role-id" } as unknown as discordJS.Role; + const guildId = "guild-id"; + + const mockSet = jest.spyOn(firebase, "set"); + mockSet.mockRejectedValueOnce(undefined); - const result = await updateOldRoleInServer(interaction, "test-role"); + const result = await addRoleToDatabase(guildId, role); - expect(result).toBe("Decreased role count"); - expect(mockSet).toHaveBeenCalledWith("mock-ref", { count: 1 }); + expect(mockSet).toHaveBeenCalled(); + + expect(result).toBe("something went wrong"); }); + }); - test("removes role when count = 1", async () => { - const discord = new MockDiscord({ command: "/mood" }); - const interaction = discord.getInteraction() as discordJS.ChatInputCommandInteraction; - - const { get: mockGet } = require('firebase/database') as MockDatabase; - mockGet.mockResolvedValueOnce({ - exists: () => true, - val: () => ({ count: 1 }) - }); + describe("Testing removeRoleFromDatabase", () => { + test("removeRoleFromDatabase should remove servers/[guild id]/roles/[role name] from the database", async () => { + const role = { name: "role-name", id: "role-id" } as unknown as discordJS.Role; + const guildId = "guild-id"; + + const mockRemove = jest.spyOn(firebase, "remove"); - const mockRoleDelete = jest.fn(); + const result = await removeRoleFromDatabase(guildId, role); - discord.addRoleToGuild("test-role", "000000"); + expect(mockRemove).toHaveBeenCalled(); + expect(mockRemove.mock.calls[0][0]).toBe(`servers/${guildId}/roles/${role.name}`); + + expect(result).toBe("role successfully removed"); + }); - jest.spyOn(discord.getRoles(), "find").mockReturnValueOnce({ - delete: mockRoleDelete - }); + test("removeRoleFromDatabase should return \"something went wrong\" if `remove` fails", async () => { + const role = { name: "role-name", id: "role-id" } as unknown as discordJS.Role; + const guildId = "guild-id"; - const result = await updateOldRoleInServer(interaction, "test-role"); + const mockRemove = jest.spyOn(firebase, "remove"); + mockRemove.mockRejectedValueOnce(undefined); - expect(result).toBe("Removed role"); - expect(mockRoleDelete).toHaveBeenCalled(); + const result = await removeRoleFromDatabase(guildId, role); + + expect(mockRemove).toHaveBeenCalled(); + + expect(result).toBe("something went wrong"); }); }); - describe("Testing removeOldRoleInServer", () => { - test("returns 'No role specified' when roleName is empty, null, or undefined", async () => { - const discord = new MockDiscord({ command: "/mood" }); - const interaction = discord.getInteraction() as discordJS.ChatInputCommandInteraction; - expect(await removeOldRoleInServer(interaction, "")).toBe("No role specified"); - expect(await removeOldRoleInServer(interaction, undefined)).toBe("No role specified"); - }); + describe("Testing removeRoleIfUnused", () => { + test("removeRoleIfUnused should return \"Invalid role specified\" if `role` is null", async () => { + const role = null; + const expectedResponse = "Invalid role specified"; - test("returns 'No server found' when guild is null", async () => { - const discord = new MockDiscord({ command: "/mood" }); - const interaction = discord.getInteraction() as discordJS.ChatInputCommandInteraction; - Object.defineProperty(interaction, 'guild', { value: null }); + const result = await removeRoleIfUnused(role); - expect(await removeOldRoleInServer(interaction, "test-role")).toBe("No server found"); + expect(result).toBe(expectedResponse); }); - test("removes role from server and database", async () => { - const discord = new MockDiscord({ command: "/mood" }); - const interaction = discord.getInteraction() as discordJS.ChatInputCommandInteraction; - - discord.addRoleToGuild("test-role", "000000"); - - const { remove: mockRemove } = require('firebase/database') as MockDatabase; + test("removeRoleIfUnused should return \"role is too young to be removed\" if `role` has not existed for long enough", async () => { + const role = { name: "role-name", id: timestampToSnowflake(1462015105796 - (MINIMUM_MOOD_LIFESPAN - 1000)) } as unknown as discordJS.Role; + const expectedResponse = "role is too young to be removed"; - const mockRoleDelete = jest.fn(); + const now = jest.spyOn(Date, "now"); + now.mockReturnValue(1462015105796); - jest.spyOn(discord.getRoles(), "find").mockReturnValueOnce({ - delete: mockRoleDelete - }); + const result = await removeRoleIfUnused(role); - const result = await removeOldRoleInServer(interaction, "test-role"); - - expect(result).toBe("Removed role"); - expect(mockRemove).toHaveBeenCalledWith("mock-ref"); - expect(mockRoleDelete).toHaveBeenCalled(); + expect(result).toBe(expectedResponse); }); - }); - describe("Testing updateNewRoleInServer", () => { - test("returns 'No role specified' when roleName is empty, null, or undefined", async () => { - const discord = new MockDiscord({ command: "/mood" }); - const interaction = discord.getInteraction() as discordJS.ChatInputCommandInteraction; + test("removeRoleIfUnused should return \"role removed\" if `role` has no users", async () => { + const discord = new MockDiscord({ command: "" }); - expect(await updateNewRoleInServer(interaction, "")).toBe("No role specified"); - expect(await updateNewRoleInServer(interaction, undefined)).toBe("No role specified"); - }); + discord.addRoleToGuild("role-name", "000000"); + + const role = discord.getRoles().find((storedRole) => storedRole.name === "role-name") as unknown as discordJS.Role; + const expectedResponse = "role removed"; - test("returns 'No server found' when guild is null", async () => { - const discord = new MockDiscord({ command: "/mood" }); - const interaction = discord.getInteraction() as discordJS.ChatInputCommandInteraction; - Object.defineProperty(interaction, 'guild', { value: null }); + const now = jest.spyOn(Date, "now"); + now.mockReturnValue(1420070400000 + (MINIMUM_MOOD_LIFESPAN + 1000)); - expect(await updateNewRoleInServer(interaction, "test-role")).toBe("No server found"); + const result = await removeRoleIfUnused(role); + + expect(result).toBe(expectedResponse); }); - test("prints error when getting role fails", async () => { - const discord = new MockDiscord({ command: "/mood" }); - const interaction = discord.getInteraction() as discordJS.ChatInputCommandInteraction; + test("removeRoleIfUnused should return \"role still in use\" if `role` is being used by another user", async () => { + const discord = new MockDiscord({ command: "" }); - const error = new Error("TEST ERROR"); + discord.addRoleToGuild("role-name", "000000"); - const spyConsoleError = jest.spyOn(console, "error").mockImplementationOnce(() => {}); // Mock implementation to prevent actual error printing + const role = discord.getRoles().find((storedRole) => storedRole.name === "role-name") as unknown as discordJS.Role; + discord.addRoleToMember(role.id); - const { get: mockGet } = require('firebase/database') as MockDatabase; - mockGet.mockRejectedValueOnce(error); + const expectedResponse = "role still in use"; + + const now = jest.spyOn(Date, "now"); + now.mockReturnValue(1420070400000 + (MINIMUM_MOOD_LIFESPAN + 1000)); - await updateNewRoleInServer(interaction, "test-role"); + const result = await removeRoleIfUnused(role); - expect(spyConsoleError).toHaveBeenCalledWith(error); + expect(result).toBe(expectedResponse); }); + }); - test("increments existing role count", async () => { - const discord = new MockDiscord({ command: "/mood" }); - const interaction = discord.getInteraction() as discordJS.ChatInputCommandInteraction; - - const { set: mockSet } = require('firebase/database') as MockDatabase; + describe("Testing cleanupMoods", () => { + test("cleanupMoods should return \"Bot does not have access to the specified guild\" if fetching the guild throws an error", async () => { + const discord = new MockDiscord({ command: "" }); + const guildId = "0"; + const expectedResponse = "Bot does not have access to the specified guild"; - const result = await updateNewRoleInServer(interaction, "test-role"); + const mockFetch = jest.spyOn(discord.getUser().client.guilds, "fetch"); + mockFetch.mockRejectedValue("mock-err") - expect(result).toBe("Updated role count"); - expect(mockSet).toHaveBeenCalledWith("mock-ref", { count: 3 }); + const result = await cleanupMoods(discord.getUser().client, guildId); + + expect(result).toBe(expectedResponse); }); - test("creates new role with count 1 when role doesn't exist", async () => { - const discord = new MockDiscord({ command: "/mood" }); - const interaction = discord.getInteraction() as discordJS.ChatInputCommandInteraction; - - const { get: mockGet, set: mockSet } = require('firebase/database') as MockDatabase; - mockGet.mockResolvedValueOnce({ - exists: () => false, - val: () => null - }); + test("cleanupMoods should return \"all unused roles removed\"", async () => { + const discord = new MockDiscord({ command: "" }); + const guildId = discord.getGuild().id; + const expectedResponse = "all unused roles removed"; + + const mockFetch = jest.spyOn(discord.getUser().client.guilds, "fetch"); + + // issue with ts and overloads + // @ts-ignore + mockFetch.mockResolvedValue(discord.getGuild()); - const result = await updateNewRoleInServer(interaction, "test-role"); + const result = await cleanupMoods(discord.getUser().client, guildId); - expect(result).toBe("Updated role count"); - expect(mockSet).toHaveBeenCalledWith("mock-ref", { count: 1 }); + expect(result).toBe(expectedResponse); }); }); -}); \ No newline at end of file +}); \ No newline at end of file diff --git a/src/helpers.ts b/src/helpers.ts index 55beb89..1c03278 100644 --- a/src/helpers.ts +++ b/src/helpers.ts @@ -1,145 +1,122 @@ -import { CacheType, ChatInputCommandInteraction} from "discord.js"; +import { CacheType, ChatInputCommandInteraction, Client, FetchMembersOptions, Guild, Role, Snowflake} from "discord.js"; import db from './firebase'; // Import from your firebase.ts file -import { ref, set, get, child, remove } from "firebase/database"; +import { ref, set, get, child, remove } from "firebase/database"; -// TODO: remove db dependancy, use interaction.guild.roles.cache.find(role => role.members.size) to find the number of users with a role -// maybe only use db to store which roles are moods +// the minimum amount of time a mood can be in a server before it gets deleted automatically +export const MINIMUM_MOOD_LIFESPAN: number = 0.5 * (1000 * 60); /** - * determines whether a role should be removed from a given guild + * extracts the timestamp field of discord's Snowflake structure * - * @param interaction the interaction containing the guild information - * @param roleName the name of the role being modified - * @returns a string promise describing the outcome + * https://discord.com/developers/docs/reference#snowflakes + * + * @param snowflake the snowflake to extract the timestamp from + * @returns the timestamp of the snowflake */ -export async function updateOldRoleInServer(interaction: ChatInputCommandInteraction, roleName: string | undefined): Promise{ - // if no role is given, exit - if (roleName === "" || roleName === null || roleName === undefined){ - return "No role specified" - } - - // if the guild is invalid, exit - if (!interaction.guild){ - return "No server found"; - } +export function getTimestampFromSnowflake(snowflake: Snowflake): number { + return Number((BigInt(snowflake) >> 22n) + 1420070400000n); +} - // retrieve database info - // TODO: remove the child() call, and add the path here - var dbRef = ref(db); +/** + * fills the timestamp field of discord's Snowflake structure + * + * https://discord.com/developers/docs/reference#snowflakes + * + * @param timestamp the unix timestamp of the snowflake + * @returns the new snowflake + */ +export function timestampToSnowflake(timestamp: number): string { + return (BigInt(timestamp - 1420070400000) << 22n).toString(); +} - // attempt to fetch the data associated with `roleName` - var roleObject = null - await get(child(dbRef, 'servers/' + interaction.guildId + '/roles/' + roleName)).then((snapshot) => { - if (snapshot.exists()) { - roleObject = snapshot.val(); - } else { - console.log("No data available when getting role"); - } - }).catch((error) => { - console.error(error); +/** + * adds a role to the database under a given guild + * + * @param guildId the ID of the server containing the role + * @param roleName the name of the role to add to the database + * @returns a string containing the status of the operation + */ +export async function addRoleToDatabase(guildId: string, role: Role): Promise { + let rolesReference = ref(db); + + return await set(child(rolesReference, `servers/${guildId}/roles/${role.name}`), role.id).then((): string => { + return "role successfully set" + }).catch((): string => { + return "something went wrong"; }); +} - // ensure the role was retrieved properly - if (roleObject === null){ - return "Role object null"; - } - - // if multiple people have the role, decrement the count - // if one person has the role, remove it (since they are the function caller) - // otherwise, no users have the role - let roleCount = roleObject["count"]; - if (roleCount > 1){ - // decrement the count - await set(ref(db, 'servers/' + interaction.guildId + '/roles/' + roleName), { - count: roleCount - 1 - }) - return "Decreased role count"; - } else if (roleCount === 1){ - // remove the role - return removeOldRoleInServer(interaction, roleName); - } else { - // no role found! - return "No role found"; - } +/** + * removes a role from the VC database associated with a given guild + * + * @param guildId the ID of the server containing the role + * @param roleName the name of the role to add to the database + * @returns a string containing the status of the operation + */ +export async function removeRoleFromDatabase(guildId: string, role: Role): Promise { + let rolesReference = ref(db); + + return await remove(child(rolesReference, `servers/${guildId}/roles/${role.name}`)).then((): string => { + return "role successfully removed" + }).catch((): string => { + return "something went wrong"; + }); } /** - * attempts to remove a role from a given server + * removes a role from the VC database and guild if it is unused * - * @param interaction the interaction containing the guild information - * @param roleName the name of the role being modified - * @returns a string promise describing the outcome + * @param guildId the ID of the server containing the role + * @param roleName the name of the role to add to the database + * @returns a string containing the status of the operation */ -export async function removeOldRoleInServer(interaction: ChatInputCommandInteraction, roleName: string | undefined): Promise{ +export async function removeRoleIfUnused(role: Role | null): Promise { // if no role is given, exit - if (roleName === "" || roleName === null || roleName === undefined){ - return "No role specified" + if (!role){ + return "Invalid role specified"; } + + let timeDifference = Date.now() - getTimestampFromSnowflake(role.id); - // if the guild is invalid, exit - if (!interaction.guild){ - return "No server found"; + if (timeDifference < MINIMUM_MOOD_LIFESPAN) { + return "role is too young to be removed" } - // remove the role in discord - interaction.guild.roles.cache.find(role => role.name === roleName)!.delete(); - - // remove the role in the db - await remove(ref(db, 'servers/' + interaction.guildId + '/roles/' + roleName)); + + return await role.guild.members.fetch().then((members): string => { + // console.log(members); + if (members.some(member => member.roles.cache.some(memberRole => memberRole.id === role.id))) { + return "role still in use" + } - // return successful message - return "Removed role"; + console.log(`removing role ${role.id} (${role.name})`); + role.delete("Role out of use"); + removeRoleFromDatabase(role.guild.id, role); + return "role removed" + }); } /** - * determines whether a role should be removed from a given guild or simply incremented + * removes all unused moods * - * @param interaction the interaction containing the guild information - * @param roleName the name of the role being modified - * @returns a string promise describing the outcome + * @param guildId the ID of the server to clean + * @returns a string containing the status of the operation */ -export async function updateNewRoleInServer(interaction: ChatInputCommandInteraction, roleName: string | undefined): Promise{ - // if no role is given, exit - if (roleName === "" || roleName === null || roleName === undefined){ - return "No role specified" - } +export async function cleanupMoods(client: Client, guildId: string): Promise { + return client.guilds.fetch(guildId).then(async (guild) => { + let rolesReference = ref(db); + + let snapshot = await get(child(rolesReference, `servers/${guildId}/roles`)); - // retrieve database info - // TODO: remove the child() call, and add the path here - var dbRef = ref(db); + snapshot.forEach((roleSnapshot) => { + let roleSnowflake: Snowflake = roleSnapshot.val(); - // if the guild is invalid, exit - if (!interaction.guild){ - return "No server found"; - } - - // attempt to access the role data in the db - var roleObject = null - await get(child(dbRef, 'servers/' + interaction.guildId + '/roles/' + roleName)).then((snapshot) => { - if (snapshot.exists()) { - roleObject = snapshot.val(); - } else { - console.log("No data available when getting role"); - } + guild.roles.fetch(roleSnowflake).then(removeRoleIfUnused); + }); + + return "all unused roles removed"; }).catch((error) => { console.error(error); + return "Bot does not have access to the specified guild"; }); - - // if the role exists, increment it - // if not, create it - if (roleObject !== null){ - // increment the role count - let roleCount = roleObject["count"]; - await set(ref(db, 'servers/' + interaction.guildId + '/roles/' + roleName), { - count: roleCount + 1 - }) - } else { - // register the role with count 1 - await set(ref(db, 'servers/' + interaction.guildId + '/roles/' + roleName), { - count: 1 - }) - } - - // return a successful message - return "Updated role count"; } \ No newline at end of file diff --git a/src/index.test.ts b/src/index.test.ts index ceca8a4..542d1a1 100644 --- a/src/index.test.ts +++ b/src/index.test.ts @@ -7,7 +7,7 @@ describe("Testing slash commands", ()=>{ process.env.APP_ID = "TEST APP ID"; process.env.DISCORD_TOKEN = "TEST TOKEN"; - jest.spyOn(console, "log").mockImplementation(() => {}); + // jest.spyOn(console, "log").mockImplementation(() => {}); }); test("index.ts should run launchBot() from discordApp.ts", async ()=>{ diff --git a/src/interactions.test.ts b/src/interactions.test.ts index a6795ac..f6b5160 100644 --- a/src/interactions.test.ts +++ b/src/interactions.test.ts @@ -2,47 +2,19 @@ import * as discordJS from "discord.js"; import { embed, ping, tone, mood, clarify, requestAnonymousClarification } from "./interactions"; import { MockDiscord } from "./testing/mocks/mockDiscord"; import * as gptRequests from "./gptRequests"; +import * as firebase from "firebase/database"; +import * as helpers from "./helpers"; jest.mock("./gptRequests") jest.mock("discord.js"); - -type MockDatabase = { - get: jest.Mock; - child: jest.Mock; - ref: jest.Mock; - set: jest.Mock; - getDatabase: jest.Mock; -} - -jest.mock('firebase/database', (): MockDatabase => { - const mockSnapshot = { - exists: () => true, - val: () => ({ mood: "previous-mood" }) - }; - - // Mock functions that will be exported - const mockGet = jest.fn().mockResolvedValue(mockSnapshot); - const mockChild = jest.fn((_, path) => { - return `servers/${path}`; - }); - const mockRef = jest.fn().mockReturnValue('mock-ref'); - - return { - get: mockGet, - child: mockChild, - ref: mockRef, - set: jest.fn().mockResolvedValue(undefined), - getDatabase: jest.fn().mockReturnValue({ - ref: mockRef - }) - }; -}); +jest.mock("firebase/database"); +jest.mock("./helpers"); describe("Testing application commands", ()=>{ beforeAll(()=>{ process.env.APP_ID = "TEST APP ID"; process.env.DISCORD_TOKEN = "TEST TOKEN"; - jest.spyOn(console, "log").mockImplementation(() => {}); + // jest.spyOn(console, "log").mockImplementation(() => {}); }); describe("Testing ping command", () => { @@ -61,7 +33,7 @@ describe("Testing application commands", ()=>{ await ping(interaction); const endTime = jest.getRealSystemTime(); - expect(endTime-startTime).toBeGreaterThanOrEqual(1000); + expect(endTime-startTime).toBeGreaterThanOrEqual(999); expect(spyDeferReply).toHaveBeenCalled(); expect(spyEditReply).toHaveBeenCalledWith("pong!"); }); @@ -82,7 +54,7 @@ describe("Testing application commands", ()=>{ await ping(interaction).catch(spyReject); const endTime = jest.getRealSystemTime(); - expect(endTime-startTime).toBeGreaterThanOrEqual(1000); + expect(endTime-startTime).toBeGreaterThanOrEqual(999); expect(spyDeferReply).toHaveBeenCalled(); expect(spyEditReply).not.toHaveBeenCalled(); expect(spyReject).toHaveBeenCalled(); @@ -281,23 +253,25 @@ Here's a short list of tones: \`\` (***TODO***)`; get: jest.fn(() => 1234567890) }); - const { set: mockSet, get: mockGet } = require('firebase/database') as MockDatabase; - mockSet.mockReset(); - mockGet.mockReset(); + const mockSet = jest.spyOn(firebase, "set"); + const mockGet = jest.spyOn(firebase, "get"); + mockGet.mockResolvedValue({ exists: () => true, - val: () => ({ mood: "angry" }) - }); + val: () => ({ mood: `${helpers.timestampToSnowflake(1420070400000)}` }) + } as unknown as firebase.DataSnapshot); + + jest.useFakeTimers(); await mood(interaction); - + jest.runAllTimers(); // Check that the array of calls includes our expected call expect(mockSet.mock.calls).toContainEqual([ "mock-ref", { - mood: "happy", + mood: `${helpers.timestampToSnowflake(1420070400001)}`, timestamp: 1234567890 } ]); @@ -325,13 +299,13 @@ Here's a short list of tones: \`\` (***TODO***)`; get: jest.fn(() => 1234567890) }); - const { set: mockSet, get: mockGet } = require('firebase/database') as MockDatabase; - mockSet.mockReset(); - mockGet.mockReset(); + const mockSet = jest.spyOn(firebase, "set"); + const mockGet = jest.spyOn(firebase, "get"); + mockGet.mockResolvedValue({ exists: () => false, val: () => null - }); + } as unknown as firebase.DataSnapshot); await mood(interaction); @@ -339,7 +313,7 @@ Here's a short list of tones: \`\` (***TODO***)`; expect(mockSet.mock.calls).toContainEqual([ "mock-ref", { - mood: "excited", + mood: `${helpers.timestampToSnowflake(1420070400000)}`, timestamp: 1234567890 } ]); @@ -365,9 +339,9 @@ Here's a short list of tones: \`\` (***TODO***)`; get: jest.fn(() => 1234567890) }); - const { set: mockSet, get: mockGet } = require('firebase/database') as MockDatabase; - mockSet.mockReset(); - mockGet.mockReset(); + const mockSet = jest.spyOn(firebase, "set"); + const mockGet = jest.spyOn(firebase, "get"); + mockGet.mockRejectedValue(error); const spyStdErr = jest.spyOn(console, "error").mockImplementation(() => {}); diff --git a/src/interactions.ts b/src/interactions.ts index 0868ea9..c11369c 100644 --- a/src/interactions.ts +++ b/src/interactions.ts @@ -2,12 +2,15 @@ import { CacheType, ChatInputCommandInteraction, EmbedBuilder, - MessageContextMenuCommandInteraction + MessageContextMenuCommandInteraction, + MessageFlags, + Role, + Snowflake } from "discord.js"; import { analyzeTone, analyzeMoodColor } from "./gptRequests"; import db from './firebase'; // Import from your firebase.ts file -import { ref, set, get, child } from "firebase/database"; -import { updateOldRoleInServer, updateNewRoleInServer} from "./helpers" +import { ref, set, get, child, query, DataSnapshot } from "firebase/database"; +import { addRoleToDatabase, MINIMUM_MOOD_LIFESPAN, removeRoleFromDatabase, removeRoleIfUnused} from "./helpers" /** * the callback to a `ping` interaction @@ -22,12 +25,12 @@ export async function ping(interaction: ChatInputCommandInteraction): return new Promise((resolve, reject) => { // reply after 1 second setTimeout(() => { - if (interaction.isRepliable()) { - interaction.editReply(`pong!`); - resolve(); - } else { - reject(); - } + if (interaction.isRepliable()) { + interaction.editReply(`pong!`); + resolve(); + } else { + reject(); + } }, 1000); }) } @@ -107,58 +110,79 @@ Here's a short list of tones: \`\` (***TODO***)`); * @returns void */ export async function mood(interaction: ChatInputCommandInteraction): Promise { - var currentMood = interaction.options.getString('currentmood')!; - let oldMood = ""; + const currentMood = interaction.options.getString('currentmood')!; + let oldMood: Snowflake | null; + let newRole: Role | undefined; + + await interaction.deferReply({flags: MessageFlags.Ephemeral}); + + // ensure the mood is not an existing server role + newRole = interaction.guild?.roles.cache.find(role => role.name === currentMood); + if (newRole) { + const dbRoleRef = ref(db, `servers/${interaction.guildId}/roles/${newRole.name}`); + const inDB = await get(dbRoleRef).then(snapshot => snapshot.exists()); + + // if the role is not in our database, it should be protected + if (!inDB) { + console.log(`mood change denied, ${newRole.id} (${newRole.name}) is not a VC mood`); + interaction.editReply("That is a preexisting role in this server! Please select a new mood."); + return; + } + } + + // Get a reference to this user's section of the db + const dbUserRef = ref(db, `servers/${interaction.guildId}/username/${interaction.user.id}`); // Get the old mood from database - var dbRef = ref(db); - await get(child(dbRef, 'servers/' + interaction.guildId + '/username/' + interaction.user.id)).then((snapshot) => { + oldMood = await get(dbUserRef).then((snapshot) => { if (snapshot.exists()) { - oldMood = snapshot.val()["mood"] + return oldMood = snapshot.val()["mood"] } else { - console.log("No data available"); + console.log("No data available"); + return null; } }).catch((error) => { console.error(error); }); - let guild = interaction.guild!; - let member = await guild.members.fetch(interaction.user.id); - - - // delete the old mood from roles - if (interaction.guild?.roles.cache.find(role => role.name === oldMood)) { - if (member.roles.cache.find(role => role.name === oldMood)){ - let oldRole = interaction.guild?.roles.cache.find(role => role.name === oldMood); - member.roles.remove(oldRole!); - } + const guild = interaction.guild!; + const member = await guild.members.fetch(interaction.user.id); + + // if they had a db entry (old mood role), attempt to remove it + if (oldMood) { + guild.roles.fetch(oldMood).then(role => { + if (role) { + member.roles.remove(role); + // wait a bit for the cache to update + // maybe just clean roles after a certain interval of time eventually + setTimeout(() => { + removeRoleIfUnused(role); + }, MINIMUM_MOOD_LIFESPAN); + } + }).catch((error) => { + console.error(error); + }); } - - // set the new mood in database - await set(ref(db, 'servers/' + interaction.guildId + '/username/' + interaction.user.id), { - mood: currentMood, - timestamp: interaction.createdTimestamp - }); - + // update new role - if (interaction.guild?.roles.cache.find(role => role.name === currentMood)) { - let newRole = guild.roles.cache.find((r) => r.name === currentMood); - member.roles.add(newRole!); + if (newRole) { + member.roles.add(newRole); } else { - let moodColorHex = await analyzeMoodColor(currentMood); - await guild.roles.create({name: currentMood, color: `#${moodColorHex}`}) - let newRole = guild.roles.cache.find((r) => r.name === currentMood); + const moodColorHex = await analyzeMoodColor(currentMood); + newRole = await guild.roles.create({name: currentMood, color: `#${moodColorHex}`}); member.roles.add(newRole!); } - // Update database with roles - await updateOldRoleInServer(interaction, oldMood); - await updateNewRoleInServer(interaction, currentMood); + // set the new mood in database + await set(dbUserRef, { + mood: newRole!.id, + timestamp: interaction.createdTimestamp + }); - interaction.reply({ - ephemeral: true, - content: "Thanks for updating your mood!" - }) + // Update database with new role + await addRoleToDatabase(interaction.guildId!, newRole!); + + interaction.editReply("Thanks for updating your mood!"); } /** diff --git a/src/testing/mocks/mockDiscord.ts b/src/testing/mocks/mockDiscord.ts index 396e206..1cfba56 100644 --- a/src/testing/mocks/mockDiscord.ts +++ b/src/testing/mocks/mockDiscord.ts @@ -21,8 +21,10 @@ import { ChatInputCommandInteraction, InteractionReplyOptions, MessageCollector, - UserFlags + UserFlags, + GuildCreateOptions } from "discord.js"; +import { timestampToSnowflake } from "../../helpers"; type MockDiscordOptions = { command: string, @@ -34,7 +36,7 @@ export class MockDiscord { private user!: User; private channel!: Channel; private interaction!: CommandInteraction; - private interactionReply!: string | MessagePayload | InteractionEditReplyOptions; + private interactionReply!: string | MessagePayload | InteractionReplyOptions | InteractionEditReplyOptions; private latestMessage!: string | MessagePayload; private interactionOptions!: CommandInteractionOption; private guild: Guild; @@ -69,14 +71,12 @@ export class MockDiscord { if (roleObj) { this.memberRoles.set(roleObj.id, roleObj) } else { - const newRole = { - id: `${role}-role-id`, + const newRole = { name: role, color: 0x000000 } this.guild.roles.create(newRole); - this.memberRoles.set(role, newRole) - } + } } else { this.memberRoles.set(role.id, role); } @@ -98,30 +98,44 @@ export class MockDiscord { } as unknown as GuildMember; // Then create guild with reference to guildMember + let memberCache = new Collection([[this.user.id, this.guildMember]]); this.guild = { client: this.client, id: "guild-id", name: "mock guild", roles: { cache: this.roles, - create: jest.fn().mockImplementation((options: any) => { - // console.log("create role called with options: " + options.name + " " + options.color); - const newRole = { - id: `${options.name}-role-id`, - name: options.name, - color: options.color || 0x000000 - }; - this.roles.set(newRole.id, newRole); - // console.log("found role:", JSON.stringify(this.roles.find(role => role.name === "happy"))); - return Promise.resolve(newRole); - }) + fetch: jest.fn(), + create: jest.fn() }, members: { - cache: new Map([[this.user.id, this.guildMember]]), - fetch: jest.fn().mockResolvedValue(this.guildMember) + cache: memberCache, + fetch: jest.fn(async (query) => { + if (query == this.user.id) { + return this.guildMember; + } else { + return memberCache; + } + }), + some: jest.fn().mockResolvedValue(true) } } as unknown as Guild; + this.guild.roles.fetch = jest.fn(async (id) => this.roles.get(id)) as jest.Mock + this.guild.roles.create = jest.fn().mockImplementation((options: any) => { + // console.log("create role called with options: " + options.name + " " + options.color); + const newRole = { + id: timestampToSnowflake(1420070400000 + this.roles.size), + name: options.name, + color: options.color || 0x000000, + guild: this.guild, + delete: jest.fn((_) => this.roles.delete(`${(options.name as string).length}`,)) + }; + this.roles.set(newRole.id, newRole); + // console.log("found role:", JSON.stringify(this.roles.find(role => role.name === "happy"))); + return Promise.resolve(newRole); + }); + // Set guild reference in guildMember this.guildMember.guild = this.guild; @@ -132,7 +146,7 @@ export class MockDiscord { return this.interaction; } - public getInteractionReply(): string | MessagePayload | InteractionEditReplyOptions { + public getInteractionReply(): string | MessagePayload | InteractionReplyOptions | InteractionEditReplyOptions { return this.interactionReply; } @@ -144,6 +158,10 @@ export class MockDiscord { return this.user; } + public getClient(): User { + return this.user; + } + public getGuild(): Guild { return this.guild; } @@ -182,54 +200,6 @@ export class MockDiscord { return mockUser; } - private createMockGuild(client: Client): Guild { - return { - client: client, - id: "guild-id", - name: "mock guild", - roles: { - cache: this.roles, - create: jest.fn().mockImplementation((options: any) => { - const newRole = { id: `${options.name}-role-id`, name: options.name }; - this.roles.set(options.name, newRole); - return Promise.resolve(newRole); - }) - }, - members: { - cache: new Map(), - fetch: jest.fn().mockImplementation((userId: string) => { - return Promise.resolve(this.guildMember); - }) - }, - } as unknown as Guild - } - - private createMockGuildMember(client: Client, user: User, guild: Guild): GuildMember { - return { - client: client, - deaf: false, - mute: false, - self_mute: false, - self_deaf: false, - session_id: "session-id", - channel_id: "channel-id", - nick: "nick", - user: user, - roles: { - cache: this.memberRoles, - add: jest.fn().mockImplementation((role) => { - this.memberRoles.set(role.id, role); - return Promise.resolve(this); - }), - remove: jest.fn().mockImplementation((role) => { - this.memberRoles.delete(role.id); - return Promise.resolve(this); - }) - }, - guild: guild - } as unknown as GuildMember - } - public createMockInteraction(command: string, mockGuild: any, mockMember: any, repliable: boolean = true, options: {} = {}): CommandInteraction { return { client: this.client,