diff --git a/nodecg-io-core/extension/bundleManager.ts b/nodecg-io-core/extension/bundleManager.ts index b0a615b69..206412180 100644 --- a/nodecg-io-core/extension/bundleManager.ts +++ b/nodecg-io-core/extension/bundleManager.ts @@ -81,6 +81,7 @@ export class BundleManager extends EventEmitter { if (svcDependency === undefined) { return error(`Bundle "${bundleName} doesn't depend on the "${instance.serviceType}" service.`); } + const oldInstance = svcDependency.serviceInstance; // Update service instance of service dependency, remove client update callback from old service instance (if applicable) // and add the callback to the new instance. @@ -88,7 +89,9 @@ export class BundleManager extends EventEmitter { // Let the bundle update his reference to the client svcDependency.clientUpdateCallback(instance.client); + this.emit("change"); + this.emit("reregisterInstance", oldInstance); return emptySuccess(); } @@ -105,10 +108,15 @@ export class BundleManager extends EventEmitter { const svcDependency = bundle?.find((svcDep) => svcDep.serviceType === serviceType); if (svcDependency !== undefined) { + const oldInstance = svcDependency.serviceInstance; + // Unset service instance and let the bundle know that it hasn't access to this service anymore. svcDependency.serviceInstance = undefined; svcDependency.clientUpdateCallback(undefined); + this.emit("change"); + this.emit("reregisterInstance", oldInstance); + return true; } diff --git a/nodecg-io-core/extension/instanceManager.ts b/nodecg-io-core/extension/instanceManager.ts index 4bf73eda9..649cdd245 100644 --- a/nodecg-io-core/extension/instanceManager.ts +++ b/nodecg-io-core/extension/instanceManager.ts @@ -19,6 +19,9 @@ export class InstanceManager extends EventEmitter { private readonly bundles: BundleManager, ) { super(); + bundles.on("reregisterInstance", (serviceInstance?: string) => + this.reregisterHandlersOfInstance(serviceInstance), + ); } /** @@ -199,17 +202,14 @@ export class InstanceManager extends EventEmitter { // Check if a error happened while creating the client if (client.failed) { - this.nodecg.log.error( - `The "${inst.serviceType}" service produced an error while creating a client: ${client.errorMessage}`, - ); - inst.client = undefined; + throw client.errorMessage; // Error logging happens in catch block } else { // Update service instance object inst.client = client.result; } } catch (err) { this.nodecg.log.error( - `The "${inst.serviceType}" service function produced an error while creating a client: ${err}`, + `The "${inst.serviceType}" service produced an error while creating a client: ${err}`, ); inst.client = undefined; } @@ -228,4 +228,46 @@ export class InstanceManager extends EventEmitter { } } } + + /** + * Removes all handlers from the service client of the instance and lets bundles readd their handlers. + * @param instanceName the name of the instance which handlers should be re-registred + */ + private reregisterHandlersOfInstance(instanceName?: string): void { + if (!instanceName) return; + + const inst = this.getServiceInstance(instanceName); + if (!inst) { + this.nodecg.log.error(`Can't re-register handlers of instance "${instanceName}": instance not found`); + return; + } + + const svc = this.services.getService(inst.serviceType); + if (svc.failed) { + this.nodecg.log.error( + `Can't reregister handlers of instance "${instanceName}": can't get service: ${svc.errorMessage}`, + ); + return; + } + + // Client should be recreated because the Service has no way to reset the handlers. + if (svc.result.reCreateClientToRemoveHandlers) { + this.updateInstanceClient(inst, instanceName, svc.result); + return; + } + + if (!svc.result.removeHandlers) return; // Service provides no way to remove handlers, thus this service has no handlers + + // Remove handlers + try { + svc.result.removeHandlers(inst.client); + } catch (err) { + this.nodecg.log.error( + `Can't re-register handlers of instance "${instanceName}": error while removing handlers: ${err.toString()}`, + ); + } + // Readd handlers by running the `onAvailable` function of all bundles + // that are using this service instance. + this.bundles.handleInstanceUpdate(inst, instanceName); + } } diff --git a/nodecg-io-core/extension/serviceBundle.ts b/nodecg-io-core/extension/serviceBundle.ts index bd3caa64f..a96d048d7 100644 --- a/nodecg-io-core/extension/serviceBundle.ts +++ b/nodecg-io-core/extension/serviceBundle.ts @@ -78,6 +78,28 @@ export abstract class ServiceBundle> impleme */ abstract stopClient(client: C): void; + /** + * Removes all handlers from a service client. + * This is used when a bundle no longer uses a service client it still has its handlers registered. + * Then this function is called that should remove all handlers + * and then all bundles that are still using this client will asked to re-register their handlers + * by running the onAvailable callback of the specific bundle. + * + * Can be left unimplemented if the serivce doesn't has any handlers e.g. a http wrapper + * @param client the client of which all handlers should be removed + */ + removeHandlers?(client: C): void; + + /** + * This flag can be enabled by services if they can't implement removeHandlers but also have some handlers that + * should be reset if a bundleDependency has been changed. + * It gets rid of the handlers by stopping the client and creating a new one, to which then only the + * now wanted handlers get registered (e.g. if a bundle doesn't uses this service anymore but another still does). + * Not ideal, but if your service can't implement removeHandlers for some reason it is still better than + * having dangling handlers that still fire eventho they shouldn't. + */ + reCreateClientToRemoveHandlers = false; + private readSchema(pathSegments: string[]): unknown { const joinedPath = path.resolve(...pathSegments); try { diff --git a/nodecg-io-core/extension/types.d.ts b/nodecg-io-core/extension/types.d.ts index 11766d547..bde641d09 100644 --- a/nodecg-io-core/extension/types.d.ts +++ b/nodecg-io-core/extension/types.d.ts @@ -60,6 +60,28 @@ export interface Service> { * @param client the client that needs to be stopped. */ readonly stopClient(client: C): void; + + /** + * Removes all handlers from a service client. + * This is used when a bundle no longer uses a service client it still has its handlers registered. + * Then this function is called that should remove all handlers + * and then all bundles that are still using this client will asked to re-register their handlers + * by running the onAvailable callback of the specific bundle. + * + * Can be left unimplemented if the serivce doesn't has any handlers e.g. a http wrapper + * @param client the client of which all handlers should be removed + */ + readonly removeHandlers?(client: C): void; + + /** + * This flag can be enabled by services if they can't implement removeHandlers but also have some handlers that + * should be reset if a bundleDependency has been changed. + * It gets rid of the handlers by stopping the client and creating a new one, to which then only the + * now wanted handlers get registered (e.g. if a bundle doesn't uses this service anymore but another still does). + * Not ideal, but if your service can't implement removeHandlers for some reason it is still better than + * having dangling handlers that still fire eventho they shouldn't. + */ + reCreateClientToRemoveHandlers: boolean; } /** diff --git a/nodecg-io-discord/extension/index.ts b/nodecg-io-discord/extension/index.ts index 69828a6d4..0ca5908f5 100644 --- a/nodecg-io-discord/extension/index.ts +++ b/nodecg-io-discord/extension/index.ts @@ -38,4 +38,8 @@ class DiscordService extends ServiceBundle { this.nodecg.log.info("Stopped IRC client successfully."); }); } + + removeHandlers(client: IRCServiceClient): void { + client.getNativeClient().removeAllListeners(); + } } function sendMessage(client: IRCClient, target: string, message: string): void { diff --git a/nodecg-io-midi-input/extension/index.ts b/nodecg-io-midi-input/extension/index.ts index f6c13477b..766cac918 100644 --- a/nodecg-io-midi-input/extension/index.ts +++ b/nodecg-io-midi-input/extension/index.ts @@ -59,4 +59,8 @@ class MidiService extends ServiceBundle { stopClient(client: OBSServiceClient) { client.getNativeClient().disconnect(); } + + removeHandlers(client: OBSServiceClient) { + client.getNativeClient().removeAllListeners(); + } } diff --git a/nodecg-io-sacn-receiver/extension/index.ts b/nodecg-io-sacn-receiver/extension/index.ts index 5ce08ff0b..0b9f90636 100644 --- a/nodecg-io-sacn-receiver/extension/index.ts +++ b/nodecg-io-sacn-receiver/extension/index.ts @@ -31,4 +31,8 @@ class SacnReceiverService extends ServiceBundle } } - stopClient(_client: SlackServiceClient): void { - // Not supported by the client + stopClient(client: SlackServiceClient): void { + // Not supported by the client, at least remove all listeners + this.removeHandlers(client); + } + + removeHandlers(client: SlackServiceClient): void { + client.getNativeClient().removeAllListeners(); } } diff --git a/nodecg-io-spotify/extension/index.ts b/nodecg-io-spotify/extension/index.ts index 0e01107f5..672284472 100644 --- a/nodecg-io-spotify/extension/index.ts +++ b/nodecg-io-spotify/extension/index.ts @@ -108,6 +108,6 @@ class SpotifyService extends ServiceBundle client.getNativeClient().close(); this.nodecg.log.info("Disconnected from TIANE."); } + + removeHandlers(client: TianeServiceClient): void { + client.getNativeClient().removeAllListeners(); + } } diff --git a/nodecg-io-twitch-chat/extension/index.ts b/nodecg-io-twitch-chat/extension/index.ts index 27edf4c7f..d3d7ed4a0 100644 --- a/nodecg-io-twitch-chat/extension/index.ts +++ b/nodecg-io-twitch-chat/extension/index.ts @@ -28,10 +28,13 @@ class TwitchService extends ServiceBundle this.nodecg.log.info("Stopped twitch client successfully.")); } + + removeHandlers(client: TwitchServiceClient): void { + client.getNativeClient().removeListener(); + } } diff --git a/nodecg-io-twitch-pubsub/extension/index.ts b/nodecg-io-twitch-pubsub/extension/index.ts index 91886cf49..15e58df50 100644 --- a/nodecg-io-twitch-pubsub/extension/index.ts +++ b/nodecg-io-twitch-pubsub/extension/index.ts @@ -28,4 +28,9 @@ class TwitchPubSubService extends ServiceBundle { + client.close(); + }); + } } diff --git a/package-lock.json b/package-lock.json index f44c013f4..042576565 100644 --- a/package-lock.json +++ b/package-lock.json @@ -209,16 +209,16 @@ } }, "@babel/traverse": { - "version": "7.12.10", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.12.10.tgz", - "integrity": "sha512-6aEtf0IeRgbYWzta29lePeYSk+YAFIC3kyqESeft8o5CkFlYIMX+EQDDWEiAQ9LHOA3d0oHdgrSsID/CKqXJlg==", - "requires": { - "@babel/code-frame": "^7.10.4", - "@babel/generator": "^7.12.10", - "@babel/helper-function-name": "^7.10.4", - "@babel/helper-split-export-declaration": "^7.11.0", - "@babel/parser": "^7.12.10", - "@babel/types": "^7.12.10", + "version": "7.12.12", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.12.12.tgz", + "integrity": "sha512-s88i0X0lPy45RrLM8b9mz8RPH5FqO9G9p7ti59cToE44xFm1Q+Pjh5Gq4SXBbtb88X7Uy7pexeqRIQDDMNkL0w==", + "requires": { + "@babel/code-frame": "^7.12.11", + "@babel/generator": "^7.12.11", + "@babel/helper-function-name": "^7.12.11", + "@babel/helper-split-export-declaration": "^7.12.11", + "@babel/parser": "^7.12.11", + "@babel/types": "^7.12.12", "debug": "^4.1.0", "globals": "^11.1.0", "lodash": "^4.17.19" @@ -232,9 +232,9 @@ } }, "@babel/types": { - "version": "7.12.11", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.12.11.tgz", - "integrity": "sha512-ukA9SQtKThINm++CX1CwmliMrE54J6nIYB5XTwL5f/CLFW9owfls+YSU8tVW15RQ2w+a3fSbPjC6HdQNtWZkiA==", + "version": "7.12.12", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.12.12.tgz", + "integrity": "sha512-lnIX7piTxOH22xE7fDXDbSHg9MM1/6ORnafpJmov5rs0kX5g4BZxeXNJLXsMRiO0U5Rb8/FvMS6xlTnTHvxonQ==", "requires": { "@babel/helper-validator-identifier": "^7.12.11", "lodash": "^4.17.19", @@ -2745,9 +2745,9 @@ } }, "@serialport/bindings": { - "version": "9.0.3", - "resolved": "https://registry.npmjs.org/@serialport/bindings/-/bindings-9.0.3.tgz", - "integrity": "sha512-hnqVqEc4IqGCIjztGkd30V0KcTatQ1T/SS03MZ9KLn6e3y2PSXFqf0TqxB0qF7K9lGHWldMTiPOQaZnuV/oZLQ==", + "version": "9.0.4", + "resolved": "https://registry.npmjs.org/@serialport/bindings/-/bindings-9.0.4.tgz", + "integrity": "sha512-6dlE1vm5c1xk667f1Zm7D+msbHJ9jdnUr9l8DResKpj2iCBzbCNsW+yCYq26WxzXWc1L2HUaS3/aL+k0wm5amg==", "requires": { "@serialport/binding-abstract": "^9.0.2", "@serialport/parser-readline": "^9.0.1", @@ -3048,9 +3048,9 @@ } }, "@types/node-telegram-bot-api": { - "version": "0.50.4", - "resolved": "https://registry.npmjs.org/@types/node-telegram-bot-api/-/node-telegram-bot-api-0.50.4.tgz", - "integrity": "sha512-3wS5AOsMvIUCY1UU8l0zB0yERNOm2qEQNknPaxrDsN/ISSbLfa0blSsdfxoO63L/acdffF+Udn9XfXaJnGDF5g==", + "version": "0.51.0", + "resolved": "https://registry.npmjs.org/@types/node-telegram-bot-api/-/node-telegram-bot-api-0.51.0.tgz", + "integrity": "sha512-HtDIIYLezSl2EpezaIWKQ7Jn+y6agQKEUZ+BowtvkA+LdWkGwFRRu+cZorUcnnuR0R45KUidnak9qTrxtMyWeQ==", "requires": { "@types/node": "*", "@types/request": "*" @@ -4613,9 +4613,9 @@ } }, "caniuse-lite": { - "version": "1.0.30001168", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001168.tgz", - "integrity": "sha512-P2zmX7swIXKu+GMMR01TWa4csIKELTNnZKc+f1CjebmZJQtTAEXmpQSoKVJVVcvPGAA0TEYTOUp3VehavZSFPQ==" + "version": "1.0.30001170", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001170.tgz", + "integrity": "sha512-Dd4d/+0tsK0UNLrZs3CvNukqalnVTRrxb5mcQm8rHL49t7V5ZaTygwXkrq+FB+dVDf++4ri8eJnFEJAB8332PA==" }, "caseless": { "version": "0.12.0", @@ -4685,16 +4685,29 @@ "integrity": "sha1-wKHS86cJLgN3S/qD8UwPxXkKhmc=" }, "cheerio": { - "version": "1.0.0-rc.3", - "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0-rc.3.tgz", - "integrity": "sha512-0td5ijfUPuubwLUu0OBoe98gZj8C/AA+RW3v67GPlGOrvxWjZmBXiBCRU+I8VEiNyJzjth40POfHiz2RB3gImA==", + "version": "1.0.0-rc.5", + "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0-rc.5.tgz", + "integrity": "sha512-yoqps/VCaZgN4pfXtenwHROTp8NG6/Hlt4Jpz2FEP0ZJQ+ZUkVDd0hAPDNKhj3nakpfPt/CNs57yEtxD1bXQiw==", + "requires": { + "cheerio-select-tmp": "^0.1.0", + "dom-serializer": "~1.2.0", + "domhandler": "^4.0.0", + "entities": "~2.1.0", + "htmlparser2": "^6.0.0", + "parse5": "^6.0.0", + "parse5-htmlparser2-tree-adapter": "^6.0.0" + } + }, + "cheerio-select-tmp": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/cheerio-select-tmp/-/cheerio-select-tmp-0.1.0.tgz", + "integrity": "sha512-kx/pq9hxLo6FhjiYqUheSOV0Eb729ZwkXXPrPTeK6kl/VMgaUlsYoAOv3nOJZcHk++V9pI17YNNngtbLVPTB9A==", "requires": { - "css-select": "~1.2.0", - "dom-serializer": "~0.1.1", - "entities": "~1.1.1", - "htmlparser2": "^3.9.1", - "lodash": "^4.15.0", - "parse5": "^3.0.1" + "css-select": "^3.1.2", + "css-what": "^4.0.0", + "domelementtype": "^2.1.0", + "domhandler": "^4.0.0", + "domutils": "^2.4.4" } }, "chokidar": { @@ -5592,20 +5605,21 @@ "dev": true }, "css-select": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/css-select/-/css-select-1.2.0.tgz", - "integrity": "sha1-KzoRBTnFNV8c2NMUYj6HCxIeyFg=", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-3.1.2.tgz", + "integrity": "sha512-qmss1EihSuBNWNNhHjxzxSfJoFBM/lERB/Q4EnsJQQC62R2evJDW481091oAdOr9uh46/0n4nrg0It5cAnj1RA==", "requires": { - "boolbase": "~1.0.0", - "css-what": "2.1", - "domutils": "1.5.1", - "nth-check": "~1.0.1" + "boolbase": "^1.0.0", + "css-what": "^4.0.0", + "domhandler": "^4.0.0", + "domutils": "^2.4.3", + "nth-check": "^2.0.0" } }, "css-what": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/css-what/-/css-what-2.1.3.tgz", - "integrity": "sha512-a+EPoD+uZiNfh+5fxw2nO9QwFa6nJe2Or35fGY6Ipw1R3R4AGz1d1TEZrCegvw2YTmZ0jXirGYlzxxpYSHwpEg==" + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-4.0.0.tgz", + "integrity": "sha512-teijzG7kwYfNVsUh2H/YN62xW3KK9YhXEgSlbxMlcyjPNvdKJqFx5lrwlJgoFP1ZHlB89iGDlo/JyshKeRhv5A==" }, "currently-unhandled": { "version": "0.4.1", @@ -5981,34 +5995,36 @@ } }, "dom-serializer": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.1.1.tgz", - "integrity": "sha512-l0IU0pPzLWSHBcieZbpOKgkIn3ts3vAh7ZuFyXNwJxJXk/c4Gwj9xaTJwIDVQCXawWD0qb3IzMGH5rglQaO0XA==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.2.0.tgz", + "integrity": "sha512-n6kZFH/KlCrqs/1GHMOd5i2fd/beQHuehKdWvNNffbGHTr/almdhuVvTVFb3V7fglz+nC50fFusu3lY33h12pA==", "requires": { - "domelementtype": "^1.3.0", - "entities": "^1.1.1" + "domelementtype": "^2.0.1", + "domhandler": "^4.0.0", + "entities": "^2.0.0" } }, "domelementtype": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.1.tgz", - "integrity": "sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w==" + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.1.0.tgz", + "integrity": "sha512-LsTgx/L5VpD+Q8lmsXSHW2WpA+eBlZ9HPf3erD1IoPF00/3JKHZ3BknUVA2QGDNu69ZNmyFmCWBSO45XjYKC5w==" }, "domhandler": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-2.4.2.tgz", - "integrity": "sha512-JiK04h0Ht5u/80fdLMCEmV4zkNh2BcoMFBmZ/91WtYZ8qVXSKjiw7fXMgFPnHcSZgOo3XdinHvmnDUeMf5R4wA==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.0.0.tgz", + "integrity": "sha512-KPTbnGQ1JeEMQyO1iYXoagsI6so/C96HZiFyByU3T6iAzpXn8EGEvct6unm1ZGoed8ByO2oirxgwxBmqKF9haA==", "requires": { - "domelementtype": "1" + "domelementtype": "^2.1.0" } }, "domutils": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.5.1.tgz", - "integrity": "sha1-3NhIiib1Y9YQeeSMn3t+Mjc2gs8=", + "version": "2.4.4", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.4.4.tgz", + "integrity": "sha512-jBC0vOsECI4OMdD0GC9mGn7NXPLb+Qt6KW1YDQzeQYRUFKmNG8lh7mO5HiELfr+lLQE7loDVI4QcAxV80HS+RA==", "requires": { - "dom-serializer": "0", - "domelementtype": "1" + "dom-serializer": "^1.0.1", + "domelementtype": "^2.0.1", + "domhandler": "^4.0.0" } }, "dot-prop": { @@ -6088,9 +6104,9 @@ "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" }, "electron-to-chromium": { - "version": "1.3.628", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.628.tgz", - "integrity": "sha512-fmhO4YGo/kapy+xL9Eq/cZwDASaTHZu3psIFYo4yc+RY1LzbZr84xjKlDImDrlrmWhOxsrDi98nX097U/xK/cQ==" + "version": "1.3.632", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.632.tgz", + "integrity": "sha512-LkaEH9HHr9fodmm3txF4nFMyHN3Yr50HcpD/DBHpLCxzM9doV8AV0er6aBWva4IDs2aA9kGguces0rp+WKL7rg==" }, "elgato-stream-deck": { "version": "3.3.5", @@ -6249,9 +6265,9 @@ } }, "entities": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/entities/-/entities-1.1.2.tgz", - "integrity": "sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w==" + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.1.0.tgz", + "integrity": "sha512-hCx1oky9PFrJ611mf0ifBLBRW8lUUVRlFolb5gWRfIELabBlbp9xZvrqZLZAs+NxFnbfQoeGd8wDkygjg7U85w==" }, "env-paths": { "version": "2.2.0", @@ -8283,28 +8299,14 @@ "dev": true }, "htmlparser2": { - "version": "3.10.1", - "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.10.1.tgz", - "integrity": "sha512-IgieNijUMbkDovyoKObU1DUhm1iwNYE/fuifEoEHfd1oZKZDaONBSkal7Y01shxsM49R4XaMdGez3WnF9UfiCQ==", - "requires": { - "domelementtype": "^1.3.1", - "domhandler": "^2.3.0", - "domutils": "^1.5.1", - "entities": "^1.1.1", - "inherits": "^2.0.1", - "readable-stream": "^3.1.1" - }, - "dependencies": { - "readable-stream": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", - "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", - "requires": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - } - } + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-6.0.0.tgz", + "integrity": "sha512-numTQtDZMoh78zJpaNdJ9MXb2cv5G3jwUoe3dMQODubZvLoGvTE/Ofp6sHvH8OGKcN/8A47pGLi/k58xHP/Tfw==", + "requires": { + "domelementtype": "^2.0.1", + "domhandler": "^4.0.0", + "domutils": "^2.4.4", + "entities": "^2.0.0" } }, "http-cache-semantics": { @@ -10322,12 +10324,12 @@ "integrity": "sha512-V5QF9noGFl3EymEwUYzO+3NTDpGfQB4ve6Qfnzf3UNydMhjQRVPR1DZTuvWiLzaFJYw2fmDwAfnRNEVb64hSIg==" }, "node-telegram-bot-api": { - "version": "0.50.0", - "resolved": "https://registry.npmjs.org/node-telegram-bot-api/-/node-telegram-bot-api-0.50.0.tgz", - "integrity": "sha512-wPGJYb8RDsy2jOaWk51NWjJq+kcFLjJ3xMTYcfjkdK4b81i7d/ptjzsnmVsA31XeO1ZDDm8TwtqSr7CQkVfDVw==", + "version": "0.51.0", + "resolved": "https://registry.npmjs.org/node-telegram-bot-api/-/node-telegram-bot-api-0.51.0.tgz", + "integrity": "sha512-4SYAHBOhm8beNm/Sj6jo67GLbjMKLXejU/gjeIGsPMB9BAap4+ZT9viZkq1xC3t+0JeyQHOMudPp/vwpbK04qA==", "requires": { "array.prototype.findindex": "^2.0.2", - "bl": "^1.2.1", + "bl": "^1.2.3", "bluebird": "^3.5.1", "debug": "^3.1.0", "depd": "^1.1.1", @@ -10740,11 +10742,11 @@ } }, "nth-check": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-1.0.2.tgz", - "integrity": "sha512-WeBOdju8SnzPN5vTUJYxYUxLeXpCaVP5i5e0LF8fg7WORF2Wd7wFX/pk0tYZk7s8T+J7VLy0Da6J1+wCT0AtHg==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.0.0.tgz", + "integrity": "sha512-i4sc/Kj8htBrAiH1viZ0TgU8Y5XqCaV/FziYK6TBczxmeKm3AEFWqqF3195yKudrarqy7Zu80Ra5dobFjn9X/Q==", "requires": { - "boolbase": "~1.0.0" + "boolbase": "^1.0.0" } }, "number-is-nan": { @@ -11198,11 +11200,16 @@ } }, "parse5": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-3.0.3.tgz", - "integrity": "sha512-rgO9Zg5LLLkfJF9E6CCmXlSE4UVceloys8JrFqCcHloC3usd/kJCyPDwH2SOlzix2j3xaP9sUX3e8+kvkuleAA==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", + "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==" + }, + "parse5-htmlparser2-tree-adapter": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-6.0.1.tgz", + "integrity": "sha512-qPuWvbLgvDGilKc5BoicRovlT4MtYT6JfJyBOMDsKoiT+GiuP5qyrPCnR9HcPECIJJmZh5jRndyNThnhhb/vlA==", "requires": { - "@types/node": "*" + "parse5": "^6.0.1" } }, "parseqs": { @@ -12456,12 +12463,12 @@ } }, "serialport": { - "version": "9.0.3", - "resolved": "https://registry.npmjs.org/serialport/-/serialport-9.0.3.tgz", - "integrity": "sha512-1JjH9jtWZ5up2SQTeNPA4I3vhHCDYh1AjN3SybZYf5m9KF9tFVIOGLGIMncqnWKYx3ks/wqfCpmpYUHkFYC3wg==", + "version": "9.0.4", + "resolved": "https://registry.npmjs.org/serialport/-/serialport-9.0.4.tgz", + "integrity": "sha512-Wtl6sxciHKNdJKW8jUZm+f5KRXt0J0UP25ksM8N31l08KTdAhZ5MmKNUFpoO/YYG6TvHFOu+07PUX35m+TUw7g==", "requires": { "@serialport/binding-mock": "^9.0.2", - "@serialport/bindings": "^9.0.3", + "@serialport/bindings": "^9.0.4", "@serialport/parser-byte-length": "^9.0.1", "@serialport/parser-cctalk": "^9.0.1", "@serialport/parser-delimiter": "^9.0.1", @@ -14339,9 +14346,9 @@ "integrity": "sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==" }, "webpack": { - "version": "5.10.3", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.10.3.tgz", - "integrity": "sha512-KFPEbpNKfNU4t2CDsUZJ7KpuUbzDqGUCZqLmz4667KSUWMc9BuR3a8jpa72Emv7JUbdGwISD9OZjoI9S5BnHig==", + "version": "5.11.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.11.0.tgz", + "integrity": "sha512-ubWv7iP54RqAC/VjixgpnLLogCFbAfSOREcSWnnOlZEU8GICC5eKmJSu6YEnph2N2amKqY9rvxSwgyHxVqpaRw==", "requires": { "@types/eslint-scope": "^3.7.0", "@types/estree": "^0.0.45", @@ -14375,12 +14382,12 @@ "integrity": "sha512-XNP0PqF1XD19ZlLKvB7cMmnZswW4C/03pRHgirB30uSJTaS3A3V1/P4sS3HPvFmjoriPCJQs+JDSbm4bL1TxGQ==" }, "enhanced-resolve": { - "version": "5.4.0", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.4.0.tgz", - "integrity": "sha512-ZmqfWURB2lConOBM1JdCVfPyMRv5RdKWktLXO6123p97ovVm2CLBgw9t5MBj3jJWA6eHyOeIws9iJQoGFR4euQ==", + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.4.1.tgz", + "integrity": "sha512-4GbyIMzYktTFoRSmkbgZ1LU+RXwf4AQ8Z+rSuuh1dC8plp0PPeaWvx6+G4hh4KnUJ48VoxKbNyA1QQQIUpXjYA==", "requires": { "graceful-fs": "^4.2.4", - "tapable": "^2.0.0" + "tapable": "^2.2.0" } }, "find-up": {