refactor: cleanup charging profiles handling code main
authorJérôme Benoit <jerome.benoit@piment-noir.org>
Sun, 9 Jun 2024 21:00:48 +0000 (23:00 +0200)
committerJérôme Benoit <jerome.benoit@piment-noir.org>
Sun, 9 Jun 2024 21:00:48 +0000 (23:00 +0200)
Signed-off-by: Jérôme Benoit <jerome.benoit@piment-noir.org>
64 files changed:
.eslintignore
.github/workflows/ci.yml
CHANGELOG.md
build-requirements.js
package.json
pnpm-lock.yaml
skip-preinstall.js
sonar-project.properties
src/assets/ui-protocol/Insomnia-CSSimulatorUIHTTPProtocol.json
src/assets/ui-protocol/Insomnia-CSSimulatorUIWSProtocol.json
src/charging-station/AutomaticTransactionGenerator.ts
src/charging-station/Bootstrap.ts
src/charging-station/ChargingStation.ts
src/charging-station/Helpers.ts
src/charging-station/broadcast-channel/ChargingStationWorkerBroadcastChannel.ts
src/charging-station/index.ts
src/charging-station/ocpp/1.6/OCPP16Constants.ts
src/charging-station/ocpp/1.6/OCPP16IncomingRequestService.ts
src/charging-station/ocpp/1.6/OCPP16RequestService.ts
src/charging-station/ocpp/1.6/OCPP16ResponseService.ts
src/charging-station/ocpp/2.0/OCPP20Constants.ts
src/charging-station/ocpp/2.0/OCPP20IncomingRequestService.ts
src/charging-station/ocpp/2.0/OCPP20RequestService.ts
src/charging-station/ocpp/2.0/OCPP20ResponseService.ts
src/charging-station/ocpp/OCPPConstants.ts
src/charging-station/ocpp/OCPPIncomingRequestService.ts
src/charging-station/ocpp/OCPPRequestService.ts
src/charging-station/ocpp/OCPPResponseService.ts
src/charging-station/ocpp/OCPPServiceUtils.ts
src/charging-station/ui-server/AbstractUIServer.ts
src/charging-station/ui-server/UIServerFactory.ts
src/performance/PerformanceStatistics.ts
src/performance/storage/MikroOrmStorage.ts
src/performance/storage/MongoDBStorage.ts
src/performance/storage/Storage.ts
src/scripts/deleteChargingStations.cjs
src/scripts/setCSPublicFlag.cjs
src/types/ChargingStationEvents.ts
src/types/Statistics.ts
src/types/index.ts
src/types/ocpp/1.6/Requests.ts
src/types/ocpp/ChargingProfile.ts
src/utils/ChargingStationConfigurationUtils.ts
src/utils/CircularArray.ts [deleted file]
src/utils/Configuration.ts
src/utils/Constants.ts
src/utils/ErrorUtils.ts
src/utils/MessageChannelUtils.ts
src/utils/StatisticUtils.ts
src/utils/Utils.ts
src/utils/index.ts
src/worker/WorkerSet.ts
tests/exception/OCPPError.test.ts [new file with mode: 0644]
tests/utils/CircularArray.test.ts [deleted file]
tests/utils/ConfigurationUtils.test.ts [new file with mode: 0644]
tests/utils/ErrorUtils.test.ts [new file with mode: 0644]
tests/utils/StatisticUtils.test.ts
tests/utils/Utils.test.ts
ui/web/package.json
ui/web/src/composables/UIClient.ts
ui/web/src/composables/Utils.ts
ui/web/src/shims-vue.d.ts
ui/web/src/views/ChargingStationsView.vue
ui/web/start.js

index b14ff364d2da00bda0dcbb1ee90666d1329a1ad9..537479312061fdfbef0da43ff4d6cb9e62d3870d 100644 (file)
@@ -1,4 +1,2 @@
 dist/
 ui/web/
-# FIXME: ESM import parse error
-build-requirements.js
index 9d6b5f136f7c53f951149bc3a27af5d9b7760976..f48baf21a7062ffe14da4386fb2bf7c42c316b5c 100644 (file)
@@ -65,7 +65,7 @@ jobs:
         run: pnpm coverage
       - name: SonarCloud Scan
         if: ${{ needs.check-secrets.outputs.sonar-token-exists == 'true' && github.repository == 'sap/e-mobility-charging-stations-simulator' && matrix.os == 'ubuntu-latest' && matrix.node == '20.x' }}
-        uses: sonarsource/sonarcloud-github-action@v2.1.1
+        uses: sonarsource/sonarcloud-github-action@v2.2.0
         env:
           GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
           SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
@@ -116,7 +116,7 @@ jobs:
         run: pnpm coverage
       - name: SonarCloud Scan
         if: ${{ needs.check-secrets.outputs.sonar-token-exists == 'true' && github.repository == 'sap/e-mobility-charging-stations-simulator' && matrix.os == 'ubuntu-latest' && matrix.node == '20.x' }}
-        uses: sonarsource/sonarcloud-github-action@v2.1.1
+        uses: sonarsource/sonarcloud-github-action@v2.2.0
         with:
           projectBaseDir: ui/web
         env:
index e3a03ebf77991da0573fc6d2cbde496f465c8e03..9a0f9b852b1138e9b442798c689bc1a36ab3d49e 100644 (file)
@@ -1,6 +1,116 @@
 # Changelog
 
-## [v1.3.3](https://github.com/sap/e-mobility-charging-stations-simulator/compare/v1.3.2...v1.3.3)
+## [v1.3.5](https://github.com/sap/e-mobility-charging-stations-simulator/compare/v1.3.4...v1.3.5)
+
+- test: add ErrorUtils test [`d05b53c`](https://github.com/sap/e-mobility-charging-stations-simulator/commit/d05b53c7a03b8fad2e106caee68d5871cc6aac6e)
+- test: improve ErrorUtils coverage [`2d4928a`](https://github.com/sap/e-mobility-charging-stations-simulator/commit/2d4928a7237a906158f2e9652e08f0392eeabdcd)
+- build(deps-dev): apply updates [`c4387ed`](https://github.com/sap/e-mobility-charging-stations-simulator/commit/c4387ed4b3d2021034f452deeb35276fabe022e2)
+- feat: handle charging profile purpose TxProfile [`7abb61b`](https://github.com/sap/e-mobility-charging-stations-simulator/commit/7abb61bb4a4e1de238c6bdb31b1a017bcf56d7b6)
+- build(deps-dev): apply updates [`65b608f`](https://github.com/sap/e-mobility-charging-stations-simulator/commit/65b608f0259f6f59138406ea327d22ecd6a19361)
+- test: add tests [`b49550e`](https://github.com/sap/e-mobility-charging-stations-simulator/commit/b49550e256d11c7a30fb19cd672e5e3611d01553)
+- test: improve coverage on existing tests [`ff40d2c`](https://github.com/sap/e-mobility-charging-stations-simulator/commit/ff40d2cc466140d6f18bc15b742100dd4f060d0f)
+- fix: restart metervalues interval if MeterValueSampleInterval is changed [`b8e3363`](https://github.com/sap/e-mobility-charging-stations-simulator/commit/b8e3363a179fcf79d8bb66f47724b377d4d38a75)
+- refactor: rename Storage.handleDBError -&gt; Storage.handleDBStorageError [`a03b18c`](https://github.com/sap/e-mobility-charging-stations-simulator/commit/a03b18c4731bfd1173ff67b74a75684d3f6bb470)
+- fix: allow to set charging profile with TxProfile purpose [`65099c1`](https://github.com/sap/e-mobility-charging-stations-simulator/commit/65099c1e7297b252523172096a8d6ded22daa702)
+- fix: avoid to modify stored charging profiles [`a629e6f`](https://github.com/sap/e-mobility-charging-stations-simulator/commit/a629e6fcfeb952d77da280e69d645b17d94b2e4c)
+- test: add ConfigurationUtils test [`2a9305b`](https://github.com/sap/e-mobility-charging-stations-simulator/commit/2a9305b5ace7b5a49b5862c4282c1a88e3087da5)
+- perf: compute power limitation only once [`5b1bd2d`](https://github.com/sap/e-mobility-charging-stations-simulator/commit/5b1bd2d2c3c606aeef58cb1098def9a20c50dc4e)
+- fix: refine default configuration [`a9babd5`](https://github.com/sap/e-mobility-charging-stations-simulator/commit/a9babd5006e9b70f281d4bd654923fc3d63cd733)
+- test: improve ConfigurationUtils coverage [`8598b56`](https://github.com/sap/e-mobility-charging-stations-simulator/commit/8598b5618e5acf6b9e2538faa5225ba51aa68d10)
+- test: add Utils insertAt() test [`055d4c4`](https://github.com/sap/e-mobility-charging-stations-simulator/commit/055d4c4c39c9c1fcce050019c61caf305ec1a83e)
+- test: trivial refinements [`0acbf5e`](https://github.com/sap/e-mobility-charging-stations-simulator/commit/0acbf5e6ab020dda7ddc6785347c05c144de3bd9)
+- fix: ensure ATG status is refreshed in the UI at stop [`c004d5e`](https://github.com/sap/e-mobility-charging-stations-simulator/commit/c004d5e2e7d277ab99b3ee1b8ce363736529db9e)
+- test: improve ConfigurationUtils coverage [`329f14c`](https://github.com/sap/e-mobility-charging-stations-simulator/commit/329f14c004f74241c7cae1400e81740f3333eeee)
+- fix: add sanity check in ATG on connector id [`a4d9680`](https://github.com/sap/e-mobility-charging-stations-simulator/commit/a4d9680730c77debfb3b9455e4bd5b63e61ce664)
+- perf: add fastpath in array sorting helper [`8bfa4d2`](https://github.com/sap/e-mobility-charging-stations-simulator/commit/8bfa4d2be3f3817654791f166f4aab1b02485005)
+- fix: fix start transaction response handling with authorize [`ae8fb16`](https://github.com/sap/e-mobility-charging-stations-simulator/commit/ae8fb16df7c98a9238e61b1b358f8fbe2aee7a74)
+- fix: fix condition at ATG configuration handling [`274f9b3`](https://github.com/sap/e-mobility-charging-stations-simulator/commit/274f9b3662d8cf5e5fb0a361a1ae9fac86309e40)
+
+## [v1.3.4](https://github.com/sap/e-mobility-charging-stations-simulator/compare/v1.3.3...v1.3.4) (2024-06-06)
+
+- build(deps): bump sonarsource/sonarcloud-github-action from 2.1.1 to 2.2.0 [`#1038`](https://github.com/sap/e-mobility-charging-stations-simulator/pull/1038)
+- build(deps): bump pnpm/action-setup from 3 to 4 [`#1037`](https://github.com/sap/e-mobility-charging-stations-simulator/pull/1037)
+- fix: ensure message sequence is fired at boot notification response [`#1039`](https://github.com/sap/e-mobility-charging-stations-simulator/issues/1039)
+- refactor: code formatting [`48847bc`](https://github.com/sap/e-mobility-charging-stations-simulator/commit/48847bc0d5e594c3e4c0b81c580ac6df48052668)
+- build(deps-dev): apply updates [`7445d18`](https://github.com/sap/e-mobility-charging-stations-simulator/commit/7445d18b9b9ac750b9dc3dc3638d4fd0e8aff818)
+- build(deps-dev): apply updates [`268173c`](https://github.com/sap/e-mobility-charging-stations-simulator/commit/268173c99a4ff81e1416909244ec58a6eb56dae6)
+- build(deps-dev): apply updates [`4f146c7`](https://github.com/sap/e-mobility-charging-stations-simulator/commit/4f146c7c528d96cbe53ffeb9e578dc0c7e633af2)
+- build(deps): apply updates [`1dfc15d`](https://github.com/sap/e-mobility-charging-stations-simulator/commit/1dfc15d22b7ac2363a32540d43540b7a93277a67)
+- build(deps-dev): apply updates [`c8d7098`](https://github.com/sap/e-mobility-charging-stations-simulator/commit/c8d709814d13d9e4ea88a6c3a6701b37bfa858a4)
+- build(deps-dev): apply updates [`5218eec`](https://github.com/sap/e-mobility-charging-stations-simulator/commit/5218eec27c72bade7112c6b029d7d1eb1f42f871)
+- build(deps-dev): apply updates [`18f25d9`](https://github.com/sap/e-mobility-charging-stations-simulator/commit/18f25d958f1a57c34ed9d6e1de32ba9160c49dc2)
+- perf: use mnemonist CirculerBuffer [`840ca85`](https://github.com/sap/e-mobility-charging-stations-simulator/commit/840ca85d7c40a6ee6f3a85a50e68dbea2f90acb8)
+- build(deps-dev): apply updates [`4bbeb8a`](https://github.com/sap/e-mobility-charging-stations-simulator/commit/4bbeb8ad766752ba5da88513d9e77cba136ae85f)
+- build(deps-dev): apply updates [`4ed43d2`](https://github.com/sap/e-mobility-charging-stations-simulator/commit/4ed43d280ab39b9beaadfa90875c71bf3b2a9507)
+- build(deps-dev): apply updates [`2f2e044`](https://github.com/sap/e-mobility-charging-stations-simulator/commit/2f2e04446bb16844a71e8752ae29bff584267029)
+- build(deps): apply updates [`b1b7103`](https://github.com/sap/e-mobility-charging-stations-simulator/commit/b1b7103d2089ea75bff0a15125422adf69683fc1)
+- build(deps): apply updates [`78ffd68`](https://github.com/sap/e-mobility-charging-stations-simulator/commit/78ffd6863ea25544c4933303281c4bc7a81496f0)
+- build(deps-dev): apply updates [`a112428`](https://github.com/sap/e-mobility-charging-stations-simulator/commit/a11242837ef77110c4d4b7a6ab0fa6f9a644a253)
+- build(deps): apply updates [`f26697b`](https://github.com/sap/e-mobility-charging-stations-simulator/commit/f26697b4c9dcdf791e48e8f15160e90f6855c995)
+- build(deps-dev): apply updates [`cd01b1d`](https://github.com/sap/e-mobility-charging-stations-simulator/commit/cd01b1d8f00898e27f78f4795650a78a179f0d14)
+- build(deps): apply updates [`576c4a4`](https://github.com/sap/e-mobility-charging-stations-simulator/commit/576c4a496a355c5d995325406ec2cc37416f8a8e)
+- build(deps-dev): apply updates [`8788b81`](https://github.com/sap/e-mobility-charging-stations-simulator/commit/8788b81a3dd4add12ca01b1fe989b5c7c8927d54)
+- build(deps): apply updates [`21d5c4c`](https://github.com/sap/e-mobility-charging-stations-simulator/commit/21d5c4cdd0ccc30526f290a0be994990d5feac3f)
+- fix: fix performance statistics storage [`1c818bd`](https://github.com/sap/e-mobility-charging-stations-simulator/commit/1c818bd3b021c8e660d64f9054e02d06424a3c59)
+- build(deps): apply updates [`24a0327`](https://github.com/sap/e-mobility-charging-stations-simulator/commit/24a032720668044fc8439da3165715bab8474b26)
+- build(deps): apply updates [`47f846b`](https://github.com/sap/e-mobility-charging-stations-simulator/commit/47f846b2a74439a610321356604f2f4184cb5c0b)
+- build(deps): apply updates [`cc99095`](https://github.com/sap/e-mobility-charging-stations-simulator/commit/cc99095fab6d038ffff7ef3a2a8d33e762368670)
+- build(deps): apply updates [`73a88b8`](https://github.com/sap/e-mobility-charging-stations-simulator/commit/73a88b832be6eedd83e7b277032c8d7ba7d06a97)
+- build(deps): apply updates [`0972694`](https://github.com/sap/e-mobility-charging-stations-simulator/commit/0972694d006542648c971026f43e5f4c8498f459)
+- build(deps-dev): apply updates [`36158bb`](https://github.com/sap/e-mobility-charging-stations-simulator/commit/36158bb7c539757a8b4a898dd6093d6805376921)
+- build(deps): apply updates [`1f851da`](https://github.com/sap/e-mobility-charging-stations-simulator/commit/1f851da6440e4e4a31e959fcb8802b6c7f30beef)
+- chore: version 1.3.4 [`13a6494`](https://github.com/sap/e-mobility-charging-stations-simulator/commit/13a6494f3542b9ed8773311302fa85258a1edec7)
+- refactor: cleanup OCPP utils [`01b82de`](https://github.com/sap/e-mobility-charging-stations-simulator/commit/01b82de5b532cd149eccab7b82fe86a741289581)
+- build(deps-dev): apply updates [`55e006e`](https://github.com/sap/e-mobility-charging-stations-simulator/commit/55e006e1af126c62f26f39cd4a1f91ebd44b865d)
+- fix: ensure only circular buffer is converted to array [`312d325`](https://github.com/sap/e-mobility-charging-stations-simulator/commit/312d3254e6581f6bc939497d610048b6c6226d6d)
+- fix: fix date handling connectorsStatus configuration file section [`1fa9df8`](https://github.com/sap/e-mobility-charging-stations-simulator/commit/1fa9df8ce0e186387ecaa80efb9f40180fc36a7d)
+- fix: start heartbeat once [`d627f8e`](https://github.com/sap/e-mobility-charging-stations-simulator/commit/d627f8ef31d97da80f4de5ed0cb9386472f51bbe)
+- fix: ensure boot notification response is assigned before querying [`0320e2b`](https://github.com/sap/e-mobility-charging-stations-simulator/commit/0320e2bb72ca522c3932850cce0601ab0a895ad3)
+- build(deps-dev): apply updates [`aa345d0`](https://github.com/sap/e-mobility-charging-stations-simulator/commit/aa345d0154ff9700d8c9467c04c215ef5d07bbbf)
+- build: cleanup pnpm lock file [`fccc8f6`](https://github.com/sap/e-mobility-charging-stations-simulator/commit/fccc8f66dfabe8e91f67311f3182e26aece20293)
+- refactor: cleanup boot notification response assignation [`ab29e68`](https://github.com/sap/e-mobility-charging-stations-simulator/commit/ab29e6820d6a6d48d8ccc091ec8adae575398c3d)
+- build(deps): apply updates [`29fe6fd`](https://github.com/sap/e-mobility-charging-stations-simulator/commit/29fe6fd834029f21b22a23a3342f86b43c277c56)
+- build(deps-dev): apply updates [`fc10596`](https://github.com/sap/e-mobility-charging-stations-simulator/commit/fc105961dd56e041fc6de1df3fd51c74723ba419)
+- refactor: refine OCPP message sending error handling [`436569b`](https://github.com/sap/e-mobility-charging-stations-simulator/commit/436569b1470c8e6187c63d974304bd1b99f35ba3)
+- fix: fix clear charging profiles with no connector in payload [`ec6dd88`](https://github.com/sap/e-mobility-charging-stations-simulator/commit/ec6dd88b156eac9a14afd0d349ed58bb02fa920e)
+- fix: start web socket ping interval at successful connection [`99100f9`](https://github.com/sap/e-mobility-charging-stations-simulator/commit/99100f9c8709a7ead56c1e2745db80a75e8f6f79)
+- build(deps-dev): apply updates [`3ebab70`](https://github.com/sap/e-mobility-charging-stations-simulator/commit/3ebab7003594d1c243bcca4ef90007dc63680a52)
+- build(deps-dev): apply updates [`e4006e4`](https://github.com/sap/e-mobility-charging-stations-simulator/commit/e4006e4283d9150be5bd2f1050ff78c979a203c1)
+- fix: ensure charging profiles not related to the current transaction are [`626d3ce`](https://github.com/sap/e-mobility-charging-stations-simulator/commit/626d3ce5e6dfdc848cb2bb5833044fe6fbe68324)
+- fix: ensure inflight requests id cannot be duplicated [`3024d5b`](https://github.com/sap/e-mobility-charging-stations-simulator/commit/3024d5b2497e97bdd355243a5d236fa3f7a4d874)
+- build(deps-dev): apply updates [`69d995b`](https://github.com/sap/e-mobility-charging-stations-simulator/commit/69d995b2c8683703e7d9ce42fdd73ec02209482f)
+- fix: avoid endless loop at remote start transaction [`d0b7173`](https://github.com/sap/e-mobility-charging-stations-simulator/commit/d0b71736d6fced71a50c67e1f1e7ca842068e43e)
+- build(deps-dev): apply updates [`a6f03d2`](https://github.com/sap/e-mobility-charging-stations-simulator/commit/a6f03d2ddc8e28752b94cb0a43687d70c16683a6)
+- build(deps-dev): apply updates [`fa394dc`](https://github.com/sap/e-mobility-charging-stations-simulator/commit/fa394dc9dd5f30d5121c2ce6ed11ba5d7c30bcd3)
+- fix: reset authorize fields connector status after reservation [`239194e`](https://github.com/sap/e-mobility-charging-stations-simulator/commit/239194e9867eaea7d34fc3c8d3bff3360113d8dc)
+- build(deps-dev): apply updates [`df3e0f8`](https://github.com/sap/e-mobility-charging-stations-simulator/commit/df3e0f8da05b9680213ccd3e3beee6686f296cd1)
+- refactor: cleanup Infinity usage [`cffc32b`](https://github.com/sap/e-mobility-charging-stations-simulator/commit/cffc32b7bc5a6569525e92b562af8a93760bc339)
+- build(deps-dev): apply updates [`fa30db1`](https://github.com/sap/e-mobility-charging-stations-simulator/commit/fa30db101a2d11774bd9b29ca806597865ea06bf)
+- build: fix pnpm lockfile [`5e1bf42`](https://github.com/sap/e-mobility-charging-stations-simulator/commit/5e1bf4295e75408830ff46bb704a5139572a4120)
+- fix: properly handle undefined connector id at remote start transaction [`c0bbb3e`](https://github.com/sap/e-mobility-charging-stations-simulator/commit/c0bbb3eaf0c5dc704ea92820a2666a68ffdc27ff)
+- fix: fix error handling default options definition [`30695dc`](https://github.com/sap/e-mobility-charging-stations-simulator/commit/30695dcf67470f149e349d196b3d016482d11a17)
+- build(deps-dev): apply updates [`9e66896`](https://github.com/sap/e-mobility-charging-stations-simulator/commit/9e668960f040bf5da86a6d6e7c477d4ad39dfd04)
+- build: bump volta node version [`494983d`](https://github.com/sap/e-mobility-charging-stations-simulator/commit/494983d465621a426f5dc92fd7cccc62821616f9)
+- build(deps-dev): apply updates [`bb57ea0`](https://github.com/sap/e-mobility-charging-stations-simulator/commit/bb57ea07805938bec42dbee3da6bfda569a1b9bb)
+- refactor: convert npx to pnpm exec [`e1486a4`](https://github.com/sap/e-mobility-charging-stations-simulator/commit/e1486a4c8ce0142f2efc57c87fc8e8e05745a13f)
+- refactor: cleanup boot notification response handling [`52f1dd5`](https://github.com/sap/e-mobility-charging-stations-simulator/commit/52f1dd569da1eac66de821796cdfbcef09b48c87)
+- refactor: cleanup connection retries logic [`aa5f2ea`](https://github.com/sap/e-mobility-charging-stations-simulator/commit/aa5f2ea2958ef34e8d34e20edbe8486b8911d82b)
+- fix: pickup not reserved connector at remote start transaction [`8946ba9`](https://github.com/sap/e-mobility-charging-stations-simulator/commit/8946ba9db13e225292a62b8f4bdcd1419792697a)
+- refactor: cleanup eslint usage [`c69ae13`](https://github.com/sap/e-mobility-charging-stations-simulator/commit/c69ae13bb71df8f2017e21d919979b73dc6184f9)
+- fix: fix firmware update in progress detection [`382b62c`](https://github.com/sap/e-mobility-charging-stations-simulator/commit/382b62c45d665e66d4a2f3ad5ac7ecc6396859c7)
+- fix: fix log files path resolution at GetDiagnostics [`e56bbec`](https://github.com/sap/e-mobility-charging-stations-simulator/commit/e56bbec564af27559aade33d375dc890e882858e)
+- docs: refine code comments [`1d85f41`](https://github.com/sap/e-mobility-charging-stations-simulator/commit/1d85f415a46d0d3355ee013e449ad99d3aee9418)
+- build(deps): bump sonarsource/sonarcloud-github-action [`e48376c`](https://github.com/sap/e-mobility-charging-stations-simulator/commit/e48376cebb2f0e5d6c670b432e1b524e21702d3a)
+- build(ci): rely on packageManager field to setup pnpm [`7bba320`](https://github.com/sap/e-mobility-charging-stations-simulator/commit/7bba3209fa975827c841aeab8fa20b4837ca64b1)
+- refactor: cleanup boot notification handling internal handling [`d9c13bc`](https://github.com/sap/e-mobility-charging-stations-simulator/commit/d9c13bcac891b8686dbba36ae5c10f87948e3614)
+- fix: fix remote transaction start debug log [`7b08e7f`](https://github.com/sap/e-mobility-charging-stations-simulator/commit/7b08e7f332d1146fa5990cf29e08e328343819f1)
+- fix: ensure registration status is deleted if invalid boot notification [`18c6df2`](https://github.com/sap/e-mobility-charging-stations-simulator/commit/18c6df2b1102c307cbe8eb0c04d85c82045abf15)
+- refactor: cleanup string literal variables handling [`4c6f356`](https://github.com/sap/e-mobility-charging-stations-simulator/commit/4c6f35659fb67d395adc035ef80c566eb6eef79e)
+- perf: resize circular array to sensible default [`9b5cf75`](https://github.com/sap/e-mobility-charging-stations-simulator/commit/9b5cf75581e0338885b8e2ea408ea5a3f391d0ec)
+- fix(ci): silence linter [`4293e51`](https://github.com/sap/e-mobility-charging-stations-simulator/commit/4293e5179eabbc8f42a1c06064d15c0ec7d1ca3f)
+- refactor: helper cleanup [`f69ca7c`](https://github.com/sap/e-mobility-charging-stations-simulator/commit/f69ca7ca5f551a427e3181d38bc893cb68b2b542)
+
+## [v1.3.3](https://github.com/sap/e-mobility-charging-stations-simulator/compare/v1.3.2...v1.3.3) (2024-04-30)
 
 - fix: avoid duplicated slash in connection url [`#1034`](https://github.com/sap/e-mobility-charging-stations-simulator/issues/1034)
 - chore: switch to pnpm 9.x.x [`6eddb71`](https://github.com/sap/e-mobility-charging-stations-simulator/commit/6eddb71902ac0d0552f705190aaf62525f07c476)
 - build(deps-dev): apply updates [`a637f99`](https://github.com/sap/e-mobility-charging-stations-simulator/commit/a637f99f1d9a63bed1338809a5dbfab26925babe)
 - build(deps): apply updates [`de073a7`](https://github.com/sap/e-mobility-charging-stations-simulator/commit/de073a748bcd60308615b81c3f6da817639461a1)
 - build(deps-dev): apply updates [`5b7bbdb`](https://github.com/sap/e-mobility-charging-stations-simulator/commit/5b7bbdba3612e2f5748a4c21b46ba7bee89ddaba)
+- chore: version 1.3.3 [`6deeebd`](https://github.com/sap/e-mobility-charging-stations-simulator/commit/6deeebd11133a5c4b47452d9d9ab8cf5759e7c8a)
 - build(deps-dev): apply updates [`98d6958`](https://github.com/sap/e-mobility-charging-stations-simulator/commit/98d6958a6225cecc92e2f8b676c91be9fffd857b)
 - refactor: silence typing errors [`314793a`](https://github.com/sap/e-mobility-charging-stations-simulator/commit/314793aaf25bf1a99deb3f8209c09421235942ba)
 - build: bump volta pnpm version [`8fb8f42`](https://github.com/sap/e-mobility-charging-stations-simulator/commit/8fb8f42ace8b9295865adebaeb7845e064c05e71)
index c92b20953402121217bb38ed224222498cac1852..501933c4fa5ae659809f3ab8f96f13f710d4caa4 100644 (file)
@@ -1,7 +1,9 @@
+import { readFileSync } from 'node:fs'
+import { exit, version } from 'node:process'
+
 import chalk from 'chalk'
+// eslint-disable-next-line n/no-unpublished-import
 import { satisfies } from 'semver'
-import { version, exit } from 'node:process'
-import { readFileSync } from 'node:fs'
 
 const packageJson = JSON.parse(readFileSync('./package.json', 'utf8'))
 
index d3a7d256942445f5d7ff01f2d96f09573e633594..ad8ceae9cb7d51d0c441de5763f15b882d3e3e20 100644 (file)
@@ -1,16 +1,16 @@
 {
   "$schema": "https://json.schemastore.org/package",
   "name": "e-mobility-charging-stations-simulator",
-  "version": "1.3.3",
+  "version": "1.3.5",
   "engines": {
     "node": ">=18.18.0",
     "pnpm": ">=9.0.0"
   },
   "volta": {
-    "node": "22.1.0",
-    "pnpm": "9.1.0"
+    "node": "22.2.0",
+    "pnpm": "9.2.0"
   },
-  "packageManager": "pnpm@9.1.0",
+  "packageManager": "pnpm@9.2.0",
   "repository": {
     "type": "git",
     "url": "https://github.com/sap/e-mobility-charging-stations-simulator.git"
@@ -70,9 +70,9 @@
     "build:entities": "tsc -p tsconfig-mikro-orm.json",
     "clean:dist": "pnpm exec rimraf dist",
     "clean:node_modules": "pnpm exec rimraf node_modules",
-    "lint": "cross-env TIMING=1 eslint --cache src tests .eslintrc.cjs bundle.js mikro-orm.config-template.ts",
-    "lint:fix": "cross-env TIMING=1 eslint --cache --fix src tests .eslintrc.cjs bundle.js mikro-orm.config-template.ts",
-    "format": "prettier --cache --write .; eslint --cache --fix src .eslintrc.cjs tests bundle.js mikro-orm.config-template.ts",
+    "lint": "cross-env TIMING=1 eslint --cache src tests ./*.cjs ./*.js ./*.ts",
+    "lint:fix": "cross-env TIMING=1 eslint --cache --fix src tests ./*.cjs ./*.js ./*.ts",
+    "format": "prettier --cache --write .; eslint --cache --fix src tests ./*.cjs ./*.js ./*.ts",
     "test": "glob -c \"c8 node --import tsx --test\" \"tests/**/*.test.ts\"",
     "test:debug": "glob -c \"node --import tsx --test --inspect\" \"tests/**/*.test.ts\"",
     "coverage": "c8 report --reporter=lcov",
     }
   },
   "dependencies": {
-    "@mikro-orm/core": "^6.2.5",
-    "@mikro-orm/mariadb": "^6.2.5",
-    "@mikro-orm/reflection": "^6.2.5",
-    "@mikro-orm/sqlite": "^6.2.5",
-    "ajv": "^8.13.0",
+    "@mikro-orm/core": "^6.2.9",
+    "@mikro-orm/mariadb": "^6.2.9",
+    "@mikro-orm/reflection": "^6.2.9",
+    "@mikro-orm/sqlite": "^6.2.9",
+    "ajv": "^8.16.0",
     "ajv-formats": "^3.0.1",
     "basic-ftp": "^5.0.5",
     "chalk": "^5.3.0",
     "http-status-codes": "^2.3.0",
     "logform": "^2.6.0",
     "mnemonist": "0.40.0-rc1",
-    "mongodb": "^6.6.1",
-    "poolifier": "^4.0.2",
+    "mongodb": "^6.7.0",
+    "poolifier": "^4.0.13",
     "rambda": "^9.2.0",
-    "tar": "^7.1.0",
+    "tar": "^7.2.0",
     "winston": "^3.13.0",
     "winston-daily-rotate-file": "^5.0.0",
     "ws": "^8.17.0"
   },
   "optionalDependencies": {
     "bufferutil": "^4.0.8",
-    "utf-8-validate": "^6.0.3"
+    "utf-8-validate": "^6.0.4"
   },
   "devDependencies": {
     "@commitlint/cli": "^19.3.0",
     "@commitlint/config-conventional": "^19.2.2",
-    "@mikro-orm/cli": "^6.2.5",
+    "@mikro-orm/cli": "^6.2.9",
     "@release-it/bumper": "^6.0.1",
-    "@types/node": "^20.12.10",
+    "@types/node": "^20.14.2",
     "@types/semver": "^7.5.8",
     "@types/ws": "^8.5.10",
-    "@typescript-eslint/eslint-plugin": "^7.8.0",
-    "@typescript-eslint/parser": "^7.8.0",
+    "@typescript-eslint/eslint-plugin": "^7.12.0",
+    "@typescript-eslint/parser": "^7.12.0",
     "auto-changelog": "^2.4.0",
     "c8": "^9.1.0",
     "clinic": "^13.0.0",
     "cross-env": "^7.0.3",
-    "esbuild": "^0.21.0",
+    "esbuild": "^0.21.4",
     "esbuild-plugin-clean": "^1.0.1",
     "esbuild-plugin-copy": "^2.1.1",
     "eslint": "^8.57.0",
     "eslint-define-config": "^2.1.0",
     "eslint-import-resolver-typescript": "^3.6.1",
     "eslint-plugin-import": "^2.29.1",
-    "eslint-plugin-jsdoc": "^48.2.3",
-    "eslint-plugin-n": "^17.5.0",
+    "eslint-plugin-jsdoc": "^48.2.9",
+    "eslint-plugin-n": "^17.8.1",
     "eslint-plugin-simple-import-sort": "^12.1.0",
-    "eslint-plugin-tsdoc": "^0.2.17",
+    "eslint-plugin-tsdoc": "^0.3.0",
     "expect": "^29.7.0",
-    "glob": "^10.3.12",
+    "glob": "^10.4.1",
     "husky": "^9.0.11",
-    "lint-staged": "^15.2.2",
-    "prettier": "^3.2.5",
-    "release-it": "^17.2.1",
-    "rimraf": "^5.0.5",
-    "semver": "^7.6.0",
+    "lint-staged": "^15.2.5",
+    "prettier": "^3.3.1",
+    "release-it": "^17.3.0",
+    "rimraf": "^5.0.7",
+    "semver": "^7.6.2",
     "ts-node": "^10.9.2",
-    "tsx": "^4.9.3",
+    "tsx": "^4.15.1",
     "typescript": "~5.4.5"
   }
 }
index b1cd64c7f567dec9b97b53fb1735672f3fc1ec5c..5ec8f7601e78ded131d6887cd46ed08ff9cd5cc1 100644 (file)
@@ -18,23 +18,23 @@ importers:
   .:
     dependencies:
       '@mikro-orm/core':
-        specifier: ^6.2.5
-        version: 6.2.5
+        specifier: ^6.2.9
+        version: 6.2.9
       '@mikro-orm/mariadb':
-        specifier: ^6.2.5
-        version: 6.2.5(@mikro-orm/core@6.2.5)
+        specifier: ^6.2.9
+        version: 6.2.9(@mikro-orm/core@6.2.9)
       '@mikro-orm/reflection':
-        specifier: ^6.2.5
-        version: 6.2.5(@mikro-orm/core@6.2.5)
+        specifier: ^6.2.9
+        version: 6.2.9(@mikro-orm/core@6.2.9)
       '@mikro-orm/sqlite':
-        specifier: ^6.2.5
-        version: 6.2.5(@mikro-orm/core@6.2.5)
+        specifier: ^6.2.9
+        version: 6.2.9(@mikro-orm/core@6.2.9)(mariadb@3.3.0)
       ajv:
-        specifier: ^8.13.0
-        version: 8.13.0
+        specifier: ^8.16.0
+        version: 8.16.0
       ajv-formats:
         specifier: ^3.0.1
-        version: 3.0.1(ajv@8.13.0)
+        version: 3.0.1(ajv@8.16.0)
       basic-ftp:
         specifier: ^5.0.5
         version: 5.0.5
@@ -54,17 +54,17 @@ importers:
         specifier: 0.40.0-rc1
         version: 0.40.0-rc1
       mongodb:
-        specifier: ^6.6.1
-        version: 6.6.1(socks@2.8.3)
+        specifier: ^6.7.0
+        version: 6.7.0(socks@2.8.3)
       poolifier:
-        specifier: ^4.0.2
-        version: 4.0.2
+        specifier: ^4.0.13
+        version: 4.0.13
       rambda:
         specifier: ^9.2.0
         version: 9.2.0
       tar:
-        specifier: ^7.1.0
-        version: 7.1.0
+        specifier: ^7.2.0
+        version: 7.2.0
       winston:
         specifier: ^3.13.0
         version: 3.13.0
@@ -73,30 +73,30 @@ importers:
         version: 5.0.0(winston@3.13.0)
       ws:
         specifier: ^8.17.0
-        version: 8.17.0(bufferutil@4.0.8)(utf-8-validate@6.0.3)
+        version: 8.17.0(bufferutil@4.0.8)(utf-8-validate@6.0.4)
     optionalDependencies:
       bufferutil:
         specifier: ^4.0.8
         version: 4.0.8
       utf-8-validate:
-        specifier: ^6.0.3
-        version: 6.0.3
+        specifier: ^6.0.4
+        version: 6.0.4
     devDependencies:
       '@commitlint/cli':
         specifier: ^19.3.0
-        version: 19.3.0(@types/node@20.12.10)(typescript@5.4.5)
+        version: 19.3.0(@types/node@20.14.2)(typescript@5.4.5)
       '@commitlint/config-conventional':
         specifier: ^19.2.2
         version: 19.2.2
       '@mikro-orm/cli':
-        specifier: ^6.2.5
-        version: 6.2.5
+        specifier: ^6.2.9
+        version: 6.2.9(mariadb@3.3.0)
       '@release-it/bumper':
         specifier: ^6.0.1
-        version: 6.0.1(release-it@17.2.1(typescript@5.4.5))
+        version: 6.0.1(release-it@17.3.0(typescript@5.4.5))
       '@types/node':
-        specifier: ^20.12.10
-        version: 20.12.10
+        specifier: ^20.14.2
+        version: 20.14.2
       '@types/semver':
         specifier: ^7.5.8
         version: 7.5.8
@@ -104,11 +104,11 @@ importers:
         specifier: ^8.5.10
         version: 8.5.10
       '@typescript-eslint/eslint-plugin':
-        specifier: ^7.8.0
-        version: 7.8.0(@typescript-eslint/parser@7.8.0(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0)(typescript@5.4.5)
+        specifier: ^7.12.0
+        version: 7.12.0(@typescript-eslint/parser@7.12.0(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0)(typescript@5.4.5)
       '@typescript-eslint/parser':
-        specifier: ^7.8.0
-        version: 7.8.0(eslint@8.57.0)(typescript@5.4.5)
+        specifier: ^7.12.0
+        version: 7.12.0(eslint@8.57.0)(typescript@5.4.5)
       auto-changelog:
         specifier: ^2.4.0
         version: 2.4.0(encoding@0.1.13)
@@ -122,74 +122,74 @@ importers:
         specifier: ^7.0.3
         version: 7.0.3
       esbuild:
-        specifier: ^0.21.0
-        version: 0.21.0
+        specifier: ^0.21.4
+        version: 0.21.4
       esbuild-plugin-clean:
         specifier: ^1.0.1
-        version: 1.0.1(esbuild@0.21.0)
+        version: 1.0.1(esbuild@0.21.4)
       esbuild-plugin-copy:
         specifier: ^2.1.1
-        version: 2.1.1(esbuild@0.21.0)
+        version: 2.1.1(esbuild@0.21.4)
       eslint:
         specifier: ^8.57.0
         version: 8.57.0
       eslint-config-love:
         specifier: ^47.0.0
-        version: 47.0.0(@typescript-eslint/eslint-plugin@7.8.0(@typescript-eslint/parser@7.8.0(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0)(typescript@5.4.5))(eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.8.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0))(eslint-plugin-n@17.5.0(eslint@8.57.0))(eslint-plugin-promise@6.1.1(eslint@8.57.0))(eslint@8.57.0)(typescript@5.4.5)
+        version: 47.0.0(@typescript-eslint/eslint-plugin@7.12.0(@typescript-eslint/parser@7.12.0(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0)(typescript@5.4.5))(eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.12.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0))(eslint-plugin-n@17.8.1(eslint@8.57.0))(eslint-plugin-promise@6.1.1(eslint@8.57.0))(eslint@8.57.0)(typescript@5.4.5)
       eslint-config-standard:
         specifier: ^17.1.0
-        version: 17.1.0(eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.8.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0))(eslint-plugin-n@17.5.0(eslint@8.57.0))(eslint-plugin-promise@6.1.1(eslint@8.57.0))(eslint@8.57.0)
+        version: 17.1.0(eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.12.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0))(eslint-plugin-n@17.8.1(eslint@8.57.0))(eslint-plugin-promise@6.1.1(eslint@8.57.0))(eslint@8.57.0)
       eslint-define-config:
         specifier: ^2.1.0
         version: 2.1.0
       eslint-import-resolver-typescript:
         specifier: ^3.6.1
-        version: 3.6.1(@typescript-eslint/parser@7.8.0(eslint@8.57.0)(typescript@5.4.5))(eslint-plugin-import@2.29.1)(eslint@8.57.0)
+        version: 3.6.1(@typescript-eslint/parser@7.12.0(eslint@8.57.0)(typescript@5.4.5))(eslint-plugin-import@2.29.1)(eslint@8.57.0)
       eslint-plugin-import:
         specifier: ^2.29.1
-        version: 2.29.1(@typescript-eslint/parser@7.8.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0)
+        version: 2.29.1(@typescript-eslint/parser@7.12.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0)
       eslint-plugin-jsdoc:
-        specifier: ^48.2.3
-        version: 48.2.3(eslint@8.57.0)
+        specifier: ^48.2.9
+        version: 48.2.9(eslint@8.57.0)
       eslint-plugin-n:
-        specifier: ^17.5.0
-        version: 17.5.0(eslint@8.57.0)
+        specifier: ^17.8.1
+        version: 17.8.1(eslint@8.57.0)
       eslint-plugin-simple-import-sort:
         specifier: ^12.1.0
         version: 12.1.0(eslint@8.57.0)
       eslint-plugin-tsdoc:
-        specifier: ^0.2.17
-        version: 0.2.17
+        specifier: ^0.3.0
+        version: 0.3.0
       expect:
         specifier: ^29.7.0
         version: 29.7.0
       glob:
-        specifier: ^10.3.12
-        version: 10.3.12
+        specifier: ^10.4.1
+        version: 10.4.1
       husky:
         specifier: ^9.0.11
         version: 9.0.11
       lint-staged:
-        specifier: ^15.2.2
-        version: 15.2.2
+        specifier: ^15.2.5
+        version: 15.2.5
       prettier:
-        specifier: ^3.2.5
-        version: 3.2.5
+        specifier: ^3.3.1
+        version: 3.3.1
       release-it:
-        specifier: ^17.2.1
-        version: 17.2.1(typescript@5.4.5)
+        specifier: ^17.3.0
+        version: 17.3.0(typescript@5.4.5)
       rimraf:
-        specifier: ^5.0.5
-        version: 5.0.5
+        specifier: ^5.0.7
+        version: 5.0.7
       semver:
         specifier: ^7.5.3
-        version: 7.6.0
+        version: 7.6.2
       ts-node:
         specifier: ^10.9.2
-        version: 10.9.2(@types/node@20.12.10)(typescript@5.4.5)
+        version: 10.9.2(@types/node@20.14.2)(typescript@5.4.5)
       tsx:
-        specifier: ^4.9.3
-        version: 4.9.3
+        specifier: ^4.15.1
+        version: 4.15.1
       typescript:
         specifier: ~5.4.5
         version: 5.4.5
@@ -213,38 +213,38 @@ importers:
         version: 3.1.2(vue@3.4.27(typescript@5.4.5))
     devDependencies:
       '@rushstack/eslint-patch':
-        specifier: ^1.10.2
-        version: 1.10.2
+        specifier: ^1.10.3
+        version: 1.10.3
       '@tsconfig/node20':
         specifier: ^20.1.4
         version: 20.1.4
       '@types/jsdom':
-        specifier: ^21.1.6
-        version: 21.1.6
+        specifier: ^21.1.7
+        version: 21.1.7
       '@types/node':
-        specifier: ^20.12.10
-        version: 20.12.10
+        specifier: ^20.14.2
+        version: 20.14.2
       '@typescript-eslint/eslint-plugin':
-        specifier: ^7.8.0
-        version: 7.8.0(@typescript-eslint/parser@7.8.0(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0)(typescript@5.4.5)
+        specifier: ^7.12.0
+        version: 7.12.0(@typescript-eslint/parser@7.12.0(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0)(typescript@5.4.5)
       '@typescript-eslint/parser':
-        specifier: ^7.8.0
-        version: 7.8.0(eslint@8.57.0)(typescript@5.4.5)
+        specifier: ^7.12.0
+        version: 7.12.0(eslint@8.57.0)(typescript@5.4.5)
       '@vitejs/plugin-vue':
-        specifier: ^5.0.4
-        version: 5.0.4(vite@5.2.11(@types/node@20.12.10))(vue@3.4.27(typescript@5.4.5))
+        specifier: ^5.0.5
+        version: 5.0.5(vite@5.2.13(@types/node@20.14.2))(vue@3.4.27(typescript@5.4.5))
       '@vitejs/plugin-vue-jsx':
-        specifier: ^3.1.0
-        version: 3.1.0(vite@5.2.11(@types/node@20.12.10))(vue@3.4.27(typescript@5.4.5))
+        specifier: ^4.0.0
+        version: 4.0.0(vite@5.2.13(@types/node@20.14.2))(vue@3.4.27(typescript@5.4.5))
       '@vitest/coverage-v8':
         specifier: ^1.6.0
-        version: 1.6.0(vitest@1.6.0(@types/node@20.12.10)(jsdom@24.0.0(bufferutil@4.0.8)(utf-8-validate@6.0.3)))
+        version: 1.6.0(vitest@1.6.0(@types/node@20.14.2)(jsdom@24.1.0(bufferutil@4.0.8)(utf-8-validate@6.0.4)))
       '@vue/eslint-config-prettier':
         specifier: ^9.0.0
-        version: 9.0.0(eslint@8.57.0)(prettier@3.2.5)
+        version: 9.0.0(@types/eslint@8.56.10)(eslint@8.57.0)(prettier@3.3.1)
       '@vue/eslint-config-typescript':
         specifier: ^13.0.0
-        version: 13.0.0(eslint-plugin-vue@9.25.0(eslint@8.57.0))(eslint@8.57.0)(typescript@5.4.5)
+        version: 13.0.0(eslint-plugin-vue@9.26.0(eslint@8.57.0))(eslint@8.57.0)(typescript@5.4.5)
       '@vue/test-utils':
         specifier: ^2.4.6
         version: 2.4.6
@@ -262,34 +262,34 @@ importers:
         version: 2.1.0
       eslint-import-resolver-typescript:
         specifier: ^3.6.1
-        version: 3.6.1(@typescript-eslint/parser@7.8.0(eslint@8.57.0)(typescript@5.4.5))(eslint-plugin-import@2.29.1)(eslint@8.57.0)
+        version: 3.6.1(@typescript-eslint/parser@7.12.0(eslint@8.57.0)(typescript@5.4.5))(eslint-plugin-import@2.29.1)(eslint@8.57.0)
       eslint-plugin-import:
         specifier: ^2.29.1
-        version: 2.29.1(@typescript-eslint/parser@7.8.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0)
+        version: 2.29.1(@typescript-eslint/parser@7.12.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0)
       eslint-plugin-simple-import-sort:
         specifier: ^12.1.0
         version: 12.1.0(eslint@8.57.0)
       eslint-plugin-vue:
-        specifier: ^9.25.0
-        version: 9.25.0(eslint@8.57.0)
+        specifier: ^9.26.0
+        version: 9.26.0(eslint@8.57.0)
       jsdom:
-        specifier: ^24.0.0
-        version: 24.0.0(bufferutil@4.0.8)(utf-8-validate@6.0.3)
+        specifier: ^24.1.0
+        version: 24.1.0(bufferutil@4.0.8)(utf-8-validate@6.0.4)
       prettier:
-        specifier: ^3.2.5
-        version: 3.2.5
+        specifier: ^3.3.1
+        version: 3.3.1
       rimraf:
-        specifier: ^5.0.5
-        version: 5.0.5
+        specifier: ^5.0.7
+        version: 5.0.7
       typescript:
         specifier: ~5.4.5
         version: 5.4.5
       vite:
-        specifier: ^5.2.11
-        version: 5.2.11(@types/node@20.12.10)
+        specifier: ^5.2.13
+        version: 5.2.13(@types/node@20.14.2)
       vitest:
         specifier: ^1.6.0
-        version: 1.6.0(@types/node@20.12.10)(jsdom@24.0.0(bufferutil@4.0.8)(utf-8-validate@6.0.3))
+        version: 1.6.0(@types/node@20.14.2)(jsdom@24.1.0(bufferutil@4.0.8)(utf-8-validate@6.0.4))
 
 packages:
 
@@ -305,145 +305,145 @@ packages:
   '@assemblyscript/loader@0.19.23':
     resolution: {integrity: sha512-ulkCYfFbYj01ie1MDOyxv2F6SpRN1TOj7fQxbP07D6HmeR+gr2JLSmINKjga2emB+b1L2KGrFKBTc+e00p54nw==}
 
-  '@babel/code-frame@7.24.2':
-    resolution: {integrity: sha512-y5+tLQyV8pg3fsiln67BVLD1P13Eg4lh5RW9mF0zUuvLrv9uIQ4MCL+CRT+FTsBlBjcIan6PGsLcBN0m3ClUyQ==}
+  '@babel/code-frame@7.24.7':
+    resolution: {integrity: sha512-BcYH1CVJBO9tvyIZ2jVeXgSIMvGZ2FDRvDdOIVQyuklNKSsx+eppDEBq/g47Ayw+RqNFE+URvOShmf+f/qwAlA==}
     engines: {node: '>=6.9.0'}
 
-  '@babel/compat-data@7.24.4':
-    resolution: {integrity: sha512-vg8Gih2MLK+kOkHJp4gBEIkyaIi00jgWot2D9QOmmfLC8jINSOzmCLta6Bvz/JSBCqnegV0L80jhxkol5GWNfQ==}
+  '@babel/compat-data@7.24.7':
+    resolution: {integrity: sha512-qJzAIcv03PyaWqxRgO4mSU3lihncDT296vnyuE2O8uA4w3UHWI4S3hgeZd1L8W1Bft40w9JxJ2b412iDUFFRhw==}
     engines: {node: '>=6.9.0'}
 
-  '@babel/core@7.24.5':
-    resolution: {integrity: sha512-tVQRucExLQ02Boi4vdPp49svNGcfL2GhdTCT9aldhXgCJVAI21EtRfBettiuLUwce/7r6bFdgs6JFkcdTiFttA==}
+  '@babel/core@7.24.7':
+    resolution: {integrity: sha512-nykK+LEK86ahTkX/3TgauT0ikKoNCfKHEaZYTUVupJdTLzGNvrblu4u6fa7DhZONAltdf8e662t/abY8idrd/g==}
     engines: {node: '>=6.9.0'}
 
-  '@babel/generator@7.24.5':
-    resolution: {integrity: sha512-x32i4hEXvr+iI0NEoEfDKzlemF8AmtOP8CcrRaEcpzysWuoEb1KknpcvMsHKPONoKZiDuItklgWhB18xEhr9PA==}
+  '@babel/generator@7.24.7':
+    resolution: {integrity: sha512-oipXieGC3i45Y1A41t4tAqpnEZWgB/lC6Ehh6+rOviR5XWpTtMmLN+fGjz9vOiNRt0p6RtO6DtD0pdU3vpqdSA==}
     engines: {node: '>=6.9.0'}
 
-  '@babel/helper-annotate-as-pure@7.22.5':
-    resolution: {integrity: sha512-LvBTxu8bQSQkcyKOU+a1btnNFQ1dMAd0R6PyW3arXes06F6QLWLIrd681bxRPIXlrMGR3XYnW9JyML7dP3qgxg==}
+  '@babel/helper-annotate-as-pure@7.24.7':
+    resolution: {integrity: sha512-BaDeOonYvhdKw+JoMVkAixAAJzG2jVPIwWoKBPdYuY9b452e2rPuI9QPYh3KpofZ3pW2akOmwZLOiOsHMiqRAg==}
     engines: {node: '>=6.9.0'}
 
-  '@babel/helper-compilation-targets@7.23.6':
-    resolution: {integrity: sha512-9JB548GZoQVmzrFgp8o7KxdgkTGm6xs9DW0o/Pim72UDjzr5ObUQ6ZzYPqA+g9OTS2bBQoctLJrky0RDCAWRgQ==}
+  '@babel/helper-compilation-targets@7.24.7':
+    resolution: {integrity: sha512-ctSdRHBi20qWOfy27RUb4Fhp07KSJ3sXcuSvTrXrc4aG8NSYDo1ici3Vhg9bg69y5bj0Mr1lh0aeEgTvc12rMg==}
     engines: {node: '>=6.9.0'}
 
-  '@babel/helper-create-class-features-plugin@7.24.5':
-    resolution: {integrity: sha512-uRc4Cv8UQWnE4NXlYTIIdM7wfFkOqlFztcC/gVXDKohKoVB3OyonfelUBaJzSwpBntZ2KYGF/9S7asCHsXwW6g==}
+  '@babel/helper-create-class-features-plugin@7.24.7':
+    resolution: {integrity: sha512-kTkaDl7c9vO80zeX1rJxnuRpEsD5tA81yh11X1gQo+PhSti3JS+7qeZo9U4RHobKRiFPKaGK3svUAeb8D0Q7eg==}
     engines: {node: '>=6.9.0'}
     peerDependencies:
       '@babel/core': ^7.0.0
 
-  '@babel/helper-environment-visitor@7.22.20':
-    resolution: {integrity: sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==}
+  '@babel/helper-environment-visitor@7.24.7':
+    resolution: {integrity: sha512-DoiN84+4Gnd0ncbBOM9AZENV4a5ZiL39HYMyZJGZ/AZEykHYdJw0wW3kdcsh9/Kn+BRXHLkkklZ51ecPKmI1CQ==}
     engines: {node: '>=6.9.0'}
 
-  '@babel/helper-function-name@7.23.0':
-    resolution: {integrity: sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==}
+  '@babel/helper-function-name@7.24.7':
+    resolution: {integrity: sha512-FyoJTsj/PEUWu1/TYRiXTIHc8lbw+TDYkZuoE43opPS5TrI7MyONBE1oNvfguEXAD9yhQRrVBnXdXzSLQl9XnA==}
     engines: {node: '>=6.9.0'}
 
-  '@babel/helper-hoist-variables@7.22.5':
-    resolution: {integrity: sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==}
+  '@babel/helper-hoist-variables@7.24.7':
+    resolution: {integrity: sha512-MJJwhkoGy5c4ehfoRyrJ/owKeMl19U54h27YYftT0o2teQ3FJ3nQUf/I3LlJsX4l3qlw7WRXUmiyajvHXoTubQ==}
     engines: {node: '>=6.9.0'}
 
-  '@babel/helper-member-expression-to-functions@7.24.5':
-    resolution: {integrity: sha512-4owRteeihKWKamtqg4JmWSsEZU445xpFRXPEwp44HbgbxdWlUV1b4Agg4lkA806Lil5XM/e+FJyS0vj5T6vmcA==}
+  '@babel/helper-member-expression-to-functions@7.24.7':
+    resolution: {integrity: sha512-LGeMaf5JN4hAT471eJdBs/GK1DoYIJ5GCtZN/EsL6KUiiDZOvO/eKE11AMZJa2zP4zk4qe9V2O/hxAmkRc8p6w==}
     engines: {node: '>=6.9.0'}
 
   '@babel/helper-module-imports@7.22.15':
     resolution: {integrity: sha512-0pYVBnDKZO2fnSPCrgM/6WMc7eS20Fbok+0r88fp+YtWVLZrp4CkafFGIp+W0VKw4a22sgebPT99y+FDNMdP4w==}
     engines: {node: '>=6.9.0'}
 
-  '@babel/helper-module-imports@7.24.3':
-    resolution: {integrity: sha512-viKb0F9f2s0BCS22QSF308z/+1YWKV/76mwt61NBzS5izMzDPwdq1pTrzf+Li3npBWX9KdQbkeCt1jSAM7lZqg==}
+  '@babel/helper-module-imports@7.24.7':
+    resolution: {integrity: sha512-8AyH3C+74cgCVVXow/myrynrAGv+nTVg5vKu2nZph9x7RcRwzmh0VFallJuFTZ9mx6u4eSdXZfcOzSqTUm0HCA==}
     engines: {node: '>=6.9.0'}
 
-  '@babel/helper-module-transforms@7.24.5':
-    resolution: {integrity: sha512-9GxeY8c2d2mdQUP1Dye0ks3VDyIMS98kt/llQ2nUId8IsWqTF0l1LkSX0/uP7l7MCDrzXS009Hyhe2gzTiGW8A==}
+  '@babel/helper-module-transforms@7.24.7':
+    resolution: {integrity: sha512-1fuJEwIrp+97rM4RWdO+qrRsZlAeL1lQJoPqtCYWv0NL115XM93hIH4CSRln2w52SqvmY5hqdtauB6QFCDiZNQ==}
     engines: {node: '>=6.9.0'}
     peerDependencies:
       '@babel/core': ^7.0.0
 
-  '@babel/helper-optimise-call-expression@7.22.5':
-    resolution: {integrity: sha512-HBwaojN0xFRx4yIvpwGqxiV2tUfl7401jlok564NgB9EHS1y6QT17FmKWm4ztqjeVdXLuC4fSvHc5ePpQjoTbw==}
+  '@babel/helper-optimise-call-expression@7.24.7':
+    resolution: {integrity: sha512-jKiTsW2xmWwxT1ixIdfXUZp+P5yURx2suzLZr5Hi64rURpDYdMW0pv+Uf17EYk2Rd428Lx4tLsnjGJzYKDM/6A==}
     engines: {node: '>=6.9.0'}
 
-  '@babel/helper-plugin-utils@7.24.5':
-    resolution: {integrity: sha512-xjNLDopRzW2o6ba0gKbkZq5YWEBaK3PCyTOY1K2P/O07LGMhMqlMXPxwN4S5/RhWuCobT8z0jrlKGlYmeR1OhQ==}
+  '@babel/helper-plugin-utils@7.24.7':
+    resolution: {integrity: sha512-Rq76wjt7yz9AAc1KnlRKNAi/dMSVWgDRx43FHoJEbcYU6xOWaE2dVPwcdTukJrjxS65GITyfbvEYHvkirZ6uEg==}
     engines: {node: '>=6.9.0'}
 
-  '@babel/helper-replace-supers@7.24.1':
-    resolution: {integrity: sha512-QCR1UqC9BzG5vZl8BMicmZ28RuUBnHhAMddD8yHFHDRH9lLTZ9uUPehX8ctVPT8l0TKblJidqcgUUKGVrePleQ==}
+  '@babel/helper-replace-supers@7.24.7':
+    resolution: {integrity: sha512-qTAxxBM81VEyoAY0TtLrx1oAEJc09ZK67Q9ljQToqCnA+55eNwCORaxlKyu+rNfX86o8OXRUSNUnrtsAZXM9sg==}
     engines: {node: '>=6.9.0'}
     peerDependencies:
       '@babel/core': ^7.0.0
 
-  '@babel/helper-simple-access@7.24.5':
-    resolution: {integrity: sha512-uH3Hmf5q5n7n8mz7arjUlDOCbttY/DW4DYhE6FUsjKJ/oYC1kQQUvwEQWxRwUpX9qQKRXeqLwWxrqilMrf32sQ==}
+  '@babel/helper-simple-access@7.24.7':
+    resolution: {integrity: sha512-zBAIvbCMh5Ts+b86r/CjU+4XGYIs+R1j951gxI3KmmxBMhCg4oQMsv6ZXQ64XOm/cvzfU1FmoCyt6+owc5QMYg==}
     engines: {node: '>=6.9.0'}
 
-  '@babel/helper-skip-transparent-expression-wrappers@7.22.5':
-    resolution: {integrity: sha512-tK14r66JZKiC43p8Ki33yLBVJKlQDFoA8GYN67lWCDCqoL6EMMSuM9b+Iff2jHaM/RRFYl7K+iiru7hbRqNx8Q==}
+  '@babel/helper-skip-transparent-expression-wrappers@7.24.7':
+    resolution: {integrity: sha512-IO+DLT3LQUElMbpzlatRASEyQtfhSE0+m465v++3jyyXeBTBUjtVZg28/gHeV5mrTJqvEKhKroBGAvhW+qPHiQ==}
     engines: {node: '>=6.9.0'}
 
-  '@babel/helper-split-export-declaration@7.24.5':
-    resolution: {integrity: sha512-5CHncttXohrHk8GWOFCcCl4oRD9fKosWlIRgWm4ql9VYioKm52Mk2xsmoohvm7f3JoiLSM5ZgJuRaf5QZZYd3Q==}
+  '@babel/helper-split-export-declaration@7.24.7':
+    resolution: {integrity: sha512-oy5V7pD+UvfkEATUKvIjvIAH/xCzfsFVw7ygW2SI6NClZzquT+mwdTfgfdbUiceh6iQO0CHtCPsyze/MZ2YbAA==}
     engines: {node: '>=6.9.0'}
 
-  '@babel/helper-string-parser@7.24.1':
-    resolution: {integrity: sha512-2ofRCjnnA9y+wk8b9IAREroeUP02KHp431N2mhKniy2yKIDKpbrHv9eXwm8cBeWQYcJmzv5qKCu65P47eCF7CQ==}
+  '@babel/helper-string-parser@7.24.7':
+    resolution: {integrity: sha512-7MbVt6xrwFQbunH2DNQsAP5sTGxfqQtErvBIvIMi6EQnbgUOuVYanvREcmFrOPhoXBrTtjhhP+lW+o5UfK+tDg==}
     engines: {node: '>=6.9.0'}
 
-  '@babel/helper-validator-identifier@7.24.5':
-    resolution: {integrity: sha512-3q93SSKX2TWCG30M2G2kwaKeTYgEUp5Snjuj8qm729SObL6nbtUldAi37qbxkD5gg3xnBio+f9nqpSepGZMvxA==}
+  '@babel/helper-validator-identifier@7.24.7':
+    resolution: {integrity: sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w==}
     engines: {node: '>=6.9.0'}
 
-  '@babel/helper-validator-option@7.23.5':
-    resolution: {integrity: sha512-85ttAOMLsr53VgXkTbkx8oA6YTfT4q7/HzXSLEYmjcSTJPMPQtvq1BD79Byep5xMUYbGRzEpDsjUf3dyp54IKw==}
+  '@babel/helper-validator-option@7.24.7':
+    resolution: {integrity: sha512-yy1/KvjhV/ZCL+SM7hBrvnZJ3ZuT9OuZgIJAGpPEToANvc3iM6iDvBnRjtElWibHU6n8/LPR/EjX9EtIEYO3pw==}
     engines: {node: '>=6.9.0'}
 
-  '@babel/helpers@7.24.5':
-    resolution: {integrity: sha512-CiQmBMMpMQHwM5m01YnrM6imUG1ebgYJ+fAIW4FZe6m4qHTPaRHti+R8cggAwkdz4oXhtO4/K9JWlh+8hIfR2Q==}
+  '@babel/helpers@7.24.7':
+    resolution: {integrity: sha512-NlmJJtvcw72yRJRcnCmGvSi+3jDEg8qFu3z0AFoymmzLx5ERVWyzd9kVXr7Th9/8yIJi2Zc6av4Tqz3wFs8QWg==}
     engines: {node: '>=6.9.0'}
 
-  '@babel/highlight@7.24.5':
-    resolution: {integrity: sha512-8lLmua6AVh/8SLJRRVD6V8p73Hir9w5mJrhE+IPpILG31KKlI9iz5zmBYKcWPS59qSfgP9RaSBQSHHE81WKuEw==}
+  '@babel/highlight@7.24.7':
+    resolution: {integrity: sha512-EStJpq4OuY8xYfhGVXngigBJRWxftKX9ksiGDnmlY3o7B/V7KIAc9X4oiK87uPJSc/vs5L869bem5fhZa8caZw==}
     engines: {node: '>=6.9.0'}
 
-  '@babel/parser@7.24.5':
-    resolution: {integrity: sha512-EOv5IK8arwh3LI47dz1b0tKUb/1uhHAnHJOrjgtQMIpu1uXd9mlFrJg9IUgGUgZ41Ch0K8REPTYpO7B76b4vJg==}
+  '@babel/parser@7.24.7':
+    resolution: {integrity: sha512-9uUYRm6OqQrCqQdG1iCBwBPZgN8ciDBro2nIOFaiRz1/BCxaI7CNvQbDHvsArAC7Tw9Hda/B3U+6ui9u4HWXPw==}
     engines: {node: '>=6.0.0'}
     hasBin: true
 
-  '@babel/plugin-syntax-jsx@7.24.1':
-    resolution: {integrity: sha512-2eCtxZXf+kbkMIsXS4poTvT4Yu5rXiRa+9xGVT56raghjmBTKMpFNc9R4IDiB4emao9eO22Ox7CxuJG7BgExqA==}
+  '@babel/plugin-syntax-jsx@7.24.7':
+    resolution: {integrity: sha512-6ddciUPe/mpMnOKv/U+RSd2vvVy+Yw/JfBB0ZHYjEZt9NLHmCUylNYlsbqCCS1Bffjlb0fCwC9Vqz+sBz6PsiQ==}
     engines: {node: '>=6.9.0'}
     peerDependencies:
       '@babel/core': ^7.0.0-0
 
-  '@babel/plugin-syntax-typescript@7.24.1':
-    resolution: {integrity: sha512-Yhnmvy5HZEnHUty6i++gcfH1/l68AHnItFHnaCv6hn9dNh0hQvvQJsxpi4BMBFN5DLeHBuucT/0DgzXif/OyRw==}
+  '@babel/plugin-syntax-typescript@7.24.7':
+    resolution: {integrity: sha512-c/+fVeJBB0FeKsFvwytYiUD+LBvhHjGSI0g446PRGdSVGZLRNArBUno2PETbAly3tpiNAQR5XaZ+JslxkotsbA==}
     engines: {node: '>=6.9.0'}
     peerDependencies:
       '@babel/core': ^7.0.0-0
 
-  '@babel/plugin-transform-typescript@7.24.5':
-    resolution: {integrity: sha512-E0VWu/hk83BIFUWnsKZ4D81KXjN5L3MobvevOHErASk9IPwKHOkTgvqzvNo1yP/ePJWqqK2SpUR5z+KQbl6NVw==}
+  '@babel/plugin-transform-typescript@7.24.7':
+    resolution: {integrity: sha512-iLD3UNkgx2n/HrjBesVbYX6j0yqn/sJktvbtKKgcaLIQ4bTTQ8obAypc1VpyHPD2y4Phh9zHOaAt8e/L14wCpw==}
     engines: {node: '>=6.9.0'}
     peerDependencies:
       '@babel/core': ^7.0.0-0
 
-  '@babel/template@7.24.0':
-    resolution: {integrity: sha512-Bkf2q8lMB0AFpX0NFEqSbx1OkTHf0f+0j82mkw+ZpzBnkk7e9Ql0891vlfgi+kHwOk8tQjiQHpqh4LaSa0fKEA==}
+  '@babel/template@7.24.7':
+    resolution: {integrity: sha512-jYqfPrU9JTF0PmPy1tLYHW4Mp4KlgxJD9l2nP9fD6yT/ICi554DmrWBAEYpIelzjHf1msDP3PxJIRt/nFNfBig==}
     engines: {node: '>=6.9.0'}
 
-  '@babel/traverse@7.24.5':
-    resolution: {integrity: sha512-7aaBLeDQ4zYcUFDUD41lJc1fG8+5IU9DaNSJAgal866FGvmD5EbWQgnEC6kO1gGLsX0esNkfnJSndbTXA3r7UA==}
+  '@babel/traverse@7.24.7':
+    resolution: {integrity: sha512-yb65Ed5S/QAcewNPh0nZczy9JdYXkkAbIsEo+P7BE7yO3txAY30Y/oPa3QkQ5It3xVG2kpKMg9MsdxZaO31uKA==}
     engines: {node: '>=6.9.0'}
 
-  '@babel/types@7.24.5':
-    resolution: {integrity: sha512-6mQNsaLeXTw0nxYUYu+NSa4Hx4BlF1x1x8/PMFbiR+GBSr+2DkECc69b8hgy2frEodNcvPffeH8YfWd3LI6jhQ==}
+  '@babel/types@7.24.7':
+    resolution: {integrity: sha512-XEFXSlxiG5td2EJRe8vOmRbaXVgfcBlszKujvVmWIK/UpywWljQCfzAv3RQCGujWQ1RD4YYWEAqDXfuJiy8f5Q==}
     engines: {node: '>=6.9.0'}
 
   '@bcoe/v8-coverage@0.2.3':
@@ -556,8 +556,8 @@ packages:
   '@dabh/diagnostics@2.0.3':
     resolution: {integrity: sha512-hrlQOIi7hAfzsMqlGSFyVucrx38O+j6wiGOf//H2ecvIEqYN4ADBSS2iLMh5UFyDunCNniUIPk/q3riFv45xRA==}
 
-  '@es-joy/jsdoccomment@0.42.0':
-    resolution: {integrity: sha512-R1w57YlVA6+YE01wch3GPYn6bCsrOV3YW/5oGGE2tmX6JcL9Nr+b5IikrjMPF+v9CV3ay+obImEdsDhovhJrzw==}
+  '@es-joy/jsdoccomment@0.43.1':
+    resolution: {integrity: sha512-I238eDtOolvCuvtxrnqtlBaw0BwdQuYqK7eA6XIonicMdOOOb75mqdIzkGDUbS04+1Di007rgm9snFRNeVrOog==}
     engines: {node: '>=16'}
 
   '@esbuild/aix-ppc64@0.20.2':
@@ -566,8 +566,8 @@ packages:
     cpu: [ppc64]
     os: [aix]
 
-  '@esbuild/aix-ppc64@0.21.0':
-    resolution: {integrity: sha512-kB8I77Onff4y6hAREwsjF11ifM+xi8bBIq/viMO5NFZDX2vKlF0/mevHJYb4sNfb55jIREeUztkUfIgOFtSzdw==}
+  '@esbuild/aix-ppc64@0.21.4':
+    resolution: {integrity: sha512-Zrm+B33R4LWPLjDEVnEqt2+SLTATlru1q/xYKVn8oVTbiRBGmK2VIMoIYGJDGyftnGaC788IuzGFAlb7IQ0Y8A==}
     engines: {node: '>=12'}
     cpu: [ppc64]
     os: [aix]
@@ -578,8 +578,8 @@ packages:
     cpu: [arm64]
     os: [android]
 
-  '@esbuild/android-arm64@0.21.0':
-    resolution: {integrity: sha512-SDGbrIOL6P6WTIbDcCa2sbFgznp8o6ztjGWrA+js8JZ9HhBXavN3gPrEqUqB4+bV4AdsqlZG1tK2F06BOPNpZg==}
+  '@esbuild/android-arm64@0.21.4':
+    resolution: {integrity: sha512-fYFnz+ObClJ3dNiITySBUx+oNalYUT18/AryMxfovLkYWbutXsct3Wz2ZWAcGGppp+RVVX5FiXeLYGi97umisA==}
     engines: {node: '>=12'}
     cpu: [arm64]
     os: [android]
@@ -590,8 +590,8 @@ packages:
     cpu: [arm]
     os: [android]
 
-  '@esbuild/android-arm@0.21.0':
-    resolution: {integrity: sha512-8OvDALSbmoLJ79KCs0hxoki5I3qJA7JQMhJO6aq5O8G+pi7TPnGICdQRQcgdzwZaVc4ptp5SX7Phg6jKzvSEBg==}
+  '@esbuild/android-arm@0.21.4':
+    resolution: {integrity: sha512-E7H/yTd8kGQfY4z9t3nRPk/hrhaCajfA3YSQSBrst8B+3uTcgsi8N+ZWYCaeIDsiVs6m65JPCaQN/DxBRclF3A==}
     engines: {node: '>=12'}
     cpu: [arm]
     os: [android]
@@ -602,8 +602,8 @@ packages:
     cpu: [x64]
     os: [android]
 
-  '@esbuild/android-x64@0.21.0':
-    resolution: {integrity: sha512-G4fkcHqDtIbiE9b3KFJP+ay+TiCOHmenT5GYVi0fuHxFbX0CJ3lpTQbFuWR5s5AlYZZ1j4yY2hbggSUkaBK0pg==}
+  '@esbuild/android-x64@0.21.4':
+    resolution: {integrity: sha512-mDqmlge3hFbEPbCWxp4fM6hqq7aZfLEHZAKGP9viq9wMUBVQx202aDIfc3l+d2cKhUJM741VrCXEzRFhPDKH3Q==}
     engines: {node: '>=12'}
     cpu: [x64]
     os: [android]
@@ -614,8 +614,8 @@ packages:
     cpu: [arm64]
     os: [darwin]
 
-  '@esbuild/darwin-arm64@0.21.0':
-    resolution: {integrity: sha512-XMcLA6siz67AoEOl8WOot2Y3TOSClT15AqJdQz/sx98Dpv3oTbcv0BoqvHAhpBPgC8iyIKM98vVj6th7lA4DFg==}
+  '@esbuild/darwin-arm64@0.21.4':
+    resolution: {integrity: sha512-72eaIrDZDSiWqpmCzVaBD58c8ea8cw/U0fq/PPOTqE3c53D0xVMRt2ooIABZ6/wj99Y+h4ksT/+I+srCDLU9TA==}
     engines: {node: '>=12'}
     cpu: [arm64]
     os: [darwin]
@@ -626,8 +626,8 @@ packages:
     cpu: [x64]
     os: [darwin]
 
-  '@esbuild/darwin-x64@0.21.0':
-    resolution: {integrity: sha512-+dmvTVqVkAArjJyIbo4Rl2S4I4A/yRuivTPR9Igw0QMBVSJegJqixKxZvKLCh8xi6n8tePdq3EpfbFYH2KNNiw==}
+  '@esbuild/darwin-x64@0.21.4':
+    resolution: {integrity: sha512-uBsuwRMehGmw1JC7Vecu/upOjTsMhgahmDkWhGLWxIgUn2x/Y4tIwUZngsmVb6XyPSTXJYS4YiASKPcm9Zitag==}
     engines: {node: '>=12'}
     cpu: [x64]
     os: [darwin]
@@ -638,8 +638,8 @@ packages:
     cpu: [arm64]
     os: [freebsd]
 
-  '@esbuild/freebsd-arm64@0.21.0':
-    resolution: {integrity: sha512-g8/wBRLbsjryMBo4PGg050I1fn4qrJobkxpT1OekO6I4H2HVQfVfBAvGPhwzc9tr8CUVu0pSGSz9oDPGIjhLNw==}
+  '@esbuild/freebsd-arm64@0.21.4':
+    resolution: {integrity: sha512-8JfuSC6YMSAEIZIWNL3GtdUT5NhUA/CMUCpZdDRolUXNAXEE/Vbpe6qlGLpfThtY5NwXq8Hi4nJy4YfPh+TwAg==}
     engines: {node: '>=12'}
     cpu: [arm64]
     os: [freebsd]
@@ -650,8 +650,8 @@ packages:
     cpu: [x64]
     os: [freebsd]
 
-  '@esbuild/freebsd-x64@0.21.0':
-    resolution: {integrity: sha512-uwRL7kSN9tfFBpa7o9HQjEgxPsQsSmOz2ALQ30dxMNT22xS49s8nUtFi7bJ+kM/pcTHcnhyJwJPCY7cwlbQbWQ==}
+  '@esbuild/freebsd-x64@0.21.4':
+    resolution: {integrity: sha512-8d9y9eQhxv4ef7JmXny7591P/PYsDFc4+STaxC1GBv0tMyCdyWfXu2jBuqRsyhY8uL2HU8uPyscgE2KxCY9imQ==}
     engines: {node: '>=12'}
     cpu: [x64]
     os: [freebsd]
@@ -662,8 +662,8 @@ packages:
     cpu: [arm64]
     os: [linux]
 
-  '@esbuild/linux-arm64@0.21.0':
-    resolution: {integrity: sha512-mgOuJBbV8Uexb3BmeVl1q2preJMu0aDiwiFxIfsQhE2+rqxVAEcIrllb7SulkH9G244O/ZN1VVILdZb2NPSvpw==}
+  '@esbuild/linux-arm64@0.21.4':
+    resolution: {integrity: sha512-/GLD2orjNU50v9PcxNpYZi+y8dJ7e7/LhQukN3S4jNDXCKkyyiyAz9zDw3siZ7Eh1tRcnCHAo/WcqKMzmi4eMQ==}
     engines: {node: '>=12'}
     cpu: [arm64]
     os: [linux]
@@ -674,8 +674,8 @@ packages:
     cpu: [arm]
     os: [linux]
 
-  '@esbuild/linux-arm@0.21.0':
-    resolution: {integrity: sha512-8s/YeLaUV3QTaGzwDqiTpb78Nw/DdIaUdIlRZItGgWf/8UZHsYUIWj9RfsEXVJB5qvtrg835Dgz/gf+GmFGa7w==}
+  '@esbuild/linux-arm@0.21.4':
+    resolution: {integrity: sha512-2rqFFefpYmpMs+FWjkzSgXg5vViocqpq5a1PSRgT0AvSgxoXmGF17qfGAzKedg6wAwyM7UltrKVo9kxaJLMF/g==}
     engines: {node: '>=12'}
     cpu: [arm]
     os: [linux]
@@ -686,8 +686,8 @@ packages:
     cpu: [ia32]
     os: [linux]
 
-  '@esbuild/linux-ia32@0.21.0':
-    resolution: {integrity: sha512-7pVhVYBt3/R8x0Um9p4V8eMiQcnk6/IHkOo6tkfLnDqPn+NS6lnbfWysAYeDAqFKt6INQKtVxejh6ccbVYLBwQ==}
+  '@esbuild/linux-ia32@0.21.4':
+    resolution: {integrity: sha512-pNftBl7m/tFG3t2m/tSjuYeWIffzwAZT9m08+9DPLizxVOsUl8DdFzn9HvJrTQwe3wvJnwTdl92AonY36w/25g==}
     engines: {node: '>=12'}
     cpu: [ia32]
     os: [linux]
@@ -698,8 +698,8 @@ packages:
     cpu: [loong64]
     os: [linux]
 
-  '@esbuild/linux-loong64@0.21.0':
-    resolution: {integrity: sha512-P8Lse7CXV83ARWVaq6KwV6w86ABeViyUvw6s++tYsUuqUEZgG5697Un72usafkuD7AfOyBdFX6JqZSvIQAU0yQ==}
+  '@esbuild/linux-loong64@0.21.4':
+    resolution: {integrity: sha512-cSD2gzCK5LuVX+hszzXQzlWya6c7hilO71L9h4KHwqI4qeqZ57bAtkgcC2YioXjsbfAv4lPn3qe3b00Zt+jIfQ==}
     engines: {node: '>=12'}
     cpu: [loong64]
     os: [linux]
@@ -710,8 +710,8 @@ packages:
     cpu: [mips64el]
     os: [linux]
 
-  '@esbuild/linux-mips64el@0.21.0':
-    resolution: {integrity: sha512-lUvMkXlUMrx5vnspMWohma6vuWh+Z/mPV6DdbXW07fNgF2Tlg6SLSqqzDXv5XYV4og5awNFYcPXpgqOVsqdx7Q==}
+  '@esbuild/linux-mips64el@0.21.4':
+    resolution: {integrity: sha512-qtzAd3BJh7UdbiXCrg6npWLYU0YpufsV9XlufKhMhYMJGJCdfX/G6+PNd0+v877X1JG5VmjBLUiFB0o8EUSicA==}
     engines: {node: '>=12'}
     cpu: [mips64el]
     os: [linux]
@@ -722,8 +722,8 @@ packages:
     cpu: [ppc64]
     os: [linux]
 
-  '@esbuild/linux-ppc64@0.21.0':
-    resolution: {integrity: sha512-wLi9VRnLDRg1Gudic24gcT5aa5LZGBwLi4aYghQ9bVb8z0qYHrZnRTNxulErFvOsSgijUWS5uNLCUaLwj+tvIQ==}
+  '@esbuild/linux-ppc64@0.21.4':
+    resolution: {integrity: sha512-yB8AYzOTaL0D5+2a4xEy7OVvbcypvDR05MsB/VVPVA7nL4hc5w5Dyd/ddnayStDgJE59fAgNEOdLhBxjfx5+dg==}
     engines: {node: '>=12'}
     cpu: [ppc64]
     os: [linux]
@@ -734,8 +734,8 @@ packages:
     cpu: [riscv64]
     os: [linux]
 
-  '@esbuild/linux-riscv64@0.21.0':
-    resolution: {integrity: sha512-MOjonqpNtns0Y32NwvMZiZXw94g8EqeqI+4BQtIHj07xX61vOyqlBsJH3UbjkWvaewie1VP9IoiX2Ja/P2XCJw==}
+  '@esbuild/linux-riscv64@0.21.4':
+    resolution: {integrity: sha512-Y5AgOuVzPjQdgU59ramLoqSSiXddu7F3F+LI5hYy/d1UHN7K5oLzYBDZe23QmQJ9PIVUXwOdKJ/jZahPdxzm9w==}
     engines: {node: '>=12'}
     cpu: [riscv64]
     os: [linux]
@@ -746,8 +746,8 @@ packages:
     cpu: [s390x]
     os: [linux]
 
-  '@esbuild/linux-s390x@0.21.0':
-    resolution: {integrity: sha512-Gz/gafubuM3L1D29LnqaxcGg16aa2XES/uFTFdcvrwsRpMxkLiowaUvIiWJfatf/oCyyZu5CT8SrlMy37dGc7A==}
+  '@esbuild/linux-s390x@0.21.4':
+    resolution: {integrity: sha512-Iqc/l/FFwtt8FoTK9riYv9zQNms7B8u+vAI/rxKuN10HgQIXaPzKZc479lZ0x6+vKVQbu55GdpYpeNWzjOhgbA==}
     engines: {node: '>=12'}
     cpu: [s390x]
     os: [linux]
@@ -758,8 +758,8 @@ packages:
     cpu: [x64]
     os: [linux]
 
-  '@esbuild/linux-x64@0.21.0':
-    resolution: {integrity: sha512-OGorpObKLm8XlhoJlxtdwECfnESXu3kd8mU1yZ5Xk0vmh0d2xoJjEXJi7y7mjFpc3+XfGQRgHq/gqyIkbufnvA==}
+  '@esbuild/linux-x64@0.21.4':
+    resolution: {integrity: sha512-Td9jv782UMAFsuLZINfUpoF5mZIbAj+jv1YVtE58rFtfvoKRiKSkRGQfHTgKamLVT/fO7203bHa3wU122V/Bdg==}
     engines: {node: '>=12'}
     cpu: [x64]
     os: [linux]
@@ -770,8 +770,8 @@ packages:
     cpu: [x64]
     os: [netbsd]
 
-  '@esbuild/netbsd-x64@0.21.0':
-    resolution: {integrity: sha512-AwkJoff9D5Px7+lHafSSgDK3JreyeyPtwTsOfxhlk5NZ+bMGlvSfHkA6DKv9vD0gmGrBPTMv/uIePkNaVsDq7w==}
+  '@esbuild/netbsd-x64@0.21.4':
+    resolution: {integrity: sha512-Awn38oSXxsPMQxaV0Ipb7W/gxZtk5Tx3+W+rAPdZkyEhQ6968r9NvtkjhnhbEgWXYbgV+JEONJ6PcdBS+nlcpA==}
     engines: {node: '>=12'}
     cpu: [x64]
     os: [netbsd]
@@ -782,8 +782,8 @@ packages:
     cpu: [x64]
     os: [openbsd]
 
-  '@esbuild/openbsd-x64@0.21.0':
-    resolution: {integrity: sha512-wqv7KSmRA4qf0lFZ2Abjp2boO9tDe7YwNLZ7DNUI5rsluS0/TF78CtPUUAePukgE6b2HcXYZYuL5F2yXdQIqIg==}
+  '@esbuild/openbsd-x64@0.21.4':
+    resolution: {integrity: sha512-IsUmQeCY0aU374R82fxIPu6vkOybWIMc3hVGZ3ChRwL9hA1TwY+tS0lgFWV5+F1+1ssuvvXt3HFqe8roCip8Hg==}
     engines: {node: '>=12'}
     cpu: [x64]
     os: [openbsd]
@@ -794,8 +794,8 @@ packages:
     cpu: [x64]
     os: [sunos]
 
-  '@esbuild/sunos-x64@0.21.0':
-    resolution: {integrity: sha512-3qAZFC752nZZQOI+OG4KIawvLfdD5yMFCeIFz0OhedMpYgq9AOKygW45Ojy0E5upBqns2fUaMFk1CnNSkvJaYw==}
+  '@esbuild/sunos-x64@0.21.4':
+    resolution: {integrity: sha512-hsKhgZ4teLUaDA6FG/QIu2q0rI6I36tZVfM4DBZv3BG0mkMIdEnMbhc4xwLvLJSS22uWmaVkFkqWgIS0gPIm+A==}
     engines: {node: '>=12'}
     cpu: [x64]
     os: [sunos]
@@ -806,8 +806,8 @@ packages:
     cpu: [arm64]
     os: [win32]
 
-  '@esbuild/win32-arm64@0.21.0':
-    resolution: {integrity: sha512-06BY4wjQQ2bPjayuvKWXr5X3V+ZGnoTOX1+doLoQBUSyCDb9JZgX7o0N3t3rRNmEiMY/DuxXwu+EE+U32B4ErA==}
+  '@esbuild/win32-arm64@0.21.4':
+    resolution: {integrity: sha512-UUfMgMoXPoA/bvGUNfUBFLCh0gt9dxZYIx9W4rfJr7+hKe5jxxHmfOK8YSH4qsHLLN4Ck8JZ+v7Q5fIm1huErg==}
     engines: {node: '>=12'}
     cpu: [arm64]
     os: [win32]
@@ -818,8 +818,8 @@ packages:
     cpu: [ia32]
     os: [win32]
 
-  '@esbuild/win32-ia32@0.21.0':
-    resolution: {integrity: sha512-uTLz9mPOMkl3bfuGnSQumrUN7U1aPb8MCOdjQJOWPGdXTZhkK6Z2lLHxdTjX6C51jxXWWAo64tcRwiAYOkQhJw==}
+  '@esbuild/win32-ia32@0.21.4':
+    resolution: {integrity: sha512-yIxbspZb5kGCAHWm8dexALQ9en1IYDfErzjSEq1KzXFniHv019VT3mNtTK7t8qdy4TwT6QYHI9sEZabONHg+aw==}
     engines: {node: '>=12'}
     cpu: [ia32]
     os: [win32]
@@ -830,8 +830,8 @@ packages:
     cpu: [x64]
     os: [win32]
 
-  '@esbuild/win32-x64@0.21.0':
-    resolution: {integrity: sha512-XT0oCVNRjmrMTz/Xd+9L2eOI83gUQZg9Viiv3cuT/8VNlXVMn6QsxyBMDNFsYX+wmQRD31VMKNtkZaXvS3/JiA==}
+  '@esbuild/win32-x64@0.21.4':
+    resolution: {integrity: sha512-sywLRD3UK/qRJt0oBwdpYLBibk7KiRfbswmWRDabuncQYSlf8aLEEUor/oP6KRz8KEG+HoiVLBhPRD5JWjS8Sg==}
     engines: {node: '>=12'}
     cpu: [x64]
     os: [win32]
@@ -842,8 +842,8 @@ packages:
     peerDependencies:
       eslint: ^6.0.0 || ^7.0.0 || >=8.0.0
 
-  '@eslint-community/regexpp@4.10.0':
-    resolution: {integrity: sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA==}
+  '@eslint-community/regexpp@4.10.1':
+    resolution: {integrity: sha512-Zm2NGpWELsQAD1xsJzGQpYfvICSsFkEpU0jxBjfdC6uNEWXcHnfs9hScFWtXVDVl+rBQJGrl4g1vcKIejpH9dA==}
     engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0}
 
   '@eslint/eslintrc@2.1.4':
@@ -871,8 +871,8 @@ packages:
   '@iarna/toml@2.2.5':
     resolution: {integrity: sha512-trnsAYxU3xnS1gPHPyU961coFyLkh4gAD/0zQ5mymY4yOZ+CYvsPqUbOFSw0aDM4y0tV7tiFxL/1XfXPNC6IPg==}
 
-  '@inquirer/figures@1.0.1':
-    resolution: {integrity: sha512-mtup3wVKia3ZwULPHcbs4Mor8Voi+iIXEWD7wCNbIO6lYR62oPCTQyrddi5OMYVXHzeCSoneZwJuS8sBvlEwDw==}
+  '@inquirer/figures@1.0.3':
+    resolution: {integrity: sha512-ErXXzENMH5pJt5/ssXV0DfWUZqly8nGzf0UcBV9xTnP+KyffE2mqyxIMBrZ8ijQck2nU0TQm40EQB53YreyWHw==}
     engines: {node: '>=18'}
 
   '@isaacs/cliui@8.0.2':
@@ -927,47 +927,57 @@ packages:
     resolution: {integrity: sha512-/gKJun8NNiWGZJkGzI/Ragc53cOdcLNdzjLaIa+GEjguQs0ulsurx8WN0jijdK9yPqDvziX995sMRLyLt1uZMQ==}
     engines: {node: '>= 0.4'}
 
-  '@microsoft/tsdoc-config@0.16.2':
-    resolution: {integrity: sha512-OGiIzzoBLgWWR0UdRJX98oYO+XKGf7tiK4Zk6tQ/E4IJqGCe7dvkTvgDZV5cFJUzLGDOjeAXrnZoA6QkVySuxw==}
+  '@microsoft/tsdoc-config@0.17.0':
+    resolution: {integrity: sha512-v/EYRXnCAIHxOHW+Plb6OWuUoMotxTN0GLatnpOb1xq0KuTNw/WI3pamJx/UbsoJP5k9MCw1QxvvhPcF9pH3Zg==}
 
-  '@microsoft/tsdoc@0.14.2':
-    resolution: {integrity: sha512-9b8mPpKrfeGRuhFH5iO1iwCLeIIsV6+H1sRfxbkoGXIyQE2BTsPd9zqSqQJ+pv5sJ/hT5M1zvOFL02MnEezFug==}
+  '@microsoft/tsdoc@0.15.0':
+    resolution: {integrity: sha512-HZpPoABogPvjeJOdzCOSJsXeL/SMCBgBZMVC3X3d7YYp2gf31MfxhUoYUNwf1ERPJOnQc0wkFn9trqI6ZEdZuA==}
 
-  '@mikro-orm/cli@6.2.5':
-    resolution: {integrity: sha512-1DKde27pB0EDvJF2srRn8JmaukKh8ea+UI1AkjHNK9+owgx5BrszrYxMl60UTqUfBpt08+Krblnis7mok/OJ6w==}
+  '@mikro-orm/cli@6.2.9':
+    resolution: {integrity: sha512-9eW9ZSzdO03KBkUn5Q0OxWBv/2RrKDwOabW2FKzuWslOY3ZBX+k+e8eP6a/+T8GeGGD/uqj8xVZSgM2DuGGqrw==}
     engines: {node: '>= 18.12.0'}
     hasBin: true
 
-  '@mikro-orm/core@6.2.5':
-    resolution: {integrity: sha512-KZvirbAoFNjR/Sx30Jr7j6y5oEofNr13llPvCPUQlWQzHrFXedU1Td5AtVeBkOzp7f5FDBSv/a/wMRXqyqkrcA==}
+  '@mikro-orm/core@6.2.9':
+    resolution: {integrity: sha512-fzeg8qNwNr0f9embDhs0L75EBC8ivIOsK1GGPXe48Ab+P0Vmv1qCskSP7/vNDsz4s1xDu0h0l6fIsv1N7j4jKQ==}
     engines: {node: '>= 18.12.0'}
 
-  '@mikro-orm/knex@6.2.5':
-    resolution: {integrity: sha512-PNKzclHk21Yx4dlfoTttUCOSAqj32WSSdY4G+mxpukTtIgSc/iFd8OpkJ+x/c9tfs27o3ZyBRQRxDoC6fMA4hQ==}
+  '@mikro-orm/knex@6.2.9':
+    resolution: {integrity: sha512-eSHPiS5em+RGv/jx5lP7a1xDVVlnrG+l90/7N7WAgTGcPOzyILVw9EJOZl2KR8dh8EfPI6Wm35Lo4qkO2LoDUg==}
     engines: {node: '>= 18.12.0'}
     peerDependencies:
       '@mikro-orm/core': ^6.0.0
+      better-sqlite3: '*'
+      libsql: '*'
+      mariadb: '*'
+    peerDependenciesMeta:
+      better-sqlite3:
+        optional: true
+      libsql:
+        optional: true
+      mariadb:
+        optional: true
 
-  '@mikro-orm/mariadb@6.2.5':
-    resolution: {integrity: sha512-Bv7BOp3OsXPFOU/7qDodBOREe6//SQ7EeG8p1KhTINasUR2pQML0TOzfl7C9PgHrldIElYi9k2hIKyvNWRQsHg==}
+  '@mikro-orm/mariadb@6.2.9':
+    resolution: {integrity: sha512-V+wJ0bjX8clO64j0gRcvAZdl5FV2EJElHpn/x779/T5CuAratF68elEkKJNfqCPB6bbAPb6qrzvcI+szgjB23A==}
     engines: {node: '>= 18.12.0'}
     peerDependencies:
       '@mikro-orm/core': ^6.0.0
 
-  '@mikro-orm/reflection@6.2.5':
-    resolution: {integrity: sha512-PHRz0BRX3OGjVxe6YzWGEG3xFF6mkaLrmaV40pfyxy2vNh0P8LQkNIFfRqk4PWbpI8yNbANEeQ9TtrtYAsmQ1g==}
+  '@mikro-orm/reflection@6.2.9':
+    resolution: {integrity: sha512-JkdQnEohwngC1LiNNB+tt0ReDiCMlTAJA4/n5N4+tdSv8aspgrIX8ARgB2a6IjgWwes7xIkJJ1nb5tWdFwPSmA==}
     engines: {node: '>= 18.12.0'}
     peerDependencies:
       '@mikro-orm/core': ^6.0.0
 
-  '@mikro-orm/sqlite@6.2.5':
-    resolution: {integrity: sha512-dZVYm1gBO2Ja77SDk1bLLQRfy96QSvz4GdjN7Ap5bcuM5HcGHneM7adn5Tzq1oW0ihbfSpqXzyoynPaWgmC89A==}
+  '@mikro-orm/sqlite@6.2.9':
+    resolution: {integrity: sha512-+ZdlKEtE8HmqbZWSm44MaZwfeS1AlrhMJrZfRr5tQfvdKi5VuRQ+I87Uxo03Ni5r0JXV1wEfFyWovK5c6h1iCQ==}
     engines: {node: '>= 18.12.0'}
     peerDependencies:
       '@mikro-orm/core': ^6.0.0
 
-  '@mongodb-js/saslprep@1.1.6':
-    resolution: {integrity: sha512-jqTTXQ46H8cAxmXBu8wm1HTSIMBMrIcoVrsjdQkKdMBj3il/fSCgWyya4P2I1xjPBl69mw+nRphrPlcIqBd20Q==}
+  '@mongodb-js/saslprep@1.1.7':
+    resolution: {integrity: sha512-dCHW/oEX0KJ4NjDULBo3JiOaK5+6axtpBbS+ao2ZInoAL9/YRQLhXzSNAFz7hP4nzLkIqsfYAK/PDE3+XHny0Q==}
 
   '@nearform/heap-profiler@2.0.0':
     resolution: {integrity: sha512-846CWyq3Ky5rzcl8Z3S+VT3z6GQSlYD1G/dqbtANu29NUHoCO+W7tOZRK6eA6FjLHnNX0DvP1Mrt2oFBPnkxLw==}
@@ -1009,14 +1019,11 @@ packages:
     resolution: {integrity: sha512-r+oZUH7aMFui1ypZnAvZmn0KSqAUgE1/tUXIWaqUCa1758ts/Jio84GZuzsvUkme98kv0WFY8//n0J1Z+vsIsQ==}
     engines: {node: '>= 18'}
 
-  '@octokit/openapi-types@20.0.0':
-    resolution: {integrity: sha512-EtqRBEjp1dL/15V7WiX5LJMIxxkdiGJnabzYx5Apx4FkQIFgAfKumXeYAqqJCj1s+BMX4cPFIFC4OLCR6stlnA==}
-
   '@octokit/openapi-types@22.2.0':
     resolution: {integrity: sha512-QBhVjcUa9W7Wwhm6DBFu6ZZ+1/t/oYxqc2tp81Pi41YNuJinbFRx8B133qVOrAaBbF7D/m0Et6f9/pZt9Rc+tg==}
 
-  '@octokit/plugin-paginate-rest@9.2.1':
-    resolution: {integrity: sha512-wfGhE/TAkXZRLjksFXuDZdmGnJQHvtU/joFQdweXUgzo1XwvBCD4o4+75NtFfjfLK5IwLf9vHTfSiU3sLRYpRw==}
+  '@octokit/plugin-paginate-rest@11.3.1':
+    resolution: {integrity: sha512-ryqobs26cLtM1kQxqeZui4v8FeznirUsksiA+RYemMPJ7Micju0WSkv50dBksTuZks9O5cg4wp+t8fZ/cLY56g==}
     engines: {node: '>= 18'}
     peerDependencies:
       '@octokit/core': '5'
@@ -1027,11 +1034,11 @@ packages:
     peerDependencies:
       '@octokit/core': '5'
 
-  '@octokit/plugin-rest-endpoint-methods@10.4.1':
-    resolution: {integrity: sha512-xV1b+ceKV9KytQe3zCVqjg+8GTGfDYwaT1ATU5isiUyVtlVAO3HNdzpS4sr4GBx4hxQ46s7ITtZrAsxG22+rVg==}
+  '@octokit/plugin-rest-endpoint-methods@13.2.2':
+    resolution: {integrity: sha512-EI7kXWidkt3Xlok5uN43suK99VWqc8OaIMktY9d9+RNKl69juoTyxmLoWPIZgJYzi41qj/9zU7G/ljnNOJ5AFA==}
     engines: {node: '>= 18'}
     peerDependencies:
-      '@octokit/core': '5'
+      '@octokit/core': ^5
 
   '@octokit/request-error@5.1.0':
     resolution: {integrity: sha512-GETXfE05J0+7H2STzekpKObFe765O5dlAKUTLNGeH+x47z7JjXHfsHKo5z21D/o/IOZTUEI6nyWyR+bZVP/n5Q==}
@@ -1041,13 +1048,10 @@ packages:
     resolution: {integrity: sha512-9Bb014e+m2TgBeEJGEbdplMVWwPmL1FPtggHQRkV+WVsMggPtEkLKPlcVYm/o8xKLkpJ7B+6N8WfQMtDLX2Dpw==}
     engines: {node: '>= 18'}
 
-  '@octokit/rest@20.1.0':
-    resolution: {integrity: sha512-STVO3itHQLrp80lvcYB2UIKoeil5Ctsgd2s1AM+du3HqZIR35ZH7WE9HLwUOLXH0myA0y3AGNPo8gZtcgIbw0g==}
+  '@octokit/rest@20.1.1':
+    resolution: {integrity: sha512-MB4AYDsM5jhIHro/dq4ix1iWTLGToIGk6cWF5L6vanFaMble5jTX/UBQyiv05HsWnwUtY8JrfHy2LWfKwihqMw==}
     engines: {node: '>= 18'}
 
-  '@octokit/types@12.6.0':
-    resolution: {integrity: sha512-1rhSOfRa6H9w4YwK0yrf5faDaDTb+yLyBUKOCV4xtCDB5VmIPqd/v9yr9o6SAzOAlRxMiRiCic6JVM1/kunVkw==}
-
   '@octokit/types@13.5.0':
     resolution: {integrity: sha512-HdqWTf5Z3qwDVlzCrP8UJquMwunpDiMPt5er+QjGzL4hqr/vBVY/MauQgS1xWxCDT1oMx1EULyqxncdCY/NVSQ==}
 
@@ -1080,88 +1084,88 @@ packages:
     peerDependencies:
       release-it: ^17.0.0
 
-  '@rollup/rollup-android-arm-eabi@4.17.2':
-    resolution: {integrity: sha512-NM0jFxY8bB8QLkoKxIQeObCaDlJKewVlIEkuyYKm5An1tdVZ966w2+MPQ2l8LBZLjR+SgyV+nRkTIunzOYBMLQ==}
+  '@rollup/rollup-android-arm-eabi@4.18.0':
+    resolution: {integrity: sha512-Tya6xypR10giZV1XzxmH5wr25VcZSncG0pZIjfePT0OVBvqNEurzValetGNarVrGiq66EBVAFn15iYX4w6FKgQ==}
     cpu: [arm]
     os: [android]
 
-  '@rollup/rollup-android-arm64@4.17.2':
-    resolution: {integrity: sha512-yeX/Usk7daNIVwkq2uGoq2BYJKZY1JfyLTaHO/jaiSwi/lsf8fTFoQW/n6IdAsx5tx+iotu2zCJwz8MxI6D/Bw==}
+  '@rollup/rollup-android-arm64@4.18.0':
+    resolution: {integrity: sha512-avCea0RAP03lTsDhEyfy+hpfr85KfyTctMADqHVhLAF3MlIkq83CP8UfAHUssgXTYd+6er6PaAhx/QGv4L1EiA==}
     cpu: [arm64]
     os: [android]
 
-  '@rollup/rollup-darwin-arm64@4.17.2':
-    resolution: {integrity: sha512-kcMLpE6uCwls023+kknm71ug7MZOrtXo+y5p/tsg6jltpDtgQY1Eq5sGfHcQfb+lfuKwhBmEURDga9N0ol4YPw==}
+  '@rollup/rollup-darwin-arm64@4.18.0':
+    resolution: {integrity: sha512-IWfdwU7KDSm07Ty0PuA/W2JYoZ4iTj3TUQjkVsO/6U+4I1jN5lcR71ZEvRh52sDOERdnNhhHU57UITXz5jC1/w==}
     cpu: [arm64]
     os: [darwin]
 
-  '@rollup/rollup-darwin-x64@4.17.2':
-    resolution: {integrity: sha512-AtKwD0VEx0zWkL0ZjixEkp5tbNLzX+FCqGG1SvOu993HnSz4qDI6S4kGzubrEJAljpVkhRSlg5bzpV//E6ysTQ==}
+  '@rollup/rollup-darwin-x64@4.18.0':
+    resolution: {integrity: sha512-n2LMsUz7Ynu7DoQrSQkBf8iNrjOGyPLrdSg802vk6XT3FtsgX6JbE8IHRvposskFm9SNxzkLYGSq9QdpLYpRNA==}
     cpu: [x64]
     os: [darwin]
 
-  '@rollup/rollup-linux-arm-gnueabihf@4.17.2':
-    resolution: {integrity: sha512-3reX2fUHqN7sffBNqmEyMQVj/CKhIHZd4y631duy0hZqI8Qoqf6lTtmAKvJFYa6bhU95B1D0WgzHkmTg33In0A==}
+  '@rollup/rollup-linux-arm-gnueabihf@4.18.0':
+    resolution: {integrity: sha512-C/zbRYRXFjWvz9Z4haRxcTdnkPt1BtCkz+7RtBSuNmKzMzp3ZxdM28Mpccn6pt28/UWUCTXa+b0Mx1k3g6NOMA==}
     cpu: [arm]
     os: [linux]
 
-  '@rollup/rollup-linux-arm-musleabihf@4.17.2':
-    resolution: {integrity: sha512-uSqpsp91mheRgw96xtyAGP9FW5ChctTFEoXP0r5FAzj/3ZRv3Uxjtc7taRQSaQM/q85KEKjKsZuiZM3GyUivRg==}
+  '@rollup/rollup-linux-arm-musleabihf@4.18.0':
+    resolution: {integrity: sha512-l3m9ewPgjQSXrUMHg93vt0hYCGnrMOcUpTz6FLtbwljo2HluS4zTXFy2571YQbisTnfTKPZ01u/ukJdQTLGh9A==}
     cpu: [arm]
     os: [linux]
 
-  '@rollup/rollup-linux-arm64-gnu@4.17.2':
-    resolution: {integrity: sha512-EMMPHkiCRtE8Wdk3Qhtciq6BndLtstqZIroHiiGzB3C5LDJmIZcSzVtLRbwuXuUft1Cnv+9fxuDtDxz3k3EW2A==}
+  '@rollup/rollup-linux-arm64-gnu@4.18.0':
+    resolution: {integrity: sha512-rJ5D47d8WD7J+7STKdCUAgmQk49xuFrRi9pZkWoRD1UeSMakbcepWXPF8ycChBoAqs1pb2wzvbY6Q33WmN2ftw==}
     cpu: [arm64]
     os: [linux]
 
-  '@rollup/rollup-linux-arm64-musl@4.17.2':
-    resolution: {integrity: sha512-NMPylUUZ1i0z/xJUIx6VUhISZDRT+uTWpBcjdv0/zkp7b/bQDF+NfnfdzuTiB1G6HTodgoFa93hp0O1xl+/UbA==}
+  '@rollup/rollup-linux-arm64-musl@4.18.0':
+    resolution: {integrity: sha512-be6Yx37b24ZwxQ+wOQXXLZqpq4jTckJhtGlWGZs68TgdKXJgw54lUUoFYrg6Zs/kjzAQwEwYbp8JxZVzZLRepQ==}
     cpu: [arm64]
     os: [linux]
 
-  '@rollup/rollup-linux-powerpc64le-gnu@4.17.2':
-    resolution: {integrity: sha512-T19My13y8uYXPw/L/k0JYaX1fJKFT/PWdXiHr8mTbXWxjVF1t+8Xl31DgBBvEKclw+1b00Chg0hxE2O7bTG7GQ==}
+  '@rollup/rollup-linux-powerpc64le-gnu@4.18.0':
+    resolution: {integrity: sha512-hNVMQK+qrA9Todu9+wqrXOHxFiD5YmdEi3paj6vP02Kx1hjd2LLYR2eaN7DsEshg09+9uzWi2W18MJDlG0cxJA==}
     cpu: [ppc64]
     os: [linux]
 
-  '@rollup/rollup-linux-riscv64-gnu@4.17.2':
-    resolution: {integrity: sha512-BOaNfthf3X3fOWAB+IJ9kxTgPmMqPPH5f5k2DcCsRrBIbWnaJCgX2ll77dV1TdSy9SaXTR5iDXRL8n7AnoP5cg==}
+  '@rollup/rollup-linux-riscv64-gnu@4.18.0':
+    resolution: {integrity: sha512-ROCM7i+m1NfdrsmvwSzoxp9HFtmKGHEqu5NNDiZWQtXLA8S5HBCkVvKAxJ8U+CVctHwV2Gb5VUaK7UAkzhDjlg==}
     cpu: [riscv64]
     os: [linux]
 
-  '@rollup/rollup-linux-s390x-gnu@4.17.2':
-    resolution: {integrity: sha512-W0UP/x7bnn3xN2eYMql2T/+wpASLE5SjObXILTMPUBDB/Fg/FxC+gX4nvCfPBCbNhz51C+HcqQp2qQ4u25ok6g==}
+  '@rollup/rollup-linux-s390x-gnu@4.18.0':
+    resolution: {integrity: sha512-0UyyRHyDN42QL+NbqevXIIUnKA47A+45WyasO+y2bGJ1mhQrfrtXUpTxCOrfxCR4esV3/RLYyucGVPiUsO8xjg==}
     cpu: [s390x]
     os: [linux]
 
-  '@rollup/rollup-linux-x64-gnu@4.17.2':
-    resolution: {integrity: sha512-Hy7pLwByUOuyaFC6mAr7m+oMC+V7qyifzs/nW2OJfC8H4hbCzOX07Ov0VFk/zP3kBsELWNFi7rJtgbKYsav9QQ==}
+  '@rollup/rollup-linux-x64-gnu@4.18.0':
+    resolution: {integrity: sha512-xuglR2rBVHA5UsI8h8UbX4VJ470PtGCf5Vpswh7p2ukaqBGFTnsfzxUBetoWBWymHMxbIG0Cmx7Y9qDZzr648w==}
     cpu: [x64]
     os: [linux]
 
-  '@rollup/rollup-linux-x64-musl@4.17.2':
-    resolution: {integrity: sha512-h1+yTWeYbRdAyJ/jMiVw0l6fOOm/0D1vNLui9iPuqgRGnXA0u21gAqOyB5iHjlM9MMfNOm9RHCQ7zLIzT0x11Q==}
+  '@rollup/rollup-linux-x64-musl@4.18.0':
+    resolution: {integrity: sha512-LKaqQL9osY/ir2geuLVvRRs+utWUNilzdE90TpyoX0eNqPzWjRm14oMEE+YLve4k/NAqCdPkGYDaDF5Sw+xBfg==}
     cpu: [x64]
     os: [linux]
 
-  '@rollup/rollup-win32-arm64-msvc@4.17.2':
-    resolution: {integrity: sha512-tmdtXMfKAjy5+IQsVtDiCfqbynAQE/TQRpWdVataHmhMb9DCoJxp9vLcCBjEQWMiUYxO1QprH/HbY9ragCEFLA==}
+  '@rollup/rollup-win32-arm64-msvc@4.18.0':
+    resolution: {integrity: sha512-7J6TkZQFGo9qBKH0pk2cEVSRhJbL6MtfWxth7Y5YmZs57Pi+4x6c2dStAUvaQkHQLnEQv1jzBUW43GvZW8OFqA==}
     cpu: [arm64]
     os: [win32]
 
-  '@rollup/rollup-win32-ia32-msvc@4.17.2':
-    resolution: {integrity: sha512-7II/QCSTAHuE5vdZaQEwJq2ZACkBpQDOmQsE6D6XUbnBHW8IAhm4eTufL6msLJorzrHDFv3CF8oCA/hSIRuZeQ==}
+  '@rollup/rollup-win32-ia32-msvc@4.18.0':
+    resolution: {integrity: sha512-Txjh+IxBPbkUB9+SXZMpv+b/vnTEtFyfWZgJ6iyCmt2tdx0OF5WhFowLmnh8ENGNpfUlUZkdI//4IEmhwPieNg==}
     cpu: [ia32]
     os: [win32]
 
-  '@rollup/rollup-win32-x64-msvc@4.17.2':
-    resolution: {integrity: sha512-TGGO7v7qOq4CYmSBVEYpI1Y5xDuCEnbVC5Vth8mOsW0gDSzxNrVERPc790IGHsrT2dQSimgMr9Ub3Y1Jci5/8w==}
+  '@rollup/rollup-win32-x64-msvc@4.18.0':
+    resolution: {integrity: sha512-UOo5FdvOL0+eIVTgS4tIdbW+TtnBLWg1YBCcU2KWM7nuNwRz9bksDX1bekJJCpu25N1DVWaCwnT39dVQxzqS8g==}
     cpu: [x64]
     os: [win32]
 
-  '@rushstack/eslint-patch@1.10.2':
-    resolution: {integrity: sha512-hw437iINopmQuxWPSUEvqE56NCPsiU8N4AYtfHmJFckclktzK9YQJieD3XkDCDH4OjL+C7zgPUh73R/nrcHrqw==}
+  '@rushstack/eslint-patch@1.10.3':
+    resolution: {integrity: sha512-qC/xYId4NMebE6w/V33Fh9gWxLgURiNYgVNObbJl2LZv0GUUItCcCqC5axQSwRaAgaxl2mELq1rMzlswaQ0Zxg==}
 
   '@sinclair/typebox@0.27.8':
     resolution: {integrity: sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==}
@@ -1216,6 +1220,9 @@ packages:
   '@types/conventional-commits-parser@5.0.0':
     resolution: {integrity: sha512-loB369iXNmAZglwWATL+WRe+CRMmmBPtpolYzIebFaX4YA3x+BEfLqhUAV9WanycKI3TG1IMr5bMJDajDKLlUQ==}
 
+  '@types/eslint@8.56.10':
+    resolution: {integrity: sha512-Shavhk87gCtY2fhXDctcfS3e6FdxWkCx1iUZ9eEUbh7rTqlZT0/IzOkCOVt0fCjcFuZ9FPYfuezTBImfHCDBGQ==}
+
   '@types/estree@1.0.5':
     resolution: {integrity: sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==}
 
@@ -1234,8 +1241,8 @@ packages:
   '@types/istanbul-reports@3.0.4':
     resolution: {integrity: sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==}
 
-  '@types/jsdom@21.1.6':
-    resolution: {integrity: sha512-/7kkMsC+/kMs7gAYmmBR9P0vGTnOoLhQhyhQJSlXGI5bzTHp6xdo0TtKWQAsz6pmSAeVqKSbqeyP6hytqr9FDw==}
+  '@types/jsdom@21.1.7':
+    resolution: {integrity: sha512-yOriVnggzrnQ3a9OKOCxaVuSug3w3/SbOj5i7VwXWZEyUNl3bLF9V3MfxGbZKuwqJOQyRfqXyROBB1CoZLFWzA==}
 
   '@types/json-schema@7.0.15':
     resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==}
@@ -1246,8 +1253,8 @@ packages:
   '@types/long@4.0.2':
     resolution: {integrity: sha512-MqTGEo5bj5t157U6fA/BiDynNkn0YknVdh48CMPkTSpFTVmvao5UQmm7uEF6xBEo7qIMAlY/JSleYaE6VOdpaA==}
 
-  '@types/node@20.12.10':
-    resolution: {integrity: sha512-Eem5pH9pmWBHoGAT8Dr5fdc5rYA+4NAovdM4EktRPVAAiJhmWWfQrA0cFhAbOsQdSfIHjAud6YdkbL69+zSKjw==}
+  '@types/node@20.14.2':
+    resolution: {integrity: sha512-xyu6WAMVwv6AKFLB+e/7ySZVr/0zLCzOa7rSpq6jNwpqOrUbcACDWC+53d4n2QHOnDou0fbIsg8wZu/sxrnI4Q==}
 
   '@types/offscreencanvas@2019.3.0':
     resolution: {integrity: sha512-esIJx9bQg+QYF0ra8GnvfianIY8qWB0GBx54PK5Eps6m+xTj86KLavHv6qDhzKcu5UUOgNfJ2pWaIIV7TRUd9Q==}
@@ -1273,8 +1280,8 @@ packages:
   '@types/webidl-conversions@7.0.3':
     resolution: {integrity: sha512-CiJJvcRtIgzadHCYXw7dqEnMNRjhGZlYK05Mj9OyktqV8uVT8fD2BFOB7S1uwBE3Kj2Z+4UyPmFw/Ixgw/LAlA==}
 
-  '@types/whatwg-url@11.0.4':
-    resolution: {integrity: sha512-lXCmTWSHJvf0TRSO58nm978b8HJ/EdsSsEKLd3ODHFjo+3VGAyyTp4v50nWvwtzBxSMQrVOK7tcuN0zGPLICMw==}
+  '@types/whatwg-url@11.0.5':
+    resolution: {integrity: sha512-coYR071JRaHa+xoEvvYqvnIHaVqaYrLPbsufM9BF63HkwI5Lgmy2QR8Q5K/lYDYo5AK82wOvSOS0UsLTpTG7uQ==}
 
   '@types/ws@8.5.10':
     resolution: {integrity: sha512-vmQSUcfalpIq0R9q7uTo2lXs6eGIpt9wtnLdMv9LVpIjCA/+ufZRozlVoVelIYixx1ugCBKDhn89vnsEGOCx9A==}
@@ -1285,8 +1292,8 @@ packages:
   '@types/yargs@17.0.32':
     resolution: {integrity: sha512-xQ67Yc/laOG5uMfX/093MRlGGCIBzZMarVa+gfNKJxWAIgykYpVGkBdbqEzGDDfCrVUj6Hiff4mTZ5BA6TmAog==}
 
-  '@typescript-eslint/eslint-plugin@7.8.0':
-    resolution: {integrity: sha512-gFTT+ezJmkwutUPmB0skOj3GZJtlEGnlssems4AjkVweUPGj7jRwwqg0Hhg7++kPGJqKtTYx+R05Ftww372aIg==}
+  '@typescript-eslint/eslint-plugin@7.12.0':
+    resolution: {integrity: sha512-7F91fcbuDf/d3S8o21+r3ZncGIke/+eWk0EpO21LXhDfLahriZF9CGj4fbAetEjlaBdjdSm9a6VeXbpbT6Z40Q==}
     engines: {node: ^18.18.0 || >=20.0.0}
     peerDependencies:
       '@typescript-eslint/parser': ^7.0.0
@@ -1296,8 +1303,8 @@ packages:
       typescript:
         optional: true
 
-  '@typescript-eslint/parser@7.8.0':
-    resolution: {integrity: sha512-KgKQly1pv0l4ltcftP59uQZCi4HUYswCLbTqVZEJu7uLX8CTLyswqMLqLN+2QFz4jCptqWVV4SB7vdxcH2+0kQ==}
+  '@typescript-eslint/parser@7.12.0':
+    resolution: {integrity: sha512-dm/J2UDY3oV3TKius2OUZIFHsomQmpHtsV0FTh1WO8EKgHLQ1QCADUqscPgTpU+ih1e21FQSRjXckHn3txn6kQ==}
     engines: {node: ^18.18.0 || >=20.0.0}
     peerDependencies:
       eslint: ^8.56.0
@@ -1306,12 +1313,12 @@ packages:
       typescript:
         optional: true
 
-  '@typescript-eslint/scope-manager@7.8.0':
-    resolution: {integrity: sha512-viEmZ1LmwsGcnr85gIq+FCYI7nO90DVbE37/ll51hjv9aG+YZMb4WDE2fyWpUR4O/UrhGRpYXK/XajcGTk2B8g==}
+  '@typescript-eslint/scope-manager@7.12.0':
+    resolution: {integrity: sha512-itF1pTnN6F3unPak+kutH9raIkL3lhH1YRPGgt7QQOh43DQKVJXmWkpb+vpc/TiDHs6RSd9CTbDsc/Y+Ygq7kg==}
     engines: {node: ^18.18.0 || >=20.0.0}
 
-  '@typescript-eslint/type-utils@7.8.0':
-    resolution: {integrity: sha512-H70R3AefQDQpz9mGv13Uhi121FNMh+WEaRqcXTX09YEDky21km4dV1ZXJIp8QjXc4ZaVkXVdohvWDzbnbHDS+A==}
+  '@typescript-eslint/type-utils@7.12.0':
+    resolution: {integrity: sha512-lib96tyRtMhLxwauDWUp/uW3FMhLA6D0rJ8T7HmH7x23Gk1Gwwu8UZ94NMXBvOELn6flSPiBrCKlehkiXyaqwA==}
     engines: {node: ^18.18.0 || >=20.0.0}
     peerDependencies:
       eslint: ^8.56.0
@@ -1320,12 +1327,12 @@ packages:
       typescript:
         optional: true
 
-  '@typescript-eslint/types@7.8.0':
-    resolution: {integrity: sha512-wf0peJ+ZGlcH+2ZS23aJbOv+ztjeeP8uQ9GgwMJGVLx/Nj9CJt17GWgWWoSmoRVKAX2X+7fzEnAjxdvK2gqCLw==}
+  '@typescript-eslint/types@7.12.0':
+    resolution: {integrity: sha512-o+0Te6eWp2ppKY3mLCU+YA9pVJxhUJE15FV7kxuD9jgwIAa+w/ycGJBMrYDTpVGUM/tgpa9SeMOugSabWFq7bg==}
     engines: {node: ^18.18.0 || >=20.0.0}
 
-  '@typescript-eslint/typescript-estree@7.8.0':
-    resolution: {integrity: sha512-5pfUCOwK5yjPaJQNy44prjCwtr981dO8Qo9J9PwYXZ0MosgAbfEMB008dJ5sNo3+/BN6ytBPuSvXUg9SAqB0dg==}
+  '@typescript-eslint/typescript-estree@7.12.0':
+    resolution: {integrity: sha512-5bwqLsWBULv1h6pn7cMW5dXX/Y2amRqLaKqsASVwbBHMZSnHqE/HN4vT4fE0aFsiwxYvr98kqOWh1a8ZKXalCQ==}
     engines: {node: ^18.18.0 || >=20.0.0}
     peerDependencies:
       typescript: '*'
@@ -1333,28 +1340,28 @@ packages:
       typescript:
         optional: true
 
-  '@typescript-eslint/utils@7.8.0':
-    resolution: {integrity: sha512-L0yFqOCflVqXxiZyXrDr80lnahQfSOfc9ELAAZ75sqicqp2i36kEZZGuUymHNFoYOqxRT05up760b4iGsl02nQ==}
+  '@typescript-eslint/utils@7.12.0':
+    resolution: {integrity: sha512-Y6hhwxwDx41HNpjuYswYp6gDbkiZ8Hin9Bf5aJQn1bpTs3afYY4GX+MPYxma8jtoIV2GRwTM/UJm/2uGCVv+DQ==}
     engines: {node: ^18.18.0 || >=20.0.0}
     peerDependencies:
       eslint: ^8.56.0
 
-  '@typescript-eslint/visitor-keys@7.8.0':
-    resolution: {integrity: sha512-q4/gibTNBQNA0lGyYQCmWRS5D15n8rXh4QjK3KV+MBPlTYHpfBUT3D3PaPR/HeNiI9W6R7FvlkcGhNyAoP+caA==}
+  '@typescript-eslint/visitor-keys@7.12.0':
+    resolution: {integrity: sha512-uZk7DevrQLL3vSnfFl5bj4sL75qC9D6EdjemIdbtkuUmIheWpuiiylSY01JxJE7+zGrOWDZrp1WxOuDntvKrHQ==}
     engines: {node: ^18.18.0 || >=20.0.0}
 
   '@ungap/structured-clone@1.2.0':
     resolution: {integrity: sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==}
 
-  '@vitejs/plugin-vue-jsx@3.1.0':
-    resolution: {integrity: sha512-w9M6F3LSEU5kszVb9An2/MmXNxocAnUb3WhRr8bHlimhDrXNt6n6D2nJQR3UXpGlZHh/EsgouOHCsM8V3Ln+WA==}
-    engines: {node: ^14.18.0 || >=16.0.0}
+  '@vitejs/plugin-vue-jsx@4.0.0':
+    resolution: {integrity: sha512-A+6wL2AdQhDsLsDnY+2v4rRDI1HLJGIMc97a8FURO9tqKsH5QvjWrzsa5DH3NlZsM742W2wODl2fF+bfcTWtXw==}
+    engines: {node: ^18.0.0 || >=20.0.0}
     peerDependencies:
-      vite: ^4.0.0 || ^5.0.0
+      vite: ^5.0.0
       vue: ^3.0.0
 
-  '@vitejs/plugin-vue@5.0.4':
-    resolution: {integrity: sha512-WS3hevEszI6CEVEx28F8RjTX97k3KsrcY6kvTg7+Whm5y3oYvcqzVeGCU3hxSAn4uY2CLCkeokkGKpoctccilQ==}
+  '@vitejs/plugin-vue@5.0.5':
+    resolution: {integrity: sha512-LOjm7XeIimLBZyzinBQ6OSm3UBCNVCpLkxGC0oWmm2YPzVZoxMsdvNVimLTBzpAnR9hl/yn1SHGuRfe6/Td9rQ==}
     engines: {node: ^18.0.0 || >=20.0.0}
     peerDependencies:
       vite: ^5.0.0
@@ -1408,8 +1415,8 @@ packages:
   '@vue/compiler-ssr@3.4.27':
     resolution: {integrity: sha512-CVRzSJIltzMG5FcidsW0jKNQnNRYC8bT21VegyMMtHmhW3UOI7knmUehzswXLrExDLE6lQCZdrhD4ogI7c+vuw==}
 
-  '@vue/devtools-api@6.6.1':
-    resolution: {integrity: sha512-LgPscpE3Vs0x96PzSSB4IGVSZXZBZHpfxs+ZA1d+VEPwHdOXowy/Y2CsvCAIFrf+ssVU1pD1jidj505EpUnfbA==}
+  '@vue/devtools-api@6.6.3':
+    resolution: {integrity: sha512-0MiMsFma/HqA6g3KLKn+AGpL1kgKhFWszC9U29NfpWK5LE7bjeXxySWJrOJ77hBz+TBrBQ7o4QJqbPbqbs8rJw==}
 
   '@vue/eslint-config-prettier@9.0.0':
     resolution: {integrity: sha512-z1ZIAAUS9pKzo/ANEfd2sO+v2IUalz7cM/cTLOZ7vRFOPk5/xuRKQteOu1DErFLAh/lYGXMVZ0IfYKlyInuDVg==}
@@ -1530,8 +1537,11 @@ packages:
   ajv@6.12.6:
     resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==}
 
-  ajv@8.13.0:
-    resolution: {integrity: sha512-PRA911Blj99jR5RMeTunVbNXMF6Lp4vZXnk5GQjcnUWUTsrXtekg/pnmFFI2u/I36Y/2bITGS30GZCXei6uNkA==}
+  ajv@8.12.0:
+    resolution: {integrity: sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==}
+
+  ajv@8.16.0:
+    resolution: {integrity: sha512-F0twR8U1ZU67JIEtekUcLkXkoO5mMMmgGD8sK/xUFzJ805jxHQl92hImFAqqXMyMYjSPOyUPAwHYhB72g5sTXw==}
 
   ansi-align@3.0.1:
     resolution: {integrity: sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w==}
@@ -1605,6 +1615,7 @@ packages:
   are-we-there-yet@3.0.1:
     resolution: {integrity: sha512-QZW4EDmGwlYur0Yyf/b2uGucHQMa8aFUP7eu9ddR73vvhFyt4V0Vl3QHPcTNJ8l6qYOBdxgXdnBXQrHilfRQBg==}
     engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0}
+    deprecated: This package is no longer supported.
 
   arg@4.1.3:
     resolution: {integrity: sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==}
@@ -1709,8 +1720,8 @@ packages:
   aws-sign2@0.7.0:
     resolution: {integrity: sha512-08kcGqnYf/YmjoRhfxyu+CLxBjUtHLXLXX/vUfx9l2LYzG3c1m61nrpyFUZI6zeS+Li/wWMMidD9KgrqtGq3mA==}
 
-  aws4@1.12.0:
-    resolution: {integrity: sha512-NmWvPnx0F1SfrQbYwOi7OeaNGokp9XhzNioJ/CSBs8Qa4vxug81mhJEAVZwxXuBmYB5KDRfMq/F3RR0BIU7sWg==}
+  aws4@1.13.0:
+    resolution: {integrity: sha512-3AungXC4I8kKsS9PuS4JH2nc+0bVY/mjgrephHTIi8fpEeGsTHBUJeosp0Wc1myYMElmD0B3Oc4XL/HVJ4PV2g==}
 
   b4a@1.6.6:
     resolution: {integrity: sha512-5Tk1HLk6b6ctmjIkAcU/Ujv/1WqiDl0F0JdRCR80VsOcUlHcu7pWeWRlOqQLHfDEsVx9YH/aif5AG4ehoCtTmg==}
@@ -1767,8 +1778,8 @@ packages:
   brace-expansion@2.0.1:
     resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==}
 
-  braces@3.0.2:
-    resolution: {integrity: sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==}
+  braces@3.0.3:
+    resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==}
     engines: {node: '>=8'}
 
   brfs@2.0.2:
@@ -1812,8 +1823,8 @@ packages:
     engines: {node: '>= 0.8'}
     hasBin: true
 
-  browserslist@4.23.0:
-    resolution: {integrity: sha512-QW8HiM1shhT2GuzkvklfjcKDiWFXHOeFCIA/huJPwHsslwcydgk7X+z2zXpEijP98UCY7HbubZt5J2Zgvf0CaQ==}
+  browserslist@4.23.1:
+    resolution: {integrity: sha512-TUfofFo/KsK/bWZ9TWQ5O26tsWW4Uhmt8IYklbnUa70udB6P2wA7w7o4PY4muaEPBQaAX+CEnmmIA41NVHtPVw==}
     engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7}
     hasBin: true
 
@@ -1841,10 +1852,6 @@ packages:
     resolution: {integrity: sha512-4T53u4PdgsXqKaIctwF8ifXlRTTmEPJ8iEPWFdGZvcf7sbwYo6FKFEX9eNNAnzFZ7EzJAQ3CJeOtCRA4rDp7Pw==}
     engines: {node: '>=6.14.2'}
 
-  builtin-modules@3.3.0:
-    resolution: {integrity: sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==}
-    engines: {node: '>=6'}
-
   builtin-status-codes@3.0.0:
     resolution: {integrity: sha512-HpGFw18DgFWlncDfjTa2rcQ4W88O1mC8e8yZ2AvQY5KDaktSTwo+KRf6nHK6FRI5FyRyb/5T6+TSxfP7QyGsmQ==}
 
@@ -1899,8 +1906,8 @@ packages:
     resolution: {integrity: sha512-xlx1yCK2Oc1APsPXDL2LdlNP6+uu8OCDdhOBSVT279M/S+y75O30C2VuD8T2ogdePBBl7PfPF4504tnLgX3zfw==}
     engines: {node: '>=14.16'}
 
-  caniuse-lite@1.0.30001616:
-    resolution: {integrity: sha512-RHVYKov7IcdNjVHJFNY/78RdG4oGVjbayxv8u5IO74Wv7Hlq4PnJE6mo/OjFijjVFNy5ijnCt6H3IIo4t+wfEw==}
+  caniuse-lite@1.0.30001629:
+    resolution: {integrity: sha512-c3dl911slnQhmxUIT4HhYzT7wnBK/XYpGnYLOj4nJBaRiw52Ibe7YxlDaAeRECvA786zCuExhxIUJ2K7nHMrBw==}
 
   caseless@0.12.0:
     resolution: {integrity: sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==}
@@ -1990,8 +1997,8 @@ packages:
     resolution: {integrity: sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==}
     engines: {node: '>=6'}
 
-  cli-table3@0.6.4:
-    resolution: {integrity: sha512-Lm3L0p+/npIQWNIiyF/nAn7T5dnOwR3xNTHXYEBFBFVPXzCVNZ5lqEC/1eo/EVfpDsQ1I+TX4ORPQgp+UI0CRw==}
+  cli-table3@0.6.5:
+    resolution: {integrity: sha512-+W/5efTR7y5HRD7gACw9yQjqMVvEMLBHmboM/kPWam+H+Hmyrgjh6YncVKK122YZkXrLudzTuAukUw9FnMf7IQ==}
     engines: {node: 10.* || >= 12.*}
 
   cli-truncate@4.0.0:
@@ -2073,9 +2080,9 @@ packages:
     resolution: {integrity: sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==}
     engines: {node: '>=14'}
 
-  commander@11.1.0:
-    resolution: {integrity: sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==}
-    engines: {node: '>=16'}
+  commander@12.1.0:
+    resolution: {integrity: sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==}
+    engines: {node: '>=18'}
 
   commander@2.20.3:
     resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==}
@@ -2378,6 +2385,15 @@ packages:
       supports-color:
         optional: true
 
+  debug@4.3.5:
+    resolution: {integrity: sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==}
+    engines: {node: '>=6.0'}
+    peerDependencies:
+      supports-color: '*'
+    peerDependenciesMeta:
+      supports-color:
+        optional: true
+
   decamelize@1.2.0:
     resolution: {integrity: sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==}
     engines: {node: '>=0.10.0'}
@@ -2389,8 +2405,8 @@ packages:
     resolution: {integrity: sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==}
     engines: {node: '>=10'}
 
-  deep-eql@4.1.3:
-    resolution: {integrity: sha512-WaEtAOpRA1MQ0eohqZjpGD8zdI0Ovsm8mmFhaDN8dvDZzyoUMcYDnf5Y6iu7HTXxf8JDS23qWa4a+hKCDyOPzw==}
+  deep-eql@4.1.4:
+    resolution: {integrity: sha512-SUwdGfqdKOwxCPeVYjwSyRpJ7Z+fhpwIAtmCUdZIWZ/YP5R9WAsyuSgpLVDi9bjWoN2LXHNss/dk3urXtdQxGg==}
     engines: {node: '>=6'}
 
   deep-extend@0.6.0:
@@ -2545,8 +2561,8 @@ packages:
   ee-first@1.1.1:
     resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==}
 
-  electron-to-chromium@1.4.757:
-    resolution: {integrity: sha512-jftDaCknYSSt/+KKeXzH3LX5E2CvRLm75P3Hj+J/dv3CL0qUYcOt13d5FN1NiL5IJbbhzHrb3BomeG2tkSlZmw==}
+  electron-to-chromium@1.4.796:
+    resolution: {integrity: sha512-NglN/xprcM+SHD2XCli4oC6bWe6kHoytcyLKCWXmRL854F0qhPhaYgUswUsglnPxYaNQIg2uMY4BvaomIf3kLA==}
 
   elliptic@6.5.5:
     resolution: {integrity: sha512-7EjbcmUm17NQFu4Pmgmq2olYMj8nwMnpcddByChSUjArp8F5DQWcIcpriwO4ZToLNAJig0yiyjswfyGNje/ixw==}
@@ -2579,8 +2595,8 @@ packages:
   endpoint@0.4.5:
     resolution: {integrity: sha512-oA2ALUF+d4Y0I8/WMV/0BuAZGHxfIdAygr9ZXP4rfzmp5zpYZmYKHKAbqRQnrE1YGdPhVg4D24CQkyx2qYEoHg==}
 
-  enhanced-resolve@5.16.0:
-    resolution: {integrity: sha512-O+QWCviPNSSLAD9Ucn8Awv+poAkqn3T1XY5/N7kR7rQO9yfSGWkYZDwpJ+iKF7B8rxaQKWngSqACpgzeapSyoA==}
+  enhanced-resolve@5.17.0:
+    resolution: {integrity: sha512-dwDPwZL0dmye8Txp2gzFmA6sxALaSvdRDjPH0viLcKrtlOL3tw62nWWweVD1SdILDTJrbrL6tdWVN58Wo6U3eA==}
     engines: {node: '>=10.13.0'}
 
   entities@4.5.0:
@@ -2666,8 +2682,8 @@ packages:
     engines: {node: '>=12'}
     hasBin: true
 
-  esbuild@0.21.0:
-    resolution: {integrity: sha512-eyK64lASNug3Wo2+bQEBnYngjh9rkXUfOus403+OeVZteMon6moIhcEYbrSvcgBN6RsrRWCMoWcKDDK6UEsTOQ==}
+  esbuild@0.21.4:
+    resolution: {integrity: sha512-sFMcNNrj+Q0ZDolrp5pDhH0nRPN9hLIM3fRPwgbLYJeSHHgnXSnbV3xYgSVuOeLWH9c73VwmEverVzupIv5xuA==}
     engines: {node: '>=12'}
     hasBin: true
 
@@ -2708,8 +2724,8 @@ packages:
     engines: {node: '>=6.0'}
     hasBin: true
 
-  eslint-compat-utils@0.5.0:
-    resolution: {integrity: sha512-dc6Y8tzEcSYZMHa+CMPLi/hyo1FzNeonbhJL7Ol0ccuKQkwopJcJBA9YL/xmMTLU1eKigXo9vj9nALElWYSowg==}
+  eslint-compat-utils@0.5.1:
+    resolution: {integrity: sha512-3z3vFexKIEnjHE3zCMRo6fn/e44U7T1khUjg+Hp0ZQMCigh28rALD0nPFBcGZuiLC5rLZa2ubQHDRln09JfU2Q==}
     engines: {node: '>=12'}
     peerDependencies:
       eslint: '>=6.0.0'
@@ -2774,8 +2790,8 @@ packages:
       eslint-import-resolver-webpack:
         optional: true
 
-  eslint-plugin-es-x@7.6.0:
-    resolution: {integrity: sha512-I0AmeNgevgaTR7y2lrVCJmGYF0rjoznpDvqV/kIkZSZbZ8Rw3eu4cGlvBBULScfkSOCzqKbff5LR4CNrV7mZHA==}
+  eslint-plugin-es-x@7.7.0:
+    resolution: {integrity: sha512-aP3qj8BwiEDPttxQkZdI221DLKq9sI/qHolE2YSQL1/9+xk7dTV+tB1Fz8/IaCA+lnLA1bDEnvaS2LKs0k2Uig==}
     engines: {node: ^14.18.0 || >=16.0.0}
     peerDependencies:
       eslint: '>=8'
@@ -2790,14 +2806,14 @@ packages:
       '@typescript-eslint/parser':
         optional: true
 
-  eslint-plugin-jsdoc@48.2.3:
-    resolution: {integrity: sha512-r9DMAmFs66VNvNqRLLjHejdnJtILrt3xGi+Qx0op0oRfFGVpOR1Hb3BC++MacseHx93d8SKYPhyrC9BS7Os2QA==}
+  eslint-plugin-jsdoc@48.2.9:
+    resolution: {integrity: sha512-ErpKyr2mEUEkcdZ4nwW/cvDjClvAcvJMEXkGGll0wf8sro8h6qeQ3qlZyp1vM1dRk8Ap6rMdke8FnP94QBIaVQ==}
     engines: {node: '>=18'}
     peerDependencies:
       eslint: ^7.0.0 || ^8.0.0 || ^9.0.0
 
-  eslint-plugin-n@17.5.0:
-    resolution: {integrity: sha512-r7i+NY+RVXQi4Q7sKCG5H4464saJWddDk7QFQjtj+wU//sf15QCq3M8LwZU2yiE45yhVUT9DXW+8AbXRQKJLPQ==}
+  eslint-plugin-n@17.8.1:
+    resolution: {integrity: sha512-KdG0h0voZms8UhndNu8DeWx1eM4sY+A4iXtsNo6kOfJLYHNeTGPacGalJ9GcvrbmOL3r/7QOMwVZDSw+1SqsrA==}
     engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
     peerDependencies:
       eslint: '>=8.23.0'
@@ -2827,11 +2843,11 @@ packages:
     peerDependencies:
       eslint: '>=5.0.0'
 
-  eslint-plugin-tsdoc@0.2.17:
-    resolution: {integrity: sha512-xRmVi7Zx44lOBuYqG8vzTXuL6IdGOeF9nHX17bjJ8+VE6fsxpdGem0/SBTmAwgYMKYB1WBkqRJVQ+n8GK041pA==}
+  eslint-plugin-tsdoc@0.3.0:
+    resolution: {integrity: sha512-0MuFdBrrJVBjT/gyhkP2BqpD0np1NxNLfQ38xXDlSs/KVVpKI2A6vN7jx2Rve/CyUsvOsMGwp9KKrinv7q9g3A==}
 
-  eslint-plugin-vue@9.25.0:
-    resolution: {integrity: sha512-tDWlx14bVe6Bs+Nnh3IGrD+hb11kf2nukfm6jLsmJIhmiRQ1SUaksvwY9U5MvPB0pcrg0QK0xapQkfITs3RKOA==}
+  eslint-plugin-vue@9.26.0:
+    resolution: {integrity: sha512-eTvlxXgd4ijE1cdur850G6KalZqk65k1JKoOI2d1kT3hr8sPD07j1q98FRFdNnpxBELGPWxZmInxeHGF/GxtqQ==}
     engines: {node: ^14.17.0 || >=16.0.0}
     peerDependencies:
       eslint: ^6.2.0 || ^7.0.0 || ^8.0.0 || ^9.0.0
@@ -3004,8 +3020,8 @@ packages:
   file-uri-to-path@1.0.0:
     resolution: {integrity: sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==}
 
-  fill-range@7.0.1:
-    resolution: {integrity: sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==}
+  fill-range@7.1.1:
+    resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==}
     engines: {node: '>=8'}
 
   finalhandler@1.2.0:
@@ -3112,6 +3128,7 @@ packages:
   gauge@4.0.4:
     resolution: {integrity: sha512-f9m+BEN5jkg6a0fZjleidjN51VE1X+mPFQ2DJ0uv1V39oCLCbsGe6yjbBnp7eK7z/+GAon99a3nHuqbuuthyPg==}
     engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0}
+    deprecated: This package is no longer supported.
 
   generate-function@2.3.1:
     resolution: {integrity: sha512-eeB5GfMNeevm/GRYq20ShmsaGcmI81kIX2K9XQx5miC8KdHaC6Jm0qQ8ZNeGOi7wYB8OsdxKs+Y2oVuTFuVwKQ==}
@@ -3161,8 +3178,8 @@ packages:
     resolution: {integrity: sha512-g0QYk1dZBxGwk+Ngc+ltRH2IBp2f7zBkBMBJZCDerh6EhlhSR6+9irMCuT/09zD6qkarHUSn529sK/yL4S27mg==}
     engines: {node: '>= 0.4'}
 
-  get-tsconfig@4.7.4:
-    resolution: {integrity: sha512-ofbkKj+0pjXjhejr007J/fLf+sW+8H7K5GCm+msC8q3IpvgjobpyPqSRFemNyIMxklC0zeJpi7VDFna19FacvQ==}
+  get-tsconfig@4.7.5:
+    resolution: {integrity: sha512-ZCuZCnlqNzjb4QprAzXKdpp/gh6KTxSJuw3IBsPnV/7fV4NxC9ckB+vPTt8w7fJA0TaSD7c55BR47JD6MEDyDw==}
 
   get-uri@6.0.3:
     resolution: {integrity: sha512-BzUrJBS9EcUb4cFol8r4W3v1cPsSyajLSthNkz5BxbpDcHN5tIrM10E2eNvfnvBn3DaT3DUgx0OpsBKkaOpanw==}
@@ -3196,13 +3213,14 @@ packages:
     resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==}
     engines: {node: '>=10.13.0'}
 
-  glob@10.3.12:
-    resolution: {integrity: sha512-TCNv8vJ+xz4QiqTpfOJA7HvYv+tNIRHKfUWw/q+v2jdgN4ebz+KY9tGx5J4rHP0o84mNP+ApH66HRX8us3Khqg==}
-    engines: {node: '>=16 || 14 >=14.17'}
+  glob@10.4.1:
+    resolution: {integrity: sha512-2jelhlq3E4ho74ZyVLN03oKdAZVUa6UDZzFLVH1H7dnoax+y9qyaq8zBkfDIggjniU19z0wU18y16jMB2eyVIw==}
+    engines: {node: '>=16 || 14 >=14.18'}
     hasBin: true
 
   glob@7.2.3:
     resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==}
+    deprecated: Glob versions prior to v9 are no longer supported
 
   global-directory@4.0.1:
     resolution: {integrity: sha512-wHTUcDUoZ1H5/0iVqEudYW4/kAlN5cZ3j/bXn0Dpbizl9iaUVeWSHqiOjsgk6OW2bkLclbBjzewBz6weQ1zA2Q==}
@@ -3220,8 +3238,8 @@ packages:
     resolution: {integrity: sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==}
     engines: {node: '>=8'}
 
-  globals@15.1.0:
-    resolution: {integrity: sha512-926gJqg+4mkxwYKiFvoomM4J0kWESfk3qfTvRL2/oc/tK/eTDBbrfcKnSa2KtfdxB5onoL7D3A3qIHQFpd4+UA==}
+  globals@15.4.0:
+    resolution: {integrity: sha512-unnwvMZpv0eDUyjNyh9DH/yxUaRYrEjW/qK4QcdrHg3oO11igUQrCSgODHEqxlKg8v2CD2Sd7UkqqEBoz5U7TQ==}
     engines: {node: '>=18'}
 
   globalthis@1.0.4:
@@ -3470,6 +3488,7 @@ packages:
 
   inflight@1.0.6:
     resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==}
+    deprecated: This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.
 
   inherits@2.0.3:
     resolution: {integrity: sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==}
@@ -3488,8 +3507,8 @@ packages:
     resolution: {integrity: sha512-QQnnxNyfvmHFIsj7gkPcYymR8Jdw/o7mp5ZFihxn6h8Ci6fh3Dx4E1gPjpQEpIuPo9XVNY/ZUwh4BPMjGyL01g==}
     engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0}
 
-  ini@4.1.2:
-    resolution: {integrity: sha512-AMB1mvwR1pyBFY/nSevUX6y8nJWS63/SzUKD3JyQn97s4xgIdgQPT75IRouIiBAN4yLQBUShNYVW0+UG25daCw==}
+  ini@4.1.3:
+    resolution: {integrity: sha512-X7rqawQBvfdjS10YU1y1YVreA3SsLrW9dX2CewP2EbBJM4ypVNLDkO5y04gejPwKIY9lR+7r9gn3rFPt/kmWFg==}
     engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0}
 
   inline-source-map@0.6.3:
@@ -3499,8 +3518,8 @@ packages:
     resolution: {integrity: sha512-cntlB5ghuB0iuO65Ovoi8ogLHiWGs/5yNrtUcKjFhSSiVeAIVpD7koaSU9RM8mpXw5YDi9RdYXGQMaOURB7ycQ==}
     engines: {node: '>=6.0.0'}
 
-  inquirer@9.2.19:
-    resolution: {integrity: sha512-WpxOT71HGsFya6/mj5PUue0sWwbpbiPfAR+332zLj/siB0QA1PZM8v3GepegFV1Op189UxHUCF6y8AySdtOMVA==}
+  inquirer@9.2.22:
+    resolution: {integrity: sha512-SqLLa/Oe5rZUagTR9z+Zd6izyatHglbmbvVofo1KzuVB54YHleWzeHNLoR7FOICGOeQSqeLh1cordb3MzhGcEw==}
     engines: {node: '>=18'}
 
   insert-module-globals@7.2.1:
@@ -3571,10 +3590,6 @@ packages:
     resolution: {integrity: sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==}
     engines: {node: '>=4'}
 
-  is-builtin-module@3.2.1:
-    resolution: {integrity: sha512-BSLE3HnV2syZ0FK0iMA/yUGplUeMmNz4AW5fnTunbCIqZi4vG3WjJT9FHMy5D69xmAYBHXQhJdALdpwVxV501A==}
-    engines: {node: '>=6'}
-
   is-callable@1.2.7:
     resolution: {integrity: sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==}
     engines: {node: '>= 0.4'}
@@ -3817,8 +3832,8 @@ packages:
   iterate-value@1.0.2:
     resolution: {integrity: sha512-A6fMAio4D2ot2r/TYzr4yUWrmwNdsN5xL7+HUiyACE4DXm+q8HtPcnFTp+NnW3k4N05tZ7FVYFFb2CR13NxyHQ==}
 
-  jackspeak@2.3.6:
-    resolution: {integrity: sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ==}
+  jackspeak@3.4.0:
+    resolution: {integrity: sha512-JVYhQnN59LVPFCEcVa2C3CrEKYacvjRfqIQl+h8oi91aLYQVWRYbxjPcv1bUiUy/kLmQaANrYfNMCO3kuEDHfw==}
     engines: {node: '>=14'}
 
   jest-diff@29.7.0:
@@ -3841,8 +3856,8 @@ packages:
     resolution: {integrity: sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==}
     engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
 
-  jiti@1.21.0:
-    resolution: {integrity: sha512-gFqAIbuKyyso/3G2qhiO2OM6shY6EPP/R0+mkDbyspxKazh8BXDC5FiFsUjlczgdNz/vfra0da2y+aHrusLG/Q==}
+  jiti@1.21.3:
+    resolution: {integrity: sha512-uy2bNX5zQ+tESe+TiC7ilGRz8AtRGmnJH55NC5S0nSUjvvvM2hJHmefHErugGXN4pNv4Qx7vLsnNw9qJ9mtIsw==}
     hasBin: true
 
   jju@1.4.0:
@@ -3877,8 +3892,8 @@ packages:
     resolution: {integrity: sha512-YtOli5Cmzy3q4dP26GraSOeAhqecewG04hoO8DY56CH4KJ9Fvv5qKWUCCo3HZob7esJQHCv6/+bnTy72xZZaVQ==}
     engines: {node: '>=12.0.0'}
 
-  jsdom@24.0.0:
-    resolution: {integrity: sha512-UDS2NayCvmXSXVP6mpTj+73JnNQadZlr9N68189xib2tx5Mls7swlTNao26IoHv46BZJFvXygyRtyXd1feAk1A==}
+  jsdom@24.1.0:
+    resolution: {integrity: sha512-6gpM7pRXCwIOKxX47cgOyvyQDN/Eh0f1MeKySBV2xGdKtqJBLj8P25eY3EVCWo2mglDDzozR2r2MW4T+JiNUZA==}
     engines: {node: '>=18'}
     peerDependencies:
       canvas: ^2.11.2
@@ -3997,20 +4012,20 @@ packages:
     resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==}
     engines: {node: '>= 0.8.0'}
 
-  lilconfig@3.0.0:
-    resolution: {integrity: sha512-K2U4W2Ff5ibV7j7ydLr+zLAkIg5JJ4lPn1Ltsdt+Tz/IjQ8buJ55pZAxoP34lqIiwtF9iAvtLv3JGv7CAyAg+g==}
+  lilconfig@3.1.1:
+    resolution: {integrity: sha512-O18pf7nyvHTckunPWCV1XUNXU1piu01y2b7ATJ0ppkUkk8ocqVWBrYjJBCwHDjD/ZWcfyrA0P4gKhzWGi5EINQ==}
     engines: {node: '>=14'}
 
   lines-and-columns@1.2.4:
     resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==}
 
-  lint-staged@15.2.2:
-    resolution: {integrity: sha512-TiTt93OPh1OZOsb5B7k96A/ATl2AjIZo+vnzFZ6oHK5FuTk63ByDtxGQpHm+kFETjEWqgkF95M8FRXKR/LEBcw==}
+  lint-staged@15.2.5:
+    resolution: {integrity: sha512-j+DfX7W9YUvdzEZl3Rk47FhDF6xwDBV5wwsCPw6BwWZVPYJemusQmvb9bRsW23Sqsaa+vRloAWogbK4BUuU2zA==}
     engines: {node: '>=18.12.0'}
     hasBin: true
 
-  listr2@8.0.1:
-    resolution: {integrity: sha512-ovJXBXkKGfq+CwmKTjluEqFi3p4h8xvkxGQQAQan22YCgef4KZ1mKGjzfGh6PL6AW5Csw0QiQPNuQyH+6Xk3hA==}
+  listr2@8.2.1:
+    resolution: {integrity: sha512-irTfvpib/rNiD637xeevjO2l3Z5loZmuaRi0L0YE5LfijwVY96oyVn0DFD3o/teAok7nfobMG1THvvcHh/BP6g==}
     engines: {node: '>=18.0.0'}
 
   local-pkg@0.5.0:
@@ -4199,12 +4214,12 @@ packages:
     resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==}
     engines: {node: '>= 8'}
 
-  micromatch@4.0.5:
-    resolution: {integrity: sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==}
+  micromatch@4.0.7:
+    resolution: {integrity: sha512-LPP/3KorzCwBxfeUuZmaR6bG2kdeHSbe0P2tY3FLRU4vYrjYz5hI4QZwV0njUx3jeuKe67YukQ1LSPZBKDqO/Q==}
     engines: {node: '>=8.6'}
 
-  mikro-orm@6.2.5:
-    resolution: {integrity: sha512-8GJulcYlawnMbXHch4/HTKDg8u0Q6p4l1Jfyn0WmaN4lMz/XXTuLQTZMSdHhISXUjf9/aQdVkmRPxvKog47pVA==}
+  mikro-orm@6.2.9:
+    resolution: {integrity: sha512-zpP8D7Lw8Q2WYwd43iFQI+5e0zPUM+vEAAyJaGE87RzSiQwchqZNPuV/H74STNJYqj8mLSvwZxFvRzrQXsCRRw==}
     engines: {node: '>= 18.12.0'}
 
   miller-rabin@4.0.1:
@@ -4300,8 +4315,8 @@ packages:
     resolution: {integrity: sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==}
     engines: {node: '>=8'}
 
-  minipass@7.1.0:
-    resolution: {integrity: sha512-oGZRv2OT1lO2UF1zUcwdTb3wqUwI0kBGTgt/T7OdSj6M6N5m3o5uPf0AIW6lVxGGoiWUR7e2AwTE+xiwK8WQig==}
+  minipass@7.1.2:
+    resolution: {integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==}
     engines: {node: '>=16 || 14 >=14.17'}
 
   minizlib@2.1.2:
@@ -4352,8 +4367,8 @@ packages:
   ml-xsadd@2.0.0:
     resolution: {integrity: sha512-VoAYUqmPRmzKbbqRejjqceGFp3VF81Qe8XXFGU0UXLxB7Mf4GGvyGq5Qn3k4AiQgDEV6WzobqlPOd+j0+m6IrA==}
 
-  mlly@1.7.0:
-    resolution: {integrity: sha512-U9SDaXGEREBYQgfejV97coK0UL1r+qnF2SyO9A3qcI8MzKnsIFKHNVEkrDyNncQTKQQumsasmeq84eNMdBfsNQ==}
+  mlly@1.7.1:
+    resolution: {integrity: sha512-rrVRZRELyQzrIUAVMHxP97kv+G786pHmOKzuFII8zDYahFBS7qnHh2AlYSl1GAHhaMPCz6/oHjVMcfFYgFYHgA==}
 
   mnemonist@0.40.0-rc1:
     resolution: {integrity: sha512-38L0xGDezsPweee5i7duiaCRzlkkCJorozW6Rta60iel7ZkT4vF6jDIfr101NxE3rsAsumuOvc8yiTGZD5gG4w==}
@@ -4366,11 +4381,11 @@ packages:
   moment@2.30.1:
     resolution: {integrity: sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how==}
 
-  mongodb-connection-string-url@3.0.0:
-    resolution: {integrity: sha512-t1Vf+m1I5hC2M5RJx/7AtxgABy1cZmIPQRMXw+gEIPn/cZNF3Oiy+l0UIypUwVB5trcWHq3crg2g3uAR9aAwsQ==}
+  mongodb-connection-string-url@3.0.1:
+    resolution: {integrity: sha512-XqMGwRX0Lgn05TDB4PyG2h2kKO/FfWJyCzYQbIhXUxz7ETt0I/FqHjUeqj37irJ+Dl1ZtU82uYyj14u2XsZKfg==}
 
-  mongodb@6.6.1:
-    resolution: {integrity: sha512-FvA9ocQzRzzvhin1HHLrZDEm0gWvnksbiciYrU/0GmET/t/DdDiMJroA7rfDrHM3AInwGVYw2fwAU2oNYUyUEw==}
+  mongodb@6.7.0:
+    resolution: {integrity: sha512-TMKyHdtMcO0fYBNORiYdmM25ijsHs+Njs963r4Tro4OQZzqYigAzYQouwWRg4OIaiLRUEGUh/1UAcH5lxdSLIA==}
     engines: {node: '>=16.20.1'}
     peerDependencies:
       '@aws-sdk/credential-providers': ^3.188.0
@@ -4490,8 +4505,8 @@ packages:
   no-case@2.3.2:
     resolution: {integrity: sha512-rmTZ9kz+f3rCvK2TD1Ue/oZlns7OGoIWP4fc3llxxRXlOkHKoWPPWJOfFYpITabSow43QJbRIoHQXtt10VldyQ==}
 
-  node-abi@3.62.0:
-    resolution: {integrity: sha512-CPMcGa+y33xuL1E0TcNIu4YyaZCxnnvkVaEXrsosR3FxN+fV8xvb7Mzpb7IgKler10qeMkE6+Dp8qJhpzdq35g==}
+  node-abi@3.63.0:
+    resolution: {integrity: sha512-vAszCsOUrUxjGAmdnM/pq7gUgie0IRteCQMX6d4A534fQCR93EJU5qgzBvU6EkFfK27s0T3HEV3BOyJIr7OMYw==}
     engines: {node: '>=10'}
 
   node-addon-api@7.1.0:
@@ -4569,6 +4584,7 @@ packages:
   npmlog@6.0.2:
     resolution: {integrity: sha512-/vBvz5Jfr9dT/aFWd0FIRf+T/Q2WBsLENygUaFUqstqsycmZAP/t5BvFJTK0viFmSUxiUKTUplWy5vt+rvKIxg==}
     engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0}
+    deprecated: This package is no longer supported.
 
   nth-check@2.1.1:
     resolution: {integrity: sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==}
@@ -4577,8 +4593,8 @@ packages:
     resolution: {integrity: sha512-4jbtZXNAsfZbAHiiqjLPBiCl16dES1zI4Hpzzxw61Tk+loF+sBDBKx1ICKKKwIqQ7M0mFn1TmkN7euSncWgHiQ==}
     engines: {node: '>=0.10.0'}
 
-  nwsapi@2.2.9:
-    resolution: {integrity: sha512-2f3F0SEEer8bBu0dsNCFF50N0cTThV1nWFYcEYFZttdW0lDAoybv9cQoK7X7/68Z89S7FoRrVjP1LPX4XRf9vg==}
+  nwsapi@2.2.10:
+    resolution: {integrity: sha512-QK0sRs7MKv0tKe1+5uZIQk/C8XGza4DAnztJG8iD+TpJIORARrCxczA738awHrZoHeTjSSoHqao2teO0dC/gFQ==}
 
   oauth-sign@0.9.0:
     resolution: {integrity: sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==}
@@ -4812,9 +4828,9 @@ packages:
     resolution: {integrity: sha512-Y30dB6rab1A/nfEKsZxmr01nUotHX0c/ZiIAsCTatEe1CmS5Pm5He7fZ195bPT7RdquoaL8lLxFCMQi/bS7IJg==}
     engines: {node: '>= 0.8.0'}
 
-  path-scurry@1.10.2:
-    resolution: {integrity: sha512-7xTavNy5RQXnsjANvVvMkEjvloOinkAjv/Z6Ildz9v2RinZ4SBKTWFOVRbaF8p0vpHnyjV/UwNDdKuUv6M5qcA==}
-    engines: {node: '>=16 || 14 >=14.17'}
+  path-scurry@1.11.1:
+    resolution: {integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==}
+    engines: {node: '>=16 || 14 >=14.18'}
 
   path-type@4.0.0:
     resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==}
@@ -4840,8 +4856,8 @@ packages:
   pg-connection-string@2.6.2:
     resolution: {integrity: sha512-ch6OwaeaPYcova4kKZ15sbJ2hKb/VP48ZD2gE7i1J+L4MspCtBMAx8nMgz7bksc7IojCIIWuEhHibSMFH8m8oA==}
 
-  picocolors@1.0.0:
-    resolution: {integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==}
+  picocolors@1.0.1:
+    resolution: {integrity: sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==}
 
   picomatch@2.3.1:
     resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==}
@@ -4856,15 +4872,15 @@ packages:
     resolution: {integrity: sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==}
     engines: {node: '>=0.10.0'}
 
-  pkg-types@1.1.0:
-    resolution: {integrity: sha512-/RpmvKdxKf8uILTtoOhAgf30wYbP2Qw+L9p3Rvshx1JZVX+XQNZQFjlbmGHEGIm4CkVPlSn+NXmIM8+9oWQaSA==}
+  pkg-types@1.1.1:
+    resolution: {integrity: sha512-ko14TjmDuQJ14zsotODv7dBlwxKhUKQEhuhmbqo1uCi9BB0Z2alo/wAXg6q1dTR5TyuqYyWhjtfe/Tsh+X28jQ==}
 
   pkg-up@3.1.0:
     resolution: {integrity: sha512-nDywThFk1i4BQK4twPQ6TA4RT8bDY96yeuCVBWL3ePARCiEKDRSrNGbFIgUJpLp+XeIR65v8ra7WuJOFUBtkMA==}
     engines: {node: '>=8'}
 
-  poolifier@4.0.2:
-    resolution: {integrity: sha512-hDVMaPN2DCyUcbIRdmTGSAvNx3tidMvp1Z7cPQepnaHGoYftfuDuGqsxkE8y6z0+Olo6ei/aqQjQRZ+cH8fA8A==}
+  poolifier@4.0.13:
+    resolution: {integrity: sha512-GPITJo3LZvZXGNDWn6eDpOJ+F5+rq4tvyoXFQJfyJ92w0qr4evjoOX9hymwMGmv8TuifFMIBmgCdcTvoxRdMgA==}
     engines: {node: '>=18.0.0', pnpm: '>=9.0.0'}
 
   possible-typed-array-names@1.0.0:
@@ -4877,8 +4893,8 @@ packages:
     peerDependencies:
       postcss: ^8.0.0
 
-  postcss-selector-parser@6.0.16:
-    resolution: {integrity: sha512-A0RVJrX+IUkVZbW3ClroRWurercFhieevHB38sr2+l9eUClMqome3LmEmnhlNy+5Mr2EYN6B2Kaw9wYdd+VHiw==}
+  postcss-selector-parser@6.1.0:
+    resolution: {integrity: sha512-UMz42UD0UY0EApS0ZL9o1XnLhSTtvvvLe5Dc2H2O56fvRZi+KulDyf5ctDhhtYJBGKStV2FL1fy6253cmLgqVQ==}
     engines: {node: '>=4'}
 
   postcss-value-parser@4.2.0:
@@ -4905,8 +4921,8 @@ packages:
     resolution: {integrity: sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==}
     engines: {node: '>=6.0.0'}
 
-  prettier@3.2.5:
-    resolution: {integrity: sha512-3/GWa9aOC0YeD7LUfvOG2NiDyhOWRvt1k+rcKhOuYnMY24iiCphgneUfJDyFXd6rZCAnuLBv6UeAULtrhT/F4A==}
+  prettier@3.3.1:
+    resolution: {integrity: sha512-7CAwy5dRsxs8PHXT3twixW9/OEll8MLE0VRPCJyl7CkS6VHGPSlsVaWTiASPTyGyYRyApxlaWTzwUxVNrhcwDg==}
     engines: {node: '>=14'}
     hasBin: true
 
@@ -5099,9 +5115,9 @@ packages:
   reinterval@1.1.0:
     resolution: {integrity: sha512-QIRet3SYrGp0HUHO88jVskiG6seqUGC5iAG7AwI/BV4ypGcuqk9Du6YQBUOUqm9c8pw1eyLoIaONifRua1lsEQ==}
 
-  release-it@17.2.1:
-    resolution: {integrity: sha512-zBOpaHyjrXC3g/9rHyQlvuDw9yCn9AGphrlL+t3gWNEhbZKEQ62WNY45JxllcJMNx9orQUxBZ3o7pVCqkeuTbg==}
-    engines: {node: ^18.18.0 || ^20.8.0 || ^21.0.0}
+  release-it@17.3.0:
+    resolution: {integrity: sha512-7t9a2WEwqQKCdteshZUrO/3RX60plS5CzYAFr5+4Zj8qvRx1pFOFVglJSz4BeFAEd2yejpPxfI60+qRUzLEDZw==}
+    engines: {node: ^18.18.0 || ^20.8.0 || ^22.0.0}
     hasBin: true
 
   request@2.88.2:
@@ -5137,9 +5153,6 @@ packages:
   resolve-pkg-maps@1.0.0:
     resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==}
 
-  resolve@1.19.0:
-    resolution: {integrity: sha512-rArEXAgsBG4UgRGcynxWIWKFvh/XZCcS8UJdHhwy91zwAvCZIbcs+vAbflgBnNjYMs/i/i+/Ux6IZhML1yPvxg==}
-
   resolve@1.22.8:
     resolution: {integrity: sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==}
     hasBin: true
@@ -5180,24 +5193,28 @@ packages:
 
   rimraf@3.0.2:
     resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==}
+    deprecated: Rimraf versions prior to v4 are no longer supported
     hasBin: true
 
-  rimraf@5.0.5:
-    resolution: {integrity: sha512-CqDakW+hMe/Bz202FPEymy68P+G50RfMQK+Qo5YUqc9SPipvbGjCGKd0RSKEelbsfQuw3g5NZDSrlZZAJurH1A==}
-    engines: {node: '>=14'}
+  rimraf@5.0.7:
+    resolution: {integrity: sha512-nV6YcJo5wbLW77m+8KjH8aB/7/rxQy9SZ0HY5shnwULfS+9nmTtVXAJET5NdZmCzA4fPI/Hm1wo/Po/4mopOdg==}
+    engines: {node: '>=14.18'}
     hasBin: true
 
   ripemd160@2.0.2:
     resolution: {integrity: sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==}
 
-  rollup@4.17.2:
-    resolution: {integrity: sha512-/9ClTJPByC0U4zNLowV1tMBe8yMEAxewtR3cUNX5BoEpGH3dQEWpJLr6CLp0fPdYRF/fzVOgvDb1zXuakwF5kQ==}
+  rollup@4.18.0:
+    resolution: {integrity: sha512-QmJz14PX3rzbJCN1SG4Xe/bAAX2a6NpCP8ab2vfu2GiUr8AQcr2nCV/oEO3yneFarB67zk8ShlIyWb2LGTb3Sg==}
     engines: {node: '>=18.0.0', npm: '>=8.0.0'}
     hasBin: true
 
   rrweb-cssom@0.6.0:
     resolution: {integrity: sha512-APM0Gt1KoXBz0iIkkdB/kfvGOwC4UuJFeG/c+yV7wSc7q96cG/kJ0HiYCnzivD9SB53cLV1MlHFNfOuPaadYSw==}
 
+  rrweb-cssom@0.7.0:
+    resolution: {integrity: sha512-KlSv0pm9kgQSRxXEMgtivPJ4h826YHsuob8pSHcfSZsSXGtvpEAie8S0AnXuObEJ7nhikOb4ahwxDm0H2yW17g==}
+
   run-applescript@7.0.0:
     resolution: {integrity: sha512-9by4Ij99JUr/MCFBUkDKLWK3G9HVXmabKz9U5MlIAIuvuzkiOicRYs8XJLxX+xahD+mLiiCYDqF9dKAgtzKP1A==}
     engines: {node: '>=18'}
@@ -5259,8 +5276,8 @@ packages:
     resolution: {integrity: sha512-0Ju4+6A8iOnpL/Thra7dZsSlOHYAHIeMxfhWQRI1/VLcT3WDBZKKtQt/QkBOsiIN9ZpuvHE6cGZ0x4glCMmfiA==}
     engines: {node: '>=12'}
 
-  semver@7.6.0:
-    resolution: {integrity: sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==}
+  semver@7.6.2:
+    resolution: {integrity: sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==}
     engines: {node: '>=10'}
     hasBin: true
 
@@ -5411,8 +5428,8 @@ packages:
   spdx-expression-parse@4.0.0:
     resolution: {integrity: sha512-Clya5JIij/7C6bRR22+tnGXbc4VKlibKSVj2iHvVeX5iMW7s1SIQlqu699JkODJJIhh/pUu8L0/VLh8xflD+LQ==}
 
-  spdx-license-ids@3.0.17:
-    resolution: {integrity: sha512-sh8PWc/ftMqAAdFiBu6Fy6JUOYjqDJBJvIhpfDMyHrr0Rbp5liZqd4TjtQ/RgfLjKFZb+LMx5hpml5qOWy0qvg==}
+  spdx-license-ids@3.0.18:
+    resolution: {integrity: sha512-xxRs31BqRYHwiMzudOrpSiHtZ8i/GeionCBDSilhYRj+9gIcI8wCZTlXZKu9vZIVqViP3dcp9qE5G6AlIaD+TQ==}
 
   split2@4.2.0:
     resolution: {integrity: sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==}
@@ -5638,8 +5655,8 @@ packages:
     resolution: {integrity: sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==}
     engines: {node: '>=10'}
 
-  tar@7.1.0:
-    resolution: {integrity: sha512-ENhg4W6BmjYxl8GTaE7/h99f0aXiSWv4kikRZ9n2/JRxypZniE84ILZqimAhxxX7Zb8Px6pFdheW3EeHfhnXQQ==}
+  tar@7.2.0:
+    resolution: {integrity: sha512-hctwP0Nb4AB60bj8WQgRYaMOuJYRAPMGiQUAotms5igN8ppfQM+IvjQ5HcKu1MaZh2Wy2KWVTe563Yj8dfc14w==}
     engines: {node: '>=18'}
 
   tarn@3.0.2:
@@ -5774,11 +5791,11 @@ packages:
   tslib@1.14.1:
     resolution: {integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==}
 
-  tslib@2.6.2:
-    resolution: {integrity: sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==}
+  tslib@2.6.3:
+    resolution: {integrity: sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==}
 
-  tsx@4.9.3:
-    resolution: {integrity: sha512-czVbetlILiyJZI5zGlj2kw9vFiSeyra9liPD4nG+Thh4pKTi0AmMEQ8zdV/L2xbIVKrIqif4sUNrsMAOksx9Zg==}
+  tsx@4.15.1:
+    resolution: {integrity: sha512-k/6h17jA1KfUR7SpcteOa880zGmF56s8gMIcSqUR5avyNFi9nlCEKpMiHLrzrqyARGr52A/JablmGey1DEWbCA==}
     engines: {node: '>=18.0.0'}
     hasBin: true
 
@@ -5828,8 +5845,8 @@ packages:
     resolution: {integrity: sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==}
     engines: {node: '>=12.20'}
 
-  type@2.7.2:
-    resolution: {integrity: sha512-dzlvlNlt6AXU7EBSfpAscydQ7gXB+pPGsPnfJnZpiNJBDj7IaJzQlBZYGdEi4R9HmPdBv2XmWJ6YUtoTa7lmCw==}
+  type@2.7.3:
+    resolution: {integrity: sha512-8j+1QmAbPvLZow5Qpi6NCaN8FB60p/6x8/vfNqOk/hC+HuvFZhL4+WfekuhQLiqFZXOgQdrs3B+XxEmCc6b3FQ==}
 
   typed-array-buffer@1.0.2:
     resolution: {integrity: sha512-gEymJYKZtKXzzBzM4jqa9w6Q1Jjm7x2d+sh19AdsD4wqnMPDYyvwpsIc2Q/835kHuo3BEQ7CjelGhfTsoBb2MQ==}
@@ -5919,8 +5936,8 @@ packages:
     resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==}
     engines: {node: '>= 0.8'}
 
-  update-browserslist-db@1.0.15:
-    resolution: {integrity: sha512-K9HWH62x3/EalU1U6sjSZiylm9C8tgq2mSvshZpqc7QE69RaA2qjhkW2HlNA0tFpEbtyFz7HTqbSdN4MSwUodA==}
+  update-browserslist-db@1.0.16:
+    resolution: {integrity: sha512-KVbTxlBYlckhF5wgfyZXTWnMn7MMZjMu9XG8bPlliUOP9ThaF4QnhP8qrjrH7DRzHfSk0oQv1wToW+iA5GajEQ==}
     hasBin: true
     peerDependencies:
       browserslist: '>= 4.21.0'
@@ -5949,8 +5966,8 @@ packages:
   url@0.11.3:
     resolution: {integrity: sha512-6hxOLGfZASQK/cijlZnZJTq8OXAkt/3YGfQX45vvMYXpZoo8NdWZcY73K108Jf759lS1Bv/8wXnHDTSz17dSRw==}
 
-  utf-8-validate@6.0.3:
-    resolution: {integrity: sha512-uIuGf9TWQ/y+0Lp+KGZCMuJWc3N9BHA+l/UmHd/oUHwJJDeysyTRxNQVkbzsIWfGFbRe3OcgML/i0mvVRPOyDA==}
+  utf-8-validate@6.0.4:
+    resolution: {integrity: sha512-xu9GQDeFp+eZ6LnCywXN/zBancWvOpUMzgjLPSjy4BRHSmTelvn2E0DG0o1sTiw5hkCKBHo8rwSKncfRfv2EEQ==}
     engines: {node: '>=6.14.2'}
 
   util-deprecate@1.0.2:
@@ -5994,8 +6011,8 @@ packages:
     engines: {node: ^18.0.0 || >=20.0.0}
     hasBin: true
 
-  vite@5.2.11:
-    resolution: {integrity: sha512-HndV31LWW05i1BLPMUCE1B9E9GFbOu1MbenhS58FuK6owSO5qHm7GiCotrNY1YE5rMeQSFBGmT5ZaLEjFizgiQ==}
+  vite@5.2.13:
+    resolution: {integrity: sha512-SSq1noJfY9pR3I1TUENL3rQYDQCFqgD+lM6fTRAM8Nv6Lsg5hDLaXkjETVeBt+7vZBCMoibD+6IWnT2mJ+Zb/A==}
     engines: {node: ^18.0.0 || >=20.0.0}
     hasBin: true
     peerDependencies:
@@ -6050,11 +6067,11 @@ packages:
   vm-browserify@1.1.2:
     resolution: {integrity: sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ==}
 
-  vue-component-type-helpers@2.0.16:
-    resolution: {integrity: sha512-qisL/iAfdO++7w+SsfYQJVPj6QKvxp4i1MMxvsNO41z/8zu3KuAw9LkhKUfP/kcOWGDxESp+pQObWppXusejCA==}
+  vue-component-type-helpers@2.0.21:
+    resolution: {integrity: sha512-3NaicyZ7N4B6cft4bfb7dOnPbE9CjLcx+6wZWAg5zwszfO4qXRh+U52dN5r5ZZfc6iMaxKCEcoH9CmxxoFZHLg==}
 
-  vue-eslint-parser@9.4.2:
-    resolution: {integrity: sha512-Ry9oiGmCAK91HrKMtCrKFWmSFWvYkpGglCeFAIqDdr9zdXmMMpJOmUJS7WWsW7fX81h6mwHmUZCQQ1E0PkSwYQ==}
+  vue-eslint-parser@9.4.3:
+    resolution: {integrity: sha512-2rYRLWlIpaiN8xbPiDyXZXRgLGOtWxERV7ND5fFAv5qo1D2N9Fu9MNajBNc6o13lZ+24DAWCkQCvj4klgmcITg==}
     engines: {node: ^14.17.0 || >=16.0.0}
     peerDependencies:
       eslint: '>=6.0.0'
@@ -6259,9 +6276,10 @@ packages:
     resolution: {integrity: sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==}
     engines: {node: '>=18'}
 
-  yaml@2.3.4:
-    resolution: {integrity: sha512-8aAvwVUSHpfEqTQ4w/KMlf3HcRdt50E5ODIQJBw1fQ5RL34xabzxtUlzTXVqc4rkZsPbvrXKWnABCD7kWSmocA==}
+  yaml@2.4.5:
+    resolution: {integrity: sha512-aBx2bnqDzVOyNKfsysjA2ms5ZlnjSAW2eG3/L5G/CSujfjLJTJsEw1bGw8kCf04KodQWk1pxlGnZ56CRxiawmg==}
     engines: {node: '>= 14'}
+    hasBin: true
 
   yargs-parser@15.0.3:
     resolution: {integrity: sha512-/MVEVjTXy/cGAjdtQf8dW3V9b97bPN7rNn8ETj6BmAQL7ibC7O1Q9SPJbGjgh3SlwoBNXMzj/ZGIj8mBgl12YA==}
@@ -6293,12 +6311,12 @@ snapshots:
 
   0x@5.7.0:
     dependencies:
-      ajv: 8.13.0
+      ajv: 8.16.0
       browserify: 17.0.0
       concat-stream: 2.0.0
       d3-fg: 6.14.0
       debounce: 1.2.1
-      debug: 4.3.4
+      debug: 4.3.5
       end-of-stream: 1.4.4
       env-string: 1.0.1
       escape-string-regexp: 4.0.0
@@ -6315,7 +6333,7 @@ snapshots:
       opn: 5.5.0
       pump: 3.0.0
       pumpify: 2.0.1
-      semver: 7.6.0
+      semver: 7.6.2
       single-line-log: 1.1.2
       split2: 4.2.0
       tachyons: 4.12.0
@@ -6331,190 +6349,209 @@ snapshots:
 
   '@assemblyscript/loader@0.19.23': {}
 
-  '@babel/code-frame@7.24.2':
+  '@babel/code-frame@7.24.7':
     dependencies:
-      '@babel/highlight': 7.24.5
-      picocolors: 1.0.0
+      '@babel/highlight': 7.24.7
+      picocolors: 1.0.1
 
-  '@babel/compat-data@7.24.4': {}
+  '@babel/compat-data@7.24.7': {}
 
-  '@babel/core@7.24.5':
+  '@babel/core@7.24.7':
     dependencies:
       '@ampproject/remapping': 2.3.0
-      '@babel/code-frame': 7.24.2
-      '@babel/generator': 7.24.5
-      '@babel/helper-compilation-targets': 7.23.6
-      '@babel/helper-module-transforms': 7.24.5(@babel/core@7.24.5)
-      '@babel/helpers': 7.24.5
-      '@babel/parser': 7.24.5
-      '@babel/template': 7.24.0
-      '@babel/traverse': 7.24.5
-      '@babel/types': 7.24.5
+      '@babel/code-frame': 7.24.7
+      '@babel/generator': 7.24.7
+      '@babel/helper-compilation-targets': 7.24.7
+      '@babel/helper-module-transforms': 7.24.7(@babel/core@7.24.7)
+      '@babel/helpers': 7.24.7
+      '@babel/parser': 7.24.7
+      '@babel/template': 7.24.7
+      '@babel/traverse': 7.24.7
+      '@babel/types': 7.24.7
       convert-source-map: 2.0.0
-      debug: 4.3.4
+      debug: 4.3.5
       gensync: 1.0.0-beta.2
       json5: 2.2.3
-      semver: 7.6.0
+      semver: 7.6.2
     transitivePeerDependencies:
       - supports-color
 
-  '@babel/generator@7.24.5':
+  '@babel/generator@7.24.7':
     dependencies:
-      '@babel/types': 7.24.5
+      '@babel/types': 7.24.7
       '@jridgewell/gen-mapping': 0.3.5
       '@jridgewell/trace-mapping': 0.3.25
       jsesc: 2.5.2
 
-  '@babel/helper-annotate-as-pure@7.22.5':
+  '@babel/helper-annotate-as-pure@7.24.7':
     dependencies:
-      '@babel/types': 7.24.5
+      '@babel/types': 7.24.7
 
-  '@babel/helper-compilation-targets@7.23.6':
+  '@babel/helper-compilation-targets@7.24.7':
     dependencies:
-      '@babel/compat-data': 7.24.4
-      '@babel/helper-validator-option': 7.23.5
-      browserslist: 4.23.0
+      '@babel/compat-data': 7.24.7
+      '@babel/helper-validator-option': 7.24.7
+      browserslist: 4.23.1
       lru-cache: 5.1.1
-      semver: 7.6.0
+      semver: 7.6.2
+
+  '@babel/helper-create-class-features-plugin@7.24.7(@babel/core@7.24.7)':
+    dependencies:
+      '@babel/core': 7.24.7
+      '@babel/helper-annotate-as-pure': 7.24.7
+      '@babel/helper-environment-visitor': 7.24.7
+      '@babel/helper-function-name': 7.24.7
+      '@babel/helper-member-expression-to-functions': 7.24.7
+      '@babel/helper-optimise-call-expression': 7.24.7
+      '@babel/helper-replace-supers': 7.24.7(@babel/core@7.24.7)
+      '@babel/helper-skip-transparent-expression-wrappers': 7.24.7
+      '@babel/helper-split-export-declaration': 7.24.7
+      semver: 7.6.2
+    transitivePeerDependencies:
+      - supports-color
 
-  '@babel/helper-create-class-features-plugin@7.24.5(@babel/core@7.24.5)':
+  '@babel/helper-environment-visitor@7.24.7':
     dependencies:
-      '@babel/core': 7.24.5
-      '@babel/helper-annotate-as-pure': 7.22.5
-      '@babel/helper-environment-visitor': 7.22.20
-      '@babel/helper-function-name': 7.23.0
-      '@babel/helper-member-expression-to-functions': 7.24.5
-      '@babel/helper-optimise-call-expression': 7.22.5
-      '@babel/helper-replace-supers': 7.24.1(@babel/core@7.24.5)
-      '@babel/helper-skip-transparent-expression-wrappers': 7.22.5
-      '@babel/helper-split-export-declaration': 7.24.5
-      semver: 7.6.0
+      '@babel/types': 7.24.7
 
-  '@babel/helper-environment-visitor@7.22.20': {}
-
-  '@babel/helper-function-name@7.23.0':
+  '@babel/helper-function-name@7.24.7':
     dependencies:
-      '@babel/template': 7.24.0
-      '@babel/types': 7.24.5
+      '@babel/template': 7.24.7
+      '@babel/types': 7.24.7
 
-  '@babel/helper-hoist-variables@7.22.5':
+  '@babel/helper-hoist-variables@7.24.7':
     dependencies:
-      '@babel/types': 7.24.5
+      '@babel/types': 7.24.7
 
-  '@babel/helper-member-expression-to-functions@7.24.5':
+  '@babel/helper-member-expression-to-functions@7.24.7':
     dependencies:
-      '@babel/types': 7.24.5
+      '@babel/traverse': 7.24.7
+      '@babel/types': 7.24.7
+    transitivePeerDependencies:
+      - supports-color
 
   '@babel/helper-module-imports@7.22.15':
     dependencies:
-      '@babel/types': 7.24.5
+      '@babel/types': 7.24.7
 
-  '@babel/helper-module-imports@7.24.3':
+  '@babel/helper-module-imports@7.24.7':
     dependencies:
-      '@babel/types': 7.24.5
+      '@babel/traverse': 7.24.7
+      '@babel/types': 7.24.7
+    transitivePeerDependencies:
+      - supports-color
 
-  '@babel/helper-module-transforms@7.24.5(@babel/core@7.24.5)':
+  '@babel/helper-module-transforms@7.24.7(@babel/core@7.24.7)':
     dependencies:
-      '@babel/core': 7.24.5
-      '@babel/helper-environment-visitor': 7.22.20
-      '@babel/helper-module-imports': 7.24.3
-      '@babel/helper-simple-access': 7.24.5
-      '@babel/helper-split-export-declaration': 7.24.5
-      '@babel/helper-validator-identifier': 7.24.5
+      '@babel/core': 7.24.7
+      '@babel/helper-environment-visitor': 7.24.7
+      '@babel/helper-module-imports': 7.24.7
+      '@babel/helper-simple-access': 7.24.7
+      '@babel/helper-split-export-declaration': 7.24.7
+      '@babel/helper-validator-identifier': 7.24.7
+    transitivePeerDependencies:
+      - supports-color
 
-  '@babel/helper-optimise-call-expression@7.22.5':
+  '@babel/helper-optimise-call-expression@7.24.7':
     dependencies:
-      '@babel/types': 7.24.5
+      '@babel/types': 7.24.7
 
-  '@babel/helper-plugin-utils@7.24.5': {}
+  '@babel/helper-plugin-utils@7.24.7': {}
 
-  '@babel/helper-replace-supers@7.24.1(@babel/core@7.24.5)':
+  '@babel/helper-replace-supers@7.24.7(@babel/core@7.24.7)':
     dependencies:
-      '@babel/core': 7.24.5
-      '@babel/helper-environment-visitor': 7.22.20
-      '@babel/helper-member-expression-to-functions': 7.24.5
-      '@babel/helper-optimise-call-expression': 7.22.5
+      '@babel/core': 7.24.7
+      '@babel/helper-environment-visitor': 7.24.7
+      '@babel/helper-member-expression-to-functions': 7.24.7
+      '@babel/helper-optimise-call-expression': 7.24.7
+    transitivePeerDependencies:
+      - supports-color
 
-  '@babel/helper-simple-access@7.24.5':
+  '@babel/helper-simple-access@7.24.7':
     dependencies:
-      '@babel/types': 7.24.5
+      '@babel/traverse': 7.24.7
+      '@babel/types': 7.24.7
+    transitivePeerDependencies:
+      - supports-color
 
-  '@babel/helper-skip-transparent-expression-wrappers@7.22.5':
+  '@babel/helper-skip-transparent-expression-wrappers@7.24.7':
     dependencies:
-      '@babel/types': 7.24.5
+      '@babel/traverse': 7.24.7
+      '@babel/types': 7.24.7
+    transitivePeerDependencies:
+      - supports-color
 
-  '@babel/helper-split-export-declaration@7.24.5':
+  '@babel/helper-split-export-declaration@7.24.7':
     dependencies:
-      '@babel/types': 7.24.5
+      '@babel/types': 7.24.7
 
-  '@babel/helper-string-parser@7.24.1': {}
+  '@babel/helper-string-parser@7.24.7': {}
 
-  '@babel/helper-validator-identifier@7.24.5': {}
+  '@babel/helper-validator-identifier@7.24.7': {}
 
-  '@babel/helper-validator-option@7.23.5': {}
+  '@babel/helper-validator-option@7.24.7': {}
 
-  '@babel/helpers@7.24.5':
+  '@babel/helpers@7.24.7':
     dependencies:
-      '@babel/template': 7.24.0
-      '@babel/traverse': 7.24.5
-      '@babel/types': 7.24.5
-    transitivePeerDependencies:
-      - supports-color
+      '@babel/template': 7.24.7
+      '@babel/types': 7.24.7
 
-  '@babel/highlight@7.24.5':
+  '@babel/highlight@7.24.7':
     dependencies:
-      '@babel/helper-validator-identifier': 7.24.5
+      '@babel/helper-validator-identifier': 7.24.7
       chalk: 2.4.2
       js-tokens: 4.0.0
-      picocolors: 1.0.0
+      picocolors: 1.0.1
 
-  '@babel/parser@7.24.5':
+  '@babel/parser@7.24.7':
     dependencies:
-      '@babel/types': 7.24.5
+      '@babel/types': 7.24.7
 
-  '@babel/plugin-syntax-jsx@7.24.1(@babel/core@7.24.5)':
+  '@babel/plugin-syntax-jsx@7.24.7(@babel/core@7.24.7)':
     dependencies:
-      '@babel/core': 7.24.5
-      '@babel/helper-plugin-utils': 7.24.5
+      '@babel/core': 7.24.7
+      '@babel/helper-plugin-utils': 7.24.7
 
-  '@babel/plugin-syntax-typescript@7.24.1(@babel/core@7.24.5)':
+  '@babel/plugin-syntax-typescript@7.24.7(@babel/core@7.24.7)':
     dependencies:
-      '@babel/core': 7.24.5
-      '@babel/helper-plugin-utils': 7.24.5
+      '@babel/core': 7.24.7
+      '@babel/helper-plugin-utils': 7.24.7
 
-  '@babel/plugin-transform-typescript@7.24.5(@babel/core@7.24.5)':
+  '@babel/plugin-transform-typescript@7.24.7(@babel/core@7.24.7)':
     dependencies:
-      '@babel/core': 7.24.5
-      '@babel/helper-annotate-as-pure': 7.22.5
-      '@babel/helper-create-class-features-plugin': 7.24.5(@babel/core@7.24.5)
-      '@babel/helper-plugin-utils': 7.24.5
-      '@babel/plugin-syntax-typescript': 7.24.1(@babel/core@7.24.5)
+      '@babel/core': 7.24.7
+      '@babel/helper-annotate-as-pure': 7.24.7
+      '@babel/helper-create-class-features-plugin': 7.24.7(@babel/core@7.24.7)
+      '@babel/helper-plugin-utils': 7.24.7
+      '@babel/plugin-syntax-typescript': 7.24.7(@babel/core@7.24.7)
+    transitivePeerDependencies:
+      - supports-color
 
-  '@babel/template@7.24.0':
+  '@babel/template@7.24.7':
     dependencies:
-      '@babel/code-frame': 7.24.2
-      '@babel/parser': 7.24.5
-      '@babel/types': 7.24.5
+      '@babel/code-frame': 7.24.7
+      '@babel/parser': 7.24.7
+      '@babel/types': 7.24.7
 
-  '@babel/traverse@7.24.5':
+  '@babel/traverse@7.24.7':
     dependencies:
-      '@babel/code-frame': 7.24.2
-      '@babel/generator': 7.24.5
-      '@babel/helper-environment-visitor': 7.22.20
-      '@babel/helper-function-name': 7.23.0
-      '@babel/helper-hoist-variables': 7.22.5
-      '@babel/helper-split-export-declaration': 7.24.5
-      '@babel/parser': 7.24.5
-      '@babel/types': 7.24.5
-      debug: 4.3.4
+      '@babel/code-frame': 7.24.7
+      '@babel/generator': 7.24.7
+      '@babel/helper-environment-visitor': 7.24.7
+      '@babel/helper-function-name': 7.24.7
+      '@babel/helper-hoist-variables': 7.24.7
+      '@babel/helper-split-export-declaration': 7.24.7
+      '@babel/parser': 7.24.7
+      '@babel/types': 7.24.7
+      debug: 4.3.5
       globals: 11.12.0
     transitivePeerDependencies:
       - supports-color
 
-  '@babel/types@7.24.5':
+  '@babel/types@7.24.7':
     dependencies:
-      '@babel/helper-string-parser': 7.24.1
-      '@babel/helper-validator-identifier': 7.24.5
+      '@babel/helper-string-parser': 7.24.7
+      '@babel/helper-validator-identifier': 7.24.7
       to-fast-properties: 2.0.0
 
   '@bcoe/v8-coverage@0.2.3': {}
@@ -6573,7 +6610,7 @@ snapshots:
       d3-selection: 1.4.2
       d3-shape: 1.3.7
       d3-time-format: 2.3.0
-      debug: 4.3.4
+      debug: 4.3.5
       distributions: 2.2.0
       endpoint: 0.4.5
       hidden-markov-model-tf: 4.0.0(@tensorflow/tfjs-core@3.21.0(encoding@0.1.13))
@@ -6583,7 +6620,7 @@ snapshots:
       protocol-buffers: 4.2.0
       pump: 3.0.0
       pumpify: 2.0.1
-      semver: 7.6.0
+      semver: 7.6.2
       showdown: 1.9.1
       stream-template: 0.0.10
       streaming-json-stringify: 3.1.0
@@ -6641,11 +6678,11 @@ snapshots:
 
   '@colors/colors@1.6.0': {}
 
-  '@commitlint/cli@19.3.0(@types/node@20.12.10)(typescript@5.4.5)':
+  '@commitlint/cli@19.3.0(@types/node@20.14.2)(typescript@5.4.5)':
     dependencies:
       '@commitlint/format': 19.3.0
       '@commitlint/lint': 19.2.2
-      '@commitlint/load': 19.2.0(@types/node@20.12.10)(typescript@5.4.5)
+      '@commitlint/load': 19.2.0(@types/node@20.14.2)(typescript@5.4.5)
       '@commitlint/read': 19.2.1
       '@commitlint/types': 19.0.3
       execa: 8.0.1
@@ -6662,7 +6699,7 @@ snapshots:
   '@commitlint/config-validator@19.0.3':
     dependencies:
       '@commitlint/types': 19.0.3
-      ajv: 8.13.0
+      ajv: 8.16.0
 
   '@commitlint/ensure@19.0.3':
     dependencies:
@@ -6683,7 +6720,7 @@ snapshots:
   '@commitlint/is-ignored@19.2.2':
     dependencies:
       '@commitlint/types': 19.0.3
-      semver: 7.6.0
+      semver: 7.6.2
 
   '@commitlint/lint@19.2.2':
     dependencies:
@@ -6692,7 +6729,7 @@ snapshots:
       '@commitlint/rules': 19.0.3
       '@commitlint/types': 19.0.3
 
-  '@commitlint/load@19.2.0(@types/node@20.12.10)(typescript@5.4.5)':
+  '@commitlint/load@19.2.0(@types/node@20.14.2)(typescript@5.4.5)':
     dependencies:
       '@commitlint/config-validator': 19.0.3
       '@commitlint/execute-rule': 19.0.0
@@ -6700,7 +6737,7 @@ snapshots:
       '@commitlint/types': 19.0.3
       chalk: 5.3.0
       cosmiconfig: 9.0.0(typescript@5.4.5)
-      cosmiconfig-typescript-loader: 5.0.0(@types/node@20.12.10)(cosmiconfig@9.0.0(typescript@5.4.5))(typescript@5.4.5)
+      cosmiconfig-typescript-loader: 5.0.0(@types/node@20.14.2)(cosmiconfig@9.0.0(typescript@5.4.5))(typescript@5.4.5)
       lodash.isplainobject: 4.0.6
       lodash.merge: 4.6.2
       lodash.uniq: 4.5.0
@@ -6762,8 +6799,11 @@ snapshots:
       enabled: 2.0.0
       kuler: 2.0.0
 
-  '@es-joy/jsdoccomment@0.42.0':
+  '@es-joy/jsdoccomment@0.43.1':
     dependencies:
+      '@types/eslint': 8.56.10
+      '@types/estree': 1.0.5
+      '@typescript-eslint/types': 7.12.0
       comment-parser: 1.4.1
       esquery: 1.5.0
       jsdoc-type-pratt-parser: 4.0.0
@@ -6771,139 +6811,139 @@ snapshots:
   '@esbuild/aix-ppc64@0.20.2':
     optional: true
 
-  '@esbuild/aix-ppc64@0.21.0':
+  '@esbuild/aix-ppc64@0.21.4':
     optional: true
 
   '@esbuild/android-arm64@0.20.2':
     optional: true
 
-  '@esbuild/android-arm64@0.21.0':
+  '@esbuild/android-arm64@0.21.4':
     optional: true
 
   '@esbuild/android-arm@0.20.2':
     optional: true
 
-  '@esbuild/android-arm@0.21.0':
+  '@esbuild/android-arm@0.21.4':
     optional: true
 
   '@esbuild/android-x64@0.20.2':
     optional: true
 
-  '@esbuild/android-x64@0.21.0':
+  '@esbuild/android-x64@0.21.4':
     optional: true
 
   '@esbuild/darwin-arm64@0.20.2':
     optional: true
 
-  '@esbuild/darwin-arm64@0.21.0':
+  '@esbuild/darwin-arm64@0.21.4':
     optional: true
 
   '@esbuild/darwin-x64@0.20.2':
     optional: true
 
-  '@esbuild/darwin-x64@0.21.0':
+  '@esbuild/darwin-x64@0.21.4':
     optional: true
 
   '@esbuild/freebsd-arm64@0.20.2':
     optional: true
 
-  '@esbuild/freebsd-arm64@0.21.0':
+  '@esbuild/freebsd-arm64@0.21.4':
     optional: true
 
   '@esbuild/freebsd-x64@0.20.2':
     optional: true
 
-  '@esbuild/freebsd-x64@0.21.0':
+  '@esbuild/freebsd-x64@0.21.4':
     optional: true
 
   '@esbuild/linux-arm64@0.20.2':
     optional: true
 
-  '@esbuild/linux-arm64@0.21.0':
+  '@esbuild/linux-arm64@0.21.4':
     optional: true
 
   '@esbuild/linux-arm@0.20.2':
     optional: true
 
-  '@esbuild/linux-arm@0.21.0':
+  '@esbuild/linux-arm@0.21.4':
     optional: true
 
   '@esbuild/linux-ia32@0.20.2':
     optional: true
 
-  '@esbuild/linux-ia32@0.21.0':
+  '@esbuild/linux-ia32@0.21.4':
     optional: true
 
   '@esbuild/linux-loong64@0.20.2':
     optional: true
 
-  '@esbuild/linux-loong64@0.21.0':
+  '@esbuild/linux-loong64@0.21.4':
     optional: true
 
   '@esbuild/linux-mips64el@0.20.2':
     optional: true
 
-  '@esbuild/linux-mips64el@0.21.0':
+  '@esbuild/linux-mips64el@0.21.4':
     optional: true
 
   '@esbuild/linux-ppc64@0.20.2':
     optional: true
 
-  '@esbuild/linux-ppc64@0.21.0':
+  '@esbuild/linux-ppc64@0.21.4':
     optional: true
 
   '@esbuild/linux-riscv64@0.20.2':
     optional: true
 
-  '@esbuild/linux-riscv64@0.21.0':
+  '@esbuild/linux-riscv64@0.21.4':
     optional: true
 
   '@esbuild/linux-s390x@0.20.2':
     optional: true
 
-  '@esbuild/linux-s390x@0.21.0':
+  '@esbuild/linux-s390x@0.21.4':
     optional: true
 
   '@esbuild/linux-x64@0.20.2':
     optional: true
 
-  '@esbuild/linux-x64@0.21.0':
+  '@esbuild/linux-x64@0.21.4':
     optional: true
 
   '@esbuild/netbsd-x64@0.20.2':
     optional: true
 
-  '@esbuild/netbsd-x64@0.21.0':
+  '@esbuild/netbsd-x64@0.21.4':
     optional: true
 
   '@esbuild/openbsd-x64@0.20.2':
     optional: true
 
-  '@esbuild/openbsd-x64@0.21.0':
+  '@esbuild/openbsd-x64@0.21.4':
     optional: true
 
   '@esbuild/sunos-x64@0.20.2':
     optional: true
 
-  '@esbuild/sunos-x64@0.21.0':
+  '@esbuild/sunos-x64@0.21.4':
     optional: true
 
   '@esbuild/win32-arm64@0.20.2':
     optional: true
 
-  '@esbuild/win32-arm64@0.21.0':
+  '@esbuild/win32-arm64@0.21.4':
     optional: true
 
   '@esbuild/win32-ia32@0.20.2':
     optional: true
 
-  '@esbuild/win32-ia32@0.21.0':
+  '@esbuild/win32-ia32@0.21.4':
     optional: true
 
   '@esbuild/win32-x64@0.20.2':
     optional: true
 
-  '@esbuild/win32-x64@0.21.0':
+  '@esbuild/win32-x64@0.21.4':
     optional: true
 
   '@eslint-community/eslint-utils@4.4.0(eslint@8.57.0)':
@@ -6911,12 +6951,12 @@ snapshots:
       eslint: 8.57.0
       eslint-visitor-keys: 3.4.3
 
-  '@eslint-community/regexpp@4.10.0': {}
+  '@eslint-community/regexpp@4.10.1': {}
 
   '@eslint/eslintrc@2.1.4':
     dependencies:
       ajv: 6.12.6
-      debug: 4.3.4
+      debug: 4.3.5
       espree: 9.6.1
       globals: 13.24.0
       ignore: 5.3.1
@@ -6935,7 +6975,7 @@ snapshots:
   '@humanwhocodes/config-array@0.11.14':
     dependencies:
       '@humanwhocodes/object-schema': 2.0.3
-      debug: 4.3.4
+      debug: 4.3.5
       minimatch: 3.1.2
     transitivePeerDependencies:
       - supports-color
@@ -6946,7 +6986,7 @@ snapshots:
 
   '@iarna/toml@2.2.5': {}
 
-  '@inquirer/figures@1.0.1': {}
+  '@inquirer/figures@1.0.3': {}
 
   '@isaacs/cliui@8.0.2':
     dependencies:
@@ -6959,7 +6999,7 @@ snapshots:
 
   '@isaacs/fs-minipass@4.0.1':
     dependencies:
-      minipass: 7.1.0
+      minipass: 7.1.2
 
   '@istanbuljs/schema@0.1.3': {}
 
@@ -6982,7 +7022,7 @@ snapshots:
       '@jest/schemas': 29.6.3
       '@types/istanbul-lib-coverage': 2.0.6
       '@types/istanbul-reports': 3.0.4
-      '@types/node': 20.12.10
+      '@types/node': 20.14.2
       '@types/yargs': 17.0.32
       chalk: 4.1.2
 
@@ -7012,25 +7052,27 @@ snapshots:
     dependencies:
       call-bind: 1.0.7
 
-  '@microsoft/tsdoc-config@0.16.2':
+  '@microsoft/tsdoc-config@0.17.0':
     dependencies:
-      '@microsoft/tsdoc': 0.14.2
-      ajv: 6.12.6
+      '@microsoft/tsdoc': 0.15.0
+      ajv: 8.12.0
       jju: 1.4.0
-      resolve: 1.19.0
+      resolve: 1.22.8
 
-  '@microsoft/tsdoc@0.14.2': {}
+  '@microsoft/tsdoc@0.15.0': {}
 
-  '@mikro-orm/cli@6.2.5':
+  '@mikro-orm/cli@6.2.9(mariadb@3.3.0)':
     dependencies:
       '@jercle/yargonaut': 1.1.5
-      '@mikro-orm/core': 6.2.5
-      '@mikro-orm/knex': 6.2.5(@mikro-orm/core@6.2.5)(sqlite3@5.1.7)
+      '@mikro-orm/core': 6.2.9
+      '@mikro-orm/knex': 6.2.9(@mikro-orm/core@6.2.9)(mariadb@3.3.0)(sqlite3@5.1.7)
       fs-extra: 11.2.0
       tsconfig-paths: 4.2.0
       yargs: 17.7.2
     transitivePeerDependencies:
       - better-sqlite3
+      - libsql
+      - mariadb
       - mysql
       - mysql2
       - pg
@@ -7039,24 +7081,25 @@ snapshots:
       - supports-color
       - tedious
 
-  '@mikro-orm/core@6.2.5':
+  '@mikro-orm/core@6.2.9':
     dependencies:
       dataloader: 2.2.2
       dotenv: 16.4.5
       esprima: 4.0.1
       fs-extra: 11.2.0
       globby: 11.1.0
-      mikro-orm: 6.2.5
+      mikro-orm: 6.2.9
       reflect-metadata: 0.2.2
 
-  '@mikro-orm/knex@6.2.5(@mikro-orm/core@6.2.5)(sqlite3@5.1.7)':
+  '@mikro-orm/knex@6.2.9(@mikro-orm/core@6.2.9)(mariadb@3.3.0)(sqlite3@5.1.7)':
     dependencies:
-      '@mikro-orm/core': 6.2.5
+      '@mikro-orm/core': 6.2.9
       fs-extra: 11.2.0
       knex: 3.1.0(sqlite3@5.1.7)
       sqlstring: 2.3.3
+    optionalDependencies:
+      mariadb: 3.3.0
     transitivePeerDependencies:
-      - better-sqlite3
       - mysql
       - mysql2
       - pg
@@ -7065,13 +7108,14 @@ snapshots:
       - supports-color
       - tedious
 
-  '@mikro-orm/mariadb@6.2.5(@mikro-orm/core@6.2.5)':
+  '@mikro-orm/mariadb@6.2.9(@mikro-orm/core@6.2.9)':
     dependencies:
-      '@mikro-orm/core': 6.2.5
-      '@mikro-orm/knex': 6.2.5(@mikro-orm/core@6.2.5)(sqlite3@5.1.7)
+      '@mikro-orm/core': 6.2.9
+      '@mikro-orm/knex': 6.2.9(@mikro-orm/core@6.2.9)(mariadb@3.3.0)(sqlite3@5.1.7)
       mariadb: 3.3.0
     transitivePeerDependencies:
       - better-sqlite3
+      - libsql
       - mysql
       - mysql2
       - pg
@@ -7080,22 +7124,24 @@ snapshots:
       - supports-color
       - tedious
 
-  '@mikro-orm/reflection@6.2.5(@mikro-orm/core@6.2.5)':
+  '@mikro-orm/reflection@6.2.9(@mikro-orm/core@6.2.9)':
     dependencies:
-      '@mikro-orm/core': 6.2.5
+      '@mikro-orm/core': 6.2.9
       globby: 11.1.0
       ts-morph: 22.0.0
 
-  '@mikro-orm/sqlite@6.2.5(@mikro-orm/core@6.2.5)':
+  '@mikro-orm/sqlite@6.2.9(@mikro-orm/core@6.2.9)(mariadb@3.3.0)':
     dependencies:
-      '@mikro-orm/core': 6.2.5
-      '@mikro-orm/knex': 6.2.5(@mikro-orm/core@6.2.5)(sqlite3@5.1.7)
+      '@mikro-orm/core': 6.2.9
+      '@mikro-orm/knex': 6.2.9(@mikro-orm/core@6.2.9)(mariadb@3.3.0)(sqlite3@5.1.7)
       fs-extra: 11.2.0
       sqlite3: 5.1.7
       sqlstring-sqlite: 0.1.1
     transitivePeerDependencies:
       - better-sqlite3
       - bluebird
+      - libsql
+      - mariadb
       - mysql
       - mysql2
       - pg
@@ -7103,7 +7149,7 @@ snapshots:
       - supports-color
       - tedious
 
-  '@mongodb-js/saslprep@1.1.6':
+  '@mongodb-js/saslprep@1.1.7':
     dependencies:
       sparse-bitfield: 3.0.3
 
@@ -7127,7 +7173,7 @@ snapshots:
   '@npmcli/fs@1.1.1':
     dependencies:
       '@gar/promisify': 1.1.3
-      semver: 7.6.0
+      semver: 7.6.2
     optional: true
 
   '@npmcli/move-file@1.1.2':
@@ -7159,23 +7205,21 @@ snapshots:
       '@octokit/types': 13.5.0
       universal-user-agent: 6.0.1
 
-  '@octokit/openapi-types@20.0.0': {}
-
   '@octokit/openapi-types@22.2.0': {}
 
-  '@octokit/plugin-paginate-rest@9.2.1(@octokit/core@5.2.0)':
+  '@octokit/plugin-paginate-rest@11.3.1(@octokit/core@5.2.0)':
     dependencies:
       '@octokit/core': 5.2.0
-      '@octokit/types': 12.6.0
+      '@octokit/types': 13.5.0
 
   '@octokit/plugin-request-log@4.0.1(@octokit/core@5.2.0)':
     dependencies:
       '@octokit/core': 5.2.0
 
-  '@octokit/plugin-rest-endpoint-methods@10.4.1(@octokit/core@5.2.0)':
+  '@octokit/plugin-rest-endpoint-methods@13.2.2(@octokit/core@5.2.0)':
     dependencies:
       '@octokit/core': 5.2.0
-      '@octokit/types': 12.6.0
+      '@octokit/types': 13.5.0
 
   '@octokit/request-error@5.1.0':
     dependencies:
@@ -7190,16 +7234,12 @@ snapshots:
       '@octokit/types': 13.5.0
       universal-user-agent: 6.0.1
 
-  '@octokit/rest@20.1.0':
+  '@octokit/rest@20.1.1':
     dependencies:
       '@octokit/core': 5.2.0
-      '@octokit/plugin-paginate-rest': 9.2.1(@octokit/core@5.2.0)
+      '@octokit/plugin-paginate-rest': 11.3.1(@octokit/core@5.2.0)
       '@octokit/plugin-request-log': 4.0.1(@octokit/core@5.2.0)
-      '@octokit/plugin-rest-endpoint-methods': 10.4.1(@octokit/core@5.2.0)
-
-  '@octokit/types@12.6.0':
-    dependencies:
-      '@octokit/openapi-types': 20.0.0
+      '@octokit/plugin-rest-endpoint-methods': 13.2.2(@octokit/core@5.2.0)
 
   '@octokit/types@13.5.0':
     dependencies:
@@ -7224,66 +7264,66 @@ snapshots:
       '@pnpm/network.ca-file': 1.0.2
       config-chain: 1.1.13
 
-  '@release-it/bumper@6.0.1(release-it@17.2.1(typescript@5.4.5))':
+  '@release-it/bumper@6.0.1(release-it@17.3.0(typescript@5.4.5))':
     dependencies:
       '@iarna/toml': 2.2.5
       detect-indent: 7.0.1
       fast-glob: 3.3.2
-      ini: 4.1.2
+      ini: 4.1.3
       js-yaml: 4.1.0
       lodash-es: 4.17.21
-      release-it: 17.2.1(typescript@5.4.5)
-      semver: 7.6.0
+      release-it: 17.3.0(typescript@5.4.5)
+      semver: 7.6.2
 
-  '@rollup/rollup-android-arm-eabi@4.17.2':
+  '@rollup/rollup-android-arm-eabi@4.18.0':
     optional: true
 
-  '@rollup/rollup-android-arm64@4.17.2':
+  '@rollup/rollup-android-arm64@4.18.0':
     optional: true
 
-  '@rollup/rollup-darwin-arm64@4.17.2':
+  '@rollup/rollup-darwin-arm64@4.18.0':
     optional: true
 
-  '@rollup/rollup-darwin-x64@4.17.2':
+  '@rollup/rollup-darwin-x64@4.18.0':
     optional: true
 
-  '@rollup/rollup-linux-arm-gnueabihf@4.17.2':
+  '@rollup/rollup-linux-arm-gnueabihf@4.18.0':
     optional: true
 
-  '@rollup/rollup-linux-arm-musleabihf@4.17.2':
+  '@rollup/rollup-linux-arm-musleabihf@4.18.0':
     optional: true
 
-  '@rollup/rollup-linux-arm64-gnu@4.17.2':
+  '@rollup/rollup-linux-arm64-gnu@4.18.0':
     optional: true
 
-  '@rollup/rollup-linux-arm64-musl@4.17.2':
+  '@rollup/rollup-linux-arm64-musl@4.18.0':
     optional: true
 
-  '@rollup/rollup-linux-powerpc64le-gnu@4.17.2':
+  '@rollup/rollup-linux-powerpc64le-gnu@4.18.0':
     optional: true
 
-  '@rollup/rollup-linux-riscv64-gnu@4.17.2':
+  '@rollup/rollup-linux-riscv64-gnu@4.18.0':
     optional: true
 
-  '@rollup/rollup-linux-s390x-gnu@4.17.2':
+  '@rollup/rollup-linux-s390x-gnu@4.18.0':
     optional: true
 
-  '@rollup/rollup-linux-x64-gnu@4.17.2':
+  '@rollup/rollup-linux-x64-gnu@4.18.0':
     optional: true
 
-  '@rollup/rollup-linux-x64-musl@4.17.2':
+  '@rollup/rollup-linux-x64-musl@4.18.0':
     optional: true
 
-  '@rollup/rollup-win32-arm64-msvc@4.17.2':
+  '@rollup/rollup-win32-arm64-msvc@4.18.0':
     optional: true
 
-  '@rollup/rollup-win32-ia32-msvc@4.17.2':
+  '@rollup/rollup-win32-ia32-msvc@4.18.0':
     optional: true
 
-  '@rollup/rollup-win32-x64-msvc@4.17.2':
+  '@rollup/rollup-win32-x64-msvc@4.18.0':
     optional: true
 
-  '@rushstack/eslint-patch@1.10.2': {}
+  '@rushstack/eslint-patch@1.10.3': {}
 
   '@sinclair/typebox@0.27.8': {}
 
@@ -7338,7 +7378,12 @@ snapshots:
 
   '@types/conventional-commits-parser@5.0.0':
     dependencies:
-      '@types/node': 20.12.10
+      '@types/node': 20.14.2
+
+  '@types/eslint@8.56.10':
+    dependencies:
+      '@types/estree': 1.0.5
+      '@types/json-schema': 7.0.15
 
   '@types/estree@1.0.5': {}
 
@@ -7356,9 +7401,9 @@ snapshots:
     dependencies:
       '@types/istanbul-lib-report': 3.0.3
 
-  '@types/jsdom@21.1.6':
+  '@types/jsdom@21.1.7':
     dependencies:
-      '@types/node': 20.12.10
+      '@types/node': 20.14.2
       '@types/tough-cookie': 4.0.5
       parse5: 7.1.2
 
@@ -7368,7 +7413,7 @@ snapshots:
 
   '@types/long@4.0.2': {}
 
-  '@types/node@20.12.10':
+  '@types/node@20.14.2':
     dependencies:
       undici-types: 5.26.5
 
@@ -7388,13 +7433,13 @@ snapshots:
 
   '@types/webidl-conversions@7.0.3': {}
 
-  '@types/whatwg-url@11.0.4':
+  '@types/whatwg-url@11.0.5':
     dependencies:
       '@types/webidl-conversions': 7.0.3
 
   '@types/ws@8.5.10':
     dependencies:
-      '@types/node': 20.12.10
+      '@types/node': 20.14.2
 
   '@types/yargs-parser@21.0.3': {}
 
@@ -7402,49 +7447,47 @@ snapshots:
     dependencies:
       '@types/yargs-parser': 21.0.3
 
-  '@typescript-eslint/eslint-plugin@7.8.0(@typescript-eslint/parser@7.8.0(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0)(typescript@5.4.5)':
+  '@typescript-eslint/eslint-plugin@7.12.0(@typescript-eslint/parser@7.12.0(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0)(typescript@5.4.5)':
     dependencies:
-      '@eslint-community/regexpp': 4.10.0
-      '@typescript-eslint/parser': 7.8.0(eslint@8.57.0)(typescript@5.4.5)
-      '@typescript-eslint/scope-manager': 7.8.0
-      '@typescript-eslint/type-utils': 7.8.0(eslint@8.57.0)(typescript@5.4.5)
-      '@typescript-eslint/utils': 7.8.0(eslint@8.57.0)(typescript@5.4.5)
-      '@typescript-eslint/visitor-keys': 7.8.0
-      debug: 4.3.4
+      '@eslint-community/regexpp': 4.10.1
+      '@typescript-eslint/parser': 7.12.0(eslint@8.57.0)(typescript@5.4.5)
+      '@typescript-eslint/scope-manager': 7.12.0
+      '@typescript-eslint/type-utils': 7.12.0(eslint@8.57.0)(typescript@5.4.5)
+      '@typescript-eslint/utils': 7.12.0(eslint@8.57.0)(typescript@5.4.5)
+      '@typescript-eslint/visitor-keys': 7.12.0
       eslint: 8.57.0
       graphemer: 1.4.0
       ignore: 5.3.1
       natural-compare: 1.4.0
-      semver: 7.6.0
       ts-api-utils: 1.3.0(typescript@5.4.5)
     optionalDependencies:
       typescript: 5.4.5
     transitivePeerDependencies:
       - supports-color
 
-  '@typescript-eslint/parser@7.8.0(eslint@8.57.0)(typescript@5.4.5)':
+  '@typescript-eslint/parser@7.12.0(eslint@8.57.0)(typescript@5.4.5)':
     dependencies:
-      '@typescript-eslint/scope-manager': 7.8.0
-      '@typescript-eslint/types': 7.8.0
-      '@typescript-eslint/typescript-estree': 7.8.0(typescript@5.4.5)
-      '@typescript-eslint/visitor-keys': 7.8.0
-      debug: 4.3.4
+      '@typescript-eslint/scope-manager': 7.12.0
+      '@typescript-eslint/types': 7.12.0
+      '@typescript-eslint/typescript-estree': 7.12.0(typescript@5.4.5)
+      '@typescript-eslint/visitor-keys': 7.12.0
+      debug: 4.3.5
       eslint: 8.57.0
     optionalDependencies:
       typescript: 5.4.5
     transitivePeerDependencies:
       - supports-color
 
-  '@typescript-eslint/scope-manager@7.8.0':
+  '@typescript-eslint/scope-manager@7.12.0':
     dependencies:
-      '@typescript-eslint/types': 7.8.0
-      '@typescript-eslint/visitor-keys': 7.8.0
+      '@typescript-eslint/types': 7.12.0
+      '@typescript-eslint/visitor-keys': 7.12.0
 
-  '@typescript-eslint/type-utils@7.8.0(eslint@8.57.0)(typescript@5.4.5)':
+  '@typescript-eslint/type-utils@7.12.0(eslint@8.57.0)(typescript@5.4.5)':
     dependencies:
-      '@typescript-eslint/typescript-estree': 7.8.0(typescript@5.4.5)
-      '@typescript-eslint/utils': 7.8.0(eslint@8.57.0)(typescript@5.4.5)
-      debug: 4.3.4
+      '@typescript-eslint/typescript-estree': 7.12.0(typescript@5.4.5)
+      '@typescript-eslint/utils': 7.12.0(eslint@8.57.0)(typescript@5.4.5)
+      debug: 4.3.5
       eslint: 8.57.0
       ts-api-utils: 1.3.0(typescript@5.4.5)
     optionalDependencies:
@@ -7452,75 +7495,72 @@ snapshots:
     transitivePeerDependencies:
       - supports-color
 
-  '@typescript-eslint/types@7.8.0': {}
+  '@typescript-eslint/types@7.12.0': {}
 
-  '@typescript-eslint/typescript-estree@7.8.0(typescript@5.4.5)':
+  '@typescript-eslint/typescript-estree@7.12.0(typescript@5.4.5)':
     dependencies:
-      '@typescript-eslint/types': 7.8.0
-      '@typescript-eslint/visitor-keys': 7.8.0
-      debug: 4.3.4
+      '@typescript-eslint/types': 7.12.0
+      '@typescript-eslint/visitor-keys': 7.12.0
+      debug: 4.3.5
       globby: 11.1.0
       is-glob: 4.0.3
       minimatch: 9.0.4
-      semver: 7.6.0
+      semver: 7.6.2
       ts-api-utils: 1.3.0(typescript@5.4.5)
     optionalDependencies:
       typescript: 5.4.5
     transitivePeerDependencies:
       - supports-color
 
-  '@typescript-eslint/utils@7.8.0(eslint@8.57.0)(typescript@5.4.5)':
+  '@typescript-eslint/utils@7.12.0(eslint@8.57.0)(typescript@5.4.5)':
     dependencies:
       '@eslint-community/eslint-utils': 4.4.0(eslint@8.57.0)
-      '@types/json-schema': 7.0.15
-      '@types/semver': 7.5.8
-      '@typescript-eslint/scope-manager': 7.8.0
-      '@typescript-eslint/types': 7.8.0
-      '@typescript-eslint/typescript-estree': 7.8.0(typescript@5.4.5)
+      '@typescript-eslint/scope-manager': 7.12.0
+      '@typescript-eslint/types': 7.12.0
+      '@typescript-eslint/typescript-estree': 7.12.0(typescript@5.4.5)
       eslint: 8.57.0
-      semver: 7.6.0
     transitivePeerDependencies:
       - supports-color
       - typescript
 
-  '@typescript-eslint/visitor-keys@7.8.0':
+  '@typescript-eslint/visitor-keys@7.12.0':
     dependencies:
-      '@typescript-eslint/types': 7.8.0
+      '@typescript-eslint/types': 7.12.0
       eslint-visitor-keys: 3.4.3
 
   '@ungap/structured-clone@1.2.0': {}
 
-  '@vitejs/plugin-vue-jsx@3.1.0(vite@5.2.11(@types/node@20.12.10))(vue@3.4.27(typescript@5.4.5))':
+  '@vitejs/plugin-vue-jsx@4.0.0(vite@5.2.13(@types/node@20.14.2))(vue@3.4.27(typescript@5.4.5))':
     dependencies:
-      '@babel/core': 7.24.5
-      '@babel/plugin-transform-typescript': 7.24.5(@babel/core@7.24.5)
-      '@vue/babel-plugin-jsx': 1.2.2(@babel/core@7.24.5)
-      vite: 5.2.11(@types/node@20.12.10)
+      '@babel/core': 7.24.7
+      '@babel/plugin-transform-typescript': 7.24.7(@babel/core@7.24.7)
+      '@vue/babel-plugin-jsx': 1.2.2(@babel/core@7.24.7)
+      vite: 5.2.13(@types/node@20.14.2)
       vue: 3.4.27(typescript@5.4.5)
     transitivePeerDependencies:
       - supports-color
 
-  '@vitejs/plugin-vue@5.0.4(vite@5.2.11(@types/node@20.12.10))(vue@3.4.27(typescript@5.4.5))':
+  '@vitejs/plugin-vue@5.0.5(vite@5.2.13(@types/node@20.14.2))(vue@3.4.27(typescript@5.4.5))':
     dependencies:
-      vite: 5.2.11(@types/node@20.12.10)
+      vite: 5.2.13(@types/node@20.14.2)
       vue: 3.4.27(typescript@5.4.5)
 
-  '@vitest/coverage-v8@1.6.0(vitest@1.6.0(@types/node@20.12.10)(jsdom@24.0.0(bufferutil@4.0.8)(utf-8-validate@6.0.3)))':
+  '@vitest/coverage-v8@1.6.0(vitest@1.6.0(@types/node@20.14.2)(jsdom@24.1.0(bufferutil@4.0.8)(utf-8-validate@6.0.4)))':
     dependencies:
       '@ampproject/remapping': 2.3.0
       '@bcoe/v8-coverage': 0.2.3
-      debug: 4.3.4
+      debug: 4.3.5
       istanbul-lib-coverage: 3.2.2
       istanbul-lib-report: 3.0.1
       istanbul-lib-source-maps: 5.0.4
       istanbul-reports: 3.1.7
       magic-string: 0.30.10
       magicast: 0.3.4
-      picocolors: 1.0.0
+      picocolors: 1.0.1
       std-env: 3.7.0
       strip-literal: 2.1.0
       test-exclude: 6.0.0
-      vitest: 1.6.0(@types/node@20.12.10)(jsdom@24.0.0(bufferutil@4.0.8)(utf-8-validate@6.0.3))
+      vitest: 1.6.0(@types/node@20.14.2)(jsdom@24.1.0(bufferutil@4.0.8)(utf-8-validate@6.0.4))
     transitivePeerDependencies:
       - supports-color
 
@@ -7555,36 +7595,36 @@ snapshots:
 
   '@vue/babel-helper-vue-transform-on@1.2.2': {}
 
-  '@vue/babel-plugin-jsx@1.2.2(@babel/core@7.24.5)':
+  '@vue/babel-plugin-jsx@1.2.2(@babel/core@7.24.7)':
     dependencies:
       '@babel/helper-module-imports': 7.22.15
-      '@babel/helper-plugin-utils': 7.24.5
-      '@babel/plugin-syntax-jsx': 7.24.1(@babel/core@7.24.5)
-      '@babel/template': 7.24.0
-      '@babel/traverse': 7.24.5
-      '@babel/types': 7.24.5
+      '@babel/helper-plugin-utils': 7.24.7
+      '@babel/plugin-syntax-jsx': 7.24.7(@babel/core@7.24.7)
+      '@babel/template': 7.24.7
+      '@babel/traverse': 7.24.7
+      '@babel/types': 7.24.7
       '@vue/babel-helper-vue-transform-on': 1.2.2
-      '@vue/babel-plugin-resolve-type': 1.2.2(@babel/core@7.24.5)
+      '@vue/babel-plugin-resolve-type': 1.2.2(@babel/core@7.24.7)
       camelcase: 6.3.0
       html-tags: 3.3.1
       svg-tags: 1.0.0
     optionalDependencies:
-      '@babel/core': 7.24.5
+      '@babel/core': 7.24.7
     transitivePeerDependencies:
       - supports-color
 
-  '@vue/babel-plugin-resolve-type@1.2.2(@babel/core@7.24.5)':
+  '@vue/babel-plugin-resolve-type@1.2.2(@babel/core@7.24.7)':
     dependencies:
-      '@babel/code-frame': 7.24.2
-      '@babel/core': 7.24.5
+      '@babel/code-frame': 7.24.7
+      '@babel/core': 7.24.7
       '@babel/helper-module-imports': 7.22.15
-      '@babel/helper-plugin-utils': 7.24.5
-      '@babel/parser': 7.24.5
+      '@babel/helper-plugin-utils': 7.24.7
+      '@babel/parser': 7.24.7
       '@vue/compiler-sfc': 3.4.27
 
   '@vue/compiler-core@3.4.27':
     dependencies:
-      '@babel/parser': 7.24.5
+      '@babel/parser': 7.24.7
       '@vue/shared': 3.4.27
       entities: 4.5.0
       estree-walker: 2.0.2
@@ -7597,7 +7637,7 @@ snapshots:
 
   '@vue/compiler-sfc@3.4.27':
     dependencies:
-      '@babel/parser': 7.24.5
+      '@babel/parser': 7.24.7
       '@vue/compiler-core': 3.4.27
       '@vue/compiler-dom': 3.4.27
       '@vue/compiler-ssr': 3.4.27
@@ -7612,24 +7652,24 @@ snapshots:
       '@vue/compiler-dom': 3.4.27
       '@vue/shared': 3.4.27
 
-  '@vue/devtools-api@6.6.1': {}
+  '@vue/devtools-api@6.6.3': {}
 
-  '@vue/eslint-config-prettier@9.0.0(eslint@8.57.0)(prettier@3.2.5)':
+  '@vue/eslint-config-prettier@9.0.0(@types/eslint@8.56.10)(eslint@8.57.0)(prettier@3.3.1)':
     dependencies:
       eslint: 8.57.0
       eslint-config-prettier: 9.1.0(eslint@8.57.0)
-      eslint-plugin-prettier: 5.1.3(eslint-config-prettier@9.1.0(eslint@8.57.0))(eslint@8.57.0)(prettier@3.2.5)
-      prettier: 3.2.5
+      eslint-plugin-prettier: 5.1.3(@types/eslint@8.56.10)(eslint-config-prettier@9.1.0(eslint@8.57.0))(eslint@8.57.0)(prettier@3.3.1)
+      prettier: 3.3.1
     transitivePeerDependencies:
       - '@types/eslint'
 
-  '@vue/eslint-config-typescript@13.0.0(eslint-plugin-vue@9.25.0(eslint@8.57.0))(eslint@8.57.0)(typescript@5.4.5)':
+  '@vue/eslint-config-typescript@13.0.0(eslint-plugin-vue@9.26.0(eslint@8.57.0))(eslint@8.57.0)(typescript@5.4.5)':
     dependencies:
-      '@typescript-eslint/eslint-plugin': 7.8.0(@typescript-eslint/parser@7.8.0(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0)(typescript@5.4.5)
-      '@typescript-eslint/parser': 7.8.0(eslint@8.57.0)(typescript@5.4.5)
+      '@typescript-eslint/eslint-plugin': 7.12.0(@typescript-eslint/parser@7.12.0(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0)(typescript@5.4.5)
+      '@typescript-eslint/parser': 7.12.0(eslint@8.57.0)(typescript@5.4.5)
       eslint: 8.57.0
-      eslint-plugin-vue: 9.25.0(eslint@8.57.0)
-      vue-eslint-parser: 9.4.2(eslint@8.57.0)
+      eslint-plugin-vue: 9.26.0(eslint@8.57.0)
+      vue-eslint-parser: 9.4.3(eslint@8.57.0)
     optionalDependencies:
       typescript: 5.4.5
     transitivePeerDependencies:
@@ -7661,7 +7701,7 @@ snapshots:
   '@vue/test-utils@2.4.6':
     dependencies:
       js-beautify: 1.15.1
-      vue-component-type-helpers: 2.0.16
+      vue-component-type-helpers: 2.0.21
 
   '@vue/tsconfig@0.5.1': {}
 
@@ -7701,14 +7741,14 @@ snapshots:
 
   agent-base@6.0.2:
     dependencies:
-      debug: 4.3.4
+      debug: 4.3.5
     transitivePeerDependencies:
       - supports-color
     optional: true
 
   agent-base@7.1.1:
     dependencies:
-      debug: 4.3.4
+      debug: 4.3.5
     transitivePeerDependencies:
       - supports-color
 
@@ -7722,13 +7762,13 @@ snapshots:
       clean-stack: 2.2.0
       indent-string: 4.0.0
 
-  ajv-formats@2.1.1(ajv@8.13.0):
+  ajv-formats@2.1.1(ajv@8.16.0):
     optionalDependencies:
-      ajv: 8.13.0
+      ajv: 8.16.0
 
-  ajv-formats@3.0.1(ajv@8.13.0):
+  ajv-formats@3.0.1(ajv@8.16.0):
     optionalDependencies:
-      ajv: 8.13.0
+      ajv: 8.16.0
 
   ajv@6.12.6:
     dependencies:
@@ -7737,7 +7777,14 @@ snapshots:
       json-schema-traverse: 0.4.1
       uri-js: 4.4.1
 
-  ajv@8.13.0:
+  ajv@8.12.0:
+    dependencies:
+      fast-deep-equal: 3.1.3
+      json-schema-traverse: 1.0.0
+      require-from-string: 2.0.2
+      uri-js: 4.4.1
+
+  ajv@8.16.0:
     dependencies:
       fast-deep-equal: 3.1.3
       json-schema-traverse: 1.0.0
@@ -7888,7 +7935,7 @@ snapshots:
 
   ast-types@0.13.4:
     dependencies:
-      tslib: 2.6.2
+      tslib: 2.6.3
 
   async-retry@1.3.3:
     dependencies:
@@ -7912,7 +7959,7 @@ snapshots:
       handlebars: 4.7.8
       node-fetch: 2.7.0(encoding@0.1.13)
       parse-github-url: 1.0.2
-      semver: 7.6.0
+      semver: 7.6.2
     transitivePeerDependencies:
       - encoding
 
@@ -7920,7 +7967,7 @@ snapshots:
     dependencies:
       chalk: 4.1.2
       char-spinner: 1.0.1
-      cli-table3: 0.6.4
+      cli-table3: 0.6.5
       color-support: 1.1.3
       cross-argv: 2.0.0
       form-data: 4.0.0
@@ -7938,7 +7985,7 @@ snapshots:
       progress: 2.0.3
       reinterval: 1.1.0
       retimer: 3.0.0
-      semver: 7.6.0
+      semver: 7.6.2
       subarg: 1.0.0
       timestring: 6.0.0
 
@@ -7948,7 +7995,7 @@ snapshots:
 
   aws-sign2@0.7.0: {}
 
-  aws4@1.12.0: {}
+  aws4@1.13.0: {}
 
   b4a@1.6.6: {}
 
@@ -8015,9 +8062,9 @@ snapshots:
     dependencies:
       balanced-match: 1.0.2
 
-  braces@3.0.2:
+  braces@3.0.3:
     dependencies:
-      fill-range: 7.0.1
+      fill-range: 7.1.1
 
   brfs@2.0.2:
     dependencies:
@@ -8138,12 +8185,12 @@ snapshots:
       vm-browserify: 1.1.2
       xtend: 4.0.2
 
-  browserslist@4.23.0:
+  browserslist@4.23.1:
     dependencies:
-      caniuse-lite: 1.0.30001616
-      electron-to-chromium: 1.4.757
+      caniuse-lite: 1.0.30001629
+      electron-to-chromium: 1.4.796
       node-releases: 2.0.14
-      update-browserslist-db: 1.0.15(browserslist@4.23.0)
+      update-browserslist-db: 1.0.16(browserslist@4.23.1)
 
   bson@6.7.0: {}
 
@@ -8168,8 +8215,6 @@ snapshots:
       node-gyp-build: 4.8.1
     optional: true
 
-  builtin-modules@3.3.0: {}
-
   builtin-status-codes@3.0.0: {}
 
   bundle-name@4.1.0:
@@ -8251,7 +8296,7 @@ snapshots:
 
   camelcase@7.0.1: {}
 
-  caniuse-lite@1.0.30001616: {}
+  caniuse-lite@1.0.30001629: {}
 
   caseless@0.12.0: {}
 
@@ -8261,7 +8306,7 @@ snapshots:
     dependencies:
       assertion-error: 1.1.0
       check-error: 1.0.3
-      deep-eql: 4.1.3
+      deep-eql: 4.1.4
       get-func-name: 2.0.2
       loupe: 2.3.7
       pathval: 1.1.1
@@ -8299,7 +8344,7 @@ snapshots:
   chokidar@3.6.0:
     dependencies:
       anymatch: 3.1.3
-      braces: 3.0.2
+      braces: 3.0.3
       glob-parent: 5.1.2
       is-binary-path: 2.1.0
       is-glob: 4.0.3
@@ -8343,7 +8388,7 @@ snapshots:
 
   cli-spinners@2.9.2: {}
 
-  cli-table3@0.6.4:
+  cli-table3@0.6.5:
     dependencies:
       string-width: 4.2.3
     optionalDependencies:
@@ -8450,7 +8495,7 @@ snapshots:
 
   commander@10.0.1: {}
 
-  commander@11.1.0: {}
+  commander@12.1.0: {}
 
   commander@2.20.3: {}
 
@@ -8486,8 +8531,8 @@ snapshots:
 
   conf@10.2.0:
     dependencies:
-      ajv: 8.13.0
-      ajv-formats: 2.1.1(ajv@8.13.0)
+      ajv: 8.16.0
+      ajv-formats: 2.1.1(ajv@8.16.0)
       atomically: 1.7.0
       debounce-fn: 4.0.0
       dot-prop: 6.0.1
@@ -8495,7 +8540,7 @@ snapshots:
       json-schema-typed: 7.0.3
       onetime: 5.1.2
       pkg-up: 3.1.0
-      semver: 7.6.0
+      semver: 7.6.2
 
   confbox@0.1.7: {}
 
@@ -8557,11 +8602,11 @@ snapshots:
 
   core-util-is@1.0.3: {}
 
-  cosmiconfig-typescript-loader@5.0.0(@types/node@20.12.10)(cosmiconfig@9.0.0(typescript@5.4.5))(typescript@5.4.5):
+  cosmiconfig-typescript-loader@5.0.0(@types/node@20.14.2)(cosmiconfig@9.0.0(typescript@5.4.5))(typescript@5.4.5):
     dependencies:
-      '@types/node': 20.12.10
+      '@types/node': 20.14.2
       cosmiconfig: 9.0.0(typescript@5.4.5)
-      jiti: 1.21.0
+      jiti: 1.21.3
       typescript: 5.4.5
 
   cosmiconfig@9.0.0(typescript@5.4.5):
@@ -8728,7 +8773,7 @@ snapshots:
   d@1.0.2:
     dependencies:
       es5-ext: 0.10.64
-      type: 2.7.2
+      type: 2.7.3
 
   dargs@7.0.0: {}
 
@@ -8791,6 +8836,10 @@ snapshots:
     dependencies:
       ms: 2.1.2
 
+  debug@4.3.5:
+    dependencies:
+      ms: 2.1.2
+
   decamelize@1.2.0: {}
 
   decimal.js@10.4.3: {}
@@ -8799,7 +8848,7 @@ snapshots:
     dependencies:
       mimic-response: 3.1.0
 
-  deep-eql@4.1.3:
+  deep-eql@4.1.4:
     dependencies:
       type-detect: 4.0.8
 
@@ -8951,11 +9000,11 @@ snapshots:
       '@one-ini/wasm': 0.1.1
       commander: 10.0.1
       minimatch: 9.0.1
-      semver: 7.6.0
+      semver: 7.6.2
 
   ee-first@1.1.1: {}
 
-  electron-to-chromium@1.4.757: {}
+  electron-to-chromium@1.4.796: {}
 
   elliptic@6.5.5:
     dependencies:
@@ -8992,7 +9041,7 @@ snapshots:
     dependencies:
       inherits: 2.0.4
 
-  enhanced-resolve@5.16.0:
+  enhanced-resolve@5.17.0:
     dependencies:
       graceful-fs: 4.2.11
       tapable: 2.2.1
@@ -9128,24 +9177,24 @@ snapshots:
       es6-iterator: 2.0.3
       es6-symbol: 3.1.4
       event-emitter: 0.3.5
-      type: 2.7.2
+      type: 2.7.3
 
   es6-symbol@3.1.4:
     dependencies:
       d: 1.0.2
       ext: 1.7.0
 
-  esbuild-plugin-clean@1.0.1(esbuild@0.21.0):
+  esbuild-plugin-clean@1.0.1(esbuild@0.21.4):
     dependencies:
       chalk: 4.1.2
       del: 6.1.1
-      esbuild: 0.21.0
+      esbuild: 0.21.4
 
-  esbuild-plugin-copy@2.1.1(esbuild@0.21.0):
+  esbuild-plugin-copy@2.1.1(esbuild@0.21.4):
     dependencies:
       chalk: 4.1.2
       chokidar: 3.6.0
-      esbuild: 0.21.0
+      esbuild: 0.21.4
       fs-extra: 10.1.0
       globby: 11.1.0
 
@@ -9175,31 +9224,31 @@ snapshots:
       '@esbuild/win32-ia32': 0.20.2
       '@esbuild/win32-x64': 0.20.2
 
-  esbuild@0.21.0:
+  esbuild@0.21.4:
     optionalDependencies:
-      '@esbuild/aix-ppc64': 0.21.0
-      '@esbuild/android-arm': 0.21.0
-      '@esbuild/android-arm64': 0.21.0
-      '@esbuild/android-x64': 0.21.0
-      '@esbuild/darwin-arm64': 0.21.0
-      '@esbuild/darwin-x64': 0.21.0
-      '@esbuild/freebsd-arm64': 0.21.0
-      '@esbuild/freebsd-x64': 0.21.0
-      '@esbuild/linux-arm': 0.21.0
-      '@esbuild/linux-arm64': 0.21.0
-      '@esbuild/linux-ia32': 0.21.0
-      '@esbuild/linux-loong64': 0.21.0
-      '@esbuild/linux-mips64el': 0.21.0
-      '@esbuild/linux-ppc64': 0.21.0
-      '@esbuild/linux-riscv64': 0.21.0
-      '@esbuild/linux-s390x': 0.21.0
-      '@esbuild/linux-x64': 0.21.0
-      '@esbuild/netbsd-x64': 0.21.0
-      '@esbuild/openbsd-x64': 0.21.0
-      '@esbuild/sunos-x64': 0.21.0
-      '@esbuild/win32-arm64': 0.21.0
-      '@esbuild/win32-ia32': 0.21.0
-      '@esbuild/win32-x64': 0.21.0
+      '@esbuild/aix-ppc64': 0.21.4
+      '@esbuild/android-arm': 0.21.4
+      '@esbuild/android-arm64': 0.21.4
+      '@esbuild/android-x64': 0.21.4
+      '@esbuild/darwin-arm64': 0.21.4
+      '@esbuild/darwin-x64': 0.21.4
+      '@esbuild/freebsd-arm64': 0.21.4
+      '@esbuild/freebsd-x64': 0.21.4
+      '@esbuild/linux-arm': 0.21.4
+      '@esbuild/linux-arm64': 0.21.4
+      '@esbuild/linux-ia32': 0.21.4
+      '@esbuild/linux-loong64': 0.21.4
+      '@esbuild/linux-mips64el': 0.21.4
+      '@esbuild/linux-ppc64': 0.21.4
+      '@esbuild/linux-riscv64': 0.21.4
+      '@esbuild/linux-s390x': 0.21.4
+      '@esbuild/linux-x64': 0.21.4
+      '@esbuild/netbsd-x64': 0.21.4
+      '@esbuild/openbsd-x64': 0.21.4
+      '@esbuild/sunos-x64': 0.21.4
+      '@esbuild/win32-arm64': 0.21.4
+      '@esbuild/win32-ia32': 0.21.4
+      '@esbuild/win32-x64': 0.21.4
 
   escalade@3.1.2: {}
 
@@ -9232,18 +9281,18 @@ snapshots:
     optionalDependencies:
       source-map: 0.6.1
 
-  eslint-compat-utils@0.5.0(eslint@8.57.0):
+  eslint-compat-utils@0.5.1(eslint@8.57.0):
     dependencies:
       eslint: 8.57.0
-      semver: 7.6.0
+      semver: 7.6.2
 
-  eslint-config-love@47.0.0(@typescript-eslint/eslint-plugin@7.8.0(@typescript-eslint/parser@7.8.0(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0)(typescript@5.4.5))(eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.8.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0))(eslint-plugin-n@17.5.0(eslint@8.57.0))(eslint-plugin-promise@6.1.1(eslint@8.57.0))(eslint@8.57.0)(typescript@5.4.5):
+  eslint-config-love@47.0.0(@typescript-eslint/eslint-plugin@7.12.0(@typescript-eslint/parser@7.12.0(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0)(typescript@5.4.5))(eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.12.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0))(eslint-plugin-n@17.8.1(eslint@8.57.0))(eslint-plugin-promise@6.1.1(eslint@8.57.0))(eslint@8.57.0)(typescript@5.4.5):
     dependencies:
-      '@typescript-eslint/eslint-plugin': 7.8.0(@typescript-eslint/parser@7.8.0(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0)(typescript@5.4.5)
-      '@typescript-eslint/parser': 7.8.0(eslint@8.57.0)(typescript@5.4.5)
+      '@typescript-eslint/eslint-plugin': 7.12.0(@typescript-eslint/parser@7.12.0(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0)(typescript@5.4.5)
+      '@typescript-eslint/parser': 7.12.0(eslint@8.57.0)(typescript@5.4.5)
       eslint: 8.57.0
-      eslint-plugin-import: 2.29.1(@typescript-eslint/parser@7.8.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0)
-      eslint-plugin-n: 17.5.0(eslint@8.57.0)
+      eslint-plugin-import: 2.29.1(@typescript-eslint/parser@7.12.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0)
+      eslint-plugin-n: 17.8.1(eslint@8.57.0)
       eslint-plugin-promise: 6.1.1(eslint@8.57.0)
       typescript: 5.4.5
     transitivePeerDependencies:
@@ -9253,11 +9302,11 @@ snapshots:
     dependencies:
       eslint: 8.57.0
 
-  eslint-config-standard@17.1.0(eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.8.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0))(eslint-plugin-n@17.5.0(eslint@8.57.0))(eslint-plugin-promise@6.1.1(eslint@8.57.0))(eslint@8.57.0):
+  eslint-config-standard@17.1.0(eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.12.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0))(eslint-plugin-n@17.8.1(eslint@8.57.0))(eslint-plugin-promise@6.1.1(eslint@8.57.0))(eslint@8.57.0):
     dependencies:
       eslint: 8.57.0
-      eslint-plugin-import: 2.29.1(@typescript-eslint/parser@7.8.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0)
-      eslint-plugin-n: 17.5.0(eslint@8.57.0)
+      eslint-plugin-import: 2.29.1(@typescript-eslint/parser@7.12.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0)
+      eslint-plugin-n: 17.8.1(eslint@8.57.0)
       eslint-plugin-promise: 6.1.1(eslint@8.57.0)
 
   eslint-define-config@2.1.0: {}
@@ -9270,15 +9319,15 @@ snapshots:
     transitivePeerDependencies:
       - supports-color
 
-  eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@7.8.0(eslint@8.57.0)(typescript@5.4.5))(eslint-plugin-import@2.29.1)(eslint@8.57.0):
+  eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@7.12.0(eslint@8.57.0)(typescript@5.4.5))(eslint-plugin-import@2.29.1)(eslint@8.57.0):
     dependencies:
-      debug: 4.3.4
-      enhanced-resolve: 5.16.0
+      debug: 4.3.5
+      enhanced-resolve: 5.17.0
       eslint: 8.57.0
-      eslint-module-utils: 2.8.1(@typescript-eslint/parser@7.8.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@7.8.0(eslint@8.57.0)(typescript@5.4.5))(eslint-plugin-import@2.29.1)(eslint@8.57.0))(eslint@8.57.0)
-      eslint-plugin-import: 2.29.1(@typescript-eslint/parser@7.8.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0)
+      eslint-module-utils: 2.8.1(@typescript-eslint/parser@7.12.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@7.12.0(eslint@8.57.0)(typescript@5.4.5))(eslint-plugin-import@2.29.1)(eslint@8.57.0))(eslint@8.57.0)
+      eslint-plugin-import: 2.29.1(@typescript-eslint/parser@7.12.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0)
       fast-glob: 3.3.2
-      get-tsconfig: 4.7.4
+      get-tsconfig: 4.7.5
       is-core-module: 2.13.1
       is-glob: 4.0.3
     transitivePeerDependencies:
@@ -9287,25 +9336,25 @@ snapshots:
       - eslint-import-resolver-webpack
       - supports-color
 
-  eslint-module-utils@2.8.1(@typescript-eslint/parser@7.8.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@7.8.0(eslint@8.57.0)(typescript@5.4.5))(eslint-plugin-import@2.29.1)(eslint@8.57.0))(eslint@8.57.0):
+  eslint-module-utils@2.8.1(@typescript-eslint/parser@7.12.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@7.12.0(eslint@8.57.0)(typescript@5.4.5))(eslint-plugin-import@2.29.1)(eslint@8.57.0))(eslint@8.57.0):
     dependencies:
       debug: 3.2.7
     optionalDependencies:
-      '@typescript-eslint/parser': 7.8.0(eslint@8.57.0)(typescript@5.4.5)
+      '@typescript-eslint/parser': 7.12.0(eslint@8.57.0)(typescript@5.4.5)
       eslint: 8.57.0
       eslint-import-resolver-node: 0.3.9
-      eslint-import-resolver-typescript: 3.6.1(@typescript-eslint/parser@7.8.0(eslint@8.57.0)(typescript@5.4.5))(eslint-plugin-import@2.29.1)(eslint@8.57.0)
+      eslint-import-resolver-typescript: 3.6.1(@typescript-eslint/parser@7.12.0(eslint@8.57.0)(typescript@5.4.5))(eslint-plugin-import@2.29.1)(eslint@8.57.0)
     transitivePeerDependencies:
       - supports-color
 
-  eslint-plugin-es-x@7.6.0(eslint@8.57.0):
+  eslint-plugin-es-x@7.7.0(eslint@8.57.0):
     dependencies:
       '@eslint-community/eslint-utils': 4.4.0(eslint@8.57.0)
-      '@eslint-community/regexpp': 4.10.0
+      '@eslint-community/regexpp': 4.10.1
       eslint: 8.57.0
-      eslint-compat-utils: 0.5.0(eslint@8.57.0)
+      eslint-compat-utils: 0.5.1(eslint@8.57.0)
 
-  eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.8.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0):
+  eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.12.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0):
     dependencies:
       array-includes: 3.1.8
       array.prototype.findlastindex: 1.2.5
@@ -9315,7 +9364,7 @@ snapshots:
       doctrine: 2.1.0
       eslint: 8.57.0
       eslint-import-resolver-node: 0.3.9
-      eslint-module-utils: 2.8.1(@typescript-eslint/parser@7.8.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@7.8.0(eslint@8.57.0)(typescript@5.4.5))(eslint-plugin-import@2.29.1)(eslint@8.57.0))(eslint@8.57.0)
+      eslint-module-utils: 2.8.1(@typescript-eslint/parser@7.12.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@7.12.0(eslint@8.57.0)(typescript@5.4.5))(eslint-plugin-import@2.29.1)(eslint@8.57.0))(eslint@8.57.0)
       hasown: 2.0.2
       is-core-module: 2.13.1
       is-glob: 4.0.3
@@ -9323,49 +9372,49 @@ snapshots:
       object.fromentries: 2.0.8
       object.groupby: 1.0.3
       object.values: 1.2.0
-      semver: 7.6.0
+      semver: 7.6.2
       tsconfig-paths: 3.15.0
     optionalDependencies:
-      '@typescript-eslint/parser': 7.8.0(eslint@8.57.0)(typescript@5.4.5)
+      '@typescript-eslint/parser': 7.12.0(eslint@8.57.0)(typescript@5.4.5)
     transitivePeerDependencies:
       - eslint-import-resolver-typescript
       - eslint-import-resolver-webpack
       - supports-color
 
-  eslint-plugin-jsdoc@48.2.3(eslint@8.57.0):
+  eslint-plugin-jsdoc@48.2.9(eslint@8.57.0):
     dependencies:
-      '@es-joy/jsdoccomment': 0.42.0
+      '@es-joy/jsdoccomment': 0.43.1
       are-docs-informative: 0.0.2
       comment-parser: 1.4.1
-      debug: 4.3.4
+      debug: 4.3.5
       escape-string-regexp: 4.0.0
       eslint: 8.57.0
       esquery: 1.5.0
-      is-builtin-module: 3.2.1
-      semver: 7.6.0
+      semver: 7.6.2
       spdx-expression-parse: 4.0.0
     transitivePeerDependencies:
       - supports-color
 
-  eslint-plugin-n@17.5.0(eslint@8.57.0):
+  eslint-plugin-n@17.8.1(eslint@8.57.0):
     dependencies:
       '@eslint-community/eslint-utils': 4.4.0(eslint@8.57.0)
-      enhanced-resolve: 5.16.0
+      enhanced-resolve: 5.17.0
       eslint: 8.57.0
-      eslint-plugin-es-x: 7.6.0(eslint@8.57.0)
-      get-tsconfig: 4.7.4
-      globals: 15.1.0
+      eslint-plugin-es-x: 7.7.0(eslint@8.57.0)
+      get-tsconfig: 4.7.5
+      globals: 15.4.0
       ignore: 5.3.1
       minimatch: 9.0.4
-      semver: 7.6.0
+      semver: 7.6.2
 
-  eslint-plugin-prettier@5.1.3(eslint-config-prettier@9.1.0(eslint@8.57.0))(eslint@8.57.0)(prettier@3.2.5):
+  eslint-plugin-prettier@5.1.3(@types/eslint@8.56.10)(eslint-config-prettier@9.1.0(eslint@8.57.0))(eslint@8.57.0)(prettier@3.3.1):
     dependencies:
       eslint: 8.57.0
-      prettier: 3.2.5
+      prettier: 3.3.1
       prettier-linter-helpers: 1.0.0
       synckit: 0.8.8
     optionalDependencies:
+      '@types/eslint': 8.56.10
       eslint-config-prettier: 9.1.0(eslint@8.57.0)
 
   eslint-plugin-promise@6.1.1(eslint@8.57.0):
@@ -9376,21 +9425,21 @@ snapshots:
     dependencies:
       eslint: 8.57.0
 
-  eslint-plugin-tsdoc@0.2.17:
+  eslint-plugin-tsdoc@0.3.0:
     dependencies:
-      '@microsoft/tsdoc': 0.14.2
-      '@microsoft/tsdoc-config': 0.16.2
+      '@microsoft/tsdoc': 0.15.0
+      '@microsoft/tsdoc-config': 0.17.0
 
-  eslint-plugin-vue@9.25.0(eslint@8.57.0):
+  eslint-plugin-vue@9.26.0(eslint@8.57.0):
     dependencies:
       '@eslint-community/eslint-utils': 4.4.0(eslint@8.57.0)
       eslint: 8.57.0
       globals: 13.24.0
       natural-compare: 1.4.0
       nth-check: 2.1.1
-      postcss-selector-parser: 6.0.16
-      semver: 7.6.0
-      vue-eslint-parser: 9.4.2(eslint@8.57.0)
+      postcss-selector-parser: 6.1.0
+      semver: 7.6.2
+      vue-eslint-parser: 9.4.3(eslint@8.57.0)
       xml-name-validator: 4.0.0
     transitivePeerDependencies:
       - supports-color
@@ -9405,7 +9454,7 @@ snapshots:
   eslint@8.57.0:
     dependencies:
       '@eslint-community/eslint-utils': 4.4.0(eslint@8.57.0)
-      '@eslint-community/regexpp': 4.10.0
+      '@eslint-community/regexpp': 4.10.1
       '@eslint/eslintrc': 2.1.4
       '@eslint/js': 8.57.0
       '@humanwhocodes/config-array': 0.11.14
@@ -9415,7 +9464,7 @@ snapshots:
       ajv: 6.12.6
       chalk: 4.1.2
       cross-spawn: 7.0.3
-      debug: 4.3.4
+      debug: 4.3.5
       doctrine: 3.0.0
       escape-string-regexp: 4.0.0
       eslint-scope: 7.2.2
@@ -9452,7 +9501,7 @@ snapshots:
       d: 1.0.2
       es5-ext: 0.10.64
       event-emitter: 0.3.5
-      type: 2.7.2
+      type: 2.7.3
 
   espree@9.6.1:
     dependencies:
@@ -9556,7 +9605,7 @@ snapshots:
 
   ext@1.7.0:
     dependencies:
-      type: 2.7.2
+      type: 2.7.3
 
   extend@3.0.2: {}
 
@@ -9578,7 +9627,7 @@ snapshots:
       '@nodelib/fs.walk': 1.2.8
       glob-parent: 5.1.2
       merge2: 1.4.1
-      micromatch: 4.0.5
+      micromatch: 4.0.7
 
   fast-json-stable-stringify@2.1.0: {}
 
@@ -9613,7 +9662,7 @@ snapshots:
 
   file-uri-to-path@1.0.0: {}
 
-  fill-range@7.0.1:
+  fill-range@7.1.1:
     dependencies:
       to-regex-range: 5.0.1
 
@@ -9788,7 +9837,7 @@ snapshots:
       es-errors: 1.3.0
       get-intrinsic: 1.2.4
 
-  get-tsconfig@4.7.4:
+  get-tsconfig@4.7.5:
     dependencies:
       resolve-pkg-maps: 1.0.0
 
@@ -9796,7 +9845,7 @@ snapshots:
     dependencies:
       basic-ftp: 5.0.5
       data-uri-to-buffer: 6.0.2
-      debug: 4.3.4
+      debug: 4.3.5
       fs-extra: 11.2.0
     transitivePeerDependencies:
       - supports-color
@@ -9832,13 +9881,13 @@ snapshots:
     dependencies:
       is-glob: 4.0.3
 
-  glob@10.3.12:
+  glob@10.4.1:
     dependencies:
       foreground-child: 3.1.1
-      jackspeak: 2.3.6
+      jackspeak: 3.4.0
       minimatch: 9.0.4
-      minipass: 7.1.0
-      path-scurry: 1.10.2
+      minipass: 7.1.2
+      path-scurry: 1.11.1
 
   glob@7.2.3:
     dependencies:
@@ -9863,7 +9912,7 @@ snapshots:
     dependencies:
       type-fest: 0.20.2
 
-  globals@15.1.0: {}
+  globals@15.4.0: {}
 
   globalthis@1.0.4:
     dependencies:
@@ -9995,7 +10044,7 @@ snapshots:
       ndarray-determinant: 1.0.0
       ndarray-inv: 0.2.0
       seedrandom: 3.0.5
-      semver: 7.6.0
+      semver: 7.6.2
 
   hmac-drbg@1.0.1:
     dependencies:
@@ -10031,7 +10080,7 @@ snapshots:
     dependencies:
       '@tootallnate/once': 1.1.2
       agent-base: 6.0.2
-      debug: 4.3.4
+      debug: 4.3.5
     transitivePeerDependencies:
       - supports-color
     optional: true
@@ -10039,7 +10088,7 @@ snapshots:
   http-proxy-agent@7.0.2:
     dependencies:
       agent-base: 7.1.1
-      debug: 4.3.4
+      debug: 4.3.5
     transitivePeerDependencies:
       - supports-color
 
@@ -10061,7 +10110,7 @@ snapshots:
   https-proxy-agent@5.0.1:
     dependencies:
       agent-base: 6.0.2
-      debug: 4.3.4
+      debug: 4.3.5
     transitivePeerDependencies:
       - supports-color
     optional: true
@@ -10069,7 +10118,7 @@ snapshots:
   https-proxy-agent@7.0.4:
     dependencies:
       agent-base: 7.1.1
-      debug: 4.3.4
+      debug: 4.3.5
     transitivePeerDependencies:
       - supports-color
 
@@ -10143,7 +10192,7 @@ snapshots:
 
   ini@4.1.1: {}
 
-  ini@4.1.2: {}
+  ini@4.1.3: {}
 
   inline-source-map@0.6.3:
     dependencies:
@@ -10165,9 +10214,9 @@ snapshots:
       strip-ansi: 5.2.0
       through: 2.3.8
 
-  inquirer@9.2.19:
+  inquirer@9.2.22:
     dependencies:
-      '@inquirer/figures': 1.0.1
+      '@inquirer/figures': 1.0.3
       '@ljharb/through': 2.3.13
       ansi-escapes: 4.3.2
       chalk: 5.3.0
@@ -10262,10 +10311,6 @@ snapshots:
 
   is-buffer@2.0.5: {}
 
-  is-builtin-module@3.2.1:
-    dependencies:
-      builtin-modules: 3.3.0
-
   is-callable@1.2.7: {}
 
   is-ci@2.0.0:
@@ -10444,7 +10489,7 @@ snapshots:
   istanbul-lib-source-maps@5.0.4:
     dependencies:
       '@jridgewell/trace-mapping': 0.3.25
-      debug: 4.3.4
+      debug: 4.3.5
       istanbul-lib-coverage: 3.2.2
     transitivePeerDependencies:
       - supports-color
@@ -10461,7 +10506,7 @@ snapshots:
       es-get-iterator: 1.1.3
       iterate-iterator: 1.0.2
 
-  jackspeak@2.3.6:
+  jackspeak@3.4.0:
     dependencies:
       '@isaacs/cliui': 8.0.2
     optionalDependencies:
@@ -10485,12 +10530,12 @@ snapshots:
 
   jest-message-util@29.7.0:
     dependencies:
-      '@babel/code-frame': 7.24.2
+      '@babel/code-frame': 7.24.7
       '@jest/types': 29.6.3
       '@types/stack-utils': 2.0.3
       chalk: 4.1.2
       graceful-fs: 4.2.11
-      micromatch: 4.0.5
+      micromatch: 4.0.7
       pretty-format: 29.7.0
       slash: 3.0.0
       stack-utils: 2.0.6
@@ -10498,13 +10543,13 @@ snapshots:
   jest-util@29.7.0:
     dependencies:
       '@jest/types': 29.6.3
-      '@types/node': 20.12.10
+      '@types/node': 20.14.2
       chalk: 4.1.2
       ci-info: 3.9.0
       graceful-fs: 4.2.11
       picomatch: 2.3.1
 
-  jiti@1.21.0: {}
+  jiti@1.21.3: {}
 
   jju@1.4.0: {}
 
@@ -10512,7 +10557,7 @@ snapshots:
     dependencies:
       config-chain: 1.1.13
       editorconfig: 1.0.4
-      glob: 10.3.12
+      glob: 10.4.1
       js-cookie: 3.0.5
       nopt: 7.2.1
 
@@ -10532,7 +10577,7 @@ snapshots:
 
   jsdoc-type-pratt-parser@4.0.0: {}
 
-  jsdom@24.0.0(bufferutil@4.0.8)(utf-8-validate@6.0.3):
+  jsdom@24.1.0(bufferutil@4.0.8)(utf-8-validate@6.0.4):
     dependencies:
       cssstyle: 4.0.1
       data-urls: 5.0.0
@@ -10542,9 +10587,9 @@ snapshots:
       http-proxy-agent: 7.0.2
       https-proxy-agent: 7.0.4
       is-potential-custom-element-name: 1.0.1
-      nwsapi: 2.2.9
+      nwsapi: 2.2.10
       parse5: 7.1.2
-      rrweb-cssom: 0.6.0
+      rrweb-cssom: 0.7.0
       saxes: 6.0.0
       symbol-tree: 3.2.4
       tough-cookie: 4.1.4
@@ -10553,7 +10598,7 @@ snapshots:
       whatwg-encoding: 3.1.1
       whatwg-mimetype: 4.0.0
       whatwg-url: 14.0.0
-      ws: 8.17.0(bufferutil@4.0.8)(utf-8-validate@6.0.3)
+      ws: 8.17.0(bufferutil@4.0.8)(utf-8-validate@6.0.4)
       xml-name-validator: 5.0.0
     transitivePeerDependencies:
       - bufferutil
@@ -10657,26 +10702,26 @@ snapshots:
       prelude-ls: 1.2.1
       type-check: 0.4.0
 
-  lilconfig@3.0.0: {}
+  lilconfig@3.1.1: {}
 
   lines-and-columns@1.2.4: {}
 
-  lint-staged@15.2.2:
+  lint-staged@15.2.5:
     dependencies:
       chalk: 5.3.0
-      commander: 11.1.0
-      debug: 4.3.4
+      commander: 12.1.0
+      debug: 4.3.5
       execa: 8.0.1
-      lilconfig: 3.0.0
-      listr2: 8.0.1
-      micromatch: 4.0.5
+      lilconfig: 3.1.1
+      listr2: 8.2.1
+      micromatch: 4.0.7
       pidtree: 0.6.0
       string-argv: 0.3.2
-      yaml: 2.3.4
+      yaml: 2.4.5
     transitivePeerDependencies:
       - supports-color
 
-  listr2@8.0.1:
+  listr2@8.2.1:
     dependencies:
       cli-truncate: 4.0.0
       colorette: 2.0.20
@@ -10687,8 +10732,8 @@ snapshots:
 
   local-pkg@0.5.0:
     dependencies:
-      mlly: 1.7.0
-      pkg-types: 1.1.0
+      mlly: 1.7.1
+      pkg-types: 1.1.1
 
   locate-path@3.0.0:
     dependencies:
@@ -10793,6 +10838,7 @@ snapshots:
   lru-cache@6.0.0:
     dependencies:
       yallist: 4.0.0
+    optional: true
 
   lru-cache@7.18.3: {}
 
@@ -10814,17 +10860,17 @@ snapshots:
 
   magicast@0.3.4:
     dependencies:
-      '@babel/parser': 7.24.5
-      '@babel/types': 7.24.5
+      '@babel/parser': 7.24.7
+      '@babel/types': 7.24.7
       source-map-js: 1.2.0
 
   make-dir@3.1.0:
     dependencies:
-      semver: 7.6.0
+      semver: 7.6.2
 
   make-dir@4.0.0:
     dependencies:
-      semver: 7.6.0
+      semver: 7.6.2
 
   make-error@1.3.6: {}
 
@@ -10856,7 +10902,7 @@ snapshots:
   mariadb@3.3.0:
     dependencies:
       '@types/geojson': 7946.0.14
-      '@types/node': 20.12.10
+      '@types/node': 20.14.2
       denque: 2.1.0
       iconv-lite: 0.6.3
       lru-cache: 10.2.2
@@ -10879,12 +10925,12 @@ snapshots:
 
   merge2@1.4.1: {}
 
-  micromatch@4.0.5:
+  micromatch@4.0.7:
     dependencies:
-      braces: 3.0.2
+      braces: 3.0.3
       picomatch: 2.3.1
 
-  mikro-orm@6.2.5: {}
+  mikro-orm@6.2.9: {}
 
   miller-rabin@4.0.1:
     dependencies:
@@ -10973,7 +11019,7 @@ snapshots:
 
   minipass@5.0.0: {}
 
-  minipass@7.1.0: {}
+  minipass@7.1.2: {}
 
   minizlib@2.1.2:
     dependencies:
@@ -10982,8 +11028,8 @@ snapshots:
 
   minizlib@3.0.1:
     dependencies:
-      minipass: 7.1.0
-      rimraf: 5.0.5
+      minipass: 7.1.2
+      rimraf: 5.0.7
 
   mkdirp-classic@0.5.3: {}
 
@@ -11029,11 +11075,11 @@ snapshots:
 
   ml-xsadd@2.0.0: {}
 
-  mlly@1.7.0:
+  mlly@1.7.1:
     dependencies:
       acorn: 8.11.3
       pathe: 1.1.2
-      pkg-types: 1.1.0
+      pkg-types: 1.1.1
       ufo: 1.5.3
 
   mnemonist@0.40.0-rc1:
@@ -11060,16 +11106,16 @@ snapshots:
 
   moment@2.30.1: {}
 
-  mongodb-connection-string-url@3.0.0:
+  mongodb-connection-string-url@3.0.1:
     dependencies:
-      '@types/whatwg-url': 11.0.4
+      '@types/whatwg-url': 11.0.5
       whatwg-url: 13.0.0
 
-  mongodb@6.6.1(socks@2.8.3):
+  mongodb@6.7.0(socks@2.8.3):
     dependencies:
-      '@mongodb-js/saslprep': 1.1.6
+      '@mongodb-js/saslprep': 1.1.7
       bson: 6.7.0
-      mongodb-connection-string-url: 3.0.0
+      mongodb-connection-string-url: 3.0.1
     optionalDependencies:
       socks: 2.8.3
 
@@ -11181,9 +11227,9 @@ snapshots:
     dependencies:
       lower-case: 1.1.4
 
-  node-abi@3.62.0:
+  node-abi@3.63.0:
     dependencies:
-      semver: 7.6.0
+      semver: 7.6.2
 
   node-addon-api@7.1.0: {}
 
@@ -11219,7 +11265,7 @@ snapshots:
       nopt: 5.0.0
       npmlog: 6.0.2
       rimraf: 3.0.2
-      semver: 7.6.0
+      semver: 7.6.2
       tar: 6.2.1
       which: 2.0.2
     transitivePeerDependencies:
@@ -11266,7 +11312,7 @@ snapshots:
 
   number-is-nan@1.0.1: {}
 
-  nwsapi@2.2.9: {}
+  nwsapi@2.2.10: {}
 
   oauth-sign@0.9.0: {}
 
@@ -11442,7 +11488,7 @@ snapshots:
     dependencies:
       '@tootallnate/quickjs-emscripten': 0.23.0
       agent-base: 7.1.1
-      debug: 4.3.4
+      debug: 4.3.5
       get-uri: 6.0.3
       http-proxy-agent: 7.0.2
       https-proxy-agent: 7.0.4
@@ -11461,14 +11507,14 @@ snapshots:
       got: 12.6.1
       registry-auth-token: 4.2.2
       registry-url: 5.1.0
-      semver: 7.6.0
+      semver: 7.6.2
 
   package-json@8.1.1:
     dependencies:
       got: 12.6.1
       registry-auth-token: 5.0.2
       registry-url: 6.0.1
-      semver: 7.6.0
+      semver: 7.6.2
 
   pako@1.0.11: {}
 
@@ -11495,7 +11541,7 @@ snapshots:
 
   parse-json@5.2.0:
     dependencies:
-      '@babel/code-frame': 7.24.2
+      '@babel/code-frame': 7.24.7
       error-ex: 1.3.2
       json-parse-even-better-errors: 2.3.1
       lines-and-columns: 1.2.4
@@ -11532,10 +11578,10 @@ snapshots:
 
   path-platform@0.11.15: {}
 
-  path-scurry@1.10.2:
+  path-scurry@1.11.1:
     dependencies:
       lru-cache: 10.2.2
-      minipass: 7.1.0
+      minipass: 7.1.2
 
   path-type@4.0.0: {}
 
@@ -11557,7 +11603,7 @@ snapshots:
 
   pg-connection-string@2.6.2: {}
 
-  picocolors@1.0.0: {}
+  picocolors@1.0.1: {}
 
   picomatch@2.3.1: {}
 
@@ -11565,17 +11611,17 @@ snapshots:
 
   pify@2.3.0: {}
 
-  pkg-types@1.1.0:
+  pkg-types@1.1.1:
     dependencies:
       confbox: 0.1.7
-      mlly: 1.7.0
+      mlly: 1.7.1
       pathe: 1.1.2
 
   pkg-up@3.1.0:
     dependencies:
       find-up: 3.0.0
 
-  poolifier@4.0.2: {}
+  poolifier@4.0.13: {}
 
   possible-typed-array-names@1.0.0: {}
 
@@ -11586,7 +11632,7 @@ snapshots:
       read-cache: 1.0.0
       resolve: 1.22.8
 
-  postcss-selector-parser@6.0.16:
+  postcss-selector-parser@6.1.0:
     dependencies:
       cssesc: 3.0.0
       util-deprecate: 1.0.2
@@ -11596,7 +11642,7 @@ snapshots:
   postcss@8.4.38:
     dependencies:
       nanoid: 3.3.7
-      picocolors: 1.0.0
+      picocolors: 1.0.1
       source-map-js: 1.2.0
 
   prebuild-install@7.1.2:
@@ -11607,7 +11653,7 @@ snapshots:
       minimist: 1.2.8
       mkdirp-classic: 0.5.3
       napi-build-utils: 1.0.2
-      node-abi: 3.62.0
+      node-abi: 3.63.0
       pump: 3.0.0
       rc: 1.2.8
       simple-get: 4.0.1
@@ -11622,7 +11668,7 @@ snapshots:
     dependencies:
       fast-diff: 1.3.0
 
-  prettier@3.2.5: {}
+  prettier@3.3.1: {}
 
   pretty-bytes@5.6.0: {}
 
@@ -11682,7 +11728,7 @@ snapshots:
   proxy-agent@6.4.0:
     dependencies:
       agent-base: 7.1.1
-      debug: 4.3.4
+      debug: 4.3.5
       http-proxy-agent: 7.0.2
       https-proxy-agent: 7.0.4
       lru-cache: 7.18.3
@@ -11835,10 +11881,10 @@ snapshots:
 
   reinterval@1.1.0: {}
 
-  release-it@17.2.1(typescript@5.4.5):
+  release-it@17.3.0(typescript@5.4.5):
     dependencies:
       '@iarna/toml': 2.2.5
-      '@octokit/rest': 20.1.0
+      '@octokit/rest': 20.1.1
       async-retry: 1.3.3
       chalk: 5.3.0
       cosmiconfig: 9.0.0(typescript@5.4.5)
@@ -11846,7 +11892,7 @@ snapshots:
       git-url-parse: 14.0.0
       globby: 14.0.1
       got: 12.6.1
-      inquirer: 9.2.19
+      inquirer: 9.2.22
       is-ci: 3.0.1
       issue-parser: 7.0.0
       lodash: 4.17.21
@@ -11858,7 +11904,7 @@ snapshots:
       os-name: 5.1.0
       promise.allsettled: 1.0.7
       proxy-agent: 6.4.0
-      semver: 7.6.0
+      semver: 7.6.2
       shelljs: 0.8.5
       update-notifier: 7.0.0
       url-join: 5.0.0
@@ -11871,7 +11917,7 @@ snapshots:
   request@2.88.2:
     dependencies:
       aws-sign2: 0.7.0
-      aws4: 1.12.0
+      aws4: 1.13.0
       caseless: 0.12.0
       combined-stream: 1.0.8
       extend: 3.0.2
@@ -11907,11 +11953,6 @@ snapshots:
 
   resolve-pkg-maps@1.0.0: {}
 
-  resolve@1.19.0:
-    dependencies:
-      is-core-module: 2.13.1
-      path-parse: 1.0.7
-
   resolve@1.22.8:
     dependencies:
       is-core-module: 2.13.1
@@ -11952,39 +11993,41 @@ snapshots:
     dependencies:
       glob: 7.2.3
 
-  rimraf@5.0.5:
+  rimraf@5.0.7:
     dependencies:
-      glob: 10.3.12
+      glob: 10.4.1
 
   ripemd160@2.0.2:
     dependencies:
       hash-base: 3.1.0
       inherits: 2.0.4
 
-  rollup@4.17.2:
+  rollup@4.18.0:
     dependencies:
       '@types/estree': 1.0.5
     optionalDependencies:
-      '@rollup/rollup-android-arm-eabi': 4.17.2
-      '@rollup/rollup-android-arm64': 4.17.2
-      '@rollup/rollup-darwin-arm64': 4.17.2
-      '@rollup/rollup-darwin-x64': 4.17.2
-      '@rollup/rollup-linux-arm-gnueabihf': 4.17.2
-      '@rollup/rollup-linux-arm-musleabihf': 4.17.2
-      '@rollup/rollup-linux-arm64-gnu': 4.17.2
-      '@rollup/rollup-linux-arm64-musl': 4.17.2
-      '@rollup/rollup-linux-powerpc64le-gnu': 4.17.2
-      '@rollup/rollup-linux-riscv64-gnu': 4.17.2
-      '@rollup/rollup-linux-s390x-gnu': 4.17.2
-      '@rollup/rollup-linux-x64-gnu': 4.17.2
-      '@rollup/rollup-linux-x64-musl': 4.17.2
-      '@rollup/rollup-win32-arm64-msvc': 4.17.2
-      '@rollup/rollup-win32-ia32-msvc': 4.17.2
-      '@rollup/rollup-win32-x64-msvc': 4.17.2
+      '@rollup/rollup-android-arm-eabi': 4.18.0
+      '@rollup/rollup-android-arm64': 4.18.0
+      '@rollup/rollup-darwin-arm64': 4.18.0
+      '@rollup/rollup-darwin-x64': 4.18.0
+      '@rollup/rollup-linux-arm-gnueabihf': 4.18.0
+      '@rollup/rollup-linux-arm-musleabihf': 4.18.0
+      '@rollup/rollup-linux-arm64-gnu': 4.18.0
+      '@rollup/rollup-linux-arm64-musl': 4.18.0
+      '@rollup/rollup-linux-powerpc64le-gnu': 4.18.0
+      '@rollup/rollup-linux-riscv64-gnu': 4.18.0
+      '@rollup/rollup-linux-s390x-gnu': 4.18.0
+      '@rollup/rollup-linux-x64-gnu': 4.18.0
+      '@rollup/rollup-linux-x64-musl': 4.18.0
+      '@rollup/rollup-win32-arm64-msvc': 4.18.0
+      '@rollup/rollup-win32-ia32-msvc': 4.18.0
+      '@rollup/rollup-win32-x64-msvc': 4.18.0
       fsevents: 2.3.3
 
   rrweb-cssom@0.6.0: {}
 
+  rrweb-cssom@0.7.0: {}
+
   run-applescript@7.0.0: {}
 
   run-async@2.4.1: {}
@@ -12001,7 +12044,7 @@ snapshots:
 
   rxjs@7.8.1:
     dependencies:
-      tslib: 2.6.2
+      tslib: 2.6.3
 
   safe-array-concat@1.1.2:
     dependencies:
@@ -12042,15 +12085,13 @@ snapshots:
 
   semver-diff@3.1.1:
     dependencies:
-      semver: 7.6.0
+      semver: 7.6.2
 
   semver-diff@4.0.0:
     dependencies:
-      semver: 7.6.0
+      semver: 7.6.2
 
-  semver@7.6.0:
-    dependencies:
-      lru-cache: 6.0.0
+  semver@7.6.2: {}
 
   send@0.18.0:
     dependencies:
@@ -12182,7 +12223,7 @@ snapshots:
   socks-proxy-agent@6.2.1:
     dependencies:
       agent-base: 6.0.2
-      debug: 4.3.4
+      debug: 4.3.5
       socks: 2.8.3
     transitivePeerDependencies:
       - supports-color
@@ -12191,7 +12232,7 @@ snapshots:
   socks-proxy-agent@8.0.3:
     dependencies:
       agent-base: 7.1.1
-      debug: 4.3.4
+      debug: 4.3.5
       socks: 2.8.3
     transitivePeerDependencies:
       - supports-color
@@ -12228,9 +12269,9 @@ snapshots:
   spdx-expression-parse@4.0.0:
     dependencies:
       spdx-exceptions: 2.5.0
-      spdx-license-ids: 3.0.17
+      spdx-license-ids: 3.0.18
 
-  spdx-license-ids@3.0.17: {}
+  spdx-license-ids@3.0.18: {}
 
   split2@4.2.0: {}
 
@@ -12469,7 +12510,7 @@ snapshots:
   synckit@0.8.8:
     dependencies:
       '@pkgr/core': 0.1.1
-      tslib: 2.6.2
+      tslib: 2.6.3
 
   syntax-error@1.4.0:
     dependencies:
@@ -12503,11 +12544,11 @@ snapshots:
       mkdirp: 1.0.4
       yallist: 4.0.0
 
-  tar@7.1.0:
+  tar@7.2.0:
     dependencies:
       '@isaacs/fs-minipass': 4.0.1
       chownr: 3.0.0
-      minipass: 7.1.0
+      minipass: 7.1.2
       minizlib: 3.0.1
       mkdirp: 3.0.1
       yallist: 5.0.0
@@ -12615,14 +12656,14 @@ snapshots:
       '@ts-morph/common': 0.23.0
       code-block-writer: 13.0.1
 
-  ts-node@10.9.2(@types/node@20.12.10)(typescript@5.4.5):
+  ts-node@10.9.2(@types/node@20.14.2)(typescript@5.4.5):
     dependencies:
       '@cspotcode/source-map-support': 0.8.1
       '@tsconfig/node10': 1.0.11
       '@tsconfig/node12': 1.0.11
       '@tsconfig/node14': 1.0.3
       '@tsconfig/node16': 1.0.4
-      '@types/node': 20.12.10
+      '@types/node': 20.14.2
       acorn: 8.11.3
       acorn-walk: 8.3.2
       arg: 4.1.3
@@ -12648,12 +12689,12 @@ snapshots:
 
   tslib@1.14.1: {}
 
-  tslib@2.6.2: {}
+  tslib@2.6.3: {}
 
-  tsx@4.9.3:
+  tsx@4.15.1:
     dependencies:
-      esbuild: 0.20.2
-      get-tsconfig: 4.7.4
+      esbuild: 0.21.4
+      get-tsconfig: 4.7.5
     optionalDependencies:
       fsevents: 2.3.3
 
@@ -12694,7 +12735,7 @@ snapshots:
 
   type-fest@2.19.0: {}
 
-  type@2.7.2: {}
+  type@2.7.3: {}
 
   typed-array-buffer@1.0.2:
     dependencies:
@@ -12795,11 +12836,11 @@ snapshots:
 
   unpipe@1.0.0: {}
 
-  update-browserslist-db@1.0.15(browserslist@4.23.0):
+  update-browserslist-db@1.0.16(browserslist@4.23.1):
     dependencies:
-      browserslist: 4.23.0
+      browserslist: 4.23.1
       escalade: 3.1.2
-      picocolors: 1.0.0
+      picocolors: 1.0.1
 
   update-notifier@5.1.0:
     dependencies:
@@ -12814,7 +12855,7 @@ snapshots:
       is-yarn-global: 0.3.0
       latest-version: 5.1.0
       pupa: 2.1.1
-      semver: 7.6.0
+      semver: 7.6.2
       semver-diff: 3.1.1
       xdg-basedir: 4.0.0
 
@@ -12829,7 +12870,7 @@ snapshots:
       is-npm: 6.0.0
       latest-version: 7.0.0
       pupa: 3.1.0
-      semver: 7.6.0
+      semver: 7.6.2
       semver-diff: 4.0.0
       xdg-basedir: 5.1.0
 
@@ -12851,7 +12892,7 @@ snapshots:
       punycode: 1.4.1
       qs: 6.12.1
 
-  utf-8-validate@6.0.3:
+  utf-8-validate@6.0.4:
     dependencies:
       node-gyp-build: 4.8.1
     optional: true
@@ -12894,13 +12935,13 @@ snapshots:
       core-util-is: 1.0.2
       extsprintf: 1.3.0
 
-  vite-node@1.6.0(@types/node@20.12.10):
+  vite-node@1.6.0(@types/node@20.14.2):
     dependencies:
       cac: 6.7.14
-      debug: 4.3.4
+      debug: 4.3.5
       pathe: 1.1.2
-      picocolors: 1.0.0
-      vite: 5.2.11(@types/node@20.12.10)
+      picocolors: 1.0.1
+      vite: 5.2.13(@types/node@20.14.2)
     transitivePeerDependencies:
       - '@types/node'
       - less
@@ -12911,16 +12952,16 @@ snapshots:
       - supports-color
       - terser
 
-  vite@5.2.11(@types/node@20.12.10):
+  vite@5.2.13(@types/node@20.14.2):
     dependencies:
       esbuild: 0.20.2
       postcss: 8.4.38
-      rollup: 4.17.2
+      rollup: 4.18.0
     optionalDependencies:
-      '@types/node': 20.12.10
+      '@types/node': 20.14.2
       fsevents: 2.3.3
 
-  vitest@1.6.0(@types/node@20.12.10)(jsdom@24.0.0(bufferutil@4.0.8)(utf-8-validate@6.0.3)):
+  vitest@1.6.0(@types/node@20.14.2)(jsdom@24.1.0(bufferutil@4.0.8)(utf-8-validate@6.0.4)):
     dependencies:
       '@vitest/expect': 1.6.0
       '@vitest/runner': 1.6.0
@@ -12929,22 +12970,22 @@ snapshots:
       '@vitest/utils': 1.6.0
       acorn-walk: 8.3.2
       chai: 4.4.1
-      debug: 4.3.4
+      debug: 4.3.5
       execa: 8.0.1
       local-pkg: 0.5.0
       magic-string: 0.30.10
       pathe: 1.1.2
-      picocolors: 1.0.0
+      picocolors: 1.0.1
       std-env: 3.7.0
       strip-literal: 2.1.0
       tinybench: 2.8.0
       tinypool: 0.8.4
-      vite: 5.2.11(@types/node@20.12.10)
-      vite-node: 1.6.0(@types/node@20.12.10)
+      vite: 5.2.13(@types/node@20.14.2)
+      vite-node: 1.6.0(@types/node@20.14.2)
       why-is-node-running: 2.2.2
     optionalDependencies:
-      '@types/node': 20.12.10
-      jsdom: 24.0.0(bufferutil@4.0.8)(utf-8-validate@6.0.3)
+      '@types/node': 20.14.2
+      jsdom: 24.1.0(bufferutil@4.0.8)(utf-8-validate@6.0.4)
     transitivePeerDependencies:
       - less
       - lightningcss
@@ -12956,24 +12997,24 @@ snapshots:
 
   vm-browserify@1.1.2: {}
 
-  vue-component-type-helpers@2.0.16: {}
+  vue-component-type-helpers@2.0.21: {}
 
-  vue-eslint-parser@9.4.2(eslint@8.57.0):
+  vue-eslint-parser@9.4.3(eslint@8.57.0):
     dependencies:
-      debug: 4.3.4
+      debug: 4.3.5
       eslint: 8.57.0
       eslint-scope: 7.2.2
       eslint-visitor-keys: 3.4.3
       espree: 9.6.1
       esquery: 1.5.0
       lodash: 4.17.21
-      semver: 7.6.0
+      semver: 7.6.2
     transitivePeerDependencies:
       - supports-color
 
   vue-router@4.3.2(vue@3.4.27(typescript@5.4.5)):
     dependencies:
-      '@vue/devtools-api': 6.6.1
+      '@vue/devtools-api': 6.6.3
       vue: 3.4.27(typescript@5.4.5)
 
   vue-toast-notification@3.1.2(vue@3.4.27(typescript@5.4.5)):
@@ -13148,10 +13189,10 @@ snapshots:
       signal-exit: 3.0.7
       typedarray-to-buffer: 3.1.5
 
-  ws@8.17.0(bufferutil@4.0.8)(utf-8-validate@6.0.3):
+  ws@8.17.0(bufferutil@4.0.8)(utf-8-validate@6.0.4):
     optionalDependencies:
       bufferutil: 4.0.8
-      utf-8-validate: 6.0.3
+      utf-8-validate: 6.0.4
 
   xdg-basedir@4.0.0: {}
 
@@ -13175,7 +13216,7 @@ snapshots:
 
   yallist@5.0.0: {}
 
-  yaml@2.3.4: {}
+  yaml@2.4.5: {}
 
   yargs-parser@15.0.3:
     dependencies:
index e181f0e008798cb6151a924d13807f4e1d1f8e60..fb2477d707f2b57a8f3bb0760a775a92f13ee5b2 100644 (file)
@@ -1,6 +1,6 @@
 import { env, exit } from 'node:process'
 
-const skipPreinstall = parseInt(env.SKIP_PREINSTALL) || env.VCAP_APPLICATION != null
+const skipPreinstall = Number.parseInt(env.SKIP_PREINSTALL) || env.VCAP_APPLICATION != null
 if (skipPreinstall) {
   // eslint-disable-next-line n/no-process-exit
   exit()
index e17480be1567f9cf9aca9a4c17d8ff81f1ba31a1..6b31499aaeba67af3bd66118c5fdd2ec35ece3aa 100644 (file)
@@ -3,7 +3,7 @@ sonar.organization=sap-1
 
 # This is the name and version displayed in the SonarCloud UI.
 sonar.projectName=e-mobility-charging-stations-simulator
-sonar.projectVersion=1.3.3
+sonar.projectVersion=1.3.5
 
 # Path is relative to the sonar-project.properties file. Replace "\" by "/" on Windows.
 sonar.sources=src
index da32bbcbe72fd610919fc704ab5e1cb21234d5a1..e172ad29bbd5386c843a558f37b4f0080b92807c 100644 (file)
         "username": "admin",
         "password": "admin"
       },
-      "dataPropertyOrder": { "&": ["baseUrl", "protocol", "version", "username", "password"] },
+      "dataPropertyOrder": {
+        "&": ["baseUrl", "protocol", "version", "username", "password"]
+      },
       "color": null,
       "isPrivate": false,
       "metaSortKey": 1661789025528,
index 1312150c6d97b57eae80ffe854adbb4c42fd283f..3d9a5405f723c131bc6cdd607fe6910c9722a867 100644 (file)
         "protocol": "ui",
         "version": "0.0.1"
       },
-      "dataPropertyOrder": { "&": ["baseUrl", "username", "password", "protocol", "version"] },
+      "dataPropertyOrder": {
+        "&": ["baseUrl", "username", "password", "protocol", "version"]
+      },
       "color": null,
       "isPrivate": false,
       "metaSortKey": 1671183662529,
index 4b9b8f6cdbd6ef55cf4bf4fdf65a804640b1b6d1..9f1c4d39af45133373e889711eab2739e8c11da4 100644 (file)
@@ -8,6 +8,7 @@ import { BaseError } from '../exception/index.js'
 import { PerformanceStatistics } from '../performance/index.js'
 import {
   AuthorizationStatus,
+  ChargingStationEvents,
   RequestCommand,
   type StartTransactionRequest,
   type StartTransactionResponse,
@@ -262,9 +263,10 @@ export class AutomaticTransactionGenerator {
       )}`
     )
     logger.debug(
-      `${this.logPrefix(connectorId)} connector status: %j`,
+      `${this.logPrefix(connectorId)} stopped with connector status: %j`,
       this.connectorsStatus.get(connectorId)
     )
+    this.chargingStation.emit(ChargingStationEvents.updated)
   }
 
   private setStartConnectorStatus (
@@ -294,6 +296,7 @@ export class AutomaticTransactionGenerator {
     this.connectorsStatus.get(connectorId)!.skippedConsecutiveTransactions = 0
     // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
     this.connectorsStatus.get(connectorId)!.start = true
+    this.chargingStation.emit(ChargingStationEvents.updated)
   }
 
   private canStartConnector (connectorId: number): boolean {
@@ -333,9 +336,9 @@ export class AutomaticTransactionGenerator {
     const connectorStatus = this.chargingStation.getConnectorStatus(connectorId)
     if (connectorStatus?.transactionStarted === true) {
       logger.info(
-        `${this.logPrefix(
-          connectorId
-        )} entered in transaction loop while a transaction ${connectorStatus.transactionId} is already started on connector ${connectorId}`
+        `${this.logPrefix(connectorId)} entered in transaction loop while a transaction ${
+          connectorStatus.transactionId
+        } is already started on connector ${connectorId}`
       )
       return false
     }
@@ -378,9 +381,9 @@ export class AutomaticTransactionGenerator {
     while (connectorStatus?.transactionStarted === true) {
       if (!logged) {
         logger.info(
-          `${this.logPrefix(
-            connectorId
-          )} transaction loop waiting for started transaction ${connectorStatus.transactionId} on connector ${connectorId} to be stopped`
+          `${this.logPrefix(connectorId)} transaction loop waiting for started transaction ${
+            connectorStatus.transactionId
+          } on connector ${connectorId} to be stopped`
         )
         logged = true
       }
@@ -408,15 +411,21 @@ export class AutomaticTransactionGenerator {
 
   private getConnectorStatus (connectorId: number): Status {
     const statusIndex = connectorId - 1
+    if (statusIndex < 0) {
+      logger.error(`${this.logPrefix(connectorId)} invalid connector id`)
+      throw new BaseError(`Invalid connector id ${connectorId}`)
+    }
     let connectorStatus: Status | undefined
     if (this.chargingStation.getAutomaticTransactionGeneratorStatuses()?.[statusIndex] != null) {
       connectorStatus = clone<Status>(
         // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
         this.chargingStation.getAutomaticTransactionGeneratorStatuses()![statusIndex]
       )
-    } else if (this.chargingStation.getAutomaticTransactionGeneratorStatuses() != null) {
+    } else {
       logger.warn(
-        `${this.logPrefix(connectorId)} no status found for connector #${connectorId} in charging station configuration file. New status will be created`
+        `${this.logPrefix(
+          connectorId
+        )} no status found for connector #${connectorId} in charging station configuration file. New status will be created`
       )
     }
     if (connectorStatus != null) {
@@ -507,7 +516,9 @@ export class AutomaticTransactionGenerator {
     startResponse = await this.chargingStation.ocppRequestService.requestHandler<
     Partial<StartTransactionRequest>,
     StartTransactionResponse
-    >(this.chargingStation, RequestCommand.START_TRANSACTION, { connectorId })
+    >(this.chargingStation, RequestCommand.START_TRANSACTION, {
+      connectorId
+    })
     this.handleStartTransactionResponse(connectorId, startResponse)
     PerformanceStatistics.endMeasure(measureId, beginId)
     return startResponse
index 5293a9a83c28a9a1791f166606d3ca275f2cbb67..d12f78f9b326e79152a11e33d3ccf9f09f2bd2d6 100644 (file)
@@ -225,9 +225,13 @@ export class Bootstrap extends EventEmitter {
         )
         console.info(
           chalk.green(
-            `Charging stations simulator ${
-              this.version
-            } started with ${this.numberOfConfiguredChargingStations} configured and ${this.numberOfProvisionedChargingStations} provisioned charging station(s) from ${this.numberOfChargingStationTemplates} charging station template(s) and ${
+            `Charging stations simulator ${this.version} started with ${
+              this.numberOfConfiguredChargingStations
+            } configured and ${
+              this.numberOfProvisionedChargingStations
+            } provisioned charging station(s) from ${
+              this.numberOfChargingStationTemplates
+            } charging station template(s) and ${
               Configuration.workerDynamicPoolInUse() ? `${workerConfiguration.poolMinSize}/` : ''
             }${this.workerImplementation?.size}${
               Configuration.workerPoolInUse() ? `/${workerConfiguration.poolMaxSize}` : ''
@@ -373,7 +377,9 @@ export class Bootstrap extends EventEmitter {
         poolOptions: {
           messageHandler: this.messageHandler.bind(this) as MessageHandler<Worker>,
           ...(workerConfiguration.resourceLimits != null && {
-            workerOptions: { resourceLimits: workerConfiguration.resourceLimits }
+            workerOptions: {
+              resourceLimits: workerConfiguration.resourceLimits
+            }
           })
         }
       }
@@ -418,7 +424,11 @@ export class Bootstrap extends EventEmitter {
           break
         default:
           throw new BaseError(
-            `Unknown charging station worker message event: '${event}' received with data: ${JSON.stringify(data, undefined, 2)}`
+            `Unknown charging station worker message event: '${event}' received with data: ${JSON.stringify(
+              data,
+              undefined,
+              2
+            )}`
           )
       }
     } catch (error) {
@@ -436,7 +446,9 @@ export class Bootstrap extends EventEmitter {
         data.stationInfo.chargingStationId
       } (hashId: ${data.stationInfo.hashId}) added (${
         this.numberOfAddedChargingStations
-      } added from ${this.numberOfConfiguredChargingStations} configured and ${this.numberOfProvisionedChargingStations} provisioned charging station(s))`
+      } added from ${this.numberOfConfiguredChargingStations} configured and ${
+        this.numberOfProvisionedChargingStations
+      } provisioned charging station(s))`
     )
   }
 
@@ -451,7 +463,9 @@ export class Bootstrap extends EventEmitter {
         data.stationInfo.chargingStationId
       } (hashId: ${data.stationInfo.hashId}) deleted (${
         this.numberOfAddedChargingStations
-      } added from ${this.numberOfConfiguredChargingStations} configured and ${this.numberOfProvisionedChargingStations} provisioned charging station(s))`
+      } added from ${this.numberOfConfiguredChargingStations} configured and ${
+        this.numberOfProvisionedChargingStations
+      } provisioned charging station(s))`
     )
   }
 
index 080349eae731cbe27e9ba6b00354da0d40a66f7e..7dbb0d3ebd7f7ae2900885f8e7706daa56e30b36 100644 (file)
@@ -131,6 +131,7 @@ import {
   hasFeatureProfile,
   hasReservationExpired,
   initializeConnectorsMapStatus,
+  prepareConnectorStatus,
   propagateSerialNumber,
   setChargingStationOptions,
   stationTemplateToStationInfo,
@@ -181,7 +182,6 @@ export class ChargingStation extends EventEmitter {
   private ocppIncomingRequestService!: OCPPIncomingRequestService
   private readonly messageBuffer: Set<string>
   private configuredSupervisionUrl!: URL
-  private wsConnectionRetried: boolean
   private wsConnectionRetryCount: number
   private templateFileWatcher?: FSWatcher
   private templateFileHash!: string
@@ -196,7 +196,6 @@ export class ChargingStation extends EventEmitter {
     this.starting = false
     this.stopping = false
     this.wsConnection = null
-    this.wsConnectionRetried = false
     this.wsConnectionRetryCount = 0
     this.index = index
     this.templateFile = templateFile
@@ -225,16 +224,21 @@ export class ChargingStation extends EventEmitter {
     })
     this.on(ChargingStationEvents.accepted, () => {
       this.startMessageSequence(
-        this.wsConnectionRetried
+        this.wsConnectionRetryCount > 0
           ? true
           : this.getAutomaticTransactionGeneratorConfiguration()?.stopAbsoluteDuration
       ).catch((error: unknown) => {
         logger.error(`${this.logPrefix()} Error while starting the message sequence:`, error)
       })
-      this.wsConnectionRetried = false
+      this.wsConnectionRetryCount = 0
     })
     this.on(ChargingStationEvents.rejected, () => {
-      this.wsConnectionRetried = false
+      this.wsConnectionRetryCount = 0
+    })
+    this.on(ChargingStationEvents.connected, () => {
+      if (this.wsPingSetInterval == null) {
+        this.startWebSocketPing()
+      }
     })
     this.on(ChargingStationEvents.disconnected, () => {
       try {
@@ -269,7 +273,9 @@ export class ChargingStation extends EventEmitter {
         : this.configuredSupervisionUrl.href
     }`
     return new URL(
-      `${wsConnectionBaseUrlStr}${!wsConnectionBaseUrlStr.endsWith('/') ? '/' : ''}${this.stationInfo?.chargingStationId}`
+      `${wsConnectionBaseUrlStr}${
+        !wsConnectionBaseUrlStr.endsWith('/') ? '/' : ''
+      }${this.stationInfo?.chargingStationId}`
     )
   }
 
@@ -411,14 +417,17 @@ export class ChargingStation extends EventEmitter {
     const connectorChargingProfilesPowerLimit =
       getChargingStationConnectorChargingProfilesPowerLimit(this, connectorId)
     return min(
-      isNaN(connectorMaximumPower) ? Infinity : connectorMaximumPower,
+      isNaN(connectorMaximumPower) ? Number.POSITIVE_INFINITY : connectorMaximumPower,
       // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
       isNaN(connectorAmperageLimitationPowerLimit!)
-        ? Infinity
+        ? Number.POSITIVE_INFINITY
         : // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
         connectorAmperageLimitationPowerLimit!,
       // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-      isNaN(connectorChargingProfilesPowerLimit!) ? Infinity : connectorChargingProfilesPowerLimit!
+      isNaN(connectorChargingProfilesPowerLimit!)
+        ? Number.POSITIVE_INFINITY
+        : // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
+        connectorChargingProfilesPowerLimit!
     )
   }
 
@@ -549,7 +558,8 @@ export class ChargingStation extends EventEmitter {
   }
 
   public startHeartbeat (): void {
-    if (this.getHeartbeatInterval() > 0 && this.heartbeatSetInterval == null) {
+    const heartbeatInterval = this.getHeartbeatInterval()
+    if (heartbeatInterval > 0 && this.heartbeatSetInterval == null) {
       this.heartbeatSetInterval = setInterval(() => {
         this.ocppRequestService
           .requestHandler<HeartbeatRequest, HeartbeatResponse>(this, RequestCommand.HEARTBEAT)
@@ -559,21 +569,21 @@ export class ChargingStation extends EventEmitter {
               error
             )
           })
-      }, this.getHeartbeatInterval())
+      }, heartbeatInterval)
       logger.info(
         `${this.logPrefix()} Heartbeat started every ${formatDurationMilliSeconds(
-          this.getHeartbeatInterval()
+          heartbeatInterval
         )}`
       )
     } else if (this.heartbeatSetInterval != null) {
       logger.info(
         `${this.logPrefix()} Heartbeat already started every ${formatDurationMilliSeconds(
-          this.getHeartbeatInterval()
+          heartbeatInterval
         )}`
       )
     } else {
       logger.error(
-        `${this.logPrefix()} Heartbeat interval set to ${this.getHeartbeatInterval()}, not starting the heartbeat`
+        `${this.logPrefix()} Heartbeat interval set to ${heartbeatInterval}, not starting the heartbeat`
       )
     }
   }
@@ -661,6 +671,11 @@ export class ChargingStation extends EventEmitter {
     }
   }
 
+  public restartMeterValues (connectorId: number, interval: number): void {
+    this.stopMeterValues(connectorId)
+    this.startMeterValues(connectorId, interval)
+  }
+
   private add (): void {
     this.emit(ChargingStationEvents.added)
   }
@@ -1359,7 +1374,9 @@ export class ChargingStation extends EventEmitter {
       addConfigurationKey(this, StandardParametersKey.HeartbeatInterval, '0')
     }
     if (getConfigurationKey(this, StandardParametersKey.HeartBeatInterval) == null) {
-      addConfigurationKey(this, StandardParametersKey.HeartBeatInterval, '0', { visible: false })
+      addConfigurationKey(this, StandardParametersKey.HeartBeatInterval, '0', {
+        visible: false
+      })
     }
     if (
       this.stationInfo?.supervisionUrlOcppConfiguration === true &&
@@ -1377,7 +1394,9 @@ export class ChargingStation extends EventEmitter {
       isNotEmptyString(this.stationInfo.supervisionUrlOcppKey) &&
       getConfigurationKey(this, this.stationInfo.supervisionUrlOcppKey) != null
     ) {
-      deleteConfigurationKey(this, this.stationInfo.supervisionUrlOcppKey, { save: false })
+      deleteConfigurationKey(this, this.stationInfo.supervisionUrlOcppKey, {
+        save: false
+      })
     }
     if (
       isNotEmptyString(this.stationInfo?.amperageLimitationOcppKey) &&
@@ -1459,7 +1478,10 @@ export class ChargingStation extends EventEmitter {
   private initializeConnectorsOrEvsesFromFile (configuration: ChargingStationConfiguration): void {
     if (configuration.connectorsStatus != null && configuration.evsesStatus == null) {
       for (const [connectorId, connectorStatus] of configuration.connectorsStatus.entries()) {
-        this.connectors.set(connectorId, clone<ConnectorStatus>(connectorStatus))
+        this.connectors.set(
+          connectorId,
+          prepareConnectorStatus(clone<ConnectorStatus>(connectorStatus))
+        )
       }
     } else if (configuration.evsesStatus != null && configuration.connectorsStatus == null) {
       for (const [evseId, evseStatusConfiguration] of configuration.evsesStatus.entries()) {
@@ -1471,7 +1493,7 @@ export class ChargingStation extends EventEmitter {
             // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
             evseStatusConfiguration.connectorsStatus!.map((connectorStatus, connectorId) => [
               connectorId,
-              connectorStatus
+              prepareConnectorStatus(connectorStatus)
             ])
           )
         })
@@ -1736,7 +1758,9 @@ export class ChargingStation extends EventEmitter {
               ...(this.connectors.size > 0 && {
                 connectorsStatus: configurationData.connectorsStatus
               }),
-              ...(this.evses.size > 0 && { evsesStatus: configurationData.evsesStatus })
+              ...(this.evses.size > 0 && {
+                evsesStatus: configurationData.evsesStatus
+              })
             } satisfies ChargingStationConfiguration)
           )
           .digest('hex')
@@ -1811,27 +1835,27 @@ export class ChargingStation extends EventEmitter {
 
   private async onOpen (): Promise<void> {
     if (this.isWebSocketConnectionOpened()) {
+      this.emit(ChargingStationEvents.connected)
       this.emit(ChargingStationEvents.updated)
       logger.info(
-        `${this.logPrefix()} Connection to OCPP server through ${this.wsConnectionUrl.href} succeeded`
+        `${this.logPrefix()} Connection to OCPP server through ${
+          this.wsConnectionUrl.href
+        } succeeded`
       )
       let registrationRetryCount = 0
       if (!this.isRegistered()) {
         // Send BootNotification
         do {
-          this.bootNotificationResponse = await this.ocppRequestService.requestHandler<
+          await this.ocppRequestService.requestHandler<
           BootNotificationRequest,
           BootNotificationResponse
           >(this, RequestCommand.BOOT_NOTIFICATION, this.bootNotificationRequest, {
             skipBufferingOnError: true
           })
-          // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
-          if (this.bootNotificationResponse?.currentTime != null) {
-            // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-            this.bootNotificationResponse.currentTime = convertToDate(
-              this.bootNotificationResponse.currentTime
-            )!
-          }
+          // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
+          this.bootNotificationResponse!.currentTime = convertToDate(
+            this.bootNotificationResponse?.currentTime
+          )!
           if (!this.isRegistered()) {
             this.stationInfo?.registrationMaxRetries !== -1 && ++registrationRetryCount
             await sleep(
@@ -1848,22 +1872,13 @@ export class ChargingStation extends EventEmitter {
             this.stationInfo?.registrationMaxRetries === -1)
         )
       }
-      if (this.isRegistered()) {
-        this.emit(ChargingStationEvents.registered)
-        if (this.inAcceptedState()) {
-          this.emit(ChargingStationEvents.accepted)
-        }
-      } else {
-        if (this.inRejectedState()) {
-          this.emit(ChargingStationEvents.rejected)
-        }
+      if (!this.isRegistered()) {
         logger.error(
           `${this.logPrefix()} Registration failure: maximum retries reached (${registrationRetryCount}) or retry disabled (${
             this.stationInfo?.registrationMaxRetries
           })`
         )
       }
-      this.wsConnectionRetryCount = 0
       this.emit(ChargingStationEvents.updated)
     } else {
       logger.warn(
@@ -1915,7 +1930,7 @@ export class ChargingStation extends EventEmitter {
     }
     throw new OCPPError(
       ErrorType.PROTOCOL_ERROR,
-      `Cached request for message id ${messageId} ${getMessageTypeString(
+      `Cached request for message id '${messageId}' ${getMessageTypeString(
         messageType
       )} is not an array`,
       undefined,
@@ -1925,6 +1940,14 @@ export class ChargingStation extends EventEmitter {
 
   private async handleIncomingMessage (request: IncomingRequest): Promise<void> {
     const [messageType, messageId, commandName, commandPayload] = request
+    if (this.requests.has(messageId)) {
+      throw new OCPPError(
+        ErrorType.SECURITY_ERROR,
+        `Received message with duplicate message id '${messageId}'`,
+        commandName,
+        commandPayload
+      )
+    }
     if (this.stationInfo?.enableStatistics === true) {
       this.performanceStatistics?.addRequestStatistic(commandName, messageType)
     }
@@ -1949,7 +1972,7 @@ export class ChargingStation extends EventEmitter {
       // Error
       throw new OCPPError(
         ErrorType.INTERNAL_ERROR,
-        `Response for unknown message id ${messageId}`,
+        `Response for unknown message id '${messageId}'`,
         undefined,
         commandPayload
       )
@@ -1974,7 +1997,7 @@ export class ChargingStation extends EventEmitter {
       // Error
       throw new OCPPError(
         ErrorType.INTERNAL_ERROR,
-        `Error response for unknown message id ${messageId}`,
+        `Error response for unknown message id '${messageId}'`,
         undefined,
         { errorType, errorMessage, errorDetails }
       )
@@ -2059,10 +2082,10 @@ export class ChargingStation extends EventEmitter {
       }
       if (!(error instanceof OCPPError)) {
         logger.warn(
-          `${this.logPrefix()} Error thrown at incoming OCPP command '${
+          `${this.logPrefix()} Error thrown at incoming OCPP command ${
             commandName ?? requestCommandName ?? Constants.UNKNOWN_OCPP_COMMAND
             // eslint-disable-next-line @typescript-eslint/no-base-to-string
-          }' message '${data.toString()}' handling is not an OCPPError:`,
+          } message '${data.toString()}' handling is not an OCPPError:`,
           error
         )
       }
@@ -2072,7 +2095,9 @@ export class ChargingStation extends EventEmitter {
           // eslint-disable-next-line @typescript-eslint/no-base-to-string
         }' message '${data.toString()}'${
           this.requests.has(messageId)
-            ? ` matching cached request '${JSON.stringify(this.getCachedRequest(messageType, messageId))}'`
+            ? ` matching cached request '${JSON.stringify(
+                this.getCachedRequest(messageType, messageId)
+              )}'`
             : ''
         } processing error:`,
         error
@@ -2214,9 +2239,13 @@ export class ChargingStation extends EventEmitter {
       })
     }
     // Start WebSocket ping
-    this.startWebSocketPing()
+    if (this.wsPingSetInterval == null) {
+      this.startWebSocketPing()
+    }
     // Start heartbeat
-    this.startHeartbeat()
+    if (this.heartbeatSetInterval == null) {
+      this.startHeartbeat()
+    }
     // Initialize connectors status
     if (this.hasEvses) {
       for (const [evseId, evseStatus] of this.evses) {
@@ -2306,13 +2335,14 @@ export class ChargingStation extends EventEmitter {
     }
   }
 
+  private getWebSocketPingInterval (): number {
+    return getConfigurationKey(this, StandardParametersKey.WebSocketPingInterval) != null
+      ? convertToInt(getConfigurationKey(this, StandardParametersKey.WebSocketPingInterval)?.value)
+      : 0
+  }
+
   private startWebSocketPing (): void {
-    const webSocketPingInterval =
-      getConfigurationKey(this, StandardParametersKey.WebSocketPingInterval) != null
-        ? convertToInt(
-          getConfigurationKey(this, StandardParametersKey.WebSocketPingInterval)?.value
-        )
-        : 0
+    const webSocketPingInterval = this.getWebSocketPingInterval()
     if (webSocketPingInterval > 0 && this.wsPingSetInterval == null) {
       this.wsPingSetInterval = setInterval(() => {
         if (this.isWebSocketConnectionOpened()) {
@@ -2402,7 +2432,6 @@ export class ChargingStation extends EventEmitter {
       this.wsConnectionRetryCount < this.stationInfo!.autoReconnectMaxRetries! ||
       this.stationInfo?.autoReconnectMaxRetries === -1
     ) {
-      this.wsConnectionRetried = true
       ++this.wsConnectionRetryCount
       const reconnectDelay =
         this.stationInfo?.reconnectExponentialDelay === true
@@ -2429,9 +2458,7 @@ export class ChargingStation extends EventEmitter {
       )
     } else if (this.stationInfo?.autoReconnectMaxRetries !== -1) {
       logger.error(
-        `${this.logPrefix()} WebSocket connection retries failure: maximum retries reached (${
-          this.wsConnectionRetryCount
-        }) or retries disabled (${this.stationInfo?.autoReconnectMaxRetries})`
+        `${this.logPrefix()} WebSocket connection retries failure: maximum retries reached (${this.wsConnectionRetryCount.toString()}) or retries disabled (${this.stationInfo?.autoReconnectMaxRetries?.toString()})`
       )
     }
   }
index 735a0b39c9bcf967f69297aa1a66618d2b4f9752..816db88bb8f4470aa0581f74c7160516a61790bb 100644 (file)
@@ -31,6 +31,7 @@ import {
   BootReasonEnumType,
   type ChargingProfile,
   ChargingProfileKindType,
+  ChargingProfilePurposeType,
   ChargingRateUnitType,
   type ChargingSchedulePeriod,
   type ChargingStationConfiguration,
@@ -306,7 +307,11 @@ export const checkConnectorsConfiguration = (
     )
     stationTemplate.randomConnectors = true
   }
-  return { configuredMaxConnectors, templateMaxConnectors, templateMaxAvailableConnectors }
+  return {
+    configuredMaxConnectors,
+    templateMaxConnectors,
+    templateMaxAvailableConnectors
+  }
 }
 
 export const checkStationInfoConnectorStatus = (
@@ -323,27 +328,6 @@ export const checkStationInfoConnectorStatus = (
   }
 }
 
-export const buildConnectorsMap = (
-  connectors: Record<string, ConnectorStatus>,
-  logPrefix: string,
-  templateFile: string
-): Map<number, ConnectorStatus> => {
-  const connectorsMap = new Map<number, ConnectorStatus>()
-  if (getMaxNumberOfConnectors(connectors) > 0) {
-    for (const connector in connectors) {
-      const connectorStatus = connectors[connector]
-      const connectorId = convertToInt(connector)
-      checkStationInfoConnectorStatus(connectorId, connectorStatus, logPrefix, templateFile)
-      connectorsMap.set(connectorId, clone<ConnectorStatus>(connectorStatus))
-    }
-  } else {
-    logger.warn(
-      `${logPrefix} Charging station information from template ${templateFile} with no connectors, cannot build connectors map`
-    )
-  }
-  return connectorsMap
-}
-
 export const setChargingStationOptions = (
   stationInfo: ChargingStationInfo,
   options?: ChargingStationOptions
@@ -375,6 +359,27 @@ export const setChargingStationOptions = (
   return stationInfo
 }
 
+export const buildConnectorsMap = (
+  connectors: Record<string, ConnectorStatus>,
+  logPrefix: string,
+  templateFile: string
+): Map<number, ConnectorStatus> => {
+  const connectorsMap = new Map<number, ConnectorStatus>()
+  if (getMaxNumberOfConnectors(connectors) > 0) {
+    for (const connector in connectors) {
+      const connectorStatus = connectors[connector]
+      const connectorId = convertToInt(connector)
+      checkStationInfoConnectorStatus(connectorId, connectorStatus, logPrefix, templateFile)
+      connectorsMap.set(connectorId, clone<ConnectorStatus>(connectorStatus))
+    }
+  } else {
+    logger.warn(
+      `${logPrefix} Charging station information from template ${templateFile} with no connectors, cannot build connectors map`
+    )
+  }
+  return connectorsMap
+}
+
 export const initializeConnectorsMapStatus = (
   connectors: Map<number, ConnectorStatus>,
   logPrefix: string
@@ -401,29 +406,60 @@ export const initializeConnectorsMapStatus = (
   }
 }
 
+export const resetAuthorizeConnectorStatus = (connectorStatus: ConnectorStatus): void => {
+  connectorStatus.idTagLocalAuthorized = false
+  connectorStatus.idTagAuthorized = false
+  delete connectorStatus.localAuthorizeIdTag
+  delete connectorStatus.authorizeIdTag
+}
+
 export const resetConnectorStatus = (connectorStatus: ConnectorStatus | undefined): void => {
   if (connectorStatus == null) {
     return
   }
-  connectorStatus.chargingProfiles =
-    connectorStatus.transactionId != null && isNotEmptyArray(connectorStatus.chargingProfiles)
-      ? connectorStatus.chargingProfiles.filter(
-        chargingProfile => chargingProfile.transactionId !== connectorStatus.transactionId
-      )
-      : []
-  connectorStatus.idTagLocalAuthorized = false
-  connectorStatus.idTagAuthorized = false
+  if (isNotEmptyArray(connectorStatus.chargingProfiles)) {
+    connectorStatus.chargingProfiles = connectorStatus.chargingProfiles.filter(
+      chargingProfile =>
+        (chargingProfile.chargingProfilePurpose === ChargingProfilePurposeType.TX_PROFILE &&
+          chargingProfile.transactionId != null &&
+          connectorStatus.transactionId != null &&
+          chargingProfile.transactionId !== connectorStatus.transactionId) ||
+        chargingProfile.chargingProfilePurpose !== ChargingProfilePurposeType.TX_PROFILE
+    )
+  }
+  resetAuthorizeConnectorStatus(connectorStatus)
   connectorStatus.transactionRemoteStarted = false
   connectorStatus.transactionStarted = false
   delete connectorStatus.transactionStart
   delete connectorStatus.transactionId
-  delete connectorStatus.localAuthorizeIdTag
-  delete connectorStatus.authorizeIdTag
   delete connectorStatus.transactionIdTag
   connectorStatus.transactionEnergyActiveImportRegisterValue = 0
   delete connectorStatus.transactionBeginMeterValue
 }
 
+export const prepareConnectorStatus = (connectorStatus: ConnectorStatus): ConnectorStatus => {
+  if (connectorStatus.reservation != null) {
+    // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
+    connectorStatus.reservation.expiryDate = convertToDate(connectorStatus.reservation.expiryDate)!
+  }
+  if (isNotEmptyArray(connectorStatus.chargingProfiles)) {
+    connectorStatus.chargingProfiles = connectorStatus.chargingProfiles
+      .filter(
+        chargingProfile =>
+          chargingProfile.chargingProfilePurpose !== ChargingProfilePurposeType.TX_PROFILE
+      )
+      .map(chargingProfile => {
+        chargingProfile.chargingSchedule.startSchedule = convertToDate(
+          chargingProfile.chargingSchedule.startSchedule
+        )
+        chargingProfile.validFrom = convertToDate(chargingProfile.validFrom)
+        chargingProfile.validTo = convertToDate(chargingProfile.validTo)
+        return chargingProfile
+      })
+  }
+  return connectorStatus
+}
+
 export const createBootNotificationRequest = (
   stationInfo: ChargingStationInfo,
   bootReason: BootReasonEnumType = BootReasonEnumType.PowerUp
@@ -524,7 +560,10 @@ export const createSerialNumber = (
     randomSerialNumber?: boolean
   }
 ): void => {
-  params = { ...{ randomSerialNumberUpperCase: true, randomSerialNumber: true }, ...params }
+  params = {
+    ...{ randomSerialNumberUpperCase: true, randomSerialNumber: true },
+    ...params
+  }
   const serialNumberSuffix =
     params.randomSerialNumber === true
       ? getRandomSerialNumberSuffix({
@@ -590,45 +629,57 @@ export const getAmperageLimitationUnitDivider = (stationInfo: ChargingStationInf
 }
 
 /**
- * Gets the connector cloned charging profiles applying a power limitation
- * and sorted by connector id descending then stack level descending
+ * Gets the connector charging profiles relevant for power limitation shallow cloned and sorted by priorities
  *
- * @param chargingStation -
- * @param connectorId -
+ * @param chargingStation - Charging station
+ * @param connectorId - Connector id
  * @returns connector charging profiles array
  */
 export const getConnectorChargingProfiles = (
   chargingStation: ChargingStation,
   connectorId: number
 ): ChargingProfile[] => {
-  return clone<ChargingProfile[]>(
-    (chargingStation.getConnectorStatus(connectorId)?.chargingProfiles ?? [])
-      .sort((a, b) => b.stackLevel - a.stackLevel)
-      .concat(
-        (chargingStation.getConnectorStatus(0)?.chargingProfiles ?? []).sort(
-          (a, b) => b.stackLevel - a.stackLevel
+  // FIXME: handle charging profile purpose CHARGE_POINT_MAX_PROFILE
+  return (chargingStation.getConnectorStatus(connectorId)?.chargingProfiles ?? [])
+    .slice()
+    .sort((a, b) => {
+      if (
+        a.chargingProfilePurpose === ChargingProfilePurposeType.TX_PROFILE &&
+        b.chargingProfilePurpose === ChargingProfilePurposeType.TX_DEFAULT_PROFILE
+      ) {
+        return -1
+      } else if (
+        a.chargingProfilePurpose === ChargingProfilePurposeType.TX_DEFAULT_PROFILE &&
+        b.chargingProfilePurpose === ChargingProfilePurposeType.TX_PROFILE
+      ) {
+        return 1
+      }
+      return b.stackLevel - a.stackLevel
+    })
+    .concat(
+      (chargingStation.getConnectorStatus(0)?.chargingProfiles ?? [])
+        .filter(
+          chargingProfile =>
+            chargingProfile.chargingProfilePurpose === ChargingProfilePurposeType.TX_DEFAULT_PROFILE
         )
-      )
-  )
+        .sort((a, b) => b.stackLevel - a.stackLevel)
+    )
 }
 
 export const getChargingStationConnectorChargingProfilesPowerLimit = (
   chargingStation: ChargingStation,
   connectorId: number
 ): number | undefined => {
-  let limit: number | undefined, chargingProfile: ChargingProfile | undefined
-  // Get charging profiles sorted by connector id then stack level
   const chargingProfiles = getConnectorChargingProfiles(chargingStation, connectorId)
   if (isNotEmptyArray(chargingProfiles)) {
-    const result = getLimitFromChargingProfiles(
+    const chargingProfilesLimit = getLimitFromChargingProfiles(
       chargingStation,
       connectorId,
       chargingProfiles,
       chargingStation.logPrefix()
     )
-    if (result != null) {
-      limit = result.limit
-      chargingProfile = result.chargingProfile
+    if (chargingProfilesLimit != null) {
+      let { limit, chargingProfile } = chargingProfilesLimit
       switch (chargingStation.stationInfo?.currentOutType) {
         case CurrentType.AC:
           limit =
@@ -656,13 +707,13 @@ export const getChargingStationConnectorChargingProfilesPowerLimit = (
           `${chargingStation.logPrefix()} ${moduleName}.getChargingStationConnectorChargingProfilesPowerLimit: Charging profile id ${
             chargingProfile.chargingProfileId
           } limit ${limit} is greater than connector id ${connectorId} maximum ${connectorMaximumPower}: %j`,
-          result
+          chargingProfilesLimit
         )
         limit = connectorMaximumPower
       }
+      return limit
     }
   }
-  return limit
 }
 
 export const getDefaultVoltageOut = (
@@ -831,9 +882,10 @@ const getLimitFromChargingProfiles = (
   chargingProfiles: ChargingProfile[],
   logPrefix: string
 ): ChargingProfilesLimit | undefined => {
-  const debugLogMsg = `${logPrefix} ${moduleName}.getLimitFromChargingProfiles: Matching charging profile found for power limitation: %j`
+  const debugLogMsg = `${logPrefix} ${moduleName}.getLimitFromChargingProfiles: Charging profiles limit found: %j`
   const currentDate = new Date()
   const connectorStatus = chargingStation.getConnectorStatus(connectorId)
+  let previousActiveChargingProfile: ChargingProfile | undefined
   for (const chargingProfile of chargingProfiles) {
     const chargingSchedule = chargingProfile.chargingSchedule
     if (chargingSchedule.startSchedule == null) {
@@ -895,12 +947,12 @@ const getLimitFromChargingProfiles = (
         }
         // Handle only one schedule period
         if (chargingSchedule.chargingSchedulePeriod.length === 1) {
-          const result: ChargingProfilesLimit = {
+          const chargingProfilesLimit: ChargingProfilesLimit = {
             limit: chargingSchedule.chargingSchedulePeriod[0].limit,
             chargingProfile
           }
-          logger.debug(debugLogMsg, result)
-          return result
+          logger.debug(debugLogMsg, chargingProfilesLimit)
+          return chargingProfilesLimit
         }
         let previousChargingSchedulePeriod: ChargingSchedulePeriod | undefined
         // Search for the right schedule period
@@ -916,16 +968,13 @@ const getLimitFromChargingProfiles = (
             )
           ) {
             // Found the schedule period: previous is the correct one
-            const result: ChargingProfilesLimit = {
-              // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-              limit: previousChargingSchedulePeriod!.limit,
-              chargingProfile
+            const chargingProfilesLimit: ChargingProfilesLimit = {
+              limit: previousChargingSchedulePeriod?.limit ?? chargingSchedulePeriod.limit,
+              chargingProfile: previousActiveChargingProfile ?? chargingProfile
             }
-            logger.debug(debugLogMsg, result)
-            return result
+            logger.debug(debugLogMsg, chargingProfilesLimit)
+            return chargingProfilesLimit
           }
-          // Keep a reference to previous one
-          previousChargingSchedulePeriod = chargingSchedulePeriod
           // Handle the last schedule period within the charging profile duration
           if (
             index === chargingSchedule.chargingSchedulePeriod.length - 1 ||
@@ -938,15 +987,19 @@ const getLimitFromChargingProfiles = (
                 chargingSchedule.startSchedule
               ) > chargingSchedule.duration)
           ) {
-            const result: ChargingProfilesLimit = {
-              limit: previousChargingSchedulePeriod.limit,
+            const chargingProfilesLimit: ChargingProfilesLimit = {
+              limit: chargingSchedulePeriod.limit,
               chargingProfile
             }
-            logger.debug(debugLogMsg, result)
-            return result
+            logger.debug(debugLogMsg, chargingProfilesLimit)
+            return chargingProfilesLimit
           }
+          // Keep a reference to previous charging schedule period
+          previousChargingSchedulePeriod = chargingSchedulePeriod
         }
       }
+      // Keep a reference to previous active charging profile
+      previousActiveChargingProfile = chargingProfile
     }
   }
 }
index b5fc1cef13cc76b3f8e5250227485594c55e4210..9acdd3a42c94c491587ead7839156d95949ec797 100644 (file)
@@ -155,23 +155,21 @@ export class ChargingStationWorkerBroadcastChannel extends WorkerBroadcastChanne
       [
         BroadcastChannelProcedureName.BOOT_NOTIFICATION,
         async (requestPayload?: BroadcastChannelRequestPayload) => {
-          this.chargingStation.bootNotificationResponse =
-            await this.chargingStation.ocppRequestService.requestHandler<
-            BootNotificationRequest,
-            BootNotificationResponse
-            >(
-              this.chargingStation,
-              RequestCommand.BOOT_NOTIFICATION,
-              {
-                ...this.chargingStation.bootNotificationRequest,
-                ...requestPayload
-              },
-              {
-                skipBufferingOnError: true,
-                throwError: true
-              }
-            )
-          return this.chargingStation.bootNotificationResponse
+          return await this.chargingStation.ocppRequestService.requestHandler<
+          BootNotificationRequest,
+          BootNotificationResponse
+          >(
+            this.chargingStation,
+            RequestCommand.BOOT_NOTIFICATION,
+            {
+              ...this.chargingStation.bootNotificationRequest,
+              ...requestPayload
+            },
+            {
+              skipBufferingOnError: true,
+              throwError: true
+            }
+          )
         }
       ],
       [
index 8d8a83c3586549c074e4e4b1feeff5cf905d6b98..1a5f955f52011ae05e8979f81ba9e3614d42964f 100644 (file)
@@ -14,5 +14,6 @@ export {
   hasReservationExpired,
   prepareChargingProfileKind,
   removeExpiredReservations,
+  resetAuthorizeConnectorStatus,
   resetConnectorStatus
 } from './Helpers.js'
index 4a604f1c4635d8d39658c8537ab04f19e49fe49e..214c5a85bf9797377d49d64813aa04d4116a319c 100644 (file)
@@ -7,15 +7,33 @@ export class OCPP16Constants extends OCPPConstants {
   > = Object.freeze([
       { to: OCPP16ChargePointStatus.Available },
       // { from: OCPP16ChargePointStatus.Available, to: OCPP16ChargePointStatus.Available },
-      { from: OCPP16ChargePointStatus.Available, to: OCPP16ChargePointStatus.Unavailable },
-      { from: OCPP16ChargePointStatus.Available, to: OCPP16ChargePointStatus.Faulted },
+      {
+        from: OCPP16ChargePointStatus.Available,
+        to: OCPP16ChargePointStatus.Unavailable
+      },
+      {
+        from: OCPP16ChargePointStatus.Available,
+        to: OCPP16ChargePointStatus.Faulted
+      },
       { to: OCPP16ChargePointStatus.Unavailable },
-      { from: OCPP16ChargePointStatus.Unavailable, to: OCPP16ChargePointStatus.Available },
+      {
+        from: OCPP16ChargePointStatus.Unavailable,
+        to: OCPP16ChargePointStatus.Available
+      },
       // { from: OCPP16ChargePointStatus.Unavailable, to: OCPP16ChargePointStatus.Unavailable },
-      { from: OCPP16ChargePointStatus.Unavailable, to: OCPP16ChargePointStatus.Faulted },
+      {
+        from: OCPP16ChargePointStatus.Unavailable,
+        to: OCPP16ChargePointStatus.Faulted
+      },
       { to: OCPP16ChargePointStatus.Faulted },
-      { from: OCPP16ChargePointStatus.Faulted, to: OCPP16ChargePointStatus.Available },
-      { from: OCPP16ChargePointStatus.Faulted, to: OCPP16ChargePointStatus.Unavailable }
+      {
+        from: OCPP16ChargePointStatus.Faulted,
+        to: OCPP16ChargePointStatus.Available
+      },
+      {
+        from: OCPP16ChargePointStatus.Faulted,
+        to: OCPP16ChargePointStatus.Unavailable
+      }
     // { from: OCPP16ChargePointStatus.Faulted, to: OCPP16ChargePointStatus.Faulted }
     ])
 
@@ -23,93 +41,252 @@ export class OCPP16Constants extends OCPPConstants {
     Object.freeze([
       { to: OCPP16ChargePointStatus.Available },
       // { from: OCPP16ChargePointStatus.Available, to: OCPP16ChargePointStatus.Available },
-      { from: OCPP16ChargePointStatus.Available, to: OCPP16ChargePointStatus.Preparing },
-      { from: OCPP16ChargePointStatus.Available, to: OCPP16ChargePointStatus.Charging },
-      { from: OCPP16ChargePointStatus.Available, to: OCPP16ChargePointStatus.SuspendedEV },
-      { from: OCPP16ChargePointStatus.Available, to: OCPP16ChargePointStatus.SuspendedEVSE },
+      {
+        from: OCPP16ChargePointStatus.Available,
+        to: OCPP16ChargePointStatus.Preparing
+      },
+      {
+        from: OCPP16ChargePointStatus.Available,
+        to: OCPP16ChargePointStatus.Charging
+      },
+      {
+        from: OCPP16ChargePointStatus.Available,
+        to: OCPP16ChargePointStatus.SuspendedEV
+      },
+      {
+        from: OCPP16ChargePointStatus.Available,
+        to: OCPP16ChargePointStatus.SuspendedEVSE
+      },
       // { from: OCPP16ChargePointStatus.Available, to: OCPP16ChargePointStatus.Finishing },
-      { from: OCPP16ChargePointStatus.Available, to: OCPP16ChargePointStatus.Reserved },
-      { from: OCPP16ChargePointStatus.Available, to: OCPP16ChargePointStatus.Unavailable },
-      { from: OCPP16ChargePointStatus.Available, to: OCPP16ChargePointStatus.Faulted },
+      {
+        from: OCPP16ChargePointStatus.Available,
+        to: OCPP16ChargePointStatus.Reserved
+      },
+      {
+        from: OCPP16ChargePointStatus.Available,
+        to: OCPP16ChargePointStatus.Unavailable
+      },
+      {
+        from: OCPP16ChargePointStatus.Available,
+        to: OCPP16ChargePointStatus.Faulted
+      },
       // { to: OCPP16ChargePointStatus.Preparing },
-      { from: OCPP16ChargePointStatus.Preparing, to: OCPP16ChargePointStatus.Available },
+      {
+        from: OCPP16ChargePointStatus.Preparing,
+        to: OCPP16ChargePointStatus.Available
+      },
       // { from: OCPP16ChargePointStatus.Preparing, to: OCPP16ChargePointStatus.Preparing },
-      { from: OCPP16ChargePointStatus.Preparing, to: OCPP16ChargePointStatus.Charging },
-      { from: OCPP16ChargePointStatus.Preparing, to: OCPP16ChargePointStatus.SuspendedEV },
-      { from: OCPP16ChargePointStatus.Preparing, to: OCPP16ChargePointStatus.SuspendedEVSE },
-      { from: OCPP16ChargePointStatus.Preparing, to: OCPP16ChargePointStatus.Finishing },
+      {
+        from: OCPP16ChargePointStatus.Preparing,
+        to: OCPP16ChargePointStatus.Charging
+      },
+      {
+        from: OCPP16ChargePointStatus.Preparing,
+        to: OCPP16ChargePointStatus.SuspendedEV
+      },
+      {
+        from: OCPP16ChargePointStatus.Preparing,
+        to: OCPP16ChargePointStatus.SuspendedEVSE
+      },
+      {
+        from: OCPP16ChargePointStatus.Preparing,
+        to: OCPP16ChargePointStatus.Finishing
+      },
       // { from: OCPP16ChargePointStatus.Preparing, to: OCPP16ChargePointStatus.Reserved },
       // { from: OCPP16ChargePointStatus.Preparing, to: OCPP16ChargePointStatus.Unavailable },
-      { from: OCPP16ChargePointStatus.Preparing, to: OCPP16ChargePointStatus.Faulted },
+      {
+        from: OCPP16ChargePointStatus.Preparing,
+        to: OCPP16ChargePointStatus.Faulted
+      },
       // { to: OCPP16ChargePointStatus.Charging },
-      { from: OCPP16ChargePointStatus.Charging, to: OCPP16ChargePointStatus.Available },
+      {
+        from: OCPP16ChargePointStatus.Charging,
+        to: OCPP16ChargePointStatus.Available
+      },
       // { from: OCPP16ChargePointStatus.Charging, to: OCPP16ChargePointStatus.Preparing },
       // { from: OCPP16ChargePointStatus.Charging, to: OCPP16ChargePointStatus.Charging },
-      { from: OCPP16ChargePointStatus.Charging, to: OCPP16ChargePointStatus.SuspendedEV },
-      { from: OCPP16ChargePointStatus.Charging, to: OCPP16ChargePointStatus.SuspendedEVSE },
-      { from: OCPP16ChargePointStatus.Charging, to: OCPP16ChargePointStatus.Finishing },
+      {
+        from: OCPP16ChargePointStatus.Charging,
+        to: OCPP16ChargePointStatus.SuspendedEV
+      },
+      {
+        from: OCPP16ChargePointStatus.Charging,
+        to: OCPP16ChargePointStatus.SuspendedEVSE
+      },
+      {
+        from: OCPP16ChargePointStatus.Charging,
+        to: OCPP16ChargePointStatus.Finishing
+      },
       // { from: OCPP16ChargePointStatus.Charging, to: OCPP16ChargePointStatus.Reserved },
-      { from: OCPP16ChargePointStatus.Charging, to: OCPP16ChargePointStatus.Unavailable },
-      { from: OCPP16ChargePointStatus.Charging, to: OCPP16ChargePointStatus.Faulted },
+      {
+        from: OCPP16ChargePointStatus.Charging,
+        to: OCPP16ChargePointStatus.Unavailable
+      },
+      {
+        from: OCPP16ChargePointStatus.Charging,
+        to: OCPP16ChargePointStatus.Faulted
+      },
       // { to: OCPP16ChargePointStatus.SuspendedEV },
-      { from: OCPP16ChargePointStatus.SuspendedEV, to: OCPP16ChargePointStatus.Available },
+      {
+        from: OCPP16ChargePointStatus.SuspendedEV,
+        to: OCPP16ChargePointStatus.Available
+      },
       // { from: OCPP16ChargePointStatus.SuspendedEV, to: OCPP16ChargePointStatus.Preparing },
-      { from: OCPP16ChargePointStatus.SuspendedEV, to: OCPP16ChargePointStatus.Charging },
+      {
+        from: OCPP16ChargePointStatus.SuspendedEV,
+        to: OCPP16ChargePointStatus.Charging
+      },
       // { from: OCPP16ChargePointStatus.SuspendedEV, OCPP16ChargePointStatus.SuspendedEV },
-      { from: OCPP16ChargePointStatus.SuspendedEV, to: OCPP16ChargePointStatus.SuspendedEVSE },
-      { from: OCPP16ChargePointStatus.SuspendedEV, to: OCPP16ChargePointStatus.Finishing },
+      {
+        from: OCPP16ChargePointStatus.SuspendedEV,
+        to: OCPP16ChargePointStatus.SuspendedEVSE
+      },
+      {
+        from: OCPP16ChargePointStatus.SuspendedEV,
+        to: OCPP16ChargePointStatus.Finishing
+      },
       // { from: OCPP16ChargePointStatus.SuspendedEV, to: OCPP16ChargePointStatus.Reserved },
-      { from: OCPP16ChargePointStatus.SuspendedEV, to: OCPP16ChargePointStatus.Unavailable },
-      { from: OCPP16ChargePointStatus.SuspendedEV, to: OCPP16ChargePointStatus.Faulted },
+      {
+        from: OCPP16ChargePointStatus.SuspendedEV,
+        to: OCPP16ChargePointStatus.Unavailable
+      },
+      {
+        from: OCPP16ChargePointStatus.SuspendedEV,
+        to: OCPP16ChargePointStatus.Faulted
+      },
       // { to: OCPP16ChargePointStatus.SuspendedEVSE },
-      { from: OCPP16ChargePointStatus.SuspendedEVSE, to: OCPP16ChargePointStatus.Available },
+      {
+        from: OCPP16ChargePointStatus.SuspendedEVSE,
+        to: OCPP16ChargePointStatus.Available
+      },
       // { from: OCPP16ChargePointStatus.SuspendedEVSE, to: OCPP16ChargePointStatus.Preparing },
-      { from: OCPP16ChargePointStatus.SuspendedEVSE, to: OCPP16ChargePointStatus.Charging },
-      { from: OCPP16ChargePointStatus.SuspendedEVSE, to: OCPP16ChargePointStatus.SuspendedEV },
+      {
+        from: OCPP16ChargePointStatus.SuspendedEVSE,
+        to: OCPP16ChargePointStatus.Charging
+      },
+      {
+        from: OCPP16ChargePointStatus.SuspendedEVSE,
+        to: OCPP16ChargePointStatus.SuspendedEV
+      },
       // { from: OCPP16ChargePointStatus.SuspendedEVSE, to: OCPP16ChargePointStatus.SuspendedEVSE },
-      { from: OCPP16ChargePointStatus.SuspendedEVSE, to: OCPP16ChargePointStatus.Finishing },
+      {
+        from: OCPP16ChargePointStatus.SuspendedEVSE,
+        to: OCPP16ChargePointStatus.Finishing
+      },
       // { from: OCPP16ChargePointStatus.SuspendedEVSE, to: OCPP16ChargePointStatus.Reserved },
-      { from: OCPP16ChargePointStatus.SuspendedEVSE, to: OCPP16ChargePointStatus.Unavailable },
-      { from: OCPP16ChargePointStatus.SuspendedEVSE, to: OCPP16ChargePointStatus.Faulted },
+      {
+        from: OCPP16ChargePointStatus.SuspendedEVSE,
+        to: OCPP16ChargePointStatus.Unavailable
+      },
+      {
+        from: OCPP16ChargePointStatus.SuspendedEVSE,
+        to: OCPP16ChargePointStatus.Faulted
+      },
       // { to: OCPP16ChargePointStatus.Finishing},
-      { from: OCPP16ChargePointStatus.Finishing, to: OCPP16ChargePointStatus.Available },
-      { from: OCPP16ChargePointStatus.Finishing, to: OCPP16ChargePointStatus.Preparing },
+      {
+        from: OCPP16ChargePointStatus.Finishing,
+        to: OCPP16ChargePointStatus.Available
+      },
+      {
+        from: OCPP16ChargePointStatus.Finishing,
+        to: OCPP16ChargePointStatus.Preparing
+      },
       // { from: OCPP16ChargePointStatus.Finishing, to: OCPP16ChargePointStatus.Charging },
       // { from: OCPP16ChargePointStatus.Finishing, to: OCPP16ChargePointStatus.SuspendedEV },
       // { from: OCPP16ChargePointStatus.Finishing, to: OCPP16ChargePointStatus.SuspendedEVSE },
       // { from: OCPP16ChargePointStatus.Finishing, to: OCPP16ChargePointStatus.Finishing },
       // { from: OCPP16ChargePointStatus.Finishing, to: OCPP16ChargePointStatus.Reserved },
-      { from: OCPP16ChargePointStatus.Finishing, to: OCPP16ChargePointStatus.Unavailable },
-      { from: OCPP16ChargePointStatus.Finishing, to: OCPP16ChargePointStatus.Faulted },
+      {
+        from: OCPP16ChargePointStatus.Finishing,
+        to: OCPP16ChargePointStatus.Unavailable
+      },
+      {
+        from: OCPP16ChargePointStatus.Finishing,
+        to: OCPP16ChargePointStatus.Faulted
+      },
       // { to: OCPP16ChargePointStatus.Reserved },
-      { from: OCPP16ChargePointStatus.Reserved, to: OCPP16ChargePointStatus.Available },
-      { from: OCPP16ChargePointStatus.Reserved, to: OCPP16ChargePointStatus.Preparing },
+      {
+        from: OCPP16ChargePointStatus.Reserved,
+        to: OCPP16ChargePointStatus.Available
+      },
+      {
+        from: OCPP16ChargePointStatus.Reserved,
+        to: OCPP16ChargePointStatus.Preparing
+      },
       // { from: OCPP16ChargePointStatus.Reserved, to: OCPP16ChargePointStatus.Charging },
       // { from: OCPP16ChargePointStatus.Reserved, to: OCPP16ChargePointStatus.SuspendedEV },
       // { from: OCPP16ChargePointStatus.Reserved, to: OCPP16ChargePointStatus.SuspendedEVSE },
       // { from: OCPP16ChargePointStatus.Reserved, to: OCPP16ChargePointStatus.Finishing },
       // { from: OCPP16ChargePointStatus.Reserved, to: OCPP16ChargePointStatus.Reserved },
-      { from: OCPP16ChargePointStatus.Reserved, to: OCPP16ChargePointStatus.Unavailable },
-      { from: OCPP16ChargePointStatus.Reserved, to: OCPP16ChargePointStatus.Faulted },
+      {
+        from: OCPP16ChargePointStatus.Reserved,
+        to: OCPP16ChargePointStatus.Unavailable
+      },
+      {
+        from: OCPP16ChargePointStatus.Reserved,
+        to: OCPP16ChargePointStatus.Faulted
+      },
       { to: OCPP16ChargePointStatus.Unavailable },
-      { from: OCPP16ChargePointStatus.Unavailable, to: OCPP16ChargePointStatus.Available },
-      { from: OCPP16ChargePointStatus.Unavailable, to: OCPP16ChargePointStatus.Preparing },
-      { from: OCPP16ChargePointStatus.Unavailable, to: OCPP16ChargePointStatus.Charging },
-      { from: OCPP16ChargePointStatus.Unavailable, to: OCPP16ChargePointStatus.SuspendedEV },
-      { from: OCPP16ChargePointStatus.Unavailable, to: OCPP16ChargePointStatus.SuspendedEVSE },
+      {
+        from: OCPP16ChargePointStatus.Unavailable,
+        to: OCPP16ChargePointStatus.Available
+      },
+      {
+        from: OCPP16ChargePointStatus.Unavailable,
+        to: OCPP16ChargePointStatus.Preparing
+      },
+      {
+        from: OCPP16ChargePointStatus.Unavailable,
+        to: OCPP16ChargePointStatus.Charging
+      },
+      {
+        from: OCPP16ChargePointStatus.Unavailable,
+        to: OCPP16ChargePointStatus.SuspendedEV
+      },
+      {
+        from: OCPP16ChargePointStatus.Unavailable,
+        to: OCPP16ChargePointStatus.SuspendedEVSE
+      },
       // { from: OCPP16ChargePointStatus.Unavailable, to: OCPP16ChargePointStatus.Finishing },
       // { from: OCPP16ChargePointStatus.Unavailable, to: OCPP16ChargePointStatus.Reserved },
       // { from: OCPP16ChargePointStatus.Unavailable, to: OCPP16ChargePointStatus.Unavailable },
-      { from: OCPP16ChargePointStatus.Unavailable, to: OCPP16ChargePointStatus.Faulted },
+      {
+        from: OCPP16ChargePointStatus.Unavailable,
+        to: OCPP16ChargePointStatus.Faulted
+      },
       { to: OCPP16ChargePointStatus.Faulted },
-      { from: OCPP16ChargePointStatus.Faulted, to: OCPP16ChargePointStatus.Available },
-      { from: OCPP16ChargePointStatus.Faulted, to: OCPP16ChargePointStatus.Preparing },
-      { from: OCPP16ChargePointStatus.Faulted, to: OCPP16ChargePointStatus.Charging },
-      { from: OCPP16ChargePointStatus.Faulted, to: OCPP16ChargePointStatus.SuspendedEV },
-      { from: OCPP16ChargePointStatus.Faulted, to: OCPP16ChargePointStatus.SuspendedEVSE },
-      { from: OCPP16ChargePointStatus.Faulted, to: OCPP16ChargePointStatus.Finishing },
-      { from: OCPP16ChargePointStatus.Faulted, to: OCPP16ChargePointStatus.Reserved },
-      { from: OCPP16ChargePointStatus.Faulted, to: OCPP16ChargePointStatus.Unavailable }
+      {
+        from: OCPP16ChargePointStatus.Faulted,
+        to: OCPP16ChargePointStatus.Available
+      },
+      {
+        from: OCPP16ChargePointStatus.Faulted,
+        to: OCPP16ChargePointStatus.Preparing
+      },
+      {
+        from: OCPP16ChargePointStatus.Faulted,
+        to: OCPP16ChargePointStatus.Charging
+      },
+      {
+        from: OCPP16ChargePointStatus.Faulted,
+        to: OCPP16ChargePointStatus.SuspendedEV
+      },
+      {
+        from: OCPP16ChargePointStatus.Faulted,
+        to: OCPP16ChargePointStatus.SuspendedEVSE
+      },
+      {
+        from: OCPP16ChargePointStatus.Faulted,
+        to: OCPP16ChargePointStatus.Finishing
+      },
+      {
+        from: OCPP16ChargePointStatus.Faulted,
+        to: OCPP16ChargePointStatus.Reserved
+      },
+      {
+        from: OCPP16ChargePointStatus.Faulted,
+        to: OCPP16ChargePointStatus.Unavailable
+      }
       // { from: OCPP16ChargePointStatus.Faulted, to: OCPP16ChargePointStatus.Faulted }
     ])
 }
index 84fb39c18ca1bb70968a2deab618427c3e17f909..ec55ce971d11bb5d3ce32d94de0e6f18b6a182ad 100644 (file)
@@ -26,6 +26,7 @@ import {
   getConnectorChargingProfiles,
   prepareChargingProfileKind,
   removeExpiredReservations,
+  resetAuthorizeConnectorStatus,
   setConfigurationKeyValue
 } from '../../../charging-station/index.js'
 import { OCPPError } from '../../../exception/index.js'
@@ -105,6 +106,7 @@ import {
   convertToDate,
   convertToInt,
   formatDurationMilliSeconds,
+  handleIncomingRequestError,
   isAsyncFunction,
   isNotEmptyArray,
   isNotEmptyString,
@@ -420,7 +422,7 @@ export class OCPP16IncomingRequestService extends OCPPIncomingRequestService {
         if (response.status === GenericStatus.Accepted) {
           const { connectorId, idTag } = request
           // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-          chargingStation.getConnectorStatus(connectorId)!.transactionRemoteStarted = true
+          chargingStation.getConnectorStatus(connectorId!)!.transactionRemoteStarted = true
           chargingStation.ocppRequestService
             .requestHandler<Partial<OCPP16StartTransactionRequest>, OCPP16StartTransactionResponse>(
             chargingStation,
@@ -431,13 +433,17 @@ export class OCPP16IncomingRequestService extends OCPPIncomingRequestService {
             }
           )
             .then(response => {
-              if (response.status === OCPP16AuthorizationStatus.ACCEPTED) {
+              if (response.idTagInfo.status === OCPP16AuthorizationStatus.ACCEPTED) {
                 logger.debug(
-                  `${chargingStation.logPrefix()} Remote start transaction ACCEPTED on ${chargingStation.stationInfo?.chargingStationId}#${connectorId} for idTag '${idTag}'`
+                  `${chargingStation.logPrefix()} Remote start transaction ACCEPTED on ${
+                    chargingStation.stationInfo?.chargingStationId
+                  }#${connectorId} for idTag '${idTag}'`
                 )
               } else {
                 logger.debug(
-                  `${chargingStation.logPrefix()} Remote start transaction REJECTED on ${chargingStation.stationInfo?.chargingStationId}#${connectorId} for idTag '${idTag}'`
+                  `${chargingStation.logPrefix()} Remote start transaction REJECTED on ${
+                    chargingStation.stationInfo?.chargingStationId
+                  }#${connectorId} for idTag '${idTag}'`
                 )
               }
             })
@@ -465,11 +471,15 @@ export class OCPP16IncomingRequestService extends OCPPIncomingRequestService {
             .then(response => {
               if (response.status === GenericStatus.Accepted) {
                 logger.debug(
-                  `${chargingStation.logPrefix()} Remote stop transaction ACCEPTED on ${chargingStation.stationInfo?.chargingStationId}#${connectorId} for transaction '${transactionId}'`
+                  `${chargingStation.logPrefix()} Remote stop transaction ACCEPTED on ${
+                    chargingStation.stationInfo?.chargingStationId
+                  }#${connectorId} for transaction '${transactionId}'`
                 )
               } else {
                 logger.debug(
-                  `${chargingStation.logPrefix()} Remote stop transaction REJECTED on ${chargingStation.stationInfo?.chargingStationId}#${connectorId} for transaction '${transactionId}'`
+                  `${chargingStation.logPrefix()} Remote stop transaction REJECTED on ${
+                    chargingStation.stationInfo?.chargingStationId
+                  }#${connectorId} for transaction '${transactionId}'`
                 )
               }
             })
@@ -502,15 +512,10 @@ export class OCPP16IncomingRequestService extends OCPPIncomingRequestService {
         switch (requestedMessage) {
           case OCPP16MessageTrigger.BootNotification:
             chargingStation.ocppRequestService
-              .requestHandler<OCPP16BootNotificationRequest, OCPP16BootNotificationResponse>(
-              chargingStation,
-              OCPP16RequestCommand.BOOT_NOTIFICATION,
-              chargingStation.bootNotificationRequest as OCPP16BootNotificationRequest,
-              { skipBufferingOnError: true, triggerMessage: true }
-            )
-              .then(response => {
-                chargingStation.bootNotificationResponse = response
-              })
+              .requestHandler<
+            OCPP16BootNotificationRequest,
+            OCPP16BootNotificationResponse
+            >(chargingStation, OCPP16RequestCommand.BOOT_NOTIFICATION, chargingStation.bootNotificationRequest as OCPP16BootNotificationRequest, { skipBufferingOnError: true, triggerMessage: true })
               .catch(errorHandler)
             break
           case OCPP16MessageTrigger.Heartbeat:
@@ -647,7 +652,7 @@ export class OCPP16IncomingRequestService extends OCPPIncomingRequestService {
         // Throw exception
         throw new OCPPError(
           ErrorType.NOT_IMPLEMENTED,
-          `'${commandName}' is not implemented to handle request PDU ${JSON.stringify(
+          `${commandName} is not implemented to handle request PDU ${JSON.stringify(
             commandPayload,
             undefined,
             2
@@ -835,6 +840,25 @@ export class OCPP16IncomingRequestService extends OCPPIncomingRequestService {
       ) {
         chargingStation.restartWebSocketPing()
       }
+      if (
+        (keyToChange.key as OCPP16StandardParametersKey) ===
+          OCPP16StandardParametersKey.MeterValueSampleInterval &&
+        chargingStation.getNumberOfRunningTransactions() > 0 &&
+        valueChanged
+      ) {
+        for (
+          let connectorId = 1;
+          connectorId <= chargingStation.getNumberOfConnectors();
+          connectorId++
+        ) {
+          if (chargingStation.getConnectorStatus(connectorId)?.transactionStarted === true) {
+            chargingStation.restartMeterValues(
+              connectorId,
+              secondsToMilliseconds(convertToInt(value))
+            )
+          }
+        }
+      }
       if (keyToChange.reboot === true) {
         return OCPP16Constants.OCPP_CONFIGURATION_RESPONSE_REBOOT_REQUIRED
       }
@@ -894,6 +918,7 @@ export class OCPP16IncomingRequestService extends OCPPIncomingRequestService {
       csChargingProfiles.chargingProfilePurpose === OCPP16ChargingProfilePurposeType.TX_PROFILE &&
       connectorId > 0 &&
       connectorStatus?.transactionStarted === true &&
+      csChargingProfiles.transactionId != null &&
       csChargingProfiles.transactionId !== connectorStatus.transactionId
     ) {
       logger.error(
@@ -954,7 +979,6 @@ export class OCPP16IncomingRequestService extends OCPPIncomingRequestService {
       start: currentDate,
       end: addSeconds(currentDate, duration)
     }
-    // Get charging profiles sorted by connector id then stack level
     const chargingProfiles: OCPP16ChargingProfile[] = getConnectorChargingProfiles(
       chargingStation,
       connectorId
@@ -1045,41 +1069,46 @@ export class OCPP16IncomingRequestService extends OCPPIncomingRequestService {
       return OCPP16Constants.OCPP_CLEAR_CHARGING_PROFILE_RESPONSE_UNKNOWN
     }
     const { connectorId } = commandPayload
-    // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-    if (!chargingStation.hasConnector(connectorId!)) {
-      logger.error(
-        `${chargingStation.logPrefix()} Trying to clear a charging profile(s) to a non existing connector id ${connectorId}`
-      )
-      return OCPP16Constants.OCPP_CLEAR_CHARGING_PROFILE_RESPONSE_UNKNOWN
-    }
-    // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-    const connectorStatus = chargingStation.getConnectorStatus(connectorId!)
-    if (connectorId != null && isNotEmptyArray(connectorStatus?.chargingProfiles)) {
-      connectorStatus.chargingProfiles = []
-      logger.debug(
-        `${chargingStation.logPrefix()} Charging profile(s) cleared on connector id ${connectorId}`
-      )
-      return OCPP16Constants.OCPP_CLEAR_CHARGING_PROFILE_RESPONSE_ACCEPTED
-    }
-    if (connectorId == null) {
+    if (connectorId != null) {
+      if (!chargingStation.hasConnector(connectorId)) {
+        logger.error(
+          `${chargingStation.logPrefix()} Trying to clear a charging profile(s) to a non existing connector id ${connectorId}`
+        )
+        return OCPP16Constants.OCPP_CLEAR_CHARGING_PROFILE_RESPONSE_UNKNOWN
+      }
+      const connectorStatus = chargingStation.getConnectorStatus(connectorId)
+      if (isNotEmptyArray(connectorStatus?.chargingProfiles)) {
+        connectorStatus.chargingProfiles = []
+        logger.debug(
+          `${chargingStation.logPrefix()} Charging profile(s) cleared on connector id ${connectorId}`
+        )
+        return OCPP16Constants.OCPP_CLEAR_CHARGING_PROFILE_RESPONSE_ACCEPTED
+      }
+    } else {
       let clearedCP = false
       if (chargingStation.hasEvses) {
         for (const evseStatus of chargingStation.evses.values()) {
           for (const status of evseStatus.connectors.values()) {
-            clearedCP = OCPP16ServiceUtils.clearChargingProfiles(
+            const clearedConnectorCP = OCPP16ServiceUtils.clearChargingProfiles(
               chargingStation,
               commandPayload,
               status.chargingProfiles
             )
+            if (clearedConnectorCP && !clearedCP) {
+              clearedCP = true
+            }
           }
         }
       } else {
         for (const id of chargingStation.connectors.keys()) {
-          clearedCP = OCPP16ServiceUtils.clearChargingProfiles(
+          const clearedConnectorCP = OCPP16ServiceUtils.clearChargingProfiles(
             chargingStation,
             commandPayload,
             chargingStation.getConnectorStatus(id)?.chargingProfiles
           )
+          if (clearedConnectorCP && !clearedCP) {
+            clearedCP = true
+          }
         }
       }
       if (clearedCP) {
@@ -1152,6 +1181,29 @@ export class OCPP16IncomingRequestService extends OCPPIncomingRequestService {
     chargingStation: ChargingStation,
     commandPayload: RemoteStartTransactionRequest
   ): Promise<GenericResponse> {
+    if (commandPayload.connectorId == null) {
+      for (
+        let connectorId = 1;
+        connectorId <= chargingStation.getNumberOfConnectors();
+        connectorId++
+      ) {
+        if (
+          chargingStation.getConnectorStatus(connectorId)?.transactionStarted === false &&
+          !OCPP16ServiceUtils.hasReservation(chargingStation, connectorId, commandPayload.idTag)
+        ) {
+          commandPayload.connectorId = connectorId
+          break
+        }
+      }
+      if (commandPayload.connectorId == null) {
+        logger.debug(
+          `${chargingStation.logPrefix()} Remote start transaction REJECTED on ${
+            chargingStation.stationInfo?.chargingStationId
+          }, idTag '${commandPayload.idTag}': no available connector found`
+        )
+        return OCPP16Constants.OCPP_RESPONSE_REJECTED
+      }
+    }
     const { connectorId: transactionConnectorId, idTag, chargingProfile } = commandPayload
     if (!chargingStation.hasConnector(transactionConnectorId)) {
       return this.notifyRemoteStartTransactionRejected(
@@ -1196,7 +1248,9 @@ export class OCPP16IncomingRequestService extends OCPPIncomingRequestService {
       )
     }
     logger.debug(
-      `${chargingStation.logPrefix()} Remote start transaction ACCEPTED on ${chargingStation.stationInfo?.chargingStationId}#${transactionConnectorId}}, idTag '${idTag}'`
+      `${chargingStation.logPrefix()} Remote start transaction ACCEPTED on ${
+        chargingStation.stationInfo?.chargingStationId
+      }#${transactionConnectorId}}, idTag '${idTag}'`
     )
     return OCPP16Constants.OCPP_RESPONSE_ACCEPTED
   }
@@ -1208,7 +1262,11 @@ export class OCPP16IncomingRequestService extends OCPPIncomingRequestService {
   ): GenericResponse {
     const connectorStatus = chargingStation.getConnectorStatus(connectorId)
     logger.debug(
-      `${chargingStation.logPrefix()} Remote start transaction REJECTED on ${chargingStation.stationInfo?.chargingStationId}#${connectorId}, idTag '${idTag}', availability '${connectorStatus?.availability}', status '${connectorStatus?.status}'`
+      `${chargingStation.logPrefix()} Remote start transaction REJECTED on ${
+        chargingStation.stationInfo?.chargingStationId
+      }#${connectorId}, idTag '${idTag}', availability '${
+        connectorStatus?.availability
+      }', status '${connectorStatus?.status}'`
     )
     return OCPP16Constants.OCPP_RESPONSE_REJECTED
   }
@@ -1218,10 +1276,15 @@ export class OCPP16IncomingRequestService extends OCPPIncomingRequestService {
     connectorId: number,
     chargingProfile: OCPP16ChargingProfile
   ): boolean {
-    if (chargingProfile.chargingProfilePurpose === OCPP16ChargingProfilePurposeType.TX_PROFILE) {
+    if (
+      chargingProfile.chargingProfilePurpose === OCPP16ChargingProfilePurposeType.TX_PROFILE &&
+      chargingProfile.transactionId == null
+    ) {
       OCPP16ServiceUtils.setChargingProfile(chargingStation, connectorId, chargingProfile)
       logger.debug(
-        `${chargingStation.logPrefix()} Charging profile(s) set at remote start transaction on ${chargingStation.stationInfo?.chargingStationId}#${connectorId}`,
+        `${chargingStation.logPrefix()} Charging profile(s) set at remote start transaction on ${
+          chargingStation.stationInfo?.chargingStationId
+        }#${connectorId}`,
         chargingProfile
       )
       return true
@@ -1229,7 +1292,7 @@ export class OCPP16IncomingRequestService extends OCPPIncomingRequestService {
     logger.debug(
       `${chargingStation.logPrefix()} Not allowed to set ${
         chargingProfile.chargingProfilePurpose
-      } charging profile(s) at remote start transaction`
+      } charging profile(s)${chargingProfile.transactionId != null ? ' with transactionId set' : ''} at remote start transaction`
     )
     return false
   }
@@ -1270,7 +1333,10 @@ export class OCPP16IncomingRequestService extends OCPPIncomingRequestService {
     // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
     commandPayload.retrieveDate = convertToDate(commandPayload.retrieveDate)!
     const { retrieveDate } = commandPayload
-    if (chargingStation.stationInfo?.firmwareStatus !== OCPP16FirmwareStatus.Installed) {
+    if (
+      chargingStation.stationInfo?.firmwareStatus != null &&
+      chargingStation.stationInfo.firmwareStatus !== OCPP16FirmwareStatus.Installed
+    ) {
       logger.warn(
         `${chargingStation.logPrefix()} ${moduleName}.handleRequestUpdateFirmware: Cannot simulate firmware update: firmware update is already in progress`
       )
@@ -1459,7 +1525,10 @@ export class OCPP16IncomingRequestService extends OCPPIncomingRequestService {
         const logConfiguration = Configuration.getConfigurationSection<LogConfiguration>(
           ConfigurationSection.log
         )
-        const logFiles = readdirSync(resolve(dirname(fileURLToPath(import.meta.url)), '../'))
+        const logFiles = readdirSync(
+          // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
+          resolve((fileURLToPath(import.meta.url), '../', dirname(logConfiguration.file!)))
+        )
           // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
           .filter(file => file.endsWith(extname(logConfiguration.file!)))
           // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
@@ -1531,7 +1600,7 @@ export class OCPP16IncomingRequestService extends OCPPIncomingRequestService {
         })
         ftpClient?.close()
         // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-        return this.handleIncomingRequestError<GetDiagnosticsResponse>(
+        return handleIncomingRequestError<GetDiagnosticsResponse>(
           chargingStation,
           OCPP16IncomingRequestCommand.GET_DIAGNOSTICS,
           error as Error,
@@ -1601,7 +1670,7 @@ export class OCPP16IncomingRequestService extends OCPPIncomingRequestService {
       return OCPP16Constants.OCPP_DATA_TRANSFER_RESPONSE_UNKNOWN_VENDOR_ID
     } catch (error) {
       // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-      return this.handleIncomingRequestError<OCPP16DataTransferResponse>(
+      return handleIncomingRequestError<OCPP16DataTransferResponse>(
         chargingStation,
         OCPP16IncomingRequestCommand.DATA_TRANSFER,
         error as Error,
@@ -1626,19 +1695,28 @@ export class OCPP16IncomingRequestService extends OCPPIncomingRequestService {
     // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
     commandPayload.expiryDate = convertToDate(commandPayload.expiryDate)!
     const { reservationId, idTag, connectorId } = commandPayload
+    if (!chargingStation.hasConnector(connectorId)) {
+      logger.error(
+        `${chargingStation.logPrefix()} Trying to reserve a non existing connector id ${connectorId}`
+      )
+      return OCPP16Constants.OCPP_RESERVATION_RESPONSE_REJECTED
+    }
+    if (connectorId > 0 && !chargingStation.isConnectorAvailable(connectorId)) {
+      return OCPP16Constants.OCPP_RESERVATION_RESPONSE_REJECTED
+    }
+    if (connectorId === 0 && !chargingStation.getReserveConnectorZeroSupported()) {
+      return OCPP16Constants.OCPP_RESERVATION_RESPONSE_REJECTED
+    }
+    if (!(await OCPP16ServiceUtils.isIdTagAuthorized(chargingStation, connectorId, idTag))) {
+      return OCPP16Constants.OCPP_RESERVATION_RESPONSE_REJECTED
+    }
+    // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
+    const connectorStatus = chargingStation.getConnectorStatus(connectorId)!
+    resetAuthorizeConnectorStatus(connectorStatus)
     let response: OCPP16ReserveNowResponse
     try {
-      if (connectorId > 0 && !chargingStation.isConnectorAvailable(connectorId)) {
-        return OCPP16Constants.OCPP_RESERVATION_RESPONSE_REJECTED
-      }
-      if (connectorId === 0 && !chargingStation.getReserveConnectorZeroSupported()) {
-        return OCPP16Constants.OCPP_RESERVATION_RESPONSE_REJECTED
-      }
-      if (!(await OCPP16ServiceUtils.isIdTagAuthorized(chargingStation, connectorId, idTag))) {
-        return OCPP16Constants.OCPP_RESERVATION_RESPONSE_REJECTED
-      }
       await removeExpiredReservations(chargingStation)
-      switch (chargingStation.getConnectorStatus(connectorId)?.status) {
+      switch (connectorStatus.status) {
         case OCPP16ChargePointStatus.Faulted:
           response = OCPP16Constants.OCPP_RESERVATION_RESPONSE_FAULTED
           break
@@ -1675,7 +1753,7 @@ export class OCPP16IncomingRequestService extends OCPPIncomingRequestService {
       // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
       chargingStation.getConnectorStatus(connectorId)!.status = OCPP16ChargePointStatus.Available
       // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-      return this.handleIncomingRequestError<OCPP16ReserveNowResponse>(
+      return handleIncomingRequestError<OCPP16ReserveNowResponse>(
         chargingStation,
         OCPP16IncomingRequestCommand.RESERVE_NOW,
         error as Error,
@@ -1713,11 +1791,13 @@ export class OCPP16IncomingRequestService extends OCPPIncomingRequestService {
       return OCPP16Constants.OCPP_CANCEL_RESERVATION_RESPONSE_ACCEPTED
     } catch (error) {
       // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-      return this.handleIncomingRequestError<GenericResponse>(
+      return handleIncomingRequestError<GenericResponse>(
         chargingStation,
         OCPP16IncomingRequestCommand.CANCEL_RESERVATION,
         error as Error,
-        { errorResponse: OCPP16Constants.OCPP_CANCEL_RESERVATION_RESPONSE_REJECTED }
+        {
+          errorResponse: OCPP16Constants.OCPP_CANCEL_RESERVATION_RESPONSE_REJECTED
+        }
       )!
     }
   }
index b9643469a791831937d9774e4ef0b9fb68abacbf..6f772e0700d52f8c77280304f41ec7ae564ba7d4 100644 (file)
@@ -172,7 +172,7 @@ export class OCPP16RequestService extends OCPPRequestService {
   ): Promise<ResponseType> {
     // FIXME?: add sanity checks on charging station availability, connector availability, connector status, etc.
     if (OCPP16ServiceUtils.isRequestCommandSupported(chargingStation, commandName)) {
-      // Post request actions hook
+      // Pre request actions hook
       switch (commandName) {
         case OCPP16RequestCommand.START_TRANSACTION:
           await OCPP16ServiceUtils.sendAndSetConnectorStatus(
@@ -193,7 +193,7 @@ export class OCPP16RequestService extends OCPPRequestService {
     // OCPPError usage here is debatable: it's an error in the OCPP stack but not targeted to sendError().
     throw new OCPPError(
       ErrorType.NOT_SUPPORTED,
-      `Unsupported OCPP command '${commandName}'`,
+      `Unsupported OCPP command ${commandName}`,
       commandName,
       commandParams
     )
@@ -277,7 +277,7 @@ export class OCPP16RequestService extends OCPPRequestService {
         throw new OCPPError(
           ErrorType.NOT_SUPPORTED,
           // eslint-disable-next-line @typescript-eslint/restrict-template-expressions
-          `Unsupported OCPP command '${commandName}'`,
+          `Unsupported OCPP command ${commandName}`,
           commandName,
           commandParams
         )
index e6c3b43472c8ef0975f3e855deebf51b7c013919..df8374214f8e8865fea5453e9ae4075ea5ee2ece 100644 (file)
@@ -13,6 +13,7 @@ import {
 import { OCPPError } from '../../../exception/index.js'
 import {
   type ChangeConfigurationResponse,
+  ChargingStationEvents,
   ErrorType,
   type GenericResponse,
   type GetConfigurationResponse,
@@ -468,7 +469,7 @@ export class OCPP16ResponseService extends OCPPResponseService {
         // Throw exception
         throw new OCPPError(
           ErrorType.NOT_IMPLEMENTED,
-          `'${commandName}' is not implemented to handle response PDU ${JSON.stringify(
+          `${commandName} is not implemented to handle response PDU ${JSON.stringify(
             payload,
             undefined,
             2
@@ -509,24 +510,30 @@ export class OCPP16ResponseService extends OCPPResponseService {
     chargingStation: ChargingStation,
     payload: OCPP16BootNotificationResponse
   ): void {
-    if (payload.status === RegistrationStatusEnumType.ACCEPTED) {
-      addConfigurationKey(
-        chargingStation,
-        OCPP16StandardParametersKey.HeartbeatInterval,
-        payload.interval.toString(),
-        {},
-        { overwrite: true, save: true }
-      )
-      addConfigurationKey(
-        chargingStation,
-        OCPP16StandardParametersKey.HeartBeatInterval,
-        payload.interval.toString(),
-        { visible: false },
-        { overwrite: true, save: true }
-      )
-      OCPP16ServiceUtils.startHeartbeatInterval(chargingStation, payload.interval)
-    }
     if (Object.values(RegistrationStatusEnumType).includes(payload.status)) {
+      chargingStation.bootNotificationResponse = payload
+      if (chargingStation.isRegistered()) {
+        chargingStation.emit(ChargingStationEvents.registered)
+        if (chargingStation.inAcceptedState()) {
+          addConfigurationKey(
+            chargingStation,
+            OCPP16StandardParametersKey.HeartbeatInterval,
+            payload.interval.toString(),
+            {},
+            { overwrite: true, save: true }
+          )
+          addConfigurationKey(
+            chargingStation,
+            OCPP16StandardParametersKey.HeartBeatInterval,
+            payload.interval.toString(),
+            { visible: false },
+            { overwrite: true, save: true }
+          )
+          chargingStation.emit(ChargingStationEvents.accepted)
+        }
+      } else if (chargingStation.inRejectedState()) {
+        chargingStation.emit(ChargingStationEvents.rejected)
+      }
       const logMsg = `${chargingStation.logPrefix()} Charging station in '${
         payload.status
       }' state on the central server`
@@ -534,6 +541,7 @@ export class OCPP16ResponseService extends OCPPResponseService {
         ? logger.warn(logMsg)
         : logger.info(logMsg)
     } else {
+      delete chargingStation.bootNotificationResponse
       logger.error(
         `${chargingStation.logPrefix()} Charging station boot notification response received: %j with undefined registration status`,
         payload
@@ -583,9 +591,9 @@ export class OCPP16ResponseService extends OCPPResponseService {
         authorizeConnectorStatus.idTagAuthorized = false
         delete authorizeConnectorStatus.authorizeIdTag
         logger.debug(
-          `${chargingStation.logPrefix()} idTag '${requestPayload.idTag}' rejected with status '${
-            payload.idTagInfo.status
-          }'`
+          `${chargingStation.logPrefix()} idTag '${
+            requestPayload.idTag
+          }' rejected with status '${payload.idTagInfo.status}'`
         )
       }
     } else {
@@ -642,6 +650,7 @@ export class OCPP16ResponseService extends OCPPResponseService {
     }
     if (
       connectorStatus?.idTagAuthorized === true &&
+      connectorStatus.authorizeIdTag != null &&
       connectorStatus.authorizeIdTag !== requestPayload.idTag
     ) {
       logger.error(
@@ -656,6 +665,7 @@ export class OCPP16ResponseService extends OCPPResponseService {
     }
     if (
       connectorStatus?.idTagLocalAuthorized === true &&
+      connectorStatus.localAuthorizeIdTag != null &&
       connectorStatus.localAuthorizeIdTag !== requestPayload.idTag
     ) {
       logger.error(
@@ -698,7 +708,9 @@ export class OCPP16ResponseService extends OCPPResponseService {
       connectorStatus?.status !== OCPP16ChargePointStatus.Preparing
     ) {
       logger.error(
-        `${chargingStation.logPrefix()} Trying to start a transaction on connector id ${connectorId} with status ${connectorStatus?.status}`
+        `${chargingStation.logPrefix()} Trying to start a transaction on connector id ${connectorId} with status ${
+          connectorStatus?.status
+        }`
       )
       return
     }
@@ -733,9 +745,9 @@ export class OCPP16ResponseService extends OCPPResponseService {
             logger.warn(
               `${chargingStation.logPrefix()} Reserved transaction ${
                 payload.transactionId
-              } started with a different idTag ${requestPayload.idTag} than the reservation one ${
-                reservation.idTag
-              }`
+              } started with a different idTag ${
+                requestPayload.idTag
+              } than the reservation one ${reservation.idTag}`
             )
           }
           if (hasReservationExpired(reservation)) {
@@ -774,11 +786,9 @@ export class OCPP16ResponseService extends OCPPResponseService {
         OCPP16ChargePointStatus.Charging
       )
       logger.info(
-        `${chargingStation.logPrefix()} Transaction with id ${
-          payload.transactionId
-        } STARTED on ${chargingStation.stationInfo?.chargingStationId}#${connectorId} for idTag '${
-          requestPayload.idTag
-        }'`
+        `${chargingStation.logPrefix()} Transaction with id ${payload.transactionId} STARTED on ${
+          chargingStation.stationInfo?.chargingStationId
+        }#${connectorId} for idTag '${requestPayload.idTag}'`
       )
       if (chargingStation.stationInfo?.powerSharedByConnectors === true) {
         // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
index 7acf7aef03ba32df4c3631a91d7ffff164b556ac..b4c73bc28963e7f998c625ce40a9257c16d274fb 100644 (file)
@@ -13,7 +13,10 @@ export class OCPP20Constants extends OCPPConstants {
         from: OCPP20ConnectorStatusEnumType.Available,
         to: OCPP20ConnectorStatusEnumType.Unavailable
       },
-      { from: OCPP20ConnectorStatusEnumType.Available, to: OCPP20ConnectorStatusEnumType.Faulted },
+      {
+        from: OCPP20ConnectorStatusEnumType.Available,
+        to: OCPP20ConnectorStatusEnumType.Faulted
+      },
       { to: OCPP20ConnectorStatusEnumType.Unavailable },
       {
         from: OCPP20ConnectorStatusEnumType.Unavailable,
@@ -28,7 +31,10 @@ export class OCPP20Constants extends OCPPConstants {
         to: OCPP20ConnectorStatusEnumType.Faulted
       },
       { to: OCPP20ConnectorStatusEnumType.Faulted },
-      { from: OCPP20ConnectorStatusEnumType.Faulted, to: OCPP20ConnectorStatusEnumType.Available },
+      {
+        from: OCPP20ConnectorStatusEnumType.Faulted,
+        to: OCPP20ConnectorStatusEnumType.Available
+      },
       {
         from: OCPP20ConnectorStatusEnumType.Faulted,
         to: OCPP20ConnectorStatusEnumType.Unavailable
@@ -40,31 +46,55 @@ export class OCPP20Constants extends OCPPConstants {
     [
       { to: OCPP20ConnectorStatusEnumType.Available },
       // { from: OCPP20ConnectorStatusEnumType.Available, to: OCPP20ConnectorStatusEnumType.Available },
-      { from: OCPP20ConnectorStatusEnumType.Available, to: OCPP20ConnectorStatusEnumType.Occupied },
-      { from: OCPP20ConnectorStatusEnumType.Available, to: OCPP20ConnectorStatusEnumType.Reserved },
+      {
+        from: OCPP20ConnectorStatusEnumType.Available,
+        to: OCPP20ConnectorStatusEnumType.Occupied
+      },
+      {
+        from: OCPP20ConnectorStatusEnumType.Available,
+        to: OCPP20ConnectorStatusEnumType.Reserved
+      },
       {
         from: OCPP20ConnectorStatusEnumType.Available,
         to: OCPP20ConnectorStatusEnumType.Unavailable
       },
-      { from: OCPP20ConnectorStatusEnumType.Available, to: OCPP20ConnectorStatusEnumType.Faulted },
+      {
+        from: OCPP20ConnectorStatusEnumType.Available,
+        to: OCPP20ConnectorStatusEnumType.Faulted
+      },
       // { to: OCPP20ConnectorStatusEnumType.Occupied },
-      { from: OCPP20ConnectorStatusEnumType.Occupied, to: OCPP20ConnectorStatusEnumType.Available },
+      {
+        from: OCPP20ConnectorStatusEnumType.Occupied,
+        to: OCPP20ConnectorStatusEnumType.Available
+      },
       // { from: OCPP20ConnectorStatusEnumType.Occupied, to: OCPP20ConnectorStatusEnumType.Occupied },
       // { from: OCPP20ConnectorStatusEnumType.Occupied, to: OCPP20ConnectorStatusEnumType.Reserved },
       {
         from: OCPP20ConnectorStatusEnumType.Occupied,
         to: OCPP20ConnectorStatusEnumType.Unavailable
       },
-      { from: OCPP20ConnectorStatusEnumType.Occupied, to: OCPP20ConnectorStatusEnumType.Faulted },
+      {
+        from: OCPP20ConnectorStatusEnumType.Occupied,
+        to: OCPP20ConnectorStatusEnumType.Faulted
+      },
       // { to: OCPP20ConnectorStatusEnumType.Reserved },
-      { from: OCPP20ConnectorStatusEnumType.Reserved, to: OCPP20ConnectorStatusEnumType.Available },
-      { from: OCPP20ConnectorStatusEnumType.Reserved, to: OCPP20ConnectorStatusEnumType.Occupied },
+      {
+        from: OCPP20ConnectorStatusEnumType.Reserved,
+        to: OCPP20ConnectorStatusEnumType.Available
+      },
+      {
+        from: OCPP20ConnectorStatusEnumType.Reserved,
+        to: OCPP20ConnectorStatusEnumType.Occupied
+      },
       // { from: OCPP20ConnectorStatusEnumType.Reserved, to: OCPP20ConnectorStatusEnumType.Reserved },
       {
         from: OCPP20ConnectorStatusEnumType.Reserved,
         to: OCPP20ConnectorStatusEnumType.Unavailable
       },
-      { from: OCPP20ConnectorStatusEnumType.Reserved, to: OCPP20ConnectorStatusEnumType.Faulted },
+      {
+        from: OCPP20ConnectorStatusEnumType.Reserved,
+        to: OCPP20ConnectorStatusEnumType.Faulted
+      },
       { to: OCPP20ConnectorStatusEnumType.Unavailable },
       {
         from: OCPP20ConnectorStatusEnumType.Unavailable,
@@ -81,9 +111,18 @@ export class OCPP20Constants extends OCPPConstants {
         to: OCPP20ConnectorStatusEnumType.Faulted
       },
       { to: OCPP20ConnectorStatusEnumType.Faulted },
-      { from: OCPP20ConnectorStatusEnumType.Faulted, to: OCPP20ConnectorStatusEnumType.Available },
-      { from: OCPP20ConnectorStatusEnumType.Faulted, to: OCPP20ConnectorStatusEnumType.Occupied },
-      { from: OCPP20ConnectorStatusEnumType.Faulted, to: OCPP20ConnectorStatusEnumType.Reserved },
+      {
+        from: OCPP20ConnectorStatusEnumType.Faulted,
+        to: OCPP20ConnectorStatusEnumType.Available
+      },
+      {
+        from: OCPP20ConnectorStatusEnumType.Faulted,
+        to: OCPP20ConnectorStatusEnumType.Occupied
+      },
+      {
+        from: OCPP20ConnectorStatusEnumType.Faulted,
+        to: OCPP20ConnectorStatusEnumType.Reserved
+      },
       {
         from: OCPP20ConnectorStatusEnumType.Faulted,
         to: OCPP20ConnectorStatusEnumType.Unavailable
index b1cd51fc8e935a7cebfe05a935a623ca4e41dc6c..4ae587d43f7de90a119341843b8682985c95dccc 100644 (file)
@@ -109,7 +109,7 @@ export class OCPP20IncomingRequestService extends OCPPIncomingRequestService {
         // Throw exception
         throw new OCPPError(
           ErrorType.NOT_IMPLEMENTED,
-          `'${commandName}' is not implemented to handle request PDU ${JSON.stringify(
+          `${commandName} is not implemented to handle request PDU ${JSON.stringify(
             commandPayload,
             undefined,
             2
index c9c4b17b24d6060e7ac102e9ab70664f97c2d13a..38dbedf87f9b7f426507cfa8e92bf42ca5ef606d 100644 (file)
@@ -80,7 +80,7 @@ export class OCPP20RequestService extends OCPPRequestService {
   ): Promise<ResponseType> {
     // FIXME?: add sanity checks on charging station availability, connector availability, connector status, etc.
     if (OCPP20ServiceUtils.isRequestCommandSupported(chargingStation, commandName)) {
-      // TODO: post request actions hook
+      // TODO: pre request actions hook
       return (await this.sendMessage(
         chargingStation,
         generateUUID(),
@@ -92,7 +92,7 @@ export class OCPP20RequestService extends OCPPRequestService {
     // OCPPError usage here is debatable: it's an error in the OCPP stack but not targeted to sendError().
     throw new OCPPError(
       ErrorType.NOT_SUPPORTED,
-      `Unsupported OCPP command '${commandName}'`,
+      `Unsupported OCPP command ${commandName}`,
       commandName,
       commandParams
     )
@@ -119,7 +119,7 @@ export class OCPP20RequestService extends OCPPRequestService {
         throw new OCPPError(
           ErrorType.NOT_SUPPORTED,
           // eslint-disable-next-line @typescript-eslint/restrict-template-expressions
-          `Unsupported OCPP command '${commandName}'`,
+          `Unsupported OCPP command ${commandName}`,
           commandName,
           commandParams
         )
index 6ab91c074d01ec4f24b01a4c5fbdffb374ad1fa9..9851d3339371d8fe3e47cb7a5dcaa835d7bcace0 100644 (file)
@@ -5,6 +5,7 @@ import type { ValidateFunction } from 'ajv'
 import { addConfigurationKey, type ChargingStation } from '../../../charging-station/index.js'
 import { OCPPError } from '../../../exception/index.js'
 import {
+  ChargingStationEvents,
   ErrorType,
   type JsonType,
   type OCPP20BootNotificationResponse,
@@ -141,7 +142,7 @@ export class OCPP20ResponseService extends OCPPResponseService {
         // Throw exception
         throw new OCPPError(
           ErrorType.NOT_IMPLEMENTED,
-          `'${commandName}' is not implemented to handle response PDU ${JSON.stringify(
+          `${commandName} is not implemented to handle response PDU ${JSON.stringify(
             payload,
             undefined,
             2
@@ -182,17 +183,23 @@ export class OCPP20ResponseService extends OCPPResponseService {
     chargingStation: ChargingStation,
     payload: OCPP20BootNotificationResponse
   ): void {
-    if (payload.status === RegistrationStatusEnumType.ACCEPTED) {
-      addConfigurationKey(
-        chargingStation,
-        OCPP20OptionalVariableName.HeartbeatInterval,
-        payload.interval.toString(),
-        {},
-        { overwrite: true, save: true }
-      )
-      OCPP20ServiceUtils.startHeartbeatInterval(chargingStation, payload.interval)
-    }
     if (Object.values(RegistrationStatusEnumType).includes(payload.status)) {
+      chargingStation.bootNotificationResponse = payload
+      if (chargingStation.isRegistered()) {
+        chargingStation.emit(ChargingStationEvents.registered)
+        if (chargingStation.inAcceptedState()) {
+          addConfigurationKey(
+            chargingStation,
+            OCPP20OptionalVariableName.HeartbeatInterval,
+            payload.interval.toString(),
+            {},
+            { overwrite: true, save: true }
+          )
+          chargingStation.emit(ChargingStationEvents.accepted)
+        }
+      } else if (chargingStation.inRejectedState()) {
+        chargingStation.emit(ChargingStationEvents.rejected)
+      }
       const logMsg = `${chargingStation.logPrefix()} Charging station in '${
         payload.status
       }' state on the central server`
@@ -200,6 +207,7 @@ export class OCPP20ResponseService extends OCPPResponseService {
         ? logger.warn(logMsg)
         : logger.info(logMsg)
     } else {
+      delete chargingStation.bootNotificationResponse
       logger.error(
         `${chargingStation.logPrefix()} Charging station boot notification response received: %j with undefined registration status`,
         payload
index b036738719944fae935f62c03ec137c06acca761..2abb197892d1bb1dc35e0dd87d0739d37e9f3d58 100644 (file)
@@ -26,8 +26,13 @@ export class OCPPConstants {
 
   static readonly OCPP_REQUEST_EMPTY = Constants.EMPTY_FROZEN_OBJECT
   static readonly OCPP_RESPONSE_EMPTY = Constants.EMPTY_FROZEN_OBJECT
-  static readonly OCPP_RESPONSE_ACCEPTED = Object.freeze({ status: GenericStatus.Accepted })
-  static readonly OCPP_RESPONSE_REJECTED = Object.freeze({ status: GenericStatus.Rejected })
+  static readonly OCPP_RESPONSE_ACCEPTED = Object.freeze({
+    status: GenericStatus.Accepted
+  })
+
+  static readonly OCPP_RESPONSE_REJECTED = Object.freeze({
+    status: GenericStatus.Rejected
+  })
 
   static readonly OCPP_CONFIGURATION_RESPONSE_ACCEPTED = Object.freeze({
     status: ConfigurationStatus.ACCEPTED
@@ -65,7 +70,10 @@ export class OCPPConstants {
     status: ClearChargingProfileStatus.UNKNOWN
   })
 
-  static readonly OCPP_RESPONSE_UNLOCKED = Object.freeze({ status: UnlockStatus.UNLOCKED })
+  static readonly OCPP_RESPONSE_UNLOCKED = Object.freeze({
+    status: UnlockStatus.UNLOCKED
+  })
+
   static readonly OCPP_RESPONSE_UNLOCK_FAILED = Object.freeze({
     status: UnlockStatus.UNLOCK_FAILED
   })
index 7c88547a6c63ce285e2009e6561b9d813fc99b53..545438d5d61dda84a995c1c4351562a1c8a94e1b 100644 (file)
@@ -7,14 +7,13 @@ import { type ChargingStation, getIdTagsFile } from '../../charging-station/inde
 import { OCPPError } from '../../exception/index.js'
 import type {
   ClearCacheResponse,
-  HandleErrorParams,
   IncomingRequestCommand,
   JsonType,
   OCPPVersion
 } from '../../types/index.js'
-import { logger, setDefaultErrorParams } from '../../utils/index.js'
+import { logger } from '../../utils/index.js'
 import { OCPPConstants } from './OCPPConstants.js'
-import { OCPPServiceUtils } from './OCPPServiceUtils.js'
+import { ajvErrorsToErrorType } from './OCPPServiceUtils.js'
 type Ajv = _Ajv.default
 // eslint-disable-next-line @typescript-eslint/no-redeclare
 const Ajv = _Ajv.default
@@ -50,28 +49,6 @@ export abstract class OCPPIncomingRequestService extends EventEmitter {
     return OCPPIncomingRequestService.instance as T
   }
 
-  protected handleIncomingRequestError<T extends JsonType>(
-    chargingStation: ChargingStation,
-    commandName: IncomingRequestCommand,
-    error: Error,
-    params: HandleErrorParams<T> = { throwError: true, consoleOut: false }
-  ): T | undefined {
-    setDefaultErrorParams(params)
-    logger.error(
-      `${chargingStation.logPrefix()} ${moduleName}.handleIncomingRequestError: Incoming request command '${commandName}' error:`,
-      error
-    )
-    if (params.throwError === false && params.errorResponse != null) {
-      return params.errorResponse
-    }
-    if (params.throwError === true && params.errorResponse == null) {
-      throw error
-    }
-    if (params.throwError === true && params.errorResponse != null) {
-      return params.errorResponse
-    }
-  }
-
   protected validateIncomingRequestPayload<T extends JsonType>(
     chargingStation: ChargingStation,
     commandName: IncomingRequestCommand,
@@ -89,7 +66,7 @@ export abstract class OCPPIncomingRequestService extends EventEmitter {
       validate?.errors
     )
     throw new OCPPError(
-      OCPPServiceUtils.ajvErrorsToErrorType(validate?.errors),
+      ajvErrorsToErrorType(validate?.errors),
       'Incoming request PDU is invalid',
       commandName,
       JSON.stringify(validate?.errors, undefined, 2)
index 3a27a1923d7a0234efed3c223337e7e26ba2347f..48aca2ccafb2fe79b6adab93bd2894c372d790cf 100644 (file)
@@ -28,7 +28,11 @@ import {
 } from '../../utils/index.js'
 import { OCPPConstants } from './OCPPConstants.js'
 import type { OCPPResponseService } from './OCPPResponseService.js'
-import { OCPPServiceUtils } from './OCPPServiceUtils.js'
+import {
+  ajvErrorsToErrorType,
+  convertDateToISOString,
+  getMessageTypeString
+} from './OCPPServiceUtils.js'
 type Ajv = _Ajv.default
 // eslint-disable-next-line @typescript-eslint/no-redeclare
 const Ajv = _Ajv.default
@@ -94,9 +98,15 @@ export abstract class OCPPRequestService {
         commandName
       )
     } catch (error) {
-      handleSendMessageError(chargingStation, commandName, error as Error, {
-        throwError: true
-      })
+      handleSendMessageError(
+        chargingStation,
+        commandName,
+        MessageType.CALL_RESULT_MESSAGE,
+        error as Error,
+        {
+          throwError: true
+        }
+      )
       return null
     }
   }
@@ -117,7 +127,12 @@ export abstract class OCPPRequestService {
         commandName
       )
     } catch (error) {
-      handleSendMessageError(chargingStation, commandName, error as Error)
+      handleSendMessageError(
+        chargingStation,
+        commandName,
+        MessageType.CALL_ERROR_MESSAGE,
+        error as Error
+      )
       return null
     }
   }
@@ -143,9 +158,15 @@ export abstract class OCPPRequestService {
         params
       )
     } catch (error) {
-      handleSendMessageError(chargingStation, commandName, error as Error, {
-        throwError: params.throwError
-      })
+      handleSendMessageError(
+        chargingStation,
+        commandName,
+        MessageType.CALL_MESSAGE,
+        error as Error,
+        {
+          throwError: params.throwError
+        }
+      )
       return null
     }
   }
@@ -166,7 +187,7 @@ export abstract class OCPPRequestService {
     }
     const validate = this.payloadValidateFunctions.get(commandName as RequestCommand)
     payload = clone<T>(payload)
-    OCPPServiceUtils.convertDateToISOString<T>(payload)
+    convertDateToISOString<T>(payload)
     if (validate?.(payload) === true) {
       return true
     }
@@ -176,7 +197,7 @@ export abstract class OCPPRequestService {
     )
     // OCPPError usage here is debatable: it's an error in the OCPP stack but not targeted to sendError().
     throw new OCPPError(
-      OCPPServiceUtils.ajvErrorsToErrorType(validate?.errors),
+      ajvErrorsToErrorType(validate?.errors),
       'Request PDU is invalid',
       commandName,
       JSON.stringify(validate?.errors, undefined, 2)
@@ -205,7 +226,7 @@ export abstract class OCPPRequestService {
       commandName as IncomingRequestCommand
     )
     payload = clone<T>(payload)
-    OCPPServiceUtils.convertDateToISOString<T>(payload)
+    convertDateToISOString<T>(payload)
     if (validate?.(payload) === true) {
       return true
     }
@@ -215,7 +236,7 @@ export abstract class OCPPRequestService {
     )
     // OCPPError usage here is debatable: it's an error in the OCPP stack but not targeted to sendError().
     throw new OCPPError(
-      OCPPServiceUtils.ajvErrorsToErrorType(validate?.errors),
+      ajvErrorsToErrorType(validate?.errors),
       'Response PDU is invalid',
       commandName,
       JSON.stringify(validate?.errors, undefined, 2)
@@ -291,7 +312,7 @@ export abstract class OCPPRequestService {
             )
           }
           logger.error(
-            `${chargingStation.logPrefix()} Error occurred at ${OCPPServiceUtils.getMessageTypeString(
+            `${chargingStation.logPrefix()} Error occurred at ${getMessageTypeString(
               messageType
             )} command ${commandName} with PDU %j:`,
             messagePayload,
@@ -358,7 +379,7 @@ export abstract class OCPPRequestService {
             clearTimeout(sendTimeout)
             if (error == null) {
               logger.debug(
-                `${chargingStation.logPrefix()} >> Command '${commandName}' sent ${OCPPServiceUtils.getMessageTypeString(
+                `${chargingStation.logPrefix()} >> Command '${commandName}' sent ${getMessageTypeString(
                   messageType
                 )} payload: ${messageToSend}`
               )
@@ -383,7 +404,11 @@ export abstract class OCPPRequestService {
                     params.skipBufferingOnError === false ? '' : 'non '
                   }buffered message id '${messageId}' with content '${messageToSend}'`,
                   commandName,
-                  { name: error.name, message: error.message, stack: error.stack }
+                  {
+                    name: error.name,
+                    message: error.message,
+                    stack: error.stack
+                  }
                 )
               )
             }
index 0e9c6164d299a927dd8adf3f58a15d7247e6ced6..00d539b7c214b1f4ed973299d31836dbcf4b2ae3 100644 (file)
@@ -10,7 +10,7 @@ import type {
   RequestCommand
 } from '../../types/index.js'
 import { Constants, logger } from '../../utils/index.js'
-import { OCPPServiceUtils } from './OCPPServiceUtils.js'
+import { ajvErrorsToErrorType } from './OCPPServiceUtils.js'
 type Ajv = _Ajv.default
 // eslint-disable-next-line @typescript-eslint/no-redeclare
 const Ajv = _Ajv.default
@@ -69,7 +69,7 @@ export abstract class OCPPResponseService {
       validate?.errors
     )
     throw new OCPPError(
-      OCPPServiceUtils.ajvErrorsToErrorType(validate?.errors),
+      ajvErrorsToErrorType(validate?.errors),
       'Response PDU is invalid',
       commandName,
       JSON.stringify(validate?.errors, undefined, 2)
index 256544fa50090a5a88319f08fdcbe47c2c845f05..b077b03a6603610c8464c07170f5e6d07df77802 100644 (file)
@@ -264,6 +264,38 @@ const checkConnectorStatusTransition = (
   return transitionAllowed
 }
 
+export const ajvErrorsToErrorType = (errors: ErrorObject[] | undefined | null): ErrorType => {
+  if (isNotEmptyArray(errors)) {
+    for (const error of errors as DefinedError[]) {
+      switch (error.keyword) {
+        case 'type':
+          return ErrorType.TYPE_CONSTRAINT_VIOLATION
+        case 'dependencies':
+        case 'required':
+          return ErrorType.OCCURRENCE_CONSTRAINT_VIOLATION
+        case 'pattern':
+        case 'format':
+          return ErrorType.PROPERTY_CONSTRAINT_VIOLATION
+      }
+    }
+  }
+  return ErrorType.FORMAT_VIOLATION
+}
+
+export const convertDateToISOString = <T extends JsonType>(object: T): void => {
+  for (const key in object) {
+    // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion, @typescript-eslint/no-non-null-assertion
+    if (isDate(object![key])) {
+      // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion, @typescript-eslint/no-non-null-assertion
+      (object![key] as string) = (object![key] as Date).toISOString()
+      // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion, @typescript-eslint/no-non-null-assertion, @typescript-eslint/no-unnecessary-condition
+    } else if (typeof object![key] === 'object' && object![key] !== null) {
+      // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion, @typescript-eslint/no-non-null-assertion
+      convertDateToISOString<T>(object![key] as T)
+    }
+  }
+}
+
 export const buildMeterValue = (
   chargingStation: ChargingStation,
   connectorId: number,
@@ -273,6 +305,7 @@ export const buildMeterValue = (
 ): MeterValue => {
   const connector = chargingStation.getConnectorStatus(connectorId)
   let meterValue: MeterValue
+  let connectorMaximumAvailablePower: number | undefined
   let socSampledValueTemplate: SampledValueTemplate | undefined
   let voltageSampledValueTemplate: SampledValueTemplate | undefined
   let powerSampledValueTemplate: SampledValueTemplate | undefined
@@ -297,7 +330,7 @@ export const buildMeterValue = (
         const socMinimumValue = socSampledValueTemplate.minimumValue ?? 0
         const socSampledValueTemplateValue = isNotEmptyString(socSampledValueTemplate.value)
           ? getRandomFloatFluctuatedRounded(
-            parseInt(socSampledValueTemplate.value),
+            Number.parseInt(socSampledValueTemplate.value),
             socSampledValueTemplate.fluctuationPercent ?? Constants.DEFAULT_FLUCTUATION_PERCENT
           )
           : randomInt(socMinimumValue, socMaximumValue)
@@ -314,7 +347,9 @@ export const buildMeterValue = (
             `${chargingStation.logPrefix()} MeterValues measurand ${
               meterValue.sampledValue[sampledValuesIndex].measurand ??
               MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER
-            }: connector id ${connectorId}, transaction id ${connector?.transactionId}, value: ${socMinimumValue}/${
+            }: connector id ${connectorId}, transaction id ${
+              connector?.transactionId
+            }, value: ${socMinimumValue}/${
               meterValue.sampledValue[sampledValuesIndex].value
             }/${socMaximumValue}`
           )
@@ -328,7 +363,7 @@ export const buildMeterValue = (
       )
       if (voltageSampledValueTemplate != null) {
         const voltageSampledValueTemplateValue = isNotEmptyString(voltageSampledValueTemplate.value)
-          ? parseInt(voltageSampledValueTemplate.value)
+          ? Number.parseInt(voltageSampledValueTemplate.value)
           : // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
           chargingStation.stationInfo.voltageOut!
         const fluctuationPercent =
@@ -363,7 +398,7 @@ export const buildMeterValue = (
             const voltagePhaseLineToNeutralSampledValueTemplateValue = isNotEmptyString(
               voltagePhaseLineToNeutralSampledValueTemplate.value
             )
-              ? parseInt(voltagePhaseLineToNeutralSampledValueTemplate.value)
+              ? Number.parseInt(voltagePhaseLineToNeutralSampledValueTemplate.value)
               : // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
               chargingStation.stationInfo.voltageOut!
             const fluctuationPhaseToNeutralPercent =
@@ -405,7 +440,7 @@ export const buildMeterValue = (
               const voltagePhaseLineToLineSampledValueTemplateValue = isNotEmptyString(
                 voltagePhaseLineToLineSampledValueTemplate.value
               )
-                ? parseInt(voltagePhaseLineToLineSampledValueTemplate.value)
+                ? Number.parseInt(voltagePhaseLineToLineSampledValueTemplate.value)
                 : voltagePhaseLineToLineValueRounded
               const fluctuationPhaseLineToLinePercent =
                 voltagePhaseLineToLineSampledValueTemplate.fluctuationPercent ??
@@ -470,7 +505,7 @@ export const buildMeterValue = (
         // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
         const powerMeasurandValues: MeasurandValues = {} as MeasurandValues
         const unitDivider = powerSampledValueTemplate.unit === MeterValueUnit.KILO_WATT ? 1000 : 1
-        const connectorMaximumAvailablePower =
+        connectorMaximumAvailablePower =
           chargingStation.getConnectorMaximumAvailablePower(connectorId)
         const connectorMaximumPower = Math.round(connectorMaximumAvailablePower)
         const connectorMaximumPowerPerPhase = Math.round(
@@ -646,7 +681,9 @@ export const buildMeterValue = (
             `${chargingStation.logPrefix()} MeterValues measurand ${
               meterValue.sampledValue[sampledValuesIndex].measurand ??
               MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER
-            }: connector id ${connectorId}, transaction id ${connector?.transactionId}, value: ${connectorMinimumPowerRounded}/${
+            }: connector id ${connectorId}, transaction id ${
+              connector?.transactionId
+            }, value: ${connectorMinimumPowerRounded}/${
               meterValue.sampledValue[sampledValuesIndex].value
             }/${connectorMaximumPowerRounded}`
           )
@@ -689,7 +726,9 @@ export const buildMeterValue = (
                 MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER
               }: phase ${
                 meterValue.sampledValue[sampledValuesPerPhaseIndex].phase
-              }, connector id ${connectorId}, transaction id ${connector?.transactionId}, value: ${connectorMinimumPowerPerPhaseRounded}/${
+              }, connector id ${connectorId}, transaction id ${
+                connector?.transactionId
+              }, value: ${connectorMinimumPowerPerPhaseRounded}/${
                 meterValue.sampledValue[sampledValuesPerPhaseIndex].value
               }/${connectorMaximumPowerPerPhaseRounded}`
             )
@@ -736,8 +775,9 @@ export const buildMeterValue = (
         } measurand value`
         // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
         const currentMeasurandValues: MeasurandValues = {} as MeasurandValues
-        const connectorMaximumAvailablePower =
-          chargingStation.getConnectorMaximumAvailablePower(connectorId)
+        connectorMaximumAvailablePower == null &&
+          (connectorMaximumAvailablePower =
+            chargingStation.getConnectorMaximumAvailablePower(connectorId))
         const connectorMinimumAmperage = currentSampledValueTemplate.minimumValue ?? 0
         let connectorMaximumAmperage: number
         switch (chargingStation.stationInfo.currentOutType) {
@@ -901,7 +941,9 @@ export const buildMeterValue = (
             `${chargingStation.logPrefix()} MeterValues measurand ${
               meterValue.sampledValue[sampledValuesIndex].measurand ??
               MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER
-            }: connector id ${connectorId}, transaction id ${connector?.transactionId}, value: ${connectorMinimumAmperage}/${
+            }: connector id ${connectorId}, transaction id ${
+              connector?.transactionId
+            }, value: ${connectorMinimumAmperage}/${
               meterValue.sampledValue[sampledValuesIndex].value
             }/${connectorMaximumAmperage}`
           )
@@ -936,7 +978,9 @@ export const buildMeterValue = (
                 MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER
               }: phase ${
                 meterValue.sampledValue[sampledValuesPerPhaseIndex].phase
-              }, connector id ${connectorId}, transaction id ${connector?.transactionId}, value: ${connectorMinimumAmperage}/${
+              }, connector id ${connectorId}, transaction id ${
+                connector?.transactionId
+              }, value: ${connectorMinimumAmperage}/${
                 meterValue.sampledValue[sampledValuesPerPhaseIndex].value
               }/${connectorMaximumAmperage}`
             )
@@ -949,8 +993,9 @@ export const buildMeterValue = (
         checkMeasurandPowerDivider(chargingStation, energySampledValueTemplate.measurand)
         const unitDivider =
           energySampledValueTemplate.unit === MeterValueUnit.KILO_WATT_HOUR ? 1000 : 1
-        const connectorMaximumAvailablePower =
-          chargingStation.getConnectorMaximumAvailablePower(connectorId)
+        connectorMaximumAvailablePower == null &&
+          (connectorMaximumAvailablePower =
+            chargingStation.getConnectorMaximumAvailablePower(connectorId))
         const connectorMaximumEnergyRounded = roundTo(
           (connectorMaximumAvailablePower * interval) / (3600 * 1000),
           2
@@ -1009,7 +1054,9 @@ export const buildMeterValue = (
             `${chargingStation.logPrefix()} MeterValues measurand ${
               meterValue.sampledValue[sampledValuesIndex].measurand ??
               MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER
-            }: connector id ${connectorId}, transaction id ${connector?.transactionId}, value: ${connectorMinimumEnergyRounded}/${energyValueRounded}/${connectorMaximumEnergyRounded}, duration: ${interval}ms`
+            }: connector id ${connectorId}, transaction id ${
+              connector?.transactionId
+            }, value: ${connectorMinimumEnergyRounded}/${energyValueRounded}/${connectorMaximumEnergyRounded}, duration: ${interval}ms`
           )
         }
       }
@@ -1081,7 +1128,11 @@ const getLimitFromSampledValueTemplateCustomValue = (
   value: string | undefined,
   maxLimit: number,
   minLimit: number,
-  options?: { limitationEnabled?: boolean, fallbackValue?: number, unitMultiplier?: number }
+  options?: {
+    limitationEnabled?: boolean
+    fallbackValue?: number
+    unitMultiplier?: number
+  }
 ): number => {
   options = {
     ...{
@@ -1091,11 +1142,14 @@ const getLimitFromSampledValueTemplateCustomValue = (
     },
     ...options
   }
-  const parsedValue = parseInt(value ?? '')
+  const parsedValue = Number.parseInt(value ?? '')
   if (options.limitationEnabled === true) {
     return max(
-      // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-      min((!isNaN(parsedValue) ? parsedValue : Infinity) * options.unitMultiplier!, maxLimit),
+      min(
+        // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
+        (!isNaN(parsedValue) ? parsedValue : Number.POSITIVE_INFINITY) * options.unitMultiplier!,
+        maxLimit
+      ),
       minLimit
     )
   }
@@ -1242,7 +1296,6 @@ const getMeasurandDefaultLocation = (
 
 // eslint-disable-next-line @typescript-eslint/no-extraneous-class
 export class OCPPServiceUtils {
-  public static readonly getMessageTypeString = getMessageTypeString
   public static readonly sendAndSetConnectorStatus = sendAndSetConnectorStatus
   public static readonly restoreConnectorStatus = restoreConnectorStatus
   public static readonly isIdTagAuthorized = isIdTagAuthorized
@@ -1254,24 +1307,6 @@ export class OCPPServiceUtils {
     // This is intentional
   }
 
-  public static ajvErrorsToErrorType (errors: ErrorObject[] | undefined | null): ErrorType {
-    if (isNotEmptyArray(errors)) {
-      for (const error of errors as DefinedError[]) {
-        switch (error.keyword) {
-          case 'type':
-            return ErrorType.TYPE_CONSTRAINT_VIOLATION
-          case 'dependencies':
-          case 'required':
-            return ErrorType.OCCURRENCE_CONSTRAINT_VIOLATION
-          case 'pattern':
-          case 'format':
-            return ErrorType.PROPERTY_CONSTRAINT_VIOLATION
-        }
-      }
-    }
-    return ErrorType.FORMAT_VIOLATION
-  }
-
   public static isRequestCommandSupported (
     chargingStation: ChargingStation,
     command: RequestCommand
@@ -1346,28 +1381,6 @@ export class OCPPServiceUtils {
     return true
   }
 
-  public static convertDateToISOString<T extends JsonType>(object: T): void {
-    for (const key in object) {
-      // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion, @typescript-eslint/no-non-null-assertion
-      if (isDate(object![key])) {
-        // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion, @typescript-eslint/no-non-null-assertion
-        (object![key] as string) = (object![key] as Date).toISOString()
-        // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion, @typescript-eslint/no-non-null-assertion, @typescript-eslint/no-unnecessary-condition
-      } else if (typeof object![key] === 'object' && object![key] !== null) {
-        // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion, @typescript-eslint/no-non-null-assertion
-        OCPPServiceUtils.convertDateToISOString<T>(object![key] as T)
-      }
-    }
-  }
-
-  public static startHeartbeatInterval (chargingStation: ChargingStation, interval: number): void {
-    if (chargingStation.heartbeatSetInterval == null) {
-      chargingStation.startHeartbeat()
-    } else if (chargingStation.getHeartbeatInterval() !== interval) {
-      chargingStation.restartHeartbeat()
-    }
-  }
-
   protected static parseJsonSchemaFile<T extends JsonType>(
     relativePath: string,
     ocppVersion: OCPPVersion,
index 9d2705f28f677f37ffcc869c60587ade090745f5..a786fbbddc2ed43623316f297a7f5ac94503d474 100644 (file)
@@ -166,7 +166,9 @@ export abstract class AbstractUIServer {
     const authorizationProtocol = req.headers['sec-websocket-protocol']?.split(/,\s+/).pop()
     const [username, password] = getUsernameAndPasswordFromAuthorizationToken(
       // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-      `${authorizationProtocol}${Array(((4 - (authorizationProtocol!.length % 4)) % 4) + 1).join('=')}`
+      `${authorizationProtocol}${Array(((4 - (authorizationProtocol!.length % 4)) % 4) + 1).join(
+        '='
+      )}`
         .split('.')
         .pop() ?? '',
       next
index 34138e02b0204636b79d5ab884fe9f6328514d8f..cf176bdc0403d2be85890204ba7b67e06f9b6c4a 100644 (file)
@@ -68,8 +68,10 @@ export class UIServerFactory {
             uiServerConfiguration.type as ApplicationProtocol
           )
         ) {
-          // eslint-disable-next-line @typescript-eslint/no-base-to-string
-          const logMsg = `Unknown application protocol type '${uiServerConfiguration.type}' in '${ConfigurationSection.uiServer}' configuration section from values '${ApplicationProtocol.toString()}', defaulting to '${
+          const logMsg = `Unknown application protocol type '${uiServerConfiguration.type}' in '${
+            ConfigurationSection.uiServer
+            // eslint-disable-next-line @typescript-eslint/no-base-to-string
+          }' configuration section from values '${ApplicationProtocol.toString()}', defaulting to '${
             ApplicationProtocol.WS
           }'`
           logger.warn(`${UIServerFactory.logPrefix()} ${logMsg}`)
index 265cb6c963918b1a3970a95e5822742f3202c0d4..864446c6ce30ee1bad805c65a61eec9b46755e2d 100644 (file)
@@ -5,6 +5,7 @@ import type { URL } from 'node:url'
 import { parentPort } from 'node:worker_threads'
 
 import { secondsToMilliseconds } from 'date-fns'
+import { CircularBuffer } from 'mnemonist'
 import { is, mean, median } from 'rambda'
 
 import { BaseError } from '../exception/index.js'
@@ -22,7 +23,6 @@ import {
 } from '../types/index.js'
 import {
   buildPerformanceStatisticsMessage,
-  CircularArray,
   Configuration,
   Constants,
   extractTimeSeriesValues,
@@ -179,9 +179,9 @@ export class PerformanceStatistics {
       )
     if (performanceStorageConfiguration.enabled === true) {
       logger.info(
-        `${this.logPrefix()} storage enabled: type ${performanceStorageConfiguration.type}, uri: ${
-          performanceStorageConfiguration.uri
-        }`
+        `${this.logPrefix()} storage enabled: type ${
+          performanceStorageConfiguration.type
+        }, uri: ${performanceStorageConfiguration.uri}`
       )
     }
   }
@@ -267,29 +267,37 @@ export class PerformanceStatistics {
     // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
     this.statistics.statisticsData.get(entry.name)!.minTimeMeasurement = min(
       entry.duration,
-      this.statistics.statisticsData.get(entry.name)?.minTimeMeasurement ?? Infinity
+      this.statistics.statisticsData.get(entry.name)?.minTimeMeasurement ?? Number.POSITIVE_INFINITY
     )
     // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
     this.statistics.statisticsData.get(entry.name)!.maxTimeMeasurement = max(
       entry.duration,
-      this.statistics.statisticsData.get(entry.name)?.maxTimeMeasurement ?? -Infinity
+      this.statistics.statisticsData.get(entry.name)?.maxTimeMeasurement ?? Number.NEGATIVE_INFINITY
     )
     // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
     this.statistics.statisticsData.get(entry.name)!.totalTimeMeasurement =
       (this.statistics.statisticsData.get(entry.name)?.totalTimeMeasurement ?? 0) + entry.duration
-    this.statistics.statisticsData.get(entry.name)?.measurementTimeSeries instanceof CircularArray
-      ? this.statistics.statisticsData
-        .get(entry.name)
-        ?.measurementTimeSeries?.push({ timestamp: entry.startTime, value: entry.duration })
-      : // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-        (this.statistics.statisticsData.get(entry.name)!.measurementTimeSeries =
-          new CircularArray<TimestampedData>(Constants.DEFAULT_CIRCULAR_BUFFER_CAPACITY, {
-            timestamp: entry.startTime,
-            value: entry.duration
-          }))
+    if (
+      !(
+        this.statistics.statisticsData.get(entry.name)?.measurementTimeSeries instanceof
+        CircularBuffer
+      )
+    ) {
+      // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
+      this.statistics.statisticsData.get(entry.name)!.measurementTimeSeries =
+        new CircularBuffer<TimestampedData>(
+          Array<TimestampedData>,
+          Constants.DEFAULT_CIRCULAR_BUFFER_CAPACITY
+        )
+    }
+    this.statistics.statisticsData.get(entry.name)?.measurementTimeSeries?.push({
+      timestamp: entry.startTime,
+      value: entry.duration
+    })
     const timeMeasurementValues = extractTimeSeriesValues(
       // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-      this.statistics.statisticsData.get(entry.name)!.measurementTimeSeries!
+      this.statistics.statisticsData.get(entry.name)!
+        .measurementTimeSeries as CircularBuffer<TimestampedData>
     )
     // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
     this.statistics.statisticsData.get(entry.name)!.avgTimeMeasurement = mean(timeMeasurementValues)
index 7b4545bdff36ba824597c22549889641c6f60538..7269ce76dae82587822e38cfafd485e3aca03e64 100644 (file)
@@ -28,7 +28,11 @@ export class MikroOrmStorage extends Storage {
         }))
       } satisfies PerformanceRecord)
     } catch (error) {
-      this.handleDBError(this.storageType, error as Error, Constants.PERFORMANCE_RECORDS_TABLE)
+      this.handleDBStorageError(
+        this.storageType,
+        error as Error,
+        Constants.PERFORMANCE_RECORDS_TABLE
+      )
     }
   }
 
@@ -46,7 +50,7 @@ export class MikroOrmStorage extends Storage {
         }
       }
     } catch (error) {
-      this.handleDBError(this.storageType, error as Error)
+      this.handleDBStorageError(this.storageType, error as Error)
     }
   }
 
@@ -58,7 +62,7 @@ export class MikroOrmStorage extends Storage {
         delete this.orm
       }
     } catch (error) {
-      this.handleDBError(this.storageType, error as Error)
+      this.handleDBStorageError(this.storageType, error as Error)
     }
   }
 
index c3c98022d4204c63aa6d940f7cac887d2424ed58..982e55bf682800ba02da10dc717bf6dea08fa736 100644 (file)
@@ -25,9 +25,15 @@ export class MongoDBStorage extends Storage {
       await this.client
         ?.db(this.dbName)
         .collection<Statistics>(Constants.PERFORMANCE_RECORDS_TABLE)
-        .replaceOne({ id: performanceStatistics.id }, performanceStatistics, { upsert: true })
+        .replaceOne({ id: performanceStatistics.id }, performanceStatistics, {
+          upsert: true
+        })
     } catch (error) {
-      this.handleDBError(StorageType.MONGO_DB, error as Error, Constants.PERFORMANCE_RECORDS_TABLE)
+      this.handleDBStorageError(
+        StorageType.MONGO_DB,
+        error as Error,
+        Constants.PERFORMANCE_RECORDS_TABLE
+      )
     }
   }
 
@@ -38,7 +44,7 @@ export class MongoDBStorage extends Storage {
         this.connected = true
       }
     } catch (error) {
-      this.handleDBError(StorageType.MONGO_DB, error as Error)
+      this.handleDBStorageError(StorageType.MONGO_DB, error as Error)
     }
   }
 
@@ -50,7 +56,7 @@ export class MongoDBStorage extends Storage {
         this.connected = false
       }
     } catch (error) {
-      this.handleDBError(StorageType.MONGO_DB, error as Error)
+      this.handleDBStorageError(StorageType.MONGO_DB, error as Error)
     }
   }
 
index aee3ae9efbb5ca86b17a8a7ddf3fcd01b7b80684..ccdbb3f835411c27521e1c17df33002d7cfd259a 100644 (file)
@@ -22,13 +22,16 @@ export abstract class Storage {
     this.logPrefix = logPrefix
   }
 
-  protected handleDBError (
+  protected handleDBStorageError (
     type: StorageType,
     error: Error,
     table?: string,
-    params: HandleErrorParams<EmptyObject> = { throwError: false, consoleOut: false }
+    params: HandleErrorParams<EmptyObject> = {
+      throwError: false,
+      consoleOut: false
+    }
   ): void {
-    setDefaultErrorParams(params, { throwError: false, consoleOut: false })
+    params = setDefaultErrorParams(params, { throwError: false, consoleOut: false })
     const inTableOrCollectionStr = table != null && ` in table or collection '${table}'`
     logger.error(
       `${this.logPrefix} ${this.getDBNameFromStorageType(type)} error '${
index 19fd71855cdd5ed9451573e72e93deab177c9c46..345381425e7422f428b4a8fed775b2344ad057b4 100755 (executable)
@@ -14,7 +14,7 @@ const config = JSON.parse(fs.readFileSync('scriptConfig.json', 'utf8'))
 // Mongo Connection and Query
 if (config?.mongoConnectionString) {
   // eslint-disable-next-line n/handle-callback-err
-  MongoClient.connect(config.mongoConnectionString, async function (_err, client) {
+  MongoClient.connect(config.mongoConnectionString, async (_err, client) => {
     const db = client.db()
 
     for await (const tenantID of config.tenantIDs) {
index d41dc1665bb1c4c7f783b35a1fb05f5e0902d269..09e5873b62319fec802d382d21ea54b907c6701f 100755 (executable)
@@ -15,7 +15,7 @@ const config = JSON.parse(fs.readFileSync('scriptConfig.json', 'utf8'))
 // Mongo Connection and Query
 if (config?.mongoConnectionString) {
   // eslint-disable-next-line n/handle-callback-err
-  MongoClient.connect(config.mongoConnectionString, async function (_err, client) {
+  MongoClient.connect(config.mongoConnectionString, async (_err, client) => {
     const db = client.db()
 
     for await (const tenantID of config.tenantIDs) {
index b690bc916f2dca73d604349dc508f11177ff0643..3fa6adeccf6310ebebac3dbb679133dfe9f10aa3 100644 (file)
@@ -7,6 +7,7 @@ export enum ChargingStationEvents {
   registered = 'registered',
   accepted = 'accepted',
   rejected = 'rejected',
+  connected = 'connected',
   disconnected = 'disconnected',
   connectorStatusChanged = 'connectorStatusChanged'
 }
index 4c03dd9d73c62c06f35d432bbc18cf9be62ec082..9601a90cb70e2ace501599190aba61f1d834c14a 100644 (file)
@@ -1,4 +1,5 @@
-import type { CircularArray } from '../utils/index.js'
+import type { CircularBuffer } from 'mnemonist'
+
 import type { WorkerData } from '../worker/index.js'
 import type { IncomingRequestCommand, RequestCommand } from './ocpp/Requests.js'
 
@@ -12,7 +13,7 @@ export type StatisticsData = Partial<{
   responseCount: number
   errorCount: number
   timeMeasurementCount: number
-  measurementTimeSeries: CircularArray<TimestampedData>
+  measurementTimeSeries: CircularBuffer<TimestampedData> | TimestampedData[]
   currentTimeMeasurement: number
   minTimeMeasurement: number
   maxTimeMeasurement: number
index 868dd73df07ea4fa37b95a333357c8bf4436a381..6fa70636b9d3e9b153d90c8f5dd20a4b36d75018 100644 (file)
@@ -162,6 +162,7 @@ export { ChargePointErrorCode } from './ocpp/ChargePointErrorCode.js'
 export {
   type ChargingProfile,
   ChargingProfileKindType,
+  ChargingProfilePurposeType,
   ChargingRateUnitType,
   type ChargingSchedulePeriod,
   RecurrencyKindType
index c57be2032751277115f298947575d7877457d4cd..e186679f5004938c7662615dfa4fde8d29133300 100644 (file)
@@ -77,7 +77,7 @@ export interface ChangeConfigurationRequest extends JsonObject {
 }
 
 export interface RemoteStartTransactionRequest extends JsonObject {
-  connectorId: number
+  connectorId?: number
   idTag: string
   chargingProfile?: OCPP16ChargingProfile
 }
index efc25b90083ad54a28aa977ee587e63851d643f0..8fc773b73a5352642006bd249a4f6fc42e44e09e 100644 (file)
@@ -1,6 +1,7 @@
 import {
   type OCPP16ChargingProfile,
   OCPP16ChargingProfileKindType,
+  OCPP16ChargingProfilePurposeType,
   OCPP16ChargingRateUnitType,
   type OCPP16ChargingSchedulePeriod,
   OCPP16RecurrencyKindType
@@ -10,6 +11,12 @@ export type ChargingProfile = OCPP16ChargingProfile
 
 export type ChargingSchedulePeriod = OCPP16ChargingSchedulePeriod
 
+export const ChargingProfilePurposeType = {
+  ...OCPP16ChargingProfilePurposeType
+} as const
+// eslint-disable-next-line @typescript-eslint/no-redeclare
+export type ChargingProfilePurposeType = OCPP16ChargingProfilePurposeType
+
 export const ChargingProfileKindType = {
   ...OCPP16ChargingProfileKindType
 } as const
index 7b5346d52392deb1996673bc7210e1a3bf300708..c5330a0d95ecd700b997d618261ab70909967e71 100644 (file)
@@ -25,7 +25,7 @@ export const buildConnectorsStatus = (chargingStation: ChargingStation): Connect
   )
 }
 
-export const enum OutputFormat {
+export enum OutputFormat {
   configuration = 'configuration',
   worker = 'worker'
 }
diff --git a/src/utils/CircularArray.ts b/src/utils/CircularArray.ts
deleted file mode 100644 (file)
index f84b21a..0000000
+++ /dev/null
@@ -1,96 +0,0 @@
-// Copyright Jerome Benoit. 2021-2024. All Rights Reserved.
-
-export const DEFAULT_CIRCULAR_ARRAY_SIZE = 1024
-
-/**
- * Array with a maximum length and shifting items when full.
- */
-export class CircularArray<T> extends Array<T> {
-  public size: number
-
-  constructor (size: number = DEFAULT_CIRCULAR_ARRAY_SIZE, ...items: T[]) {
-    super()
-    this.checkSize(size)
-    this.size = size
-    if (arguments.length > 1) {
-      this.push(...items)
-    }
-  }
-
-  public push (...items: T[]): number {
-    const length = super.push(...items)
-    if (length > this.size) {
-      super.splice(0, length - this.size)
-    }
-    return this.length
-  }
-
-  public unshift (...items: T[]): number {
-    const length = super.unshift(...items)
-    if (length > this.size) {
-      super.splice(this.size, items.length)
-    }
-    return this.length
-  }
-
-  public concat (...items: Array<T | ConcatArray<T>>): CircularArray<T> {
-    const concatenatedCircularArray = super.concat(items as T[]) as CircularArray<T>
-    concatenatedCircularArray.size = this.size
-    if (concatenatedCircularArray.length > concatenatedCircularArray.size) {
-      concatenatedCircularArray.splice(
-        0,
-        concatenatedCircularArray.length - concatenatedCircularArray.size
-      )
-    }
-    return concatenatedCircularArray
-  }
-
-  public splice (start: number, deleteCount?: number, ...items: T[]): CircularArray<T> {
-    let itemsRemoved: T[] = []
-    if (arguments.length >= 3 && deleteCount != null) {
-      itemsRemoved = super.splice(start, deleteCount, ...items)
-      if (this.length > this.size) {
-        const itemsOverflowing = super.splice(0, this.length - this.size)
-        itemsRemoved = new CircularArray<T>(
-          itemsRemoved.length + itemsOverflowing.length,
-          ...itemsRemoved,
-          ...itemsOverflowing
-        )
-      }
-    } else if (arguments.length === 2) {
-      itemsRemoved = super.splice(start, deleteCount)
-    } else {
-      itemsRemoved = super.splice(start)
-    }
-    return itemsRemoved as CircularArray<T>
-  }
-
-  public resize (size: number): void {
-    this.checkSize(size)
-    if (size === 0) {
-      this.length = 0
-    } else if (size < this.size) {
-      for (let i = size; i < this.size; i++) {
-        super.pop()
-      }
-    }
-    this.size = size
-  }
-
-  public empty (): boolean {
-    return this.length === 0
-  }
-
-  public full (): boolean {
-    return this.length === this.size
-  }
-
-  private checkSize (size: number): void {
-    if (!Number.isSafeInteger(size)) {
-      throw new TypeError(`Invalid circular array size: ${size} is not a safe integer`)
-    }
-    if (size < 0) {
-      throw new RangeError(`Invalid circular array size: ${size} < 0`)
-    }
-  }
-}
index 25a1475bc2a5f6ec9a6ea40df049048db9538ad8..06f543a58f017bcb3dec3cf10a4683fad3f79180 100644 (file)
@@ -1,4 +1,4 @@
-import { type FSWatcher, readFileSync, watch } from 'node:fs'
+import { existsSync, type FSWatcher, readFileSync, watch } from 'node:fs'
 import { dirname, join } from 'node:path'
 import { env } from 'node:process'
 import { fileURLToPath } from 'node:url'
@@ -44,28 +44,85 @@ type ConfigurationSectionType =
   | WorkerConfiguration
   | UIServerConfiguration
 
+const defaultUIServerConfiguration: UIServerConfiguration = {
+  enabled: false,
+  type: ApplicationProtocol.WS,
+  version: ApplicationProtocolVersion.VERSION_11,
+  options: {
+    host: Constants.DEFAULT_UI_SERVER_HOST,
+    port: Constants.DEFAULT_UI_SERVER_PORT
+  }
+}
+
+const defaultStorageConfiguration: StorageConfiguration = {
+  enabled: true,
+  type: StorageType.NONE
+}
+
+const defaultLogConfiguration: LogConfiguration = {
+  enabled: true,
+  file: 'logs/combined.log',
+  errorFile: 'logs/error.log',
+  statisticsInterval: Constants.DEFAULT_LOG_STATISTICS_INTERVAL,
+  level: 'info',
+  format: 'simple',
+  rotate: true
+}
+
+const defaultWorkerConfiguration: WorkerConfiguration = {
+  processType: WorkerProcessType.workerSet,
+  startDelay: DEFAULT_WORKER_START_DELAY,
+  elementsPerWorker: 'auto',
+  elementAddDelay: DEFAULT_ELEMENT_ADD_DELAY,
+  poolMinSize: DEFAULT_POOL_MIN_SIZE,
+  poolMaxSize: DEFAULT_POOL_MAX_SIZE
+}
+
 // eslint-disable-next-line @typescript-eslint/no-extraneous-class
 export class Configuration {
   public static configurationChangeCallback?: () => Promise<void>
 
-  private static readonly configurationFile = join(
-    dirname(fileURLToPath(import.meta.url)),
-    'assets',
-    'config.json'
-  )
-
+  private static configurationFile: string | undefined
   private static configurationFileReloading = false
   private static configurationData?: ConfigurationData
   private static configurationFileWatcher?: FSWatcher
-  private static readonly configurationSectionCache = new Map<
-  ConfigurationSection,
-  ConfigurationSectionType
-  >([
-    [ConfigurationSection.log, Configuration.buildLogSection()],
-    [ConfigurationSection.performanceStorage, Configuration.buildPerformanceStorageSection()],
-    [ConfigurationSection.worker, Configuration.buildWorkerSection()],
-    [ConfigurationSection.uiServer, Configuration.buildUIServerSection()]
-  ])
+  private static configurationSectionCache: Map<ConfigurationSection, ConfigurationSectionType>
+
+  static {
+    const configurationFile = join(dirname(fileURLToPath(import.meta.url)), 'assets', 'config.json')
+    if (existsSync(configurationFile)) {
+      Configuration.configurationFile = configurationFile
+    } else {
+      console.error(
+        `${chalk.green(logPrefix())} ${chalk.red(
+          "Configuration file './src/assets/config.json' not found, using default configuration"
+        )}`
+      )
+      Configuration.configurationData = {
+        stationTemplateUrls: [
+          {
+            file: 'siemens.station-template.json',
+            numberOfStations: 1
+          }
+        ],
+        supervisionUrls: 'ws://localhost:8180/steve/websocket/CentralSystemService',
+        supervisionUrlDistribution: SupervisionUrlDistribution.ROUND_ROBIN,
+        uiServer: defaultUIServerConfiguration,
+        performanceStorage: defaultStorageConfiguration,
+        log: defaultLogConfiguration,
+        worker: defaultWorkerConfiguration
+      }
+    }
+    Configuration.configurationSectionCache = new Map<
+    ConfigurationSection,
+    ConfigurationSectionType
+    >([
+      [ConfigurationSection.log, Configuration.buildLogSection()],
+      [ConfigurationSection.performanceStorage, Configuration.buildPerformanceStorageSection()],
+      [ConfigurationSection.worker, Configuration.buildWorkerSection()],
+      [ConfigurationSection.uiServer, Configuration.buildUIServerSection()]
+    ])
+  }
 
   private constructor () {
     // This is intentional
@@ -152,15 +209,7 @@ export class Configuration {
   }
 
   private static buildUIServerSection (): UIServerConfiguration {
-    let uiServerConfiguration: UIServerConfiguration = {
-      enabled: false,
-      type: ApplicationProtocol.WS,
-      version: ApplicationProtocolVersion.VERSION_11,
-      options: {
-        host: Constants.DEFAULT_UI_SERVER_HOST,
-        port: Constants.DEFAULT_UI_SERVER_PORT
-      }
-    }
+    let uiServerConfiguration: UIServerConfiguration = defaultUIServerConfiguration
     if (hasOwnProp(Configuration.getConfigurationData(), ConfigurationSection.uiServer)) {
       uiServerConfiguration = mergeDeepRight(
         uiServerConfiguration,
@@ -171,7 +220,7 @@ export class Configuration {
     if (isCFEnvironment()) {
       delete uiServerConfiguration.options?.host
       // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-      uiServerConfiguration.options!.port = parseInt(env.PORT!)
+      uiServerConfiguration.options!.port = Number.parseInt(env.PORT!)
     }
     return uiServerConfiguration
   }
@@ -195,10 +244,7 @@ export class Configuration {
         break
       case StorageType.NONE:
       default:
-        storageConfiguration = {
-          enabled: true,
-          type: StorageType.NONE
-        }
+        storageConfiguration = defaultStorageConfiguration
         break
     }
     if (hasOwnProp(Configuration.getConfigurationData(), ConfigurationSection.performanceStorage)) {
@@ -220,15 +266,6 @@ export class Configuration {
   }
 
   private static buildLogSection (): LogConfiguration {
-    const defaultLogConfiguration: LogConfiguration = {
-      enabled: true,
-      file: 'logs/combined.log',
-      errorFile: 'logs/error.log',
-      statisticsInterval: Constants.DEFAULT_LOG_STATISTICS_INTERVAL,
-      level: 'info',
-      format: 'simple',
-      rotate: true
-    }
     const deprecatedLogConfiguration: LogConfiguration = {
       ...(hasOwnProp(Configuration.getConfigurationData(), 'logEnabled') && {
         enabled: Configuration.getConfigurationData()?.logEnabled
@@ -271,15 +308,6 @@ export class Configuration {
   }
 
   private static buildWorkerSection (): WorkerConfiguration {
-    const defaultWorkerConfiguration: WorkerConfiguration = {
-      processType: WorkerProcessType.workerSet,
-      startDelay: DEFAULT_WORKER_START_DELAY,
-      elementsPerWorker: 'auto',
-      elementAddDelay: DEFAULT_ELEMENT_ADD_DELAY,
-      poolMinSize: DEFAULT_POOL_MIN_SIZE,
-      poolMaxSize: DEFAULT_POOL_MAX_SIZE
-    }
-
     const deprecatedWorkerConfiguration: WorkerConfiguration = {
       ...(hasOwnProp(Configuration.getConfigurationData(), 'workerProcess') && {
         processType: Configuration.getConfigurationData()?.workerProcess
@@ -545,7 +573,11 @@ export class Configuration {
   }
 
   public static getConfigurationData (): ConfigurationData | undefined {
-    if (Configuration.configurationData == null) {
+    if (
+      Configuration.configurationData == null &&
+      Configuration.configurationFile != null &&
+      Configuration.configurationFile.length > 0
+    ) {
       try {
         Configuration.configurationData = JSON.parse(
           readFileSync(Configuration.configurationFile, 'utf8')
@@ -566,6 +598,9 @@ export class Configuration {
   }
 
   private static getConfigurationFileWatcher (): FSWatcher | undefined {
+    if (Configuration.configurationFile == null || Configuration.configurationFile.length === 0) {
+      return
+    }
     try {
       return watch(Configuration.configurationFile, (event, filename): void => {
         if (
index 3746c4fdd91e8277ebc5167c563cbd3cf88fb673..2d66659889e3a5418d083b9b60b7cdeb8960a18c 100644 (file)
@@ -67,7 +67,7 @@ export class Constants {
       stopAbsoluteDuration: false
     })
 
-  static readonly DEFAULT_CIRCULAR_BUFFER_CAPACITY = 4096
+  static readonly DEFAULT_CIRCULAR_BUFFER_CAPACITY = 386
 
   static readonly DEFAULT_HASH_ALGORITHM = 'sha384'
 
index 9c243a299e769f67c4e70859aae110651a3444cd..0a444c6b1f5d945e5577dd7fbebc6ec235df16e6 100644 (file)
@@ -3,17 +3,21 @@ import process from 'node:process'
 import chalk from 'chalk'
 
 import type { ChargingStation } from '../charging-station/index.js'
+import { getMessageTypeString } from '../charging-station/ocpp/OCPPServiceUtils.js'
 import type {
   EmptyObject,
   FileType,
   HandleErrorParams,
   IncomingRequestCommand,
   JsonType,
+  MessageType,
   RequestCommand
 } from '../types/index.js'
 import { logger } from './Logger.js'
 import { isNotEmptyString } from './Utils.js'
 
+const moduleName = 'ErrorUtils'
+
 const defaultErrorParams = {
   throwError: true,
   consoleOut: false
@@ -38,7 +42,7 @@ export const handleFileException = (
   logPrefix: string,
   params: HandleErrorParams<EmptyObject> = defaultErrorParams
 ): void => {
-  setDefaultErrorParams(params)
+  params = setDefaultErrorParams(params)
   const prefix = isNotEmptyString(logPrefix) ? `${logPrefix} ` : ''
   let logMsg: string
   switch (error.code) {
@@ -79,20 +83,48 @@ export const handleFileException = (
 export const handleSendMessageError = (
   chargingStation: ChargingStation,
   commandName: RequestCommand | IncomingRequestCommand,
+  messageType: MessageType,
   error: Error,
-  params: HandleErrorParams<EmptyObject> = { throwError: false, consoleOut: false }
+  params: HandleErrorParams<EmptyObject> = {
+    throwError: false,
+    consoleOut: false
+  }
 ): void => {
-  setDefaultErrorParams(params, { throwError: false, consoleOut: false })
-  logger.error(`${chargingStation.logPrefix()} Request command '${commandName}' error:`, error)
+  params = setDefaultErrorParams(params, { throwError: false, consoleOut: false })
+  logger.error(
+    `${chargingStation.logPrefix()} ${moduleName}.handleSendMessageError: Send ${getMessageTypeString(messageType)} command '${commandName}' error:`,
+    error
+  )
   if (params.throwError === true) {
     throw error
   }
 }
 
+export const handleIncomingRequestError = <T extends JsonType>(
+  chargingStation: ChargingStation,
+  commandName: IncomingRequestCommand,
+  error: Error,
+  params: HandleErrorParams<T> = { throwError: true, consoleOut: false }
+): T | undefined => {
+  params = setDefaultErrorParams(params)
+  logger.error(
+    `${chargingStation.logPrefix()} ${moduleName}.handleIncomingRequestError: Incoming request command '${commandName}' error:`,
+    error
+  )
+  if (params.throwError === false && params.errorResponse != null) {
+    return params.errorResponse
+  }
+  if (params.throwError === true && params.errorResponse == null) {
+    throw error
+  }
+  if (params.throwError === true && params.errorResponse != null) {
+    return params.errorResponse
+  }
+}
+
 export const setDefaultErrorParams = <T extends JsonType>(
   params: HandleErrorParams<T>,
   defaultParams: HandleErrorParams<T> = defaultErrorParams
 ): HandleErrorParams<T> => {
-  params = { ...defaultParams, ...params }
-  return params
+  return { ...defaultParams, ...params }
 }
index 4164c36bf11c96f18b8250cfd47be98bdeb897d5..f9d1e14980017606a7c1f64ec0135eb47bf8e80b 100644 (file)
@@ -1,9 +1,12 @@
+import { CircularBuffer } from 'mnemonist'
+
 import type { ChargingStation } from '../charging-station/index.js'
 import {
   type ChargingStationData,
   type ChargingStationWorkerMessage,
   ChargingStationWorkerMessageEvents,
-  type Statistics
+  type Statistics,
+  type TimestampedData
 } from '../types/index.js'
 import {
   buildChargingStationAutomaticTransactionGeneratorConfiguration,
@@ -60,9 +63,22 @@ export const buildUpdatedMessage = (
 export const buildPerformanceStatisticsMessage = (
   statistics: Statistics
 ): ChargingStationWorkerMessage<Statistics> => {
+  const statisticsData = [...statistics.statisticsData].map(([key, value]) => {
+    if (value.measurementTimeSeries instanceof CircularBuffer) {
+      value.measurementTimeSeries = value.measurementTimeSeries.toArray() as TimestampedData[]
+    }
+    return [key, value]
+  })
   return {
     event: ChargingStationWorkerMessageEvents.performanceStatistics,
-    data: statistics
+    data: {
+      id: statistics.id,
+      name: statistics.name,
+      uri: statistics.uri,
+      createdAt: statistics.createdAt,
+      updatedAt: statistics.updatedAt,
+      statisticsData
+    }
   }
 }
 
index 9f50b8eaa12b08037ef9c49b042ac96a62463bef..501dea7797ec30ecc469604ed1e93697551ad095 100644 (file)
@@ -1,10 +1,10 @@
 import { mean } from 'rambda'
 
 export const min = (...args: number[]): number =>
-  args.reduce((minimum, num) => (minimum < num ? minimum : num), Infinity)
+  args.reduce((minimum, num) => (minimum < num ? minimum : num), Number.POSITIVE_INFINITY)
 
 export const max = (...args: number[]): number =>
-  args.reduce((maximum, num) => (maximum > num ? maximum : num), -Infinity)
+  args.reduce((maximum, num) => (maximum > num ? maximum : num), Number.NEGATIVE_INFINITY)
 
 // TODO: use order statistics tree https://en.wikipedia.org/wiki/Order_statistic_tree
 export const nthPercentile = (dataSet: number[], percentile: number): number => {
index aeed9b0fa44b4a073bff682583c95695cbb954ac..9a06c64ed5658e01e7409bb38ae95baaba61be5c 100644 (file)
@@ -12,6 +12,7 @@ import {
   minutesToSeconds,
   secondsToMilliseconds
 } from 'date-fns'
+import type { CircularBuffer } from 'mnemonist'
 import { is } from 'rambda'
 
 import {
@@ -112,7 +113,7 @@ export const convertToInt = (value: unknown): number => {
   }
   let changedValue: number = value as number
   if (typeof value === 'string') {
-    changedValue = parseInt(value)
+    changedValue = Number.parseInt(value)
   }
   if (isNaN(changedValue)) {
     throw new Error(`Cannot convert to integer: '${String(value)}'`)
@@ -126,7 +127,7 @@ export const convertToFloat = (value: unknown): number => {
   }
   let changedValue: number = value as number
   if (typeof value === 'string') {
-    changedValue = parseFloat(value)
+    changedValue = Number.parseFloat(value)
   }
   if (isNaN(changedValue)) {
     throw new Error(`Cannot convert to float: '${String(value)}'`)
@@ -153,7 +154,7 @@ export const getRandomFloat = (max = Number.MAX_VALUE, min = 0): number => {
   if (max < min) {
     throw new RangeError('Invalid interval')
   }
-  if (max - min === Infinity) {
+  if (max - min === Number.POSITIVE_INFINITY) {
     throw new RangeError('Invalid interval')
   }
   return (randomBytes(4).readUInt32LE() / 0xffffffff) * (max - min) + min
@@ -200,8 +201,8 @@ export const getRandomFloatFluctuatedRounded = (
   )
 }
 
-export const extractTimeSeriesValues = (timeSeries: TimestampedData[]): number[] => {
-  return timeSeries.map(timeSeriesItem => timeSeriesItem.value)
+export const extractTimeSeriesValues = (timeSeries: CircularBuffer<TimestampedData>): number[] => {
+  return (timeSeries.toArray() as TimestampedData[]).map(timeSeriesItem => timeSeriesItem.value)
 }
 
 export const clone = <T>(object: T): T => {
@@ -281,7 +282,9 @@ export const JSONStringify = <
       if (is(Map, value)) {
         switch (mapFormat) {
           case MapStringifyFormat.object:
-            return { ...Object.fromEntries<Map<string, Record<string, unknown>>>(value.entries()) }
+            return {
+              ...Object.fromEntries<Map<string, Record<string, unknown>>>(value.entries())
+            }
           case MapStringifyFormat.array:
           default:
             return [...value]
@@ -325,6 +328,9 @@ export const getWebSocketCloseEventStatusString = (code: number): string => {
 }
 
 export const isArraySorted = <T>(array: T[], compareFn: (a: T, b: T) => number): boolean => {
+  if (array.length <= 1) {
+    return true
+  }
   for (let index = 0; index < array.length - 1; ++index) {
     if (compareFn(array[index], array[index + 1]) > 0) {
       return false
index e1d6734c9c1fba31a6bf7eaeaad68e3e44abd913..5fedbc57e20ab849439f4628c28390b4433015f5 100644 (file)
@@ -5,12 +5,12 @@ export {
   buildEvsesStatus,
   OutputFormat
 } from './ChargingStationConfigurationUtils.js'
-export { CircularArray } from './CircularArray.js'
 export { Configuration } from './Configuration.js'
 export { Constants } from './Constants.js'
 export { ACElectricUtils, DCElectricUtils } from './ElectricUtils.js'
 export {
   handleFileException,
+  handleIncomingRequestError,
   handleSendMessageError,
   handleUncaughtException,
   handleUnhandledRejection,
index c45e6a617147edce428800d8a777178eea9b53ea..1774c24a4f17585e8ce1c6dd4bbcef1c109a5fee 100644 (file)
@@ -130,7 +130,11 @@ export class WorkerSet<D extends WorkerData, R extends WorkerData> extends Worke
         data: elementData
       } satisfies WorkerMessage<D>
       workerSetElement.worker.postMessage(message)
-      this.promiseResponseMap.set(message.uuid, { resolve, reject, workerSetElement })
+      this.promiseResponseMap.set(message.uuid, {
+        resolve,
+        reject,
+        workerSetElement
+      })
     })
     const response = await sendMessageToWorker
     // Add element sequentially to optimize memory at startup
@@ -199,7 +203,10 @@ export class WorkerSet<D extends WorkerData, R extends WorkerData> extends Worke
     worker.once('exit', () => {
       this.removeWorkerSetElement(this.getWorkerSetElementByWorker(worker))
     })
-    const workerSetElement: WorkerSetElement = { worker, numberOfWorkerElements: 0 }
+    const workerSetElement: WorkerSetElement = {
+      worker,
+      numberOfWorkerElements: 0
+    }
     this.workerSet.add(workerSetElement)
     this.workerStartup = false
     return workerSetElement
diff --git a/tests/exception/OCPPError.test.ts b/tests/exception/OCPPError.test.ts
new file mode 100644 (file)
index 0000000..c6e4bc4
--- /dev/null
@@ -0,0 +1,23 @@
+import { describe, it } from 'node:test'
+
+import { expect } from 'expect'
+
+import { OCPPError } from '../../src/exception/OCPPError.js'
+import { ErrorType } from '../../src/types/index.js'
+import { Constants } from '../../src/utils/Constants.js'
+
+await describe('OCPPError test suite', async () => {
+  await it('Verify that OCPPError can be instantiated', () => {
+    const ocppError = new OCPPError(ErrorType.GENERIC_ERROR, '')
+    expect(ocppError).toBeInstanceOf(OCPPError)
+    expect(ocppError.name).toBe('OCPPError')
+    expect(ocppError.message).toBe('')
+    expect(ocppError.code).toBe(ErrorType.GENERIC_ERROR)
+    expect(ocppError.command).toBe(Constants.UNKNOWN_OCPP_COMMAND)
+    expect(ocppError.details).toBeUndefined()
+    expect(typeof ocppError.stack === 'string').toBe(true)
+    expect(ocppError.stack).not.toBe('')
+    expect(ocppError.cause).toBeUndefined()
+    expect(ocppError.date).toBeInstanceOf(Date)
+  })
+})
diff --git a/tests/utils/CircularArray.test.ts b/tests/utils/CircularArray.test.ts
deleted file mode 100644 (file)
index 74be021..0000000
+++ /dev/null
@@ -1,147 +0,0 @@
-import { describe, it } from 'node:test'
-
-import { expect } from 'expect'
-
-import { CircularArray, DEFAULT_CIRCULAR_ARRAY_SIZE } from '../../src/utils/CircularArray.js'
-
-await describe('CircularArray test suite', async () => {
-  await it('Verify that circular array can be instantiated', () => {
-    const circularArray = new CircularArray()
-    expect(circularArray).toBeInstanceOf(CircularArray)
-  })
-
-  await it('Verify circular array default size at instance creation', () => {
-    const circularArray = new CircularArray()
-    expect(circularArray.size).toBe(DEFAULT_CIRCULAR_ARRAY_SIZE)
-  })
-
-  await it('Verify that circular array size can be set at instance creation', () => {
-    const circularArray = new CircularArray(1000)
-    expect(circularArray.size).toBe(1000)
-  })
-
-  await it('Verify that circular array size and items can be set at instance creation', () => {
-    let circularArray = new CircularArray(1000, 1, 2, 3, 4, 5)
-    expect(circularArray.size).toBe(1000)
-    expect(circularArray.length).toBe(5)
-    circularArray = new CircularArray(4, 1, 2, 3, 4, 5)
-    expect(circularArray.size).toBe(4)
-    expect(circularArray.length).toBe(4)
-  })
-
-  await it('Verify that circular array size is valid at instance creation', () => {
-    expect(() => new CircularArray(0.25)).toThrow(
-      new TypeError('Invalid circular array size: 0.25 is not a safe integer')
-    )
-    expect(() => new CircularArray(-1)).toThrow(
-      new RangeError('Invalid circular array size: -1 < 0')
-    )
-    expect(() => new CircularArray(Number.MAX_SAFE_INTEGER + 1)).toThrow(
-      new TypeError(
-        `Invalid circular array size: ${Number.MAX_SAFE_INTEGER + 1} is not a safe integer`
-      )
-    )
-  })
-
-  await it('Verify that circular array empty works as intended', () => {
-    const circularArray = new CircularArray()
-    expect(circularArray.empty()).toBe(true)
-  })
-
-  await it('Verify that circular array full works as intended', () => {
-    const circularArray = new CircularArray(5, 1, 2, 3, 4, 5)
-    expect(circularArray.full()).toBe(true)
-  })
-
-  await it('Verify that circular array push works as intended', () => {
-    let circularArray = new CircularArray(4)
-    let arrayLength = circularArray.push(1, 2, 3, 4, 5)
-    expect(arrayLength).toBe(circularArray.size)
-    expect(circularArray.length).toBe(circularArray.size)
-    expect(circularArray).toStrictEqual(new CircularArray(4, 2, 3, 4, 5))
-    arrayLength = circularArray.push(6, 7)
-    expect(arrayLength).toBe(circularArray.size)
-    expect(circularArray.length).toBe(circularArray.size)
-    expect(circularArray).toStrictEqual(new CircularArray(4, 4, 5, 6, 7))
-    circularArray = new CircularArray(100)
-    arrayLength = circularArray.push(1, 2, 3, 4, 5)
-    expect(arrayLength).toBe(5)
-    expect(circularArray.size).toBe(100)
-    expect(circularArray.length).toBe(5)
-    expect(circularArray).toStrictEqual(new CircularArray(100, 1, 2, 3, 4, 5))
-  })
-
-  await it('Verify that circular array splice works as intended', () => {
-    let circularArray = new CircularArray(1000, 1, 2, 3, 4, 5)
-    let deletedItems = circularArray.splice(2)
-    expect(deletedItems).toStrictEqual(new CircularArray(3, 3, 4, 5))
-    expect(circularArray.length).toBe(2)
-    expect(circularArray).toStrictEqual(new CircularArray(1000, 1, 2))
-    circularArray = new CircularArray(1000, 1, 2, 3, 4, 5)
-    deletedItems = circularArray.splice(2, 1)
-    expect(deletedItems).toStrictEqual(new CircularArray(1, 3))
-    expect(circularArray.length).toBe(4)
-    expect(circularArray).toStrictEqual(new CircularArray(1000, 1, 2, 4, 5))
-    circularArray = new CircularArray(4, 1, 2, 3, 4)
-    deletedItems = circularArray.splice(2, 1, 5, 6)
-    expect(deletedItems).toStrictEqual(new CircularArray(2, 3, 1))
-    expect(circularArray.length).toBe(4)
-    expect(circularArray).toStrictEqual(new CircularArray(4, 2, 5, 6, 4))
-  })
-
-  await it('Verify that circular array concat works as intended', () => {
-    let circularArray = new CircularArray(5, 1, 2, 3, 4, 5)
-    circularArray = circularArray.concat(6, 7)
-    expect(circularArray.length).toBe(5)
-    expect(circularArray).toStrictEqual(new CircularArray(5, 3, 4, 5, 6, 7))
-    circularArray = new CircularArray(1)
-    circularArray = circularArray.concat(6, 7)
-    expect(circularArray.length).toBe(1)
-    expect(circularArray).toStrictEqual(new CircularArray(1, 7))
-  })
-
-  await it('Verify that circular array unshift works as intended', () => {
-    let circularArray = new CircularArray(5, 1, 2, 3, 4, 5)
-    let arrayLength = circularArray.unshift(6, 7)
-    expect(arrayLength).toBe(5)
-    expect(circularArray.length).toBe(5)
-    expect(circularArray).toStrictEqual(new CircularArray(5, 6, 7, 1, 2, 3))
-    circularArray = new CircularArray(1)
-    arrayLength = circularArray.unshift(6, 7)
-    expect(arrayLength).toBe(1)
-    expect(circularArray.length).toBe(1)
-    expect(circularArray).toStrictEqual(new CircularArray(1, 6))
-  })
-
-  await it('Verify that circular array resize works as intended', () => {
-    expect(() => {
-      new CircularArray().resize(0.25)
-    }).toThrow(new TypeError('Invalid circular array size: 0.25 is not a safe integer'))
-    expect(() => {
-      new CircularArray().resize(-1)
-    }).toThrow(new RangeError('Invalid circular array size: -1 < 0'))
-    expect(() => {
-      new CircularArray().resize(Number.MAX_SAFE_INTEGER + 1)
-    }).toThrow(
-      new TypeError(
-        `Invalid circular array size: ${Number.MAX_SAFE_INTEGER + 1} is not a safe integer`
-      )
-    )
-    let circularArray = new CircularArray(5, 1, 2, 3, 4, 5)
-    circularArray.resize(0)
-    expect(circularArray.size).toBe(0)
-    expect(circularArray).toStrictEqual(new CircularArray(0))
-    circularArray = new CircularArray(5, 1, 2, 3, 4, 5)
-    circularArray.resize(1)
-    expect(circularArray.size).toBe(1)
-    expect(circularArray).toStrictEqual(new CircularArray(1, 1))
-    circularArray = new CircularArray(5, 1, 2, 3, 4, 5)
-    circularArray.resize(3)
-    expect(circularArray.size).toBe(3)
-    expect(circularArray).toStrictEqual(new CircularArray(3, 1, 2, 3))
-    circularArray = new CircularArray(5, 1, 2, 3, 4, 5)
-    circularArray.resize(8)
-    expect(circularArray.size).toBe(8)
-    expect(circularArray).toStrictEqual(new CircularArray(8, 1, 2, 3, 4, 5))
-  })
-})
diff --git a/tests/utils/ConfigurationUtils.test.ts b/tests/utils/ConfigurationUtils.test.ts
new file mode 100644 (file)
index 0000000..b0689b8
--- /dev/null
@@ -0,0 +1,23 @@
+/* eslint-disable @typescript-eslint/no-unsafe-member-access */
+import { describe, it } from 'node:test'
+
+import { expect } from 'expect'
+
+import { FileType } from '../../src/types/index.js'
+import { handleFileException, logPrefix } from '../../src/utils/ConfigurationUtils.js'
+
+await describe('ConfigurationUtils test suite', async () => {
+  await it('Verify logPrefix()', () => {
+    expect(logPrefix()).toContain(' Simulator configuration |')
+  })
+
+  await it('Verify handleFileException()', t => {
+    t.mock.method(console, 'error')
+    const error = new Error()
+    error.code = 'ENOENT'
+    expect(() => {
+      handleFileException('path/to/module.js', FileType.Authorization, error, 'log prefix |')
+    }).toThrow(error)
+    expect(console.error.mock.calls.length).toBe(1)
+  })
+})
diff --git a/tests/utils/ErrorUtils.test.ts b/tests/utils/ErrorUtils.test.ts
new file mode 100644 (file)
index 0000000..edf088c
--- /dev/null
@@ -0,0 +1,129 @@
+/* eslint-disable @typescript-eslint/no-unsafe-member-access */
+import { describe, it } from 'node:test'
+
+import { expect } from 'expect'
+
+import type { ChargingStation } from '../../src/charging-station/index.js'
+import {
+  FileType,
+  GenericStatus,
+  IncomingRequestCommand,
+  MessageType,
+  RequestCommand
+} from '../../src/types/index.js'
+import {
+  handleFileException,
+  handleIncomingRequestError,
+  handleSendMessageError,
+  setDefaultErrorParams
+} from '../../src/utils/ErrorUtils.js'
+import { logger } from '../../src/utils/Logger.js'
+
+await describe('ErrorUtils test suite', async () => {
+  // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
+  const chargingStation = {
+    logPrefix: () => 'CS-TEST |'
+  } as ChargingStation
+
+  await it('Verify handleFileException()', t => {
+    t.mock.method(console, 'warn')
+    t.mock.method(console, 'error')
+    t.mock.method(logger, 'warn')
+    t.mock.method(logger, 'error')
+    const error = new Error()
+    error.code = 'ENOENT'
+    expect(() => {
+      handleFileException('path/to/module.js', FileType.Authorization, error, 'log prefix |', {})
+    }).toThrow(error)
+    expect(() => {
+      handleFileException('path/to/module.js', FileType.Authorization, error, 'log prefix |', {
+        throwError: false
+      })
+    }).not.toThrow()
+    expect(logger.warn.mock.calls.length).toBe(1)
+    expect(logger.error.mock.calls.length).toBe(1)
+    expect(() => {
+      handleFileException('path/to/module.js', FileType.Authorization, error, 'log prefix |', {
+        consoleOut: true
+      })
+    }).toThrow(error)
+    expect(() => {
+      handleFileException('path/to/module.js', FileType.Authorization, error, 'log prefix |', {
+        throwError: false,
+        consoleOut: true
+      })
+    }).not.toThrow()
+    expect(console.warn.mock.calls.length).toBe(1)
+    expect(console.error.mock.calls.length).toBe(1)
+  })
+
+  await it('Verify handleSendMessageError()', t => {
+    t.mock.method(logger, 'error')
+    t.mock.method(chargingStation, 'logPrefix')
+    const error = new Error()
+    expect(() => {
+      handleSendMessageError(
+        chargingStation,
+        RequestCommand.BOOT_NOTIFICATION,
+        MessageType.CALL_MESSAGE,
+        error
+      )
+    }).not.toThrow()
+    expect(() => {
+      handleSendMessageError(
+        chargingStation,
+        RequestCommand.BOOT_NOTIFICATION,
+        MessageType.CALL_MESSAGE,
+        error,
+        { throwError: true }
+      )
+    }).toThrow(error)
+    expect(chargingStation.logPrefix.mock.calls.length).toBe(2)
+    expect(logger.error.mock.calls.length).toBe(2)
+  })
+
+  await it('Verify handleIncomingRequestError()', t => {
+    t.mock.method(logger, 'error')
+    t.mock.method(chargingStation, 'logPrefix')
+    const error = new Error()
+    expect(() => {
+      handleIncomingRequestError(chargingStation, IncomingRequestCommand.CLEAR_CACHE, error)
+    }).toThrow(error)
+    expect(() => {
+      handleIncomingRequestError(chargingStation, IncomingRequestCommand.CLEAR_CACHE, error, {
+        throwError: false
+      })
+    }).not.toThrow()
+    const errorResponse = {
+      status: GenericStatus.Rejected
+    }
+    expect(
+      handleIncomingRequestError(chargingStation, IncomingRequestCommand.CLEAR_CACHE, error, {
+        throwError: false,
+        errorResponse
+      })
+    ).toStrictEqual(errorResponse)
+    expect(chargingStation.logPrefix.mock.calls.length).toBe(3)
+    expect(logger.error.mock.calls.length).toBe(3)
+  })
+
+  await it('Verify setDefaultErrorParams()', () => {
+    expect(setDefaultErrorParams({})).toStrictEqual({ throwError: true, consoleOut: false })
+    expect(setDefaultErrorParams({ throwError: false })).toStrictEqual({
+      throwError: false,
+      consoleOut: false
+    })
+    expect(setDefaultErrorParams({ throwError: false, consoleOut: true })).toStrictEqual({
+      throwError: false,
+      consoleOut: true
+    })
+    expect(setDefaultErrorParams({ throwError: true, consoleOut: true })).toStrictEqual({
+      throwError: true,
+      consoleOut: true
+    })
+    expect(setDefaultErrorParams({}, { throwError: false, consoleOut: false })).toStrictEqual({
+      throwError: false,
+      consoleOut: false
+    })
+  })
+})
index b54cdee86a3d64325117dc59a4e3c6066a3f9c0c..c0bf1b6cc8bf4e7a0ee3329eb1f1e73b9eb45b3e 100644 (file)
@@ -6,7 +6,7 @@ import { max, min, nthPercentile, stdDeviation } from '../../src/utils/Statistic
 
 await describe('StatisticUtils test suite', async () => {
   await it('Verify min()', () => {
-    expect(min()).toBe(Infinity)
+    expect(min()).toBe(Number.POSITIVE_INFINITY)
     expect(min(0, 1)).toBe(0)
     expect(min(1, 0)).toBe(0)
     expect(min(0, -1)).toBe(-1)
@@ -14,7 +14,7 @@ await describe('StatisticUtils test suite', async () => {
   })
 
   await it('Verify max()', () => {
-    expect(max()).toBe(-Infinity)
+    expect(max()).toBe(Number.NEGATIVE_INFINITY)
     expect(max(0, 1)).toBe(1)
     expect(max(1, 0)).toBe(1)
     expect(max(0, -1)).toBe(0)
index 5672b032187e336ba48e6a85c73a0d5b5f981a02..11b9973eacc8db0160f79f924d54d98204b2f554 100644 (file)
@@ -4,8 +4,10 @@ import { describe, it } from 'node:test'
 
 import { hoursToMilliseconds, hoursToSeconds } from 'date-fns'
 import { expect } from 'expect'
+import { CircularBuffer } from 'mnemonist'
 import { satisfies } from 'semver'
 
+import type { TimestampedData } from '../../src/types/index.js'
 import { Constants } from '../../src/utils/Constants.js'
 import {
   clone,
@@ -19,6 +21,7 @@ import {
   generateUUID,
   getRandomFloat,
   hasOwnProp,
+  insertAt,
   isArraySorted,
   isAsyncFunction,
   isNotEmptyArray,
@@ -188,14 +191,19 @@ await describe('Utils test suite', async () => {
   })
 
   await it('Verify extractTimeSeriesValues()', () => {
-    expect(extractTimeSeriesValues([])).toEqual([])
-    expect(extractTimeSeriesValues([{ timestamp: Date.now(), value: 1.1 }])).toEqual([1.1])
     expect(
-      extractTimeSeriesValues([
-        { timestamp: Date.now(), value: 1.1 },
-        { timestamp: Date.now(), value: 2.2 }
-      ])
-    ).toEqual([1.1, 2.2])
+      extractTimeSeriesValues(
+        new CircularBuffer<TimestampedData>(Array, Constants.DEFAULT_CIRCULAR_BUFFER_CAPACITY)
+      )
+    ).toEqual([])
+    const circularBuffer = new CircularBuffer<TimestampedData>(
+      Array,
+      Constants.DEFAULT_CIRCULAR_BUFFER_CAPACITY
+    )
+    circularBuffer.push({ timestamp: Date.now(), value: 1.1 })
+    circularBuffer.push({ timestamp: Date.now(), value: 2.2 })
+    circularBuffer.push({ timestamp: Date.now(), value: 3.3 })
+    expect(extractTimeSeriesValues(circularBuffer)).toEqual([1.1, 2.2, 3.3])
   })
 
   await it('Verify isObject()', () => {
@@ -225,7 +233,7 @@ await describe('Utils test suite', async () => {
     expect(isAsyncFunction([])).toBe(false)
     expect(isAsyncFunction(new Date())).toBe(false)
     // eslint-disable-next-line prefer-regex-literals
-    expect(isAsyncFunction(new RegExp('[a-z]', 'i'))).toBe(false)
+    expect(isAsyncFunction(/[a-z]/i)).toBe(false)
     expect(isAsyncFunction(new Error())).toBe(false)
     expect(isAsyncFunction(new Map())).toBe(false)
     expect(isAsyncFunction(new Set())).toBe(false)
@@ -373,6 +381,11 @@ await describe('Utils test suite', async () => {
     expect(isNotEmptyArray(new WeakSet())).toBe(false)
   })
 
+  await it('Verify insertAt()', () => {
+    expect(insertAt('test', 'ing', 'test'.length)).toBe('testing')
+    expect(insertAt('test', 'ing', 2)).toBe('teingst')
+  })
+
   await it('Verify isArraySorted()', () => {
     expect(
       isArraySorted([], (a, b) => {
index 5188248a5285ba06f37b5468096961766a38e078..2d74c6ae17a82eae714d2adf659029923f02ddf3 100644 (file)
@@ -8,10 +8,10 @@
     "pnpm": ">=9.0.0"
   },
   "volta": {
-    "node": "22.1.0",
-    "pnpm": "9.1.0"
+    "node": "22.2.0",
+    "pnpm": "9.2.0"
   },
-  "packageManager": "pnpm@9.1.0",
+  "packageManager": "pnpm@9.2.0",
   "type": "module",
   "scripts": {
     "build": "vite build",
     "vue-toast-notification": "^3.1.2"
   },
   "devDependencies": {
-    "@rushstack/eslint-patch": "^1.10.2",
+    "@rushstack/eslint-patch": "^1.10.3",
     "@tsconfig/node20": "^20.1.4",
-    "@types/jsdom": "^21.1.6",
-    "@types/node": "^20.12.10",
-    "@typescript-eslint/eslint-plugin": "^7.8.0",
-    "@typescript-eslint/parser": "^7.8.0",
-    "@vitejs/plugin-vue": "^5.0.4",
-    "@vitejs/plugin-vue-jsx": "^3.1.0",
+    "@types/jsdom": "^21.1.7",
+    "@types/node": "^20.14.2",
+    "@typescript-eslint/eslint-plugin": "^7.12.0",
+    "@typescript-eslint/parser": "^7.12.0",
+    "@vitejs/plugin-vue": "^5.0.5",
+    "@vitejs/plugin-vue-jsx": "^4.0.0",
     "@vitest/coverage-v8": "^1.6.0",
     "@vue/eslint-config-prettier": "^9.0.0",
     "@vue/eslint-config-typescript": "^13.0.0",
     "eslint-import-resolver-typescript": "^3.6.1",
     "eslint-plugin-import": "^2.29.1",
     "eslint-plugin-simple-import-sort": "^12.1.0",
-    "eslint-plugin-vue": "^9.25.0",
-    "jsdom": "^24.0.0",
-    "prettier": "^3.2.5",
-    "rimraf": "^5.0.5",
+    "eslint-plugin-vue": "^9.26.0",
+    "jsdom": "^24.1.0",
+    "prettier": "^3.3.1",
+    "rimraf": "^5.0.7",
     "typescript": "~5.4.5",
-    "vite": "^5.2.11",
+    "vite": "^5.2.13",
     "vitest": "^1.6.0"
   },
   "_id": "webui@0.3.0"
index 9522c59213c666a526d48927447024f3e8fc065a..04587e2d8a98d7688eb8016a0833e01edc5b93a4 100644 (file)
@@ -105,7 +105,9 @@ export class UIClient {
   }
 
   public async deleteChargingStation(hashId: string): Promise<ResponsePayload> {
-    return this.sendRequest(ProcedureName.DELETE_CHARGING_STATIONS, { hashIds: [hashId] })
+    return this.sendRequest(ProcedureName.DELETE_CHARGING_STATIONS, {
+      hashIds: [hashId]
+    })
   }
 
   public async setSupervisionUrl(hashId: string, supervisionUrl: string): Promise<ResponsePayload> {
@@ -116,11 +118,15 @@ export class UIClient {
   }
 
   public async startChargingStation(hashId: string): Promise<ResponsePayload> {
-    return this.sendRequest(ProcedureName.START_CHARGING_STATION, { hashIds: [hashId] })
+    return this.sendRequest(ProcedureName.START_CHARGING_STATION, {
+      hashIds: [hashId]
+    })
   }
 
   public async stopChargingStation(hashId: string): Promise<ResponsePayload> {
-    return this.sendRequest(ProcedureName.STOP_CHARGING_STATION, { hashIds: [hashId] })
+    return this.sendRequest(ProcedureName.STOP_CHARGING_STATION, {
+      hashIds: [hashId]
+    })
   }
 
   public async openConnection(hashId: string): Promise<ResponsePayload> {
@@ -183,11 +189,17 @@ export class UIClient {
       this.uiServerConfiguration.authentication?.type === AuthenticationType.PROTOCOL_BASIC_AUTH
         ? [
             `${this.uiServerConfiguration.protocol}${this.uiServerConfiguration.version}`,
-            `authorization.basic.${btoa(`${this.uiServerConfiguration.authentication.username}:${this.uiServerConfiguration.authentication.password}`).replace(/={1,2}$/, '')}`
+            `authorization.basic.${btoa(
+              `${this.uiServerConfiguration.authentication.username}:${this.uiServerConfiguration.authentication.password}`
+            ).replace(/={1,2}$/, '')}`
           ]
         : `${this.uiServerConfiguration.protocol}${this.uiServerConfiguration.version}`
     this.ws = new WebSocket(
-      `${this.uiServerConfiguration.secure === true ? ApplicationProtocol.WSS : ApplicationProtocol.WS}://${this.uiServerConfiguration.host}:${this.uiServerConfiguration.port}`,
+      `${
+        this.uiServerConfiguration.secure === true
+          ? ApplicationProtocol.WSS
+          : ApplicationProtocol.WS
+      }://${this.uiServerConfiguration.host}:${this.uiServerConfiguration.port}`,
       protocols
     )
     this.ws.onopen = () => {
index 0c8a83996e905c7e046d624ad9a8bd64124d1df1..b1bebc92582b5ae64c82b6839ab244a05c0c6075 100644 (file)
@@ -27,7 +27,7 @@ export const convertToInt = (value: unknown): number => {
   }
   let changedValue: number = value as number
   if (typeof value === 'string') {
-    changedValue = parseInt(value)
+    changedValue = Number.parseInt(value)
   }
   if (isNaN(changedValue)) {
     throw new Error(`Cannot convert to integer: '${String(value)}'`)
index 6f0d76e38bac14a980a967753b9db65609cc0a46..48265c5acbcd3d56459240ccbfe0ebe4ee2bd2ee 100644 (file)
@@ -1,4 +1,4 @@
-export {}
+export type {}
 
 declare module 'vue' {
   export interface GlobalComponents {
index 695b88608b4df60c0e90ff848167057ddcbcdfb7..af6fbe99a4d771068a2429845ad6632bd13be2b0 100644 (file)
@@ -142,7 +142,9 @@ const simulatorButtonClass = computed<string>(() =>
 )
 const simulatorButtonMessage = computed<string>(
   () =>
-    `${simulatorState.value?.started === true ? 'Stop' : 'Start'} Simulator${simulatorState.value?.version != null ? ` (${simulatorState.value.version})` : ''}`
+    `${simulatorState.value?.started === true ? 'Stop' : 'Start'} Simulator${
+      simulatorState.value?.version != null ? ` (${simulatorState.value.version})` : ''
+    }`
 )
 
 const state = ref<{
@@ -286,7 +288,10 @@ onUnmounted(() => {
   unregisterWSEventListeners()
 })
 
-const uiServerConfigurations: { index: number; configuration: UIServerConfigurationSection }[] = (
+const uiServerConfigurations: {
+  index: number
+  configuration: UIServerConfigurationSection
+}[] = (
   app?.appContext.config.globalProperties.$configuration.value
     .uiServer as UIServerConfigurationSection[]
 ).map((configuration: UIServerConfigurationSection, index: number) => ({
index 46a8bb75884f67da0c4b2ecfc9138bff44fb7ab2..3eb2838e8925cb1b38e872695e66162c97883607 100644 (file)
@@ -7,7 +7,7 @@ import finalhandler from 'finalhandler'
 import serveStatic from 'serve-static'
 
 const isCFEnvironment = env.VCAP_APPLICATION != null
-const PORT = isCFEnvironment ? parseInt(env.PORT) : 3030
+const PORT = isCFEnvironment ? Number.parseInt(env.PORT) : 3030
 const uiPath = join(dirname(fileURLToPath(import.meta.url)), './dist')
 
 const serve = serveStatic(uiPath)