diff --git a/README.md b/README.md index 8be1bae..6352de7 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,13 @@ -This is a mock NMOS device written in Typescript and running on the NodeJS stack. It has support for the NMOS Modeling suite (MS-05-02 and IS-12 in particular). +This is a mock NMOS device written in Typescript and running on the NodeJS stack. + +It has support for the NMOS Control & Monitoring suite: + +* MS-05-02 +* IS-12 +* BCP-008-01 It also has support for IS-04 and IS-05 with some limitations: @@ -54,5 +60,6 @@ These are the configuration keys which can be specified in the configuration fil * [MS-05-01 NMOS Control Architecture](https://specs.amwa.tv/ms-05-01) * [MS-05-02 NMOS Control Framework](https://specs.amwa.tv/ms-05-02) * [BCP-002-02 NMOS Asset Distinguishing Information](https://specs.amwa.tv/bcp-002-02) +* [BCP-008-01 NMOS Receiver Status](https://specs.amwa.tv/bcp-008-01/) diff --git a/code/package-lock.json b/code/package-lock.json index 5f78f04..be5dd1d 100644 --- a/code/package-lock.json +++ b/code/package-lock.json @@ -365,9 +365,9 @@ "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" }, "node_modules/axios": { - "version": "1.7.2", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.2.tgz", - "integrity": "sha512-2A8QhOMrbomlDuiLeK9XibIBzuHeRcqqNOHp0Cyp5EoJ1IFDh+XZH3A6BkXtv0K4gFGCI0Y4BM7B1wOEi0Rmgw==", + "version": "1.7.9", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.9.tgz", + "integrity": "sha512-LhLcE7Hbiryz8oMDdDptSrWowmB4Bl6RCt6sIJKpRB4XtVf0iEgewX3au/pJqm+Py1kCASkb/FFKjxQaLtxJvw==", "dependencies": { "follow-redirects": "^1.15.6", "form-data": "^4.0.0", @@ -392,9 +392,9 @@ } }, "node_modules/body-parser": { - "version": "1.20.2", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz", - "integrity": "sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==", + "version": "1.20.3", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz", + "integrity": "sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==", "dependencies": { "bytes": "3.1.2", "content-type": "~1.0.5", @@ -404,7 +404,7 @@ "http-errors": "2.0.0", "iconv-lite": "0.4.24", "on-finished": "2.4.1", - "qs": "6.11.0", + "qs": "6.13.0", "raw-body": "2.5.2", "type-is": "~1.6.18", "unpipe": "1.0.0" @@ -444,15 +444,41 @@ } }, "node_modules/call-bind": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", - "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.8.tgz", + "integrity": "sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==", "dependencies": { + "call-bind-apply-helpers": "^1.0.0", "es-define-property": "^1.0.0", - "es-errors": "^1.3.0", - "function-bind": "^1.1.2", "get-intrinsic": "^1.2.4", - "set-function-length": "^1.2.1" + "set-function-length": "^1.2.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.1.tgz", + "integrity": "sha512-BhYE+WDaywFg2TBWYNXAE+8B1ATnThNBqXHP5nQu0jWJdVvY2hvkpyB3qOmtmDePiS5/BDQ8wASEWGMWRG148g==", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/call-bound": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.2.tgz", + "integrity": "sha512-0lk0PHFe/uz0vl527fG9CgdE9WdafjDbCXvBbs+LUv000TVt2Jjhqbs4Jwm8gz070w8xXyEAxrPOMullsxXeGg==", + "dependencies": { + "call-bind": "^1.0.8", + "get-intrinsic": "^1.2.5" }, "engines": { "node": ">= 0.4" @@ -608,9 +634,9 @@ } }, "node_modules/cookie": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", - "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==", + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.1.tgz", + "integrity": "sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==", "engines": { "node": ">= 0.6" } @@ -621,9 +647,9 @@ "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==" }, "node_modules/cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", "dev": true, "dependencies": { "path-key": "^3.1.0", @@ -699,6 +725,19 @@ "npm": "1.2.8000 || >= 1.4.16" } }, + "node_modules/dunder-proto": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.0.tgz", + "integrity": "sha512-9+Sj30DIu+4KvHqMfLUGLFYL2PkURSYMVXJyXe92nFRvlYq5hBjLEhblKB+vkd/WVlUYMWigiY07T91Fkk0+4A==", + "dependencies": { + "call-bind-apply-helpers": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/eastasianwidth": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", @@ -717,20 +756,17 @@ "dev": true }, "node_modules/encodeurl": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", "engines": { "node": ">= 0.8" } }, "node_modules/es-define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", - "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", - "dependencies": { - "get-intrinsic": "^1.2.4" - }, + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", "engines": { "node": ">= 0.4" } @@ -743,6 +779,17 @@ "node": ">= 0.4" } }, + "node_modules/es-object-atoms": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.0.0.tgz", + "integrity": "sha512-MZ4iQ6JwHOBQjahnjwaC1ZtIBH+2ohjamzAO3oaHcXYup7qxjF2fixyH+Q71voWHeOkI2q/TnJao/KfXYIZWbw==", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/escalade": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz", @@ -766,36 +813,36 @@ } }, "node_modules/express": { - "version": "4.19.2", - "resolved": "https://registry.npmjs.org/express/-/express-4.19.2.tgz", - "integrity": "sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q==", + "version": "4.21.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.21.2.tgz", + "integrity": "sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==", "dependencies": { "accepts": "~1.3.8", "array-flatten": "1.1.1", - "body-parser": "1.20.2", + "body-parser": "1.20.3", "content-disposition": "0.5.4", "content-type": "~1.0.4", - "cookie": "0.6.0", + "cookie": "0.7.1", "cookie-signature": "1.0.6", "debug": "2.6.9", "depd": "2.0.0", - "encodeurl": "~1.0.2", + "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "etag": "~1.8.1", - "finalhandler": "1.2.0", + "finalhandler": "1.3.1", "fresh": "0.5.2", "http-errors": "2.0.0", - "merge-descriptors": "1.0.1", + "merge-descriptors": "1.0.3", "methods": "~1.1.2", "on-finished": "2.4.1", "parseurl": "~1.3.3", - "path-to-regexp": "0.1.7", + "path-to-regexp": "0.1.12", "proxy-addr": "~2.0.7", - "qs": "6.11.0", + "qs": "6.13.0", "range-parser": "~1.2.1", "safe-buffer": "5.2.1", - "send": "0.18.0", - "serve-static": "1.15.0", + "send": "0.19.0", + "serve-static": "1.16.2", "setprototypeof": "1.2.0", "statuses": "2.0.1", "type-is": "~1.6.18", @@ -804,6 +851,10 @@ }, "engines": { "node": ">= 0.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/fill-range": { @@ -819,12 +870,12 @@ } }, "node_modules/finalhandler": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", - "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.1.tgz", + "integrity": "sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==", "dependencies": { "debug": "2.6.9", - "encodeurl": "~1.0.2", + "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "on-finished": "2.4.1", "parseurl": "~1.3.3", @@ -936,15 +987,20 @@ } }, "node_modules/get-intrinsic": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", - "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.6.tgz", + "integrity": "sha512-qxsEs+9A+u85HhllWJJFicJfPDhRmjzoYdl64aMWW9yRIJmSyxdn8IEkuIM530/7T+lv0TIHd8L6Q/ra0tEoeA==", "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "dunder-proto": "^1.0.0", + "es-define-property": "^1.0.1", "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", "function-bind": "^1.1.2", - "has-proto": "^1.0.1", - "has-symbols": "^1.0.3", - "hasown": "^2.0.0" + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.0.0" }, "engines": { "node": ">= 0.4" @@ -986,11 +1042,11 @@ } }, "node_modules/gopd": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", - "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", - "dependencies": { - "get-intrinsic": "^1.1.3" + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -1016,21 +1072,10 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/has-proto": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz", - "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/has-symbols": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", - "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", "engines": { "node": ">= 0.4" }, @@ -1245,6 +1290,14 @@ "node": "14 || >=16.14" } }, + "node_modules/math-intrinsics": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.0.0.tgz", + "integrity": "sha512-4MqMiKP90ybymYvsut0CH2g4XWbfLtmlCkXmtmdcDCxNB+mQcu1w/1+L/VD7vi/PSv7X2JYV7SCcR+jiPXnQtA==", + "engines": { + "node": ">= 0.4" + } + }, "node_modules/media-typer": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", @@ -1254,9 +1307,12 @@ } }, "node_modules/merge-descriptors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", - "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==" + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz", + "integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==", + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } }, "node_modules/methods": { "version": "1.1.2", @@ -1419,9 +1475,12 @@ } }, "node_modules/object-inspect": { - "version": "1.13.1", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz", - "integrity": "sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==", + "version": "1.13.3", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.3.tgz", + "integrity": "sha512-kDCGIbxkDSXE3euJZZXzc6to7fCrKHNI/hSRQnRuQ+BWjFNzZwiFF8fj/6o2t2G9/jTj8PSIYTfCLelLZEeRpA==", + "engines": { + "node": ">= 0.4" + }, "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -1492,9 +1551,9 @@ } }, "node_modules/path-to-regexp": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", - "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==" + "version": "0.1.12", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.12.tgz", + "integrity": "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==" }, "node_modules/picomatch": { "version": "2.3.1", @@ -1532,11 +1591,11 @@ "dev": true }, "node_modules/qs": { - "version": "6.11.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", - "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz", + "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==", "dependencies": { - "side-channel": "^1.0.4" + "side-channel": "^1.0.6" }, "engines": { "node": ">=0.6" @@ -1743,9 +1802,9 @@ } }, "node_modules/send": { - "version": "0.18.0", - "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", - "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", + "version": "0.19.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz", + "integrity": "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==", "dependencies": { "debug": "2.6.9", "depd": "2.0.0", @@ -1765,20 +1824,28 @@ "node": ">= 0.8.0" } }, + "node_modules/send/node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "engines": { + "node": ">= 0.8" + } + }, "node_modules/send/node_modules/ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" }, "node_modules/serve-static": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", - "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", + "version": "1.16.2", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.2.tgz", + "integrity": "sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==", "dependencies": { - "encodeurl": "~1.0.2", + "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "parseurl": "~1.3.3", - "send": "0.18.0" + "send": "0.19.0" }, "engines": { "node": ">= 0.8.0" @@ -1867,14 +1934,65 @@ } }, "node_modules/side-channel": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz", - "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", + "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", "dependencies": { - "call-bind": "^1.0.7", "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.4", - "object-inspect": "^1.13.1" + "object-inspect": "^1.13.3", + "side-channel-list": "^1.0.0", + "side-channel-map": "^1.0.1", + "side-channel-weakmap": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-list": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz", + "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-map": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", + "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-weakmap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", + "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3", + "side-channel-map": "^1.0.1" }, "engines": { "node": ">= 0.4" @@ -2225,9 +2343,9 @@ } }, "node_modules/ws": { - "version": "8.17.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.17.0.tgz", - "integrity": "sha512-uJq6108EgZMAl20KagGkzCKfMEjxmKvZHG7Tlq0Z6nOky7YF7aq4mOx6xK8TJ/i1LeK4Qus7INktacctDgY8Ow==", + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz", + "integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==", "engines": { "node": ">=10.0.0" }, @@ -2562,9 +2680,9 @@ "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" }, "axios": { - "version": "1.7.2", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.2.tgz", - "integrity": "sha512-2A8QhOMrbomlDuiLeK9XibIBzuHeRcqqNOHp0Cyp5EoJ1IFDh+XZH3A6BkXtv0K4gFGCI0Y4BM7B1wOEi0Rmgw==", + "version": "1.7.9", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.9.tgz", + "integrity": "sha512-LhLcE7Hbiryz8oMDdDptSrWowmB4Bl6RCt6sIJKpRB4XtVf0iEgewX3au/pJqm+Py1kCASkb/FFKjxQaLtxJvw==", "requires": { "follow-redirects": "^1.15.6", "form-data": "^4.0.0", @@ -2583,9 +2701,9 @@ "dev": true }, "body-parser": { - "version": "1.20.2", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz", - "integrity": "sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==", + "version": "1.20.3", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz", + "integrity": "sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==", "requires": { "bytes": "3.1.2", "content-type": "~1.0.5", @@ -2595,7 +2713,7 @@ "http-errors": "2.0.0", "iconv-lite": "0.4.24", "on-finished": "2.4.1", - "qs": "6.11.0", + "qs": "6.13.0", "raw-body": "2.5.2", "type-is": "~1.6.18", "unpipe": "1.0.0" @@ -2625,15 +2743,32 @@ "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==" }, "call-bind": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", - "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.8.tgz", + "integrity": "sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==", "requires": { + "call-bind-apply-helpers": "^1.0.0", "es-define-property": "^1.0.0", - "es-errors": "^1.3.0", - "function-bind": "^1.1.2", "get-intrinsic": "^1.2.4", - "set-function-length": "^1.2.1" + "set-function-length": "^1.2.2" + } + }, + "call-bind-apply-helpers": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.1.tgz", + "integrity": "sha512-BhYE+WDaywFg2TBWYNXAE+8B1ATnThNBqXHP5nQu0jWJdVvY2hvkpyB3qOmtmDePiS5/BDQ8wASEWGMWRG148g==", + "requires": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + } + }, + "call-bound": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.2.tgz", + "integrity": "sha512-0lk0PHFe/uz0vl527fG9CgdE9WdafjDbCXvBbs+LUv000TVt2Jjhqbs4Jwm8gz070w8xXyEAxrPOMullsxXeGg==", + "requires": { + "call-bind": "^1.0.8", + "get-intrinsic": "^1.2.5" } }, "chalk": { @@ -2743,9 +2878,9 @@ "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==" }, "cookie": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", - "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==" + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.1.tgz", + "integrity": "sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==" }, "cookie-signature": { "version": "1.0.6", @@ -2753,9 +2888,9 @@ "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==" }, "cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", "dev": true, "requires": { "path-key": "^3.1.0", @@ -2805,6 +2940,16 @@ "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==" }, + "dunder-proto": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.0.tgz", + "integrity": "sha512-9+Sj30DIu+4KvHqMfLUGLFYL2PkURSYMVXJyXe92nFRvlYq5hBjLEhblKB+vkd/WVlUYMWigiY07T91Fkk0+4A==", + "requires": { + "call-bind-apply-helpers": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + } + }, "eastasianwidth": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", @@ -2823,23 +2968,28 @@ "dev": true }, "encodeurl": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==" + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==" }, "es-define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", - "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", - "requires": { - "get-intrinsic": "^1.2.4" - } + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==" }, "es-errors": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==" }, + "es-object-atoms": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.0.0.tgz", + "integrity": "sha512-MZ4iQ6JwHOBQjahnjwaC1ZtIBH+2ohjamzAO3oaHcXYup7qxjF2fixyH+Q71voWHeOkI2q/TnJao/KfXYIZWbw==", + "requires": { + "es-errors": "^1.3.0" + } + }, "escalade": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz", @@ -2857,36 +3007,36 @@ "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==" }, "express": { - "version": "4.19.2", - "resolved": "https://registry.npmjs.org/express/-/express-4.19.2.tgz", - "integrity": "sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q==", + "version": "4.21.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.21.2.tgz", + "integrity": "sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==", "requires": { "accepts": "~1.3.8", "array-flatten": "1.1.1", - "body-parser": "1.20.2", + "body-parser": "1.20.3", "content-disposition": "0.5.4", "content-type": "~1.0.4", - "cookie": "0.6.0", + "cookie": "0.7.1", "cookie-signature": "1.0.6", "debug": "2.6.9", "depd": "2.0.0", - "encodeurl": "~1.0.2", + "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "etag": "~1.8.1", - "finalhandler": "1.2.0", + "finalhandler": "1.3.1", "fresh": "0.5.2", "http-errors": "2.0.0", - "merge-descriptors": "1.0.1", + "merge-descriptors": "1.0.3", "methods": "~1.1.2", "on-finished": "2.4.1", "parseurl": "~1.3.3", - "path-to-regexp": "0.1.7", + "path-to-regexp": "0.1.12", "proxy-addr": "~2.0.7", - "qs": "6.11.0", + "qs": "6.13.0", "range-parser": "~1.2.1", "safe-buffer": "5.2.1", - "send": "0.18.0", - "serve-static": "1.15.0", + "send": "0.19.0", + "serve-static": "1.16.2", "setprototypeof": "1.2.0", "statuses": "2.0.1", "type-is": "~1.6.18", @@ -2904,12 +3054,12 @@ } }, "finalhandler": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", - "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.1.tgz", + "integrity": "sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==", "requires": { "debug": "2.6.9", - "encodeurl": "~1.0.2", + "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "on-finished": "2.4.1", "parseurl": "~1.3.3", @@ -2976,15 +3126,20 @@ "dev": true }, "get-intrinsic": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", - "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.6.tgz", + "integrity": "sha512-qxsEs+9A+u85HhllWJJFicJfPDhRmjzoYdl64aMWW9yRIJmSyxdn8IEkuIM530/7T+lv0TIHd8L6Q/ra0tEoeA==", "requires": { + "call-bind-apply-helpers": "^1.0.1", + "dunder-proto": "^1.0.0", + "es-define-property": "^1.0.1", "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", "function-bind": "^1.1.2", - "has-proto": "^1.0.1", - "has-symbols": "^1.0.3", - "hasown": "^2.0.0" + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.0.0" } }, "glob": { @@ -3010,12 +3165,9 @@ } }, "gopd": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", - "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", - "requires": { - "get-intrinsic": "^1.1.3" - } + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==" }, "has-flag": { "version": "4.0.0", @@ -3031,15 +3183,10 @@ "es-define-property": "^1.0.0" } }, - "has-proto": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz", - "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==" - }, "has-symbols": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", - "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==" + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==" }, "hasown": { "version": "2.0.2", @@ -3200,15 +3347,20 @@ "integrity": "sha512-9hp3Vp2/hFQUiIwKo8XCeFVnrg8Pk3TYNPIR7tJADKi5YfcF7vEaK7avFHTlSy3kOKYaJQaalfEo6YuXdceBOQ==", "dev": true }, + "math-intrinsics": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.0.0.tgz", + "integrity": "sha512-4MqMiKP90ybymYvsut0CH2g4XWbfLtmlCkXmtmdcDCxNB+mQcu1w/1+L/VD7vi/PSv7X2JYV7SCcR+jiPXnQtA==" + }, "media-typer": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==" }, "merge-descriptors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", - "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==" + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz", + "integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==" }, "methods": { "version": "1.1.2", @@ -3319,9 +3471,9 @@ "dev": true }, "object-inspect": { - "version": "1.13.1", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz", - "integrity": "sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==" + "version": "1.13.3", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.3.tgz", + "integrity": "sha512-kDCGIbxkDSXE3euJZZXzc6to7fCrKHNI/hSRQnRuQ+BWjFNzZwiFF8fj/6o2t2G9/jTj8PSIYTfCLelLZEeRpA==" }, "on-finished": { "version": "2.4.1", @@ -3371,9 +3523,9 @@ } }, "path-to-regexp": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", - "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==" + "version": "0.1.12", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.12.tgz", + "integrity": "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==" }, "picomatch": { "version": "2.3.1", @@ -3402,11 +3554,11 @@ "dev": true }, "qs": { - "version": "6.11.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", - "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz", + "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==", "requires": { - "side-channel": "^1.0.4" + "side-channel": "^1.0.6" } }, "range-parser": { @@ -3541,9 +3693,9 @@ "dev": true }, "send": { - "version": "0.18.0", - "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", - "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", + "version": "0.19.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz", + "integrity": "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==", "requires": { "debug": "2.6.9", "depd": "2.0.0", @@ -3560,6 +3712,11 @@ "statuses": "2.0.1" }, "dependencies": { + "encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==" + }, "ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", @@ -3568,14 +3725,14 @@ } }, "serve-static": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", - "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", + "version": "1.16.2", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.2.tgz", + "integrity": "sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==", "requires": { - "encodeurl": "~1.0.2", + "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "parseurl": "~1.3.3", - "send": "0.18.0" + "send": "0.19.0" } }, "set-function-length": { @@ -3637,14 +3794,47 @@ } }, "side-channel": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz", - "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", + "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", "requires": { - "call-bind": "^1.0.7", "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.4", - "object-inspect": "^1.13.1" + "object-inspect": "^1.13.3", + "side-channel-list": "^1.0.0", + "side-channel-map": "^1.0.1", + "side-channel-weakmap": "^1.0.2" + } + }, + "side-channel-list": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz", + "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==", + "requires": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3" + } + }, + "side-channel-map": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", + "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", + "requires": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3" + } + }, + "side-channel-weakmap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", + "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", + "requires": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3", + "side-channel-map": "^1.0.1" } }, "signal-exit": { @@ -3884,9 +4074,9 @@ } }, "ws": { - "version": "8.17.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.17.0.tgz", - "integrity": "sha512-uJq6108EgZMAl20KagGkzCKfMEjxmKvZHG7Tlq0Z6nOky7YF7aq4mOx6xK8TJ/i1LeK4Qus7INktacctDgY8Ow==", + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz", + "integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==", "requires": {} }, "y18n": { diff --git a/code/src/NCModel/Features.ts b/code/src/NCModel/Features.ts index 5617271..304dd9b 100644 --- a/code/src/NCModel/Features.ts +++ b/code/src/NCModel/Features.ts @@ -11,6 +11,7 @@ import { NcElementId, NcFieldDescriptor, NcMethodDescriptor, + NcMethodResult, NcMethodStatus, NcObject, NcParameterConstraintsNumber, @@ -206,7 +207,7 @@ export class GainControl extends NcWorker export class NcIdentBeacon extends NcWorker { - public static staticClassID: number[] = [ 1, 2, 2 ]; + public static staticClassID: number[] = [ 1, 2, 1 ]; @myIdDecorator('1p1') public override classID: number[] = NcIdentBeacon.staticClassID; @@ -296,69 +297,29 @@ export class NcIdentBeacon extends NcWorker } } -enum NcConnectionStatus +enum NcOverallStatus { - Undefined = 0, - Connected = 1, - Disconnected = 2, - ConnectionError = 3 -} - -enum NcPayloadStatus -{ - Undefined = 0, - PayloadOK = 1, - PayloadFormatUnsupported = 2, - PayloadError = 3 -} - -export class NcReceiverStatus extends BaseType -{ - public connectionStatus: NcConnectionStatus; - public payloadStatus: NcPayloadStatus; - - constructor( - connectionStatus: NcConnectionStatus, - payloadStatus: NcPayloadStatus) - { - super(); - - this.connectionStatus = connectionStatus; - this.payloadStatus = payloadStatus; - } - - public static override GetTypeDescriptor(includeInherited: boolean): NcDatatypeDescriptor - { - return new NcDatatypeDescriptorStruct("NcReceiverStatus", [ - new NcFieldDescriptor("connectionStatus", "NcConnectionStatus", false, false, null, "Receiver connection status field"), - new NcFieldDescriptor("payloadStatus", "NcPayloadStatus", false, false, null, "Receiver payload status field") - ], null, null, "Receiver status data type"); - } - - public ToJson() - { - return JSON.stringify(this, jsonIgnoreReplacer); - } + Inactive = 0, + Healthy = 1, + PartiallyHealthy = 2, + Unhealthy = 3 } -export class NcReceiverMonitor extends NcWorker +export class NcStatusMonitor extends NcWorker { - public static staticClassID: number[] = [ 1, 2, 3 ]; + public static staticClassID: number[] = [ 1, 2, 2 ]; @myIdDecorator('1p1') - public override classID: number[] = NcReceiverMonitor.staticClassID; + public override classID: number[] = NcStatusMonitor.staticClassID; @myIdDecorator('3p1') - public connectionStatus: NcConnectionStatus; + public overallStatus: NcOverallStatus; @myIdDecorator('3p2') - public connectionStatusMessage: string | null; + public overallStatusMessage: string | null; @myIdDecorator('3p3') - public payloadStatus: NcPayloadStatus; - - @myIdDecorator('3p4') - public payloadStatusMessage: string | null; + public statusReportingDelay: number; public constructor( oid: number, @@ -374,35 +335,9 @@ export class NcReceiverMonitor extends NcWorker { super(oid, constantOid, ownerObject, role, userLabel, touchpoints, runtimePropertyConstraints, enabled, description, notificationContext); - this.connectionStatus = NcConnectionStatus.Undefined; - this.connectionStatusMessage = null; - - this.payloadStatus = NcPayloadStatus.Undefined; - this.payloadStatusMessage = null; - } - - public Connected() - { - this.connectionStatus = NcConnectionStatus.Connected; - this.payloadStatus = NcPayloadStatus.PayloadOK; - - this.connectionStatusMessage = null; - this.payloadStatusMessage = null; - - this.notificationContext.NotifyPropertyChanged(this.oid, new NcElementId(3, 1), NcPropertyChangeType.ValueChanged, this.connectionStatus, null); - this.notificationContext.NotifyPropertyChanged(this.oid, new NcElementId(3, 3), NcPropertyChangeType.ValueChanged, this.payloadStatus, null); - } - - public Disconnected() - { - this.connectionStatus = NcConnectionStatus.Undefined; - this.payloadStatus = NcPayloadStatus.Undefined; - - this.connectionStatusMessage = null; - this.payloadStatusMessage = null; - - this.notificationContext.NotifyPropertyChanged(this.oid, new NcElementId(3, 1), NcPropertyChangeType.ValueChanged, this.connectionStatus, null); - this.notificationContext.NotifyPropertyChanged(this.oid, new NcElementId(3, 3), NcPropertyChangeType.ValueChanged, this.payloadStatus, null); + this.overallStatus = NcOverallStatus.Inactive; + this.overallStatusMessage = "Receiver is inactive"; + this.statusReportingDelay = 3; } //'1m1' @@ -415,13 +350,11 @@ export class NcReceiverMonitor extends NcWorker switch(key) { case '3p1': - return new CommandResponseWithValue(handle, NcMethodStatus.OK, this.connectionStatus); + return new CommandResponseWithValue(handle, NcMethodStatus.OK, this.overallStatus); case '3p2': - return new CommandResponseWithValue(handle, NcMethodStatus.OK, this.connectionStatusMessage); + return new CommandResponseWithValue(handle, NcMethodStatus.OK, this.overallStatusMessage); case '3p3': - return new CommandResponseWithValue(handle, NcMethodStatus.OK, this.payloadStatus); - case '3p4': - return new CommandResponseWithValue(handle, NcMethodStatus.OK, this.payloadStatusMessage); + return new CommandResponseWithValue(handle, NcMethodStatus.OK, this.statusReportingDelay); default: return super.Get(oid, id, handle); } @@ -441,9 +374,11 @@ export class NcReceiverMonitor extends NcWorker { case '3p1': case '3p2': - case '3p3': - case '3p4': return new CommandResponseError(handle, NcMethodStatus.Readonly, 'Property is readonly'); + case '3p3': + this.statusReportingDelay = value; + this.notificationContext.NotifyPropertyChanged(this.oid, id, NcPropertyChangeType.ValueChanged, this.statusReportingDelay, null); + return new CommandResponseNoValue(handle, NcMethodStatus.OK); default: return super.Set(oid, id, value, handle); } @@ -457,10 +392,9 @@ export class NcReceiverMonitor extends NcWorker let currentClassDescriptor = new NcClassDescriptor(`${NcReceiverMonitor.name} class descriptor`, NcReceiverMonitor.staticClassID, NcReceiverMonitor.name, null, [ - new NcPropertyDescriptor(new NcElementId(3, 1), "connectionStatus", "NcConnectionStatus", true, false, false, null, "Connection status property"), - new NcPropertyDescriptor(new NcElementId(3, 2), "connectionStatusMessage", "NcString", true, true, false, null, "Connection status message property"), - new NcPropertyDescriptor(new NcElementId(3, 3), "payloadStatus", "NcPayloadStatus", true, false, false, null, "Payload status property"), - new NcPropertyDescriptor(new NcElementId(3, 4), "payloadStatusMessage", "NcString", true, true, false, null, "Payload status message property") + new NcPropertyDescriptor(new NcElementId(3, 1), "overallStatus", "NcOverallStatus", true, false, false, null, "Overall status property"), + new NcPropertyDescriptor(new NcElementId(3, 2), "overallStatusMessage", "NcString", true, true, false, null, "Overall status message property"), + new NcPropertyDescriptor(new NcElementId(3, 3), "statusReportingDelay", "NcUint32", false, false, false, null, "Status reporting delay property (in seconds, default is 3s and 0 means no delay)"), ], [], [] @@ -479,15 +413,159 @@ export class NcReceiverMonitor extends NcWorker } } -export class NcReceiverMonitorProtected extends NcReceiverMonitor +enum NcLinkStatus +{ + AllUp = 1, + SomeDown = 2, + AllDown = 3 +} + +enum NcConnectionStatus +{ + Inactive = 0, + Healthy = 1, + PartiallyHealthy = 2, + Unhealthy = 3 +} + +enum NcSynchronizationStatus +{ + NotUsed = 0, + Healthy = 1, + PartiallyHealthy = 2, + Unhealthy = 3 +} + +enum NcStreamStatus +{ + Inactive = 0, + Healthy = 1, + PartiallyHealthy = 2, + Unhealthy = 3 +} + +function DelayTask(timeMs: number | undefined) +{ + return new Promise(resolve => setTimeout(resolve, timeMs)); +} + +export class NcCounter extends BaseType +{ + public name: string; + public value: number; + public description: string | null; + + constructor( + name: string, + value: number, + description: string | null) + { + super(); + + this.name = name; + this.value = value; + this.description = description; + } + + public static override GetTypeDescriptor(includeInherited: boolean): NcDatatypeDescriptor + { + return new NcDatatypeDescriptorStruct("NcElementId", [ + new NcFieldDescriptor("name", "NcString", false, false, null, "Counter name"), + new NcFieldDescriptor("value", "NcUint64", false, false, null, "Counter value"), + new NcFieldDescriptor("description", "NcString", true, false, null, "Optional counter description") + ], null, null, "Counter data type"); + } + + public Increment() + { + this.value++; + } + + public Reset() + { + this.value = 0; + } + + public ToJson() + { + return JSON.stringify(this, jsonIgnoreReplacer); + } +} + +export class NcMethodResultCounters extends NcMethodResult +{ + public value: NcCounter[]; + + public constructor( + status: NcMethodStatus, + value: NcCounter[]) + { + super(status); + + this.value = value; + } + + public static override GetTypeDescriptor(includeInherited: boolean): NcDatatypeDescriptor + { + let currentClassDescriptor = new NcDatatypeDescriptorStruct("NcMethodResultCounters", [ + new NcFieldDescriptor("value", "NcCounter", false, true, null, "Counters") + ], "NcMethodResult", null, "Counters method result") + + if(includeInherited) + { + let baseDescriptor = super.GetTypeDescriptor(includeInherited); + + let baseDescriptorStruct = baseDescriptor as NcDatatypeDescriptorStruct; + if(baseDescriptorStruct) + currentClassDescriptor.fields = currentClassDescriptor.fields.concat(baseDescriptorStruct.fields); + } + + return currentClassDescriptor; + } +} + +export class NcReceiverMonitor extends NcStatusMonitor { - public static staticClassID: number[] = [ 1, 2, 3, 1 ]; + public static staticClassID: number[] = [ 1, 2, 2, 1 ]; @myIdDecorator('1p1') - public override classID: number[] = NcReceiverMonitorProtected.staticClassID; + public override classID: number[] = NcReceiverMonitor.staticClassID; @myIdDecorator('4p1') - public signalProtectionStatus: boolean; + public linkStatus: NcLinkStatus; + + @myIdDecorator('4p2') + public linkStatusMessage: string | null; + + @myIdDecorator('4p3') + public connectionStatus: NcConnectionStatus; + + @myIdDecorator('4p4') + public connectionStatusMessage: string | null; + + @myIdDecorator('4p5') + public externalSynchronizationStatus: NcSynchronizationStatus; + + @myIdDecorator('4p6') + public externalSynchronizationStatusMessage: string | null; + + @myIdDecorator('4p7') + public synchronizationSourceId: string | null; + + @myIdDecorator('4p8') + public synchronizationSourceChanges: number; + + @myIdDecorator('4p9') + public streamStatus: NcStreamStatus; + + @myIdDecorator('4p10') + public streamStatusMessage: string | null; + + @myIdDecorator('4p11') + public autoResetPacketCounters: boolean; + + private lostPacketCounters: NcCounter[]; + private latePacketCounters: NcCounter[]; public constructor( oid: number, @@ -503,37 +581,139 @@ export class NcReceiverMonitorProtected extends NcReceiverMonitor { super(oid, constantOid, ownerObject, role, userLabel, touchpoints, runtimePropertyConstraints, enabled, description, notificationContext); - this.connectionStatus = NcConnectionStatus.Undefined; - this.connectionStatusMessage = null; + this.linkStatus = NcLinkStatus.AllUp; + this.linkStatusMessage = "All interfaces are up"; + + this.connectionStatus = NcConnectionStatus.Inactive; + this.connectionStatusMessage = "Receiver is inactive"; + + this.lostPacketCounters = [ + new NcCounter("Nic_1", 0, "Lost packets on Nic 1"), + new NcCounter("Nic_2", 0, "Lost packets on Nic 2"), + ]; + + this.latePacketCounters = [ + new NcCounter("Nic_1", 0, "Late packets on Nic 1"), + new NcCounter("Nic_2", 0, "Late packets on Nic 2"), + ]; - this.payloadStatus = NcPayloadStatus.Undefined; - this.payloadStatusMessage = null; + this.externalSynchronizationStatus = NcSynchronizationStatus.Healthy; + this.externalSynchronizationStatusMessage = "Locked to grandmaster"; + this.synchronizationSourceId = "0xD4:AD:71:FF:FE:6F:E2:80"; + this.synchronizationSourceChanges = 0; - this.signalProtectionStatus = false; + this.streamStatus = NcStreamStatus.Inactive; + this.streamStatusMessage = "Receiver is inactive"; + + this.autoResetPacketCounters = true; } public Connected() { - this.connectionStatus = NcConnectionStatus.Connected; - this.payloadStatus = NcPayloadStatus.PayloadOK; + this.overallStatus = NcOverallStatus.Healthy; + this.overallStatusMessage = "Receiver is connected and healthy"; + + this.connectionStatus = NcConnectionStatus.Healthy; + this.connectionStatusMessage = "Receiver is connected and connection is healthy"; + + this.streamStatus = NcStreamStatus.Healthy; + this.streamStatusMessage = "Receiver is connected and stream is healthy"; + + if(this.autoResetPacketCounters) + { + this.lostPacketCounters.forEach(counter => { + counter.Reset(); + }); + + this.latePacketCounters.forEach(counter => { + counter.Reset(); + }); + } + + this.notificationContext.NotifyPropertyChanged(this.oid, new NcElementId(3, 1), NcPropertyChangeType.ValueChanged, this.overallStatus, null); + this.notificationContext.NotifyPropertyChanged(this.oid, new NcElementId(3, 2), NcPropertyChangeType.ValueChanged, this.overallStatusMessage, null); + + this.notificationContext.NotifyPropertyChanged(this.oid, new NcElementId(4, 3), NcPropertyChangeType.ValueChanged, this.connectionStatus, null); + this.notificationContext.NotifyPropertyChanged(this.oid, new NcElementId(4, 4), NcPropertyChangeType.ValueChanged, this.connectionStatusMessage, null); - this.connectionStatusMessage = null; - this.payloadStatusMessage = null; + this.notificationContext.NotifyPropertyChanged(this.oid, new NcElementId(4, 9), NcPropertyChangeType.ValueChanged, this.streamStatus, null); + this.notificationContext.NotifyPropertyChanged(this.oid, new NcElementId(4, 10), NcPropertyChangeType.ValueChanged, this.streamStatusMessage, null); - this.notificationContext.NotifyPropertyChanged(this.oid, new NcElementId(3, 1), NcPropertyChangeType.ValueChanged, this.connectionStatus, null); - this.notificationContext.NotifyPropertyChanged(this.oid, new NcElementId(3, 3), NcPropertyChangeType.ValueChanged, this.payloadStatus, null); + DelayTask(1000 * this.statusReportingDelay).then(() => this.StreamBroken()); + } + + public StreamBroken() + { + if(this.overallStatus != NcOverallStatus.Inactive) + { + this.overallStatus = NcOverallStatus.Unhealthy; + this.overallStatusMessage = "Receiver connectivity is experiencing severe issues"; + + this.connectionStatus = NcConnectionStatus.Unhealthy; + this.connectionStatusMessage = "Significant packet loss detected"; + + this.streamStatus = NcStreamStatus.Unhealthy; + this.streamStatusMessage = "Stream cannot be decoded"; + + this.lostPacketCounters.find(c => c.name === 'Nic_1')?.Increment(); + this.latePacketCounters.find(c => c.name === 'Nic_2')?.Increment(); + + this.notificationContext.NotifyPropertyChanged(this.oid, new NcElementId(3, 1), NcPropertyChangeType.ValueChanged, this.overallStatus, null); + this.notificationContext.NotifyPropertyChanged(this.oid, new NcElementId(3, 2), NcPropertyChangeType.ValueChanged, this.overallStatusMessage, null); + + this.notificationContext.NotifyPropertyChanged(this.oid, new NcElementId(4, 3), NcPropertyChangeType.ValueChanged, this.connectionStatus, null); + this.notificationContext.NotifyPropertyChanged(this.oid, new NcElementId(4, 4), NcPropertyChangeType.ValueChanged, this.connectionStatusMessage, null); + + this.notificationContext.NotifyPropertyChanged(this.oid, new NcElementId(4, 9), NcPropertyChangeType.ValueChanged, this.streamStatus, null); + this.notificationContext.NotifyPropertyChanged(this.oid, new NcElementId(4, 10), NcPropertyChangeType.ValueChanged, this.streamStatusMessage, null); + + DelayTask(1000 * this.statusReportingDelay).then(() => this.StreamFixed()); + } + } + + public StreamFixed() + { + if(this.overallStatus != NcOverallStatus.Inactive) + { + this.overallStatus = NcOverallStatus.Healthy; + this.overallStatusMessage = "Receiver is connected and healthy"; + + this.connectionStatus = NcConnectionStatus.Healthy; + this.connectionStatusMessage = "Receiver is connected and connection is healthy"; + + this.streamStatus = NcStreamStatus.Healthy; + this.streamStatusMessage = "Receiver is connected and stream is healthy"; + + this.notificationContext.NotifyPropertyChanged(this.oid, new NcElementId(3, 1), NcPropertyChangeType.ValueChanged, this.overallStatus, null); + this.notificationContext.NotifyPropertyChanged(this.oid, new NcElementId(3, 2), NcPropertyChangeType.ValueChanged, this.overallStatusMessage, null); + + this.notificationContext.NotifyPropertyChanged(this.oid, new NcElementId(4, 3), NcPropertyChangeType.ValueChanged, this.connectionStatus, null); + this.notificationContext.NotifyPropertyChanged(this.oid, new NcElementId(4, 4), NcPropertyChangeType.ValueChanged, this.connectionStatusMessage, null); + + this.notificationContext.NotifyPropertyChanged(this.oid, new NcElementId(4, 9), NcPropertyChangeType.ValueChanged, this.streamStatus, null); + this.notificationContext.NotifyPropertyChanged(this.oid, new NcElementId(4, 10), NcPropertyChangeType.ValueChanged, this.streamStatusMessage, null); + } } public Disconnected() { - this.connectionStatus = NcConnectionStatus.Undefined; - this.payloadStatus = NcPayloadStatus.Undefined; + this.overallStatus = NcOverallStatus.Inactive; + this.overallStatusMessage = "Receiver is inactive"; + + this.connectionStatus = NcConnectionStatus.Inactive; + this.connectionStatusMessage = "Receiver is inactive"; + + this.streamStatus = NcStreamStatus.Inactive; + this.streamStatusMessage = "Receiver is inactive"; + + this.notificationContext.NotifyPropertyChanged(this.oid, new NcElementId(3, 1), NcPropertyChangeType.ValueChanged, this.overallStatus, null); + this.notificationContext.NotifyPropertyChanged(this.oid, new NcElementId(3, 2), NcPropertyChangeType.ValueChanged, this.overallStatusMessage, null); - this.connectionStatusMessage = null; - this.payloadStatusMessage = null; + this.notificationContext.NotifyPropertyChanged(this.oid, new NcElementId(4, 3), NcPropertyChangeType.ValueChanged, this.connectionStatus, null); + this.notificationContext.NotifyPropertyChanged(this.oid, new NcElementId(4, 4), NcPropertyChangeType.ValueChanged, this.connectionStatusMessage, null); - this.notificationContext.NotifyPropertyChanged(this.oid, new NcElementId(3, 1), NcPropertyChangeType.ValueChanged, this.connectionStatus, null); - this.notificationContext.NotifyPropertyChanged(this.oid, new NcElementId(3, 3), NcPropertyChangeType.ValueChanged, this.payloadStatus, null); + this.notificationContext.NotifyPropertyChanged(this.oid, new NcElementId(4, 9), NcPropertyChangeType.ValueChanged, this.streamStatus, null); + this.notificationContext.NotifyPropertyChanged(this.oid, new NcElementId(4, 10), NcPropertyChangeType.ValueChanged, this.streamStatusMessage, null); } //'1m1' @@ -546,7 +726,27 @@ export class NcReceiverMonitorProtected extends NcReceiverMonitor switch(key) { case '4p1': - return new CommandResponseWithValue(handle, NcMethodStatus.OK, this.signalProtectionStatus); + return new CommandResponseWithValue(handle, NcMethodStatus.OK, this.linkStatus); + case '4p2': + return new CommandResponseWithValue(handle, NcMethodStatus.OK, this.linkStatusMessage); + case '4p3': + return new CommandResponseWithValue(handle, NcMethodStatus.OK, this.connectionStatus); + case '4p4': + return new CommandResponseWithValue(handle, NcMethodStatus.OK, this.connectionStatusMessage); + case '4p5': + return new CommandResponseWithValue(handle, NcMethodStatus.OK, this.externalSynchronizationStatus); + case '4p6': + return new CommandResponseWithValue(handle, NcMethodStatus.OK, this.externalSynchronizationStatusMessage); + case '4p7': + return new CommandResponseWithValue(handle, NcMethodStatus.OK, this.synchronizationSourceId); + case '4p8': + return new CommandResponseWithValue(handle, NcMethodStatus.OK, this.synchronizationSourceChanges); + case '4p9': + return new CommandResponseWithValue(handle, NcMethodStatus.OK, this.streamStatus); + case '4p10': + return new CommandResponseWithValue(handle, NcMethodStatus.OK, this.streamStatusMessage); + case '4p11': + return new CommandResponseWithValue(handle, NcMethodStatus.OK, this.autoResetPacketCounters); default: return super.Get(oid, id, handle); } @@ -564,8 +764,26 @@ export class NcReceiverMonitorProtected extends NcReceiverMonitor switch(key) { + case '2p1': + if(value === true) + return new CommandResponseNoValue(handle, NcMethodStatus.OK); + else + return new CommandResponseError(handle, NcMethodStatus.InvalidRequest, "Receiver monitors cannot be disabled"); case '4p1': + case '4p2': + case '4p3': + case '4p4': + case '4p5': + case '4p6': + case '4p7': + case '4p8': + case '4p9': + case '4p10': return new CommandResponseError(handle, NcMethodStatus.Readonly, 'Property is readonly'); + case '4p11': + this.autoResetPacketCounters = value; + this.notificationContext.NotifyPropertyChanged(this.oid, id, NcPropertyChangeType.ValueChanged, this.autoResetPacketCounters, null); + return new CommandResponseNoValue(handle, NcMethodStatus.OK); default: return super.Set(oid, id, value, handle); } @@ -574,14 +792,73 @@ export class NcReceiverMonitorProtected extends NcReceiverMonitor return new CommandResponseError(handle, NcMethodStatus.BadOid, 'OID could not be found'); } + public override InvokeMethod(socket: WebSocketConnection, oid: number, methodId: NcElementId, args: { [key: string]: any; } | null, handle: number): CommandResponseNoValue + { + if(oid == this.oid) + { + let key: string = `${methodId.level}m${methodId.index}`; + + switch(key) + { + case '4m1': + return new CommandResponseWithValue(handle, NcMethodStatus.OK, this.lostPacketCounters); + case '4m2': + return new CommandResponseWithValue(handle, NcMethodStatus.OK, this.latePacketCounters); + case '4m3': + this.ResetPacketCounters(); + return new CommandResponseNoValue(handle, NcMethodStatus.OK); + case '4m4': + this.ResetSynchronizationSourceChanges(); + return new CommandResponseNoValue(handle, NcMethodStatus.OK); + default: + return super.InvokeMethod(socket, oid, methodId, args, handle); + + } + } + + return new CommandResponseError(handle, NcMethodStatus.BadOid, 'OID could not be found'); + } + + private ResetPacketCounters() + { + this.lostPacketCounters.forEach(counter => { + counter.Reset(); + }); + + this.latePacketCounters.forEach(counter => { + counter.Reset(); + }); + } + + private ResetSynchronizationSourceChanges() + { + this.synchronizationSourceChanges = 0; + this.notificationContext.NotifyPropertyChanged(this.oid, new NcElementId(4, 8), NcPropertyChangeType.ValueChanged, this.synchronizationSourceChanges, null); + } + public static override GetClassDescriptor(includeInherited: boolean): NcClassDescriptor { - let currentClassDescriptor = new NcClassDescriptor(`${NcReceiverMonitorProtected.name} class descriptor`, - NcReceiverMonitorProtected.staticClassID, NcReceiverMonitorProtected.name, null, + let currentClassDescriptor = new NcClassDescriptor(`${NcReceiverMonitor.name} class descriptor`, + NcReceiverMonitor.staticClassID, NcReceiverMonitor.name, null, [ - new NcPropertyDescriptor(new NcElementId(4, 1), "signalProtectionStatus", "NcBoolean", true, false, false, null, "Indicates if signal protection is active"), + new NcPropertyDescriptor(new NcElementId(4, 1), "linkStatus", "NcLinkStatus", true, false, false, null, "Link status property"), + new NcPropertyDescriptor(new NcElementId(4, 2), "linkStatusMessage", "NcString", true, true, false, null, "Link status message property"), + new NcPropertyDescriptor(new NcElementId(4, 3), "connectionStatus", "NcConnectionStatus", true, false, false, null, "Connection status property"), + new NcPropertyDescriptor(new NcElementId(4, 4), "connectionStatusMessage", "NcString", true, true, false, null, "Connection status message property"), + new NcPropertyDescriptor(new NcElementId(4, 5), "externalSynchronizationStatus", "NcSynchronizationStatus", true, false, false, null, "External synchronization status property"), + new NcPropertyDescriptor(new NcElementId(4, 6), "externalSynchronizationStatusMessage", "NcString", true, true, false, null, "External synchronization status message property"), + new NcPropertyDescriptor(new NcElementId(4, 7), "synchronizationSourceId", "NcString", true, true, false, null, "Synchronization source id property"), + new NcPropertyDescriptor(new NcElementId(4, 8), "synchronizationSourceChanges", "NcUint64", true, false, false, null, "Synchronization source changes counter"), + new NcPropertyDescriptor(new NcElementId(4, 9), "streamStatus", "NcStreamStatus", true, false, false, null, "Stream status property"), + new NcPropertyDescriptor(new NcElementId(4, 10), "streamStatusMessage", "NcString", true, true, false, null, "Stream status message property"), + new NcPropertyDescriptor(new NcElementId(4, 11), "autoResetPacketCounters", "NcBoolean", false, false, false, null, "Automatic reset packet counters property (default: true)") + ], + [ + new NcMethodDescriptor(new NcElementId(4, 1), "GetLostPacketCounters", "NcMethodResultCounters", [], "Gets the lost packet counters"), + new NcMethodDescriptor(new NcElementId(4, 2), "GetLatePacketCounters", "NcMethodResultCounters", [], "Gets the late packet counters"), + new NcMethodDescriptor(new NcElementId(4, 3), "ResetPacketCounters", "NcMethodResult", [], "Resets the packet counters"), + new NcMethodDescriptor(new NcElementId(4, 4), "ResetSynchronizationSourceChanges", "NcMethodResult", [], "Resets the synchronization source changes counter property") ], - [], [] ); diff --git a/code/src/NCModel/Managers.ts b/code/src/NCModel/Managers.ts index b7e63b4..f4686ba 100644 --- a/code/src/NCModel/Managers.ts +++ b/code/src/NCModel/Managers.ts @@ -48,7 +48,7 @@ import { NcTouchpointResource, NcTouchpointResourceNmos, NcTouchpointResourceNmosChannelMapping} from './Core'; -import { ExampleDataType, ExampleControl, GainControl, NcIdentBeacon, NcReceiverMonitor, NcReceiverMonitorProtected, NcReceiverStatus, NcWorker } from './Features'; +import { ExampleDataType, ExampleControl, GainControl, NcIdentBeacon, NcReceiverMonitor, NcWorker, NcStatusMonitor, NcMethodResultCounters, NcCounter } from './Features'; export abstract class NcManager extends NcObject { @@ -696,9 +696,9 @@ export class NcClassManager extends NcManager '1.2': NcWorker.GetClassDescriptor(false), '1.2.0.1': GainControl.GetClassDescriptor(false), '1.2.0.2': ExampleControl.GetClassDescriptor(false), - '1.2.2': NcIdentBeacon.GetClassDescriptor(false), - '1.2.3': NcReceiverMonitor.GetClassDescriptor(false), - '1.2.3.1': NcReceiverMonitorProtected.GetClassDescriptor(false), + '1.2.1': NcIdentBeacon.GetClassDescriptor(false), + '1.2.2': NcStatusMonitor.GetClassDescriptor(false), + '1.2.2.1': NcReceiverMonitor.GetClassDescriptor(false), '1.3': NcManager.GetClassDescriptor(false), '1.3.1': NcDeviceManager.GetClassDescriptor(false), '1.3.2': NcClassManager.GetClassDescriptor(false) @@ -718,9 +718,9 @@ export class NcClassManager extends NcManager case '1.2': return NcWorker.GetClassDescriptor(true); case '1.2.0.1': return GainControl.GetClassDescriptor(true); case '1.2.0.2': return ExampleControl.GetClassDescriptor(true); - case '1.2.2': return NcIdentBeacon.GetClassDescriptor(true); - case '1.2.3': return NcReceiverMonitor.GetClassDescriptor(true); - case '1.2.3.1': return NcReceiverMonitorProtected.GetClassDescriptor(true); + case '1.2.1': return NcIdentBeacon.GetClassDescriptor(true); + case '1.2.2': return NcStatusMonitor.GetClassDescriptor(true); + case '1.2.2.1': return NcReceiverMonitor.GetClassDescriptor(true); case '1.3': return NcManager.GetClassDescriptor(true); case '1.3.1': return NcDeviceManager.GetClassDescriptor(true); case '1.3.2': return NcClassManager.GetClassDescriptor(true); @@ -790,6 +790,7 @@ export class NcClassManager extends NcManager 'NcParameterConstraints': NcParameterConstraints.GetTypeDescriptor(false), 'NcParameterConstraintsNumber': NcParameterConstraintsNumber.GetTypeDescriptor(false), 'NcParameterConstraintsString': NcParameterConstraintsString.GetTypeDescriptor(false), + 'NcCounter': NcCounter.GetTypeDescriptor(false), 'NcPropertyChangeType': new NcDatatypeDescriptorEnum("NcPropertyChangeType", [ new NcEnumItemDescriptor("ValueChanged", 0, "Current value changed"), new NcEnumItemDescriptor("SequenceItemAdded", 1, "Sequence item added"), @@ -832,19 +833,36 @@ export class NcClassManager extends NcManager 'NcMethodResultBlockMemberDescriptors': NcMethodResultBlockMemberDescriptors.GetTypeDescriptor(false), 'NcMethodResultClassDescriptor': NcMethodResultClassDescriptor.GetTypeDescriptor(false), 'NcMethodResultDatatypeDescriptor': NcMethodResultDatatypeDescriptor.GetTypeDescriptor(false), - 'NcReceiverStatus': NcReceiverStatus.GetTypeDescriptor(false), + 'NcMethodResultCounters': NcMethodResultCounters.GetTypeDescriptor(false), + 'NcOverallStatus': new NcDatatypeDescriptorEnum("NcOverallStatus", [ + new NcEnumItemDescriptor("Inactive", 0, "Inactive"), + new NcEnumItemDescriptor("Healthy", 1, "Active and healthy"), + new NcEnumItemDescriptor("PartiallyHealthy", 2, "Active and partially healthy"), + new NcEnumItemDescriptor("Unhealthy", 3, "Active and unhealthy") + ], null, "Overall monitor status enum data type"), + 'NcLinkStatus': new NcDatatypeDescriptorEnum("NcLinkStatus", [ + new NcEnumItemDescriptor("AllUp", 1, "All the associated network interfaces are down"), + new NcEnumItemDescriptor("SomeDown", 2, "Some of the associated network interfaces are down"), + new NcEnumItemDescriptor("AllDown", 3, "All the associated network interfaces are up") + ], null, "Link status enum data type"), 'NcConnectionStatus': new NcDatatypeDescriptorEnum("NcConnectionStatus", [ - new NcEnumItemDescriptor("Undefined", 0, "This is the value when there is no receiver"), - new NcEnumItemDescriptor("Connected", 1, "Connected to a stream"), - new NcEnumItemDescriptor("Disconnected", 2, "Not connected to a stream"), - new NcEnumItemDescriptor("ConnectionError", 3, "A connection error was encountered") + new NcEnumItemDescriptor("Inactive", 0, "Inactive"), + new NcEnumItemDescriptor("Healthy", 1, "Active and healthy"), + new NcEnumItemDescriptor("PartiallyHealthy", 2, "Active and partially healthy"), + new NcEnumItemDescriptor("Unhealthy", 3, "Active and unhealthy") ], null, "Connection status enum data type"), - 'NcPayloadStatus': new NcDatatypeDescriptorEnum("NcPayloadStatus", [ - new NcEnumItemDescriptor("Undefined", 0, "This is the value when there's no connection."), - new NcEnumItemDescriptor("PayloadOK", 1, "Payload is being received without errors and is the correct type"), - new NcEnumItemDescriptor("PayloadFormatUnsupported", 2, "Payload is being received but is of an unsupported type"), - new NcEnumItemDescriptor("PayloadError", 3, "A payload error was encountered") - ], null, "Payload status enum data type"), + 'NcSynchronizationStatus': new NcDatatypeDescriptorEnum("NcSynchronizationStatus", [ + new NcEnumItemDescriptor("NotUsed", 0, "Feature not in use"), + new NcEnumItemDescriptor("Healthy", 1, "Locked to a synchronization source"), + new NcEnumItemDescriptor("PartiallyHealthy", 2, "Partially locked to a synchronization source"), + new NcEnumItemDescriptor("Unhealthy", 3, "Not locked to a synchronization source") + ], null, "Synchronization status enum data type"), + 'NcStreamStatus': new NcDatatypeDescriptorEnum("NcStreamStatus", [ + new NcEnumItemDescriptor("Inactive", 0, "Inactive"), + new NcEnumItemDescriptor("Healthy", 1, "Active and healthy"), + new NcEnumItemDescriptor("PartiallyHealthy", 2, "Active and partially healthy"), + new NcEnumItemDescriptor("Unhealthy", 3, "Active and unhealthy") + ], null, "Stream status enum data type"), 'NcTouchpoint': NcTouchpoint.GetTypeDescriptor(false), 'NcTouchpointResource': NcTouchpointResource.GetTypeDescriptor(false), 'NcTouchpointNmos': NcTouchpointNmos.GetTypeDescriptor(false), @@ -888,6 +906,7 @@ export class NcClassManager extends NcManager case 'NcClassDescriptor': return NcClassDescriptor.GetTypeDescriptor(true); case 'NcParameterConstraintsNumber': return NcParameterConstraintsNumber.GetTypeDescriptor(true); case 'NcParameterConstraintsString': return NcParameterConstraintsString.GetTypeDescriptor(true); + case 'NcCounter': return NcCounter.GetTypeDescriptor(true); case 'NcBlockMemberDescriptor': return NcBlockMemberDescriptor.GetTypeDescriptor(true); case 'NcTouchpointNmos': return NcTouchpointNmos.GetTypeDescriptor(true); case 'NcTouchpointNmosChannelMapping': return NcTouchpointNmosChannelMapping.GetTypeDescriptor(true); @@ -902,6 +921,7 @@ export class NcClassManager extends NcManager case 'NcMethodResultDatatypeDescriptor': return NcMethodResultDatatypeDescriptor.GetTypeDescriptor(true); case 'NcMethodResultId': return NcMethodResultId.GetTypeDescriptor(true); case 'NcMethodResultLength': return NcMethodResultLength.GetTypeDescriptor(true); + case 'NcMethodResultCounters': return NcMethodResultCounters.GetTypeDescriptor(true); default: return this.dataTypesRegister[name]; } }