Merge dependabot/npm_and_yarn/ui/web/vite-5.0.9 into combined-prs-branch
authorJérôme Benoit <jerome.benoit@piment-noir.org>
Fri, 15 Dec 2023 02:13:10 +0000 (03:13 +0100)
committerGitHub <noreply@github.com>
Fri, 15 Dec 2023 02:13:10 +0000 (03:13 +0100)
45 files changed:
.eslintrc.json
.github/workflows/ci.yml
.github/workflows/codeql-analysis.yml
.vscode/settings.json
CHANGELOG.md
README.md
bundle.js
manifest-cf-template.yml
package.json
pnpm-lock.yaml
sonar-project.properties
src/charging-station/AutomaticTransactionGenerator.ts
src/charging-station/Bootstrap.ts
src/charging-station/ChargingStation.ts
src/charging-station/ChargingStationWorker.ts
src/charging-station/Helpers.ts
src/charging-station/broadcast-channel/ChargingStationWorkerBroadcastChannel.ts
src/charging-station/broadcast-channel/UIServiceWorkerBroadcastChannel.ts
src/charging-station/ocpp/1.6/OCPP16IncomingRequestService.ts
src/charging-station/ocpp/1.6/OCPP16ResponseService.ts
src/charging-station/ocpp/1.6/OCPP16ServiceUtils.ts
src/charging-station/ocpp/OCPPIncomingRequestService.ts
src/charging-station/ocpp/OCPPServiceUtils.ts
src/charging-station/ocpp/index.ts
src/charging-station/ui-server/ui-services/AbstractUIService.ts
src/performance/PerformanceStatistics.ts
src/types/ConfigurationData.ts
src/types/index.ts
src/types/ocpp/1.6/MeterValues.ts
src/types/ocpp/1.6/Requests.ts
src/types/ocpp/1.6/Responses.ts
src/types/ocpp/MeterValues.ts
src/utils/Configuration.ts
src/utils/ConfigurationUtils.ts [new file with mode: 0644]
src/utils/Constants.ts
src/utils/StatisticUtils.ts
src/utils/Utils.ts
src/worker/WorkerAbstract.ts
src/worker/WorkerSet.ts
src/worker/WorkerUtils.ts
tests/utils/StatisticUtils.test.ts
tests/utils/Utils.test.ts
ui/web/.vscode/settings.json
ui/web/package.json
ui/web/pnpm-lock.yaml

index ddb47174049aff56a7589146429e75c4e1660902..408af99eb97b27a0ed461f02b49e44277c176e27 100644 (file)
@@ -23,9 +23,7 @@
     "space-before-blocks": ["error", "always"],
     "curly": ["error", "all"],
     "brace-style": "error",
-    "eqeqeq": ["error", "always"],
     "no-else-return": "error",
-    "no-eq-null": "error",
     "no-extra-bind": "error",
     "no-lone-blocks": "error",
     "no-multi-spaces": "error",
       }
     ],
     "block-spacing": "error",
-    // "capitalized-comments": [
-    //   "error",
-    //   "always",
-    //   {
-    //     "ignoreConsecutiveComments": true,
-    //     "ignorePattern": "pragma|ignored"
-    //   }
-    // ],
     "eol-last": ["error", "always"],
     "consistent-this": ["error", "self"],
     "func-call-spacing": ["error", "never"],
index fef46bc437f684580e3b5715117b42ba3ad9d407..2e3a29104aeb5511843842ca01ead77955df9b44 100644 (file)
@@ -67,7 +67,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.0.2
+        uses: sonarsource/sonarcloud-github-action@v2.1.1
         env:
           GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
           SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
@@ -120,7 +120,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.0.2
+        uses: sonarsource/sonarcloud-github-action@v2.1.1
         with:
           projectBaseDir: ui/web
         env:
index 92d0b5d7778799d76e33894919aa7a1ffcd88841..ca6b410f53637b1f6c2cdbf1a1caa097759b41ef 100644 (file)
@@ -45,7 +45,7 @@ jobs:
 
       # Initializes the CodeQL tools for scanning.
       - name: Initialize CodeQL
-        uses: github/codeql-action/init@v2
+        uses: github/codeql-action/init@v3
         with:
           languages: ${{ matrix.language }}
           # If you wish to specify custom queries, you can do so here or in a config file.
@@ -56,7 +56,7 @@ jobs:
       # Autobuild attempts to build any compiled languages  (C/C++, C#, or Java).
       # If this step fails, then you should remove it and run the build manually (see below)
       - name: Autobuild
-        uses: github/codeql-action/autobuild@v2
+        uses: github/codeql-action/autobuild@v3
 
       # ℹ️ Command-line programs to run using the OS shell.
       # 📚 https://git.io/JvXDl
@@ -70,4 +70,4 @@ jobs:
       #   make release
 
       - name: Perform CodeQL Analysis
-        uses: github/codeql-action/analyze@v2
+        uses: github/codeql-action/analyze@v3
index b2c6818a3095ec1ca6ac86aaeaf434533294dcc4..487234cb3c6778e0691cd2dde03bc228725202b7 100644 (file)
@@ -1,6 +1,6 @@
 {
   "editor.codeActionsOnSave": {
-    "source.fixAll": true
+    "source.fixAll": "explicit"
   },
   "cSpell.words": [
     "backoff",
@@ -44,7 +44,8 @@
     "SRPC",
     "tsdoc",
     "VCAP",
-    "webui"
+    "webui",
+    "workerset"
   ],
   "sonarlint.connectedMode.project": {
     "connectionId": "sap-1",
index a2b10ecd91871b2d96592299c610567031b9eb21..8e65d80a33e851715503e83dc76c2976db8b3e5e 100644 (file)
@@ -1,6 +1,64 @@
 # Changelog
 
-## [v1.2.26](https://github.com/sap/e-mobility-charging-stations-simulator/compare/v1.2.25...v1.2.26)
+## [v1.2.29](https://github.com/sap/e-mobility-charging-stations-simulator/compare/v1.2.28...v1.2.29)
+
+- build(deps-dev): Bump @vitejs/plugin-vue from 4.5.0 to 4.5.1 in /ui/web [`#872`](https://github.com/sap/e-mobility-charging-stations-simulator/pull/872)
+- perf: minimize OCPPUtils exports [`41f3983`](https://github.com/sap/e-mobility-charging-stations-simulator/commit/41f3983a4f934199769f9ef1c46bfae2adc22b56)
+- build(deps): apply updates [`a735b67`](https://github.com/sap/e-mobility-charging-stations-simulator/commit/a735b6738fbd7325c9482291e73dd018cd03be0a)
+- build(deps-dev): apply updates [`5927293`](https://github.com/sap/e-mobility-charging-stations-simulator/commit/592729336b4ca314ea9199f63229c5bc9432dc25)
+- perf: reduce OCPPUtils memory usage [`041365b`](https://github.com/sap/e-mobility-charging-stations-simulator/commit/041365be4e6cfcec381c895a203815dd933afff5)
+- build(deps-dev): apply updates [`69b30c7`](https://github.com/sap/e-mobility-charging-stations-simulator/commit/69b30c7e29342d1f3cfb75f4687c517688db61e7)
+- fix: handle invalid hashIds in UI server payload [`3a6ef20`](https://github.com/sap/e-mobility-charging-stations-simulator/commit/3a6ef20ab4c64999fb15ba8df7422bc15c595200)
+- build(ci): fix linter errors [`f1e3871`](https://github.com/sap/e-mobility-charging-stations-simulator/commit/f1e3871b2a063e5ee0fddbf597df76d02f81e332)
+- build(deps-dev): apply updates [`44337ae`](https://github.com/sap/e-mobility-charging-stations-simulator/commit/44337ae065eac340a1904afad7bd2ef9fe1e6368)
+- build: fix import issue with date-fns [`c7c86b6`](https://github.com/sap/e-mobility-charging-stations-simulator/commit/c7c86b6f88b204031c77b5106a1cf2551359ff52)
+- build: fix console printing ordering [`fc04731`](https://github.com/sap/e-mobility-charging-stations-simulator/commit/fc04731e85d07c46ad4e2146d3d2652deb05b246)
+- build: properly account build time [`ce1b06a`](https://github.com/sap/e-mobility-charging-stations-simulator/commit/ce1b06a72900f8c7a22db904ccc922452f5cdf88)
+- refactor: cleanup types import [`6a5f590`](https://github.com/sap/e-mobility-charging-stations-simulator/commit/6a5f5908423693496fbafa5a83d4c40d8228981d)
+
+## [v1.2.28](https://github.com/sap/e-mobility-charging-stations-simulator/compare/v1.2.27...v1.2.28) (2023-11-30)
+
+- build(deps-dev): apply updates [`ea9eb85`](https://github.com/sap/e-mobility-charging-stations-simulator/commit/ea9eb85a00bc56cb956df74d250989a7bcb09a04)
+- refactor: cleanup buffered messages handling code [`2a2ad81`](https://github.com/sap/e-mobility-charging-stations-simulator/commit/2a2ad81b23c64c05c93a16e0e255ae1350a5c862)
+- fix: ensure no null serialized values end in UI server response payload [`31fdd91`](https://github.com/sap/e-mobility-charging-stations-simulator/commit/31fdd918e146f6d4f534ea3df5b3ceace0e23cfc)
+- fix: ensure UI server remains active at simulator stop [`73edcc9`](https://github.com/sap/e-mobility-charging-stations-simulator/commit/73edcc9405a412de91008d2926112c4b8ada3607)
+- chore: version 1.2.28 [`52e0e69`](https://github.com/sap/e-mobility-charging-stations-simulator/commit/52e0e695165cc56ab4b58e2db6a0988228b797a4)
+- fix: handle not found hashId in UI server [`f12cf7e`](https://github.com/sap/e-mobility-charging-stations-simulator/commit/f12cf7ef207d1e1b243c45b1eecf5d89d8ec772d)
+- refactor: cleanup ElementsPerWorkerType type definition [`65a1157`](https://github.com/sap/e-mobility-charging-stations-simulator/commit/65a1157a0c0f0a7b23b7a6fc23432f2c3e7cb735)
+- refactor: cleanup crypto import [`7cd0a62`](https://github.com/sap/e-mobility-charging-stations-simulator/commit/7cd0a6218a4110e12fe8bc408492913da7259f8b)
+- fix: only reset defined ATG connector status [`37e207d`](https://github.com/sap/e-mobility-charging-stations-simulator/commit/37e207d110f051eac4228f604d0b4e7b14764457)
+- refactor: add type for worker configuration attribute [`47fb5f8`](https://github.com/sap/e-mobility-charging-stations-simulator/commit/47fb5f8f8370c85553eb65f8e4bfbbc233967682)
+
+## [v1.2.27](https://github.com/sap/e-mobility-charging-stations-simulator/compare/v1.2.26...v1.2.27) (2023-11-29)
+
+- Combined PRs [`#858`](https://github.com/sap/e-mobility-charging-stations-simulator/pull/858)
+- docs: refine Web UI usage path [`#860`](https://github.com/sap/e-mobility-charging-stations-simulator/issues/860)
+- build(deps-dev): apply updates [`94327d9`](https://github.com/sap/e-mobility-charging-stations-simulator/commit/94327d938c08c347d44ea685e38cb05ff9c3e548)
+- build(deps-dev): apply updates [`625f537`](https://github.com/sap/e-mobility-charging-stations-simulator/commit/625f537bc05ade4f8169d306c4b28183b9784a3f)
+- build(deps-dev): apply updates [`f4ba026`](https://github.com/sap/e-mobility-charging-stations-simulator/commit/f4ba0266ece7c399bce9acafbb1eb66e795f3ab8)
+- refactor: factor out configuration handling helpers [`4354af5`](https://github.com/sap/e-mobility-charging-stations-simulator/commit/4354af5acc068587187dbe3729a5ca8d54fb9626)
+- build(deps-dev): apply updates [`6a148c8`](https://github.com/sap/e-mobility-charging-stations-simulator/commit/6a148c8d7d7190092d16c17251023f24a9508ec4)
+- build(deps): apply updates [`e6a97a6`](https://github.com/sap/e-mobility-charging-stations-simulator/commit/e6a97a6cdb65ddbc7ffa131d8bd2a33868e16453)
+- fix: fix performance configuration change at runtime [`6d2b7d0`](https://github.com/sap/e-mobility-charging-stations-simulator/commit/6d2b7d0121fa6ab41272ed8f4f0d7fd2ce3e8c7d)
+- perf: allow to fine tune worker_threads ressource configuration [`487f0df`](https://github.com/sap/e-mobility-charging-stations-simulator/commit/487f0dfd58d97d4755718793e313f02aaddb1a6d)
+- perf(simulator): remove worker configuration attribute from Bootstrap [`5b373a2`](https://github.com/sap/e-mobility-charging-stations-simulator/commit/5b373a2392b4615ba29bb13f3b312eccf7ae8d49)
+- chore: version 1.2.27 [`10f1514`](https://github.com/sap/e-mobility-charging-stations-simulator/commit/10f1514af1ecf9f3f27f1d183d615df39dba46c6)
+- fix: fix recursion loop getTemplateFromFile -&gt; logPrefix -&gt; getTemplateFromFile [`c1f16af`](https://github.com/sap/e-mobility-charging-stations-simulator/commit/c1f16afd333f0fc8a6a02b9baa0aff23dbd18580)
+- refactor: rename elementsPerWorkers 'single' -&gt; 'all [`c20d5d7`](https://github.com/sap/e-mobility-charging-stations-simulator/commit/c20d5d72396a96028bee5492fa7ea2475b8a109e)
+- refactor(ui): add firmware status to UI types [`2a52615`](https://github.com/sap/e-mobility-charging-stations-simulator/commit/2a5261571579826e71b40f51cb06dd842af19477)
+- fix: ignore harmless performance error at shutdown [`b1bd4a1`](https://github.com/sap/e-mobility-charging-stations-simulator/commit/b1bd4a1576a894947da22f363c4737ffc218f8d8)
+- build(deps-dev): Bump tsx from 4.3.0 to 4.4.0 [`254be70`](https://github.com/sap/e-mobility-charging-stations-simulator/commit/254be70719d745aa29228d2f4e5aaa3f7191935e)
+- fix: fix cf push by conditionnaly importing husky [`9a2f0d4`](https://github.com/sap/e-mobility-charging-stations-simulator/commit/9a2f0d41a10c7b6850f9d47a47213c4e39f2f02f)
+- refactor: cleanup undefined handling [`f1bd9d1`](https://github.com/sap/e-mobility-charging-stations-simulator/commit/f1bd9d1970f24c8234582c82fcd58c806391b78b)
+- fix: ensure event listeners are always removed at simulator stop [`ee7c1da`](https://github.com/sap/e-mobility-charging-stations-simulator/commit/ee7c1da0e12c70134f31537a1c1e7040d309af5a)
+- docs: ui/web/README.md: refine links [`b4c9f3c`](https://github.com/sap/e-mobility-charging-stations-simulator/commit/b4c9f3c1d3161c8891e848601e60a54937ec18ab)
+- docs: ui/web/README.md: fix link, take 2 [`9826239`](https://github.com/sap/e-mobility-charging-stations-simulator/commit/98262391ccaa5d00fac1ec8a1707d7fbba33cc3a)
+- docs: ui/web/README.md: fix link [`0338165`](https://github.com/sap/e-mobility-charging-stations-simulator/commit/033816546d017750bd32c9bb641a60164dde3bba)
+- Merge dependabot/github_actions/github/combine-prs-5.0.0 into combined-prs-branch [`7837631`](https://github.com/sap/e-mobility-charging-stations-simulator/commit/7837631e325d2ce63d4a0a6f9010811f079322c7)
+- Merge dependabot/npm_and_yarn/tsx-4.4.0 into combined-prs-branch [`8ef1a84`](https://github.com/sap/e-mobility-charging-stations-simulator/commit/8ef1a843db8afdd982d792f2316906fad2a57f00)
+- build(deps): Bump github/combine-prs from 4.1.0 to 5.0.0 [`da4c008`](https://github.com/sap/e-mobility-charging-stations-simulator/commit/da4c0082a7a142b476b1e104b40daaa7b4fbd218)
+
+## [v1.2.26](https://github.com/sap/e-mobility-charging-stations-simulator/compare/v1.2.25...v1.2.26) (2023-11-24)
 
 - fix(simulator): buffer OCPP payload at sending error [`#156`](https://github.com/sap/e-mobility-charging-stations-simulator/issues/156)
 - build(deps-dev): apply updates [`4a0329e`](https://github.com/sap/e-mobility-charging-stations-simulator/commit/4a0329e11a89061df3af60db199fc11763748f8d)
@@ -11,6 +69,7 @@
 - fix: add getter/setter on some station info attributes [`9fe79a1`](https://github.com/sap/e-mobility-charging-stations-simulator/commit/9fe79a139245f48ce0b6b05a90e601a749c37507)
 - refactor: improve OCPP error defaults and usage [`7375968`](https://github.com/sap/e-mobility-charging-stations-simulator/commit/7375968c99fc22707e16e5e7923ca130c824ce5b)
 - build(deps-dev): apply updates [`8e3118b`](https://github.com/sap/e-mobility-charging-stations-simulator/commit/8e3118bd3b575d372ed39222424833e38193f794)
+- chore: version 1.2.26 [`f1c0116`](https://github.com/sap/e-mobility-charging-stations-simulator/commit/f1c011603cb605e6ecd8fca595c8d3c975540d2d)
 - fix: do not log twice OCPP request sending error [`3febbc9`](https://github.com/sap/e-mobility-charging-stations-simulator/commit/3febbc9f6498f7f5a6dc754a5fa687d112cc2c9b)
 - fix: fix configuration loading from file [`7878689`](https://github.com/sap/e-mobility-charging-stations-simulator/commit/78786898ff255379a312fc2d9724515b9219b27c)
 - refactor: remove unneeded max power getter [`7ffc143`](https://github.com/sap/e-mobility-charging-stations-simulator/commit/7ffc14365e06809bde30fff5fd03fb022d7483f5)
index 5c800ed234ef740681e906fa42cf3e4a73ebf96a..2a791ce8f4ecdb89cacba4c5ef0bf6e700f30548 100644 (file)
--- a/README.md
+++ b/README.md
@@ -100,15 +100,15 @@ But the modifications to test have to be done to the files in the build target d
 
 **src/assets/config.json**:
 
-| Key                        | Value(s)                                     | Default Value                                                                                                                                                                                                                 | Value type                                                                                                                                                                                                                                                               | Description                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              |
-| -------------------------- | -------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
-| supervisionUrls            |                                              | []                                                                                                                                                                                                                            | string \| string[]                                                                                                                                                                                                                                                       | string or strings array containing global connection URIs to OCPP-J servers                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              |
-| supervisionUrlDistribution | round-robin/random/charging-station-affinity | charging-station-affinity                                                                                                                                                                                                     | string                                                                                                                                                                                                                                                                   | supervision urls distribution policy to simulated charging stations                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      |
-| log                        |                                              | {<br />"enabled": true,<br />"file": "logs/combined.log",<br />"errorFile": "logs/error.log",<br />"statisticsInterval": 60,<br />"level": "info",<br />"console": false,<br />"format": "simple",<br />"rotate": true<br />} | {<br />enabled: boolean;<br />file: string;<br />errorFile: string;<br />statisticsInterval: number;<br />level: string;<br />console: boolean;<br />format: string;<br />rotate: boolean;<br />maxFiles: string \| number;<br />maxSize: string \| number;<br />}       | Log configuration section:<br />- _enabled_: enable logging<br />- _file_: log file relative path<br />- _errorFile_: error log file relative path<br />- _statisticsInterval_: seconds between charging stations statistics output in the logs<br />- _level_: emerg/alert/crit/error/warning/notice/info/debug [winston](https://github.com/winstonjs/winston) logging level</br >- _console_: output logs on the console<br />- _format_: [winston](https://github.com/winstonjs/winston) log format<br />- _rotate_: enable daily log files rotation<br />- _maxFiles_: maximum number of log files: https://github.com/winstonjs/winston-daily-rotate-file#options<br />- _maxSize_: maximum size of log files in bytes, or units of kb, mb, and gb: https://github.com/winstonjs/winston-daily-rotate-file#options |
-| worker                     |                                              | {<br />"processType": "workerSet",<br />"startDelay": 500,<br />"elementStartDelay": 0,<br />"elementsPerWorker": 'auto',<br />"poolMinSize": 4,<br />"poolMaxSize": 16<br />}                                                | {<br />processType: WorkerProcessType;<br />startDelay: number;<br />elementStartDelay: number;<br />elementsPerWorker: number \| 'auto';<br />poolMinSize: number;<br />poolMaxSize: number;<br />}                                                                     | Worker configuration section:<br />- _processType_: worker threads process type (`workerSet`/`fixedPool`/`dynamicPool`)<br />- _startDelay_: milliseconds to wait at worker threads startup (only for `workerSet` worker threads process type)<br />- _elementStartDelay_: milliseconds to wait at charging station startup<br />- _elementsPerWorker_: number of charging stations per worker threads for the `workerSet` process type (`auto` means (number of stations) / (number of CPUs) \* 1.5 if (number of stations) > (number of CPUs), otherwise 1)<br />- _poolMinSize_: worker threads pool minimum number of threads</br >- _poolMaxSize_: worker threads pool maximum number of threads                                                                                                                    |
-| uiServer                   |                                              | {<br />"enabled": false,<br />"type": "ws",<br />"version": "1.1",<br />"options": {<br />"host": "localhost",<br />"port": 8080<br />}<br />}                                                                                | {<br />enabled: boolean;<br />type: ApplicationProtocol;<br />version: ApplicationProtocolVersion;<br />options: ServerOptions;<br />authentication: {<br />enabled: boolean;<br />type: AuthenticationType;<br />username: string;<br />password: string;<br />}<br />} | UI server configuration section:<br />- _enabled_: enable UI server<br />- _type_: 'http' or 'ws'<br />- _version_: HTTP version '1.1' or '2.0'<br />- _options_: node.js net module [listen options](https://nodejs.org/api/net.html#serverlistenoptions-callback)                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      |
-| performanceStorage         |                                              | {<br />"enabled": false,<br />"type": "jsonfile",<br />"uri": "file:///performance/performanceRecords.json"<br />}                                                                                                            | {<br />enabled: boolean;<br />type: string;<br />uri: string;<br />}                                                                                                                                                                                                     | Performance storage configuration section:<br />- _enabled_: enable performance storage<br />- _type_: 'jsonfile' or 'mongodb'<br />- _uri_: storage URI                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 |
-| stationTemplateUrls        |                                              | {}[]                                                                                                                                                                                                                          | {<br />file: string;<br />numberOfStations: number;<br />}[]                                                                                                                                                                                                             | array of charging station configuration templates URIs configuration section (charging station configuration template file name and number of stations)                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  |
+| Key                        | Value(s)                                     | Default Value                                                                                                                                                                                                                 | Value type                                                                                                                                                                                                                                                               | Description                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      |
+| -------------------------- | -------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
+| supervisionUrls            |                                              | []                                                                                                                                                                                                                            | string \| string[]                                                                                                                                                                                                                                                       | string or strings array containing global connection URIs to OCPP-J servers                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      |
+| supervisionUrlDistribution | round-robin/random/charging-station-affinity | charging-station-affinity                                                                                                                                                                                                     | string                                                                                                                                                                                                                                                                   | supervision urls distribution policy to simulated charging stations                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              |
+| log                        |                                              | {<br />"enabled": true,<br />"file": "logs/combined.log",<br />"errorFile": "logs/error.log",<br />"statisticsInterval": 60,<br />"level": "info",<br />"console": false,<br />"format": "simple",<br />"rotate": true<br />} | {<br />enabled: boolean;<br />file: string;<br />errorFile: string;<br />statisticsInterval: number;<br />level: string;<br />console: boolean;<br />format: string;<br />rotate: boolean;<br />maxFiles: string \| number;<br />maxSize: string \| number;<br />}       | Log configuration section:<br />- _enabled_: enable logging<br />- _file_: log file relative path<br />- _errorFile_: error log file relative path<br />- _statisticsInterval_: seconds between charging stations statistics output in the logs<br />- _level_: emerg/alert/crit/error/warning/notice/info/debug [winston](https://github.com/winstonjs/winston) logging level</br >- _console_: output logs on the console<br />- _format_: [winston](https://github.com/winstonjs/winston) log format<br />- _rotate_: enable daily log files rotation<br />- _maxFiles_: maximum number of log files: https://github.com/winstonjs/winston-daily-rotate-file#options<br />- _maxSize_: maximum size of log files in bytes, or units of kb, mb, and gb: https://github.com/winstonjs/winston-daily-rotate-file#options                                                                                         |
+| worker                     |                                              | {<br />"processType": "workerSet",<br />"startDelay": 500,<br />"elementStartDelay": 0,<br />"elementsPerWorker": 'auto',<br />"poolMinSize": 4,<br />"poolMaxSize": 16<br />}                                                | {<br />processType: WorkerProcessType;<br />startDelay: number;<br />elementStartDelay: number;<br />elementsPerWorker: number \| 'auto' \| 'all';<br />poolMinSize: number;<br />poolMaxSize: number;<br />}                                                            | Worker configuration section:<br />- _processType_: worker threads process type (`workerSet`/`fixedPool`/`dynamicPool`)<br />- _startDelay_: milliseconds to wait at worker threads startup (only for `workerSet` worker threads process type)<br />- _elementStartDelay_: milliseconds to wait at charging station startup<br />- _elementsPerWorker_: number of charging stations per worker threads for the `workerSet` process type (`auto` means (number of stations) / (number of CPUs) \* 1.5 if (number of stations) > (number of CPUs), otherwise 1; `all` means a unique worker will run all charging stations)<br />- _poolMinSize_: worker threads pool minimum number of threads</br >- _poolMaxSize_: worker threads pool maximum number of threads<br />- _resourceLimits_: worker threads [resource limits](https://nodejs.org/api/worker_threads.html#new-workerfilename-options) object option |
+| uiServer                   |                                              | {<br />"enabled": false,<br />"type": "ws",<br />"version": "1.1",<br />"options": {<br />"host": "localhost",<br />"port": 8080<br />}<br />}                                                                                | {<br />enabled: boolean;<br />type: ApplicationProtocol;<br />version: ApplicationProtocolVersion;<br />options: ServerOptions;<br />authentication: {<br />enabled: boolean;<br />type: AuthenticationType;<br />username: string;<br />password: string;<br />}<br />} | UI server configuration section:<br />- _enabled_: enable UI server<br />- _type_: 'http' or 'ws'<br />- _version_: HTTP version '1.1' or '2.0'<br />- _options_: node.js net module [listen options](https://nodejs.org/api/net.html#serverlistenoptions-callback)                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              |
+| performanceStorage         |                                              | {<br />"enabled": false,<br />"type": "jsonfile",<br />"uri": "file:///performance/performanceRecords.json"<br />}                                                                                                            | {<br />enabled: boolean;<br />type: string;<br />uri: string;<br />}                                                                                                                                                                                                     | Performance storage configuration section:<br />- _enabled_: enable performance storage<br />- _type_: 'jsonfile' or 'mongodb'<br />- _uri_: storage URI                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         |
+| stationTemplateUrls        |                                              | {}[]                                                                                                                                                                                                                          | {<br />file: string;<br />numberOfStations: number;<br />}[]                                                                                                                                                                                                             | array of charging station configuration templates URIs configuration section (charging station configuration template file name and number of stations)                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          |
 
 #### Worker process model
 
index dea5a97f58449ec15ef63971d195ac9cded35e33..4bdee327fd0015cef8c3a4bc8c0e79dad72e678f 100644 (file)
--- a/bundle.js
+++ b/bundle.js
@@ -9,9 +9,11 @@ import { copy } from 'esbuild-plugin-copy';
 const isDevelopmentBuild = env.BUILD === 'development';
 const sourcemap = !!isDevelopmentBuild;
 
-console.info(chalk.green(`Building in ${isDevelopmentBuild ? 'development' : 'production'} mode`));
-console.time('Build time');
 (async () => {
+  console.info(
+    chalk.green(`Building in ${isDevelopmentBuild ? 'development' : 'production'} mode`),
+  );
+  console.time('Build time');
   await build({
     entryPoints: ['./src/start.ts', './src/charging-station/ChargingStationWorker.ts'],
     bundle: true,
@@ -74,5 +76,5 @@ console.time('Build time');
       }),
     ],
   });
+  console.timeEnd('Build time');
 })();
-console.timeEnd('Build time');
index 8804ef1dd58677dd1d9ca80c946fd919ffd5b9a8..74dcbb8cbfe3fac395f6363889299891c6c0ee2d 100644 (file)
@@ -12,4 +12,4 @@ applications:
     command: node dist/start.js
     env:
       # OPTIMIZE_MEMORY: true
-      NODE_OPTIONS: --enable-source-maps --stack-trace-limit=1024 --max-old-space-size=768
+      NODE_OPTIONS: --enable-source-maps --max-old-space-size=768
index c41e14800bc66c3d5bf6a89babe891163d027e6a..731081ff6fda43209a49ed3c84264e94cdd4c30f 100644 (file)
@@ -1,14 +1,14 @@
 {
   "$schema": "https://json.schemastore.org/package",
   "name": "e-mobility-charging-stations-simulator",
-  "version": "1.2.26",
+  "version": "1.2.29",
   "engines": {
     "node": ">=18.18.0",
     "pnpm": ">=8.6.0"
   },
   "volta": {
     "node": "20.10.0",
-    "pnpm": "8.11.0"
+    "pnpm": "8.12.1"
   },
   "repository": {
     "type": "git",
     "ajv-formats": "^2.1.1",
     "basic-ftp": "^5.0.3",
     "chalk": "^5.3.0",
-    "date-fns": "^2.30.0",
+    "date-fns": "3.0.0-rc.2",
     "http-status-codes": "^2.3.0",
     "just-merge": "^3.2.0",
     "logform": "^2.6.0",
-    "mnemonist": "^0.39.5",
+    "mnemonist": "^0.39.6",
     "mongodb": "^6.3.0",
-    "poolifier": "^3.0.9",
+    "poolifier": "^3.0.14",
     "tar": "^6.2.0",
     "tslib": "^2.6.2",
     "winston": "^3.11.0",
     "winston-daily-rotate-file": "^4.7.1",
-    "ws": "^8.14.2"
+    "ws": "^8.15.1"
   },
   "optionalDependencies": {
     "bufferutil": "^4.0.8",
     "@commitlint/config-conventional": "^18.4.3",
     "@mikro-orm/cli": "^5.9.4",
     "@release-it/bumper": "^6.0.1",
-    "@types/node": "^20.10.0",
+    "@types/node": "^20.10.4",
     "@types/tar": "^6.1.10",
     "@types/ws": "^8.5.10",
-    "@typescript-eslint/eslint-plugin": "^6.13.0",
-    "@typescript-eslint/parser": "^6.13.0",
+    "@typescript-eslint/eslint-plugin": "^6.14.0",
+    "@typescript-eslint/parser": "^6.14.0",
     "auto-changelog": "^2.4.0",
     "c8": "^8.0.1",
     "clinic": "^13.0.0",
     "cross-env": "^7.0.3",
-    "esbuild": "^0.19.8",
+    "esbuild": "^0.19.9",
     "esbuild-plugin-clean": "^1.0.1",
     "esbuild-plugin-copy": "^2.1.1",
-    "eslint": "^8.54.0",
-    "eslint-config-prettier": "^9.0.0",
+    "eslint": "^8.55.0",
+    "eslint-config-prettier": "^9.1.0",
     "eslint-import-resolver-typescript": "^3.6.1",
     "eslint-plugin-import": "^2.29.0",
     "eslint-plugin-jsdoc": "^46.9.0",
-    "eslint-plugin-n": "^16.3.1",
+    "eslint-plugin-n": "^16.4.0",
     "eslint-plugin-prettier": "^5.0.1",
     "eslint-plugin-tsdoc": "^0.2.17",
     "expect": "^29.7.0",
     "glob": "^10.3.10",
     "husky": "^8.0.3",
-    "lint-staged": "^15.1.0",
-    "prettier": "^3.1.0",
-    "release-it": "^17.0.0",
+    "lint-staged": "^15.2.0",
+    "prettier": "^3.1.1",
+    "release-it": "^17.0.1",
     "rimraf": "^5.0.5",
     "semver": "^7.5.4",
-    "tsx": "^4.5.0",
-    "typescript": "~5.3.2"
+    "tsx": "^4.6.2",
+    "typescript": "~5.3.3"
   }
 }
index 0c1fd742f27d0e5226f9239456730e355d10178d..b676eca182b92cb8c0117d6749a9846a20f76e86 100644 (file)
@@ -39,8 +39,8 @@ dependencies:
     specifier: ^5.3.0
     version: 5.3.0
   date-fns:
-    specifier: ^2.30.0
-    version: 2.30.0
+    specifier: 3.0.0-rc.2
+    version: 3.0.0-rc.2
   http-status-codes:
     specifier: ^2.3.0
     version: 2.3.0
@@ -51,14 +51,14 @@ dependencies:
     specifier: ^2.6.0
     version: 2.6.0
   mnemonist:
-    specifier: ^0.39.5
-    version: 0.39.5
+    specifier: ^0.39.6
+    version: 0.39.6
   mongodb:
     specifier: ^6.3.0
     version: 6.3.0
   poolifier:
-    specifier: ^3.0.9
-    version: 3.0.9
+    specifier: ^3.0.14
+    version: 3.0.14
   tar:
     specifier: ^6.2.0
     version: 6.2.0
@@ -72,8 +72,8 @@ dependencies:
     specifier: ^4.7.1
     version: 4.7.1(winston@3.11.0)
   ws:
-    specifier: ^8.14.2
-    version: 8.14.2(bufferutil@4.0.8)(utf-8-validate@6.0.3)
+    specifier: ^8.15.1
+    version: 8.15.1(bufferutil@4.0.8)(utf-8-validate@6.0.3)
 
 optionalDependencies:
   bufferutil:
@@ -86,7 +86,7 @@ optionalDependencies:
 devDependencies:
   '@commitlint/cli':
     specifier: ^18.4.3
-    version: 18.4.3(typescript@5.3.2)
+    version: 18.4.3(typescript@5.3.3)
   '@commitlint/config-conventional':
     specifier: ^18.4.3
     version: 18.4.3
@@ -95,10 +95,10 @@ devDependencies:
     version: 5.9.4(@mikro-orm/mariadb@5.9.4)(@mikro-orm/sqlite@5.9.4)
   '@release-it/bumper':
     specifier: ^6.0.1
-    version: 6.0.1(release-it@17.0.0)
+    version: 6.0.1(release-it@17.0.1)
   '@types/node':
-    specifier: ^20.10.0
-    version: 20.10.0
+    specifier: ^20.10.4
+    version: 20.10.4
   '@types/tar':
     specifier: ^6.1.10
     version: 6.1.10
@@ -106,11 +106,11 @@ devDependencies:
     specifier: ^8.5.10
     version: 8.5.10
   '@typescript-eslint/eslint-plugin':
-    specifier: ^6.13.0
-    version: 6.13.0(@typescript-eslint/parser@6.13.0)(eslint@8.54.0)(typescript@5.3.2)
+    specifier: ^6.14.0
+    version: 6.14.0(@typescript-eslint/parser@6.14.0)(eslint@8.55.0)(typescript@5.3.3)
   '@typescript-eslint/parser':
-    specifier: ^6.13.0
-    version: 6.13.0(eslint@8.54.0)(typescript@5.3.2)
+    specifier: ^6.14.0
+    version: 6.14.0(eslint@8.55.0)(typescript@5.3.3)
   auto-changelog:
     specifier: ^2.4.0
     version: 2.4.0
@@ -124,35 +124,35 @@ devDependencies:
     specifier: ^7.0.3
     version: 7.0.3
   esbuild:
-    specifier: ^0.19.8
-    version: 0.19.8
+    specifier: ^0.19.9
+    version: 0.19.9
   esbuild-plugin-clean:
     specifier: ^1.0.1
-    version: 1.0.1(esbuild@0.19.8)
+    version: 1.0.1(esbuild@0.19.9)
   esbuild-plugin-copy:
     specifier: ^2.1.1
-    version: 2.1.1(esbuild@0.19.8)
+    version: 2.1.1(esbuild@0.19.9)
   eslint:
-    specifier: ^8.54.0
-    version: 8.54.0
+    specifier: ^8.55.0
+    version: 8.55.0
   eslint-config-prettier:
-    specifier: ^9.0.0
-    version: 9.0.0(eslint@8.54.0)
+    specifier: ^9.1.0
+    version: 9.1.0(eslint@8.55.0)
   eslint-import-resolver-typescript:
     specifier: ^3.6.1
-    version: 3.6.1(@typescript-eslint/parser@6.13.0)(eslint-plugin-import@2.29.0)(eslint@8.54.0)
+    version: 3.6.1(@typescript-eslint/parser@6.14.0)(eslint-plugin-import@2.29.0)(eslint@8.55.0)
   eslint-plugin-import:
     specifier: ^2.29.0
-    version: 2.29.0(@typescript-eslint/parser@6.13.0)(eslint-import-resolver-typescript@3.6.1)(eslint@8.54.0)
+    version: 2.29.0(@typescript-eslint/parser@6.14.0)(eslint-import-resolver-typescript@3.6.1)(eslint@8.55.0)
   eslint-plugin-jsdoc:
     specifier: ^46.9.0
-    version: 46.9.0(eslint@8.54.0)
+    version: 46.9.0(eslint@8.55.0)
   eslint-plugin-n:
-    specifier: ^16.3.1
-    version: 16.3.1(eslint@8.54.0)
+    specifier: ^16.4.0
+    version: 16.4.0(eslint@8.55.0)
   eslint-plugin-prettier:
     specifier: ^5.0.1
-    version: 5.0.1(eslint-config-prettier@9.0.0)(eslint@8.54.0)(prettier@3.1.0)
+    version: 5.0.1(eslint-config-prettier@9.1.0)(eslint@8.55.0)(prettier@3.1.1)
   eslint-plugin-tsdoc:
     specifier: ^0.2.17
     version: 0.2.17
@@ -166,14 +166,14 @@ devDependencies:
     specifier: ^8.0.3
     version: 8.0.3
   lint-staged:
-    specifier: ^15.1.0
-    version: 15.1.0
+    specifier: ^15.2.0
+    version: 15.2.0
   prettier:
-    specifier: ^3.1.0
-    version: 3.1.0
+    specifier: ^3.1.1
+    version: 3.1.1
   release-it:
-    specifier: ^17.0.0
-    version: 17.0.0(typescript@5.3.2)
+    specifier: ^17.0.1
+    version: 17.0.1(typescript@5.3.3)
   rimraf:
     specifier: ^5.0.5
     version: 5.0.5
@@ -181,11 +181,11 @@ devDependencies:
     specifier: ^7.5.3
     version: 7.5.4
   tsx:
-    specifier: ^4.5.0
-    version: 4.5.0
+    specifier: ^4.6.2
+    version: 4.6.2
   typescript:
-    specifier: ~5.3.2
-    version: 5.3.2
+    specifier: ~5.3.3
+    version: 5.3.3
 
 packages:
 
@@ -235,8 +235,8 @@ packages:
     resolution: {integrity: sha512-ulkCYfFbYj01ie1MDOyxv2F6SpRN1TOj7fQxbP07D6HmeR+gr2JLSmINKjga2emB+b1L2KGrFKBTc+e00p54nw==}
     dev: true
 
-  /@babel/code-frame@7.23.4:
-    resolution: {integrity: sha512-r1IONyb6Ia+jYR2vvIDhdWdlTGhqbBoFqLTQidzZ4kepUFH15ejXvFHxCVbtl7BOXIudsIubf4E81xeA3h3IXA==}
+  /@babel/code-frame@7.23.5:
+    resolution: {integrity: sha512-CgH3s1a96LipHCmSUmYFPwY7MNx8C3avkq7i4Wl3cfa662ldtUe4VM1TPXX70pfmrlWTb6jLqTYrZyT2ZTJBgA==}
     engines: {node: '>=6.9.0'}
     dependencies:
       '@babel/highlight': 7.23.4
@@ -257,13 +257,6 @@ packages:
       js-tokens: 4.0.0
     dev: true
 
-  /@babel/runtime@7.23.4:
-    resolution: {integrity: sha512-2Yv65nlWnWlSpe3fXEyX5i7fx5kIKo4Qbcj+hMO0odwaneFjfXw5fdum+4yL20O0QiaHpia0cYQ9xpNMqrBwHg==}
-    engines: {node: '>=6.9.0'}
-    dependencies:
-      regenerator-runtime: 0.14.0
-    dev: false
-
   /@bcoe/v8-coverage@0.2.3:
     resolution: {integrity: sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==}
     dev: true
@@ -306,8 +299,8 @@ packages:
       chalk: 4.1.2
       lodash.debounce: 4.0.8
       loose-envify: 1.4.0
-      postcss: 8.4.31
-      postcss-import: 13.0.0(postcss@8.4.31)
+      postcss: 8.4.32
+      postcss-import: 13.0.0(postcss@8.4.32)
       stream-template: 0.0.10
       webfontloader: 1.6.28
     dev: true
@@ -377,7 +370,7 @@ packages:
       d3-array: 2.12.1
       d3-fg: 6.14.0
       d3-selection: 1.4.2
-      fs-extra: 11.1.1
+      fs-extra: 11.2.0
       lodash.debounce: 4.0.8
       on-net-listen: 1.1.2
       pump: 3.0.0
@@ -413,14 +406,14 @@ packages:
     engines: {node: '>=0.1.90'}
     dev: false
 
-  /@commitlint/cli@18.4.3(typescript@5.3.2):
+  /@commitlint/cli@18.4.3(typescript@5.3.3):
     resolution: {integrity: sha512-zop98yfB3A6NveYAZ3P1Mb6bIXuCeWgnUfVNkH4yhIMQpQfzFwseadazOuSn0OOfTt0lWuFauehpm9GcqM5lww==}
     engines: {node: '>=v18'}
     hasBin: true
     dependencies:
       '@commitlint/format': 18.4.3
       '@commitlint/lint': 18.4.3
-      '@commitlint/load': 18.4.3(typescript@5.3.2)
+      '@commitlint/load': 18.4.3(typescript@5.3.3)
       '@commitlint/read': 18.4.3
       '@commitlint/types': 18.4.3
       execa: 5.1.1
@@ -490,7 +483,7 @@ packages:
       '@commitlint/types': 18.4.3
     dev: true
 
-  /@commitlint/load@18.4.3(typescript@5.3.2):
+  /@commitlint/load@18.4.3(typescript@5.3.3):
     resolution: {integrity: sha512-v6j2WhvRQJrcJaj5D+EyES2WKTxPpxENmNpNG3Ww8MZGik3jWRXtph0QTzia5ZJyPh2ib5aC/6BIDymkUUM58Q==}
     engines: {node: '>=v18'}
     dependencies:
@@ -498,10 +491,10 @@ packages:
       '@commitlint/execute-rule': 18.4.3
       '@commitlint/resolve-extends': 18.4.3
       '@commitlint/types': 18.4.3
-      '@types/node': 18.18.13
+      '@types/node': 18.19.3
       chalk: 4.1.2
-      cosmiconfig: 8.3.6(typescript@5.3.2)
-      cosmiconfig-typescript-loader: 5.0.0(@types/node@18.18.13)(cosmiconfig@8.3.6)(typescript@5.3.2)
+      cosmiconfig: 8.3.6(typescript@5.3.3)
+      cosmiconfig-typescript-loader: 5.0.0(@types/node@18.19.3)(cosmiconfig@8.3.6)(typescript@5.3.3)
       lodash.isplainobject: 4.0.6
       lodash.merge: 4.6.2
       lodash.uniq: 4.5.0
@@ -530,7 +523,7 @@ packages:
     dependencies:
       '@commitlint/top-level': 18.4.3
       '@commitlint/types': 18.4.3
-      fs-extra: 11.1.1
+      fs-extra: 11.2.0
       git-raw-commits: 2.0.11
       minimist: 1.2.8
     dev: true
@@ -603,8 +596,8 @@ packages:
     dev: true
     optional: true
 
-  /@esbuild/android-arm64@0.19.8:
-    resolution: {integrity: sha512-B8JbS61bEunhfx8kasogFENgQfr/dIp+ggYXwTqdbMAgGDhRa3AaPpQMuQU0rNxDLECj6FhDzk1cF9WHMVwrtA==}
+  /@esbuild/android-arm64@0.19.9:
+    resolution: {integrity: sha512-q4cR+6ZD0938R19MyEW3jEsMzbb/1rulLXiNAJQADD/XYp7pT+rOS5JGxvpRW8dFDEfjW4wLgC/3FXIw4zYglQ==}
     engines: {node: '>=12'}
     cpu: [arm64]
     os: [android]
@@ -621,8 +614,8 @@ packages:
     dev: true
     optional: true
 
-  /@esbuild/android-arm@0.19.8:
-    resolution: {integrity: sha512-31E2lxlGM1KEfivQl8Yf5aYU/mflz9g06H6S15ITUFQueMFtFjESRMoDSkvMo8thYvLBax+VKTPlpnx+sPicOA==}
+  /@esbuild/android-arm@0.19.9:
+    resolution: {integrity: sha512-jkYjjq7SdsWuNI6b5quymW0oC83NN5FdRPuCbs9HZ02mfVdAP8B8eeqLSYU3gb6OJEaY5CQabtTFbqBf26H3GA==}
     engines: {node: '>=12'}
     cpu: [arm]
     os: [android]
@@ -639,8 +632,8 @@ packages:
     dev: true
     optional: true
 
-  /@esbuild/android-x64@0.19.8:
-    resolution: {integrity: sha512-rdqqYfRIn4jWOp+lzQttYMa2Xar3OK9Yt2fhOhzFXqg0rVWEfSclJvZq5fZslnz6ypHvVf3CT7qyf0A5pM682A==}
+  /@esbuild/android-x64@0.19.9:
+    resolution: {integrity: sha512-KOqoPntWAH6ZxDwx1D6mRntIgZh9KodzgNOy5Ebt9ghzffOk9X2c1sPwtM9P+0eXbefnDhqYfkh5PLP5ULtWFA==}
     engines: {node: '>=12'}
     cpu: [x64]
     os: [android]
@@ -657,8 +650,8 @@ packages:
     dev: true
     optional: true
 
-  /@esbuild/darwin-arm64@0.19.8:
-    resolution: {integrity: sha512-RQw9DemMbIq35Bprbboyf8SmOr4UXsRVxJ97LgB55VKKeJOOdvsIPy0nFyF2l8U+h4PtBx/1kRf0BelOYCiQcw==}
+  /@esbuild/darwin-arm64@0.19.9:
+    resolution: {integrity: sha512-KBJ9S0AFyLVx2E5D8W0vExqRW01WqRtczUZ8NRu+Pi+87opZn5tL4Y0xT0mA4FtHctd0ZgwNoN639fUUGlNIWw==}
     engines: {node: '>=12'}
     cpu: [arm64]
     os: [darwin]
@@ -675,8 +668,8 @@ packages:
     dev: true
     optional: true
 
-  /@esbuild/darwin-x64@0.19.8:
-    resolution: {integrity: sha512-3sur80OT9YdeZwIVgERAysAbwncom7b4bCI2XKLjMfPymTud7e/oY4y+ci1XVp5TfQp/bppn7xLw1n/oSQY3/Q==}
+  /@esbuild/darwin-x64@0.19.9:
+    resolution: {integrity: sha512-vE0VotmNTQaTdX0Q9dOHmMTao6ObjyPm58CHZr1UK7qpNleQyxlFlNCaHsHx6Uqv86VgPmR4o2wdNq3dP1qyDQ==}
     engines: {node: '>=12'}
     cpu: [x64]
     os: [darwin]
@@ -693,8 +686,8 @@ packages:
     dev: true
     optional: true
 
-  /@esbuild/freebsd-arm64@0.19.8:
-    resolution: {integrity: sha512-WAnPJSDattvS/XtPCTj1tPoTxERjcTpH6HsMr6ujTT+X6rylVe8ggxk8pVxzf5U1wh5sPODpawNicF5ta/9Tmw==}
+  /@esbuild/freebsd-arm64@0.19.9:
+    resolution: {integrity: sha512-uFQyd/o1IjiEk3rUHSwUKkqZwqdvuD8GevWF065eqgYfexcVkxh+IJgwTaGZVu59XczZGcN/YMh9uF1fWD8j1g==}
     engines: {node: '>=12'}
     cpu: [arm64]
     os: [freebsd]
@@ -711,8 +704,8 @@ packages:
     dev: true
     optional: true
 
-  /@esbuild/freebsd-x64@0.19.8:
-    resolution: {integrity: sha512-ICvZyOplIjmmhjd6mxi+zxSdpPTKFfyPPQMQTK/w+8eNK6WV01AjIztJALDtwNNfFhfZLux0tZLC+U9nSyA5Zg==}
+  /@esbuild/freebsd-x64@0.19.9:
+    resolution: {integrity: sha512-WMLgWAtkdTbTu1AWacY7uoj/YtHthgqrqhf1OaEWnZb7PQgpt8eaA/F3LkV0E6K/Lc0cUr/uaVP/49iE4M4asA==}
     engines: {node: '>=12'}
     cpu: [x64]
     os: [freebsd]
@@ -729,8 +722,8 @@ packages:
     dev: true
     optional: true
 
-  /@esbuild/linux-arm64@0.19.8:
-    resolution: {integrity: sha512-z1zMZivxDLHWnyGOctT9JP70h0beY54xDDDJt4VpTX+iwA77IFsE1vCXWmprajJGa+ZYSqkSbRQ4eyLCpCmiCQ==}
+  /@esbuild/linux-arm64@0.19.9:
+    resolution: {integrity: sha512-PiPblfe1BjK7WDAKR1Cr9O7VVPqVNpwFcPWgfn4xu0eMemzRp442hXyzF/fSwgrufI66FpHOEJk0yYdPInsmyQ==}
     engines: {node: '>=12'}
     cpu: [arm64]
     os: [linux]
@@ -747,8 +740,8 @@ packages:
     dev: true
     optional: true
 
-  /@esbuild/linux-arm@0.19.8:
-    resolution: {integrity: sha512-H4vmI5PYqSvosPaTJuEppU9oz1dq2A7Mr2vyg5TF9Ga+3+MGgBdGzcyBP7qK9MrwFQZlvNyJrvz6GuCaj3OukQ==}
+  /@esbuild/linux-arm@0.19.9:
+    resolution: {integrity: sha512-C/ChPohUYoyUaqn1h17m/6yt6OB14hbXvT8EgM1ZWaiiTYz7nWZR0SYmMnB5BzQA4GXl3BgBO1l8MYqL/He3qw==}
     engines: {node: '>=12'}
     cpu: [arm]
     os: [linux]
@@ -765,8 +758,8 @@ packages:
     dev: true
     optional: true
 
-  /@esbuild/linux-ia32@0.19.8:
-    resolution: {integrity: sha512-1a8suQiFJmZz1khm/rDglOc8lavtzEMRo0v6WhPgxkrjcU0LkHj+TwBrALwoz/OtMExvsqbbMI0ChyelKabSvQ==}
+  /@esbuild/linux-ia32@0.19.9:
+    resolution: {integrity: sha512-f37i/0zE0MjDxijkPSQw1CO/7C27Eojqb+r3BbHVxMLkj8GCa78TrBZzvPyA/FNLUMzP3eyHCVkAopkKVja+6Q==}
     engines: {node: '>=12'}
     cpu: [ia32]
     os: [linux]
@@ -783,8 +776,8 @@ packages:
     dev: true
     optional: true
 
-  /@esbuild/linux-loong64@0.19.8:
-    resolution: {integrity: sha512-fHZWS2JJxnXt1uYJsDv9+b60WCc2RlvVAy1F76qOLtXRO+H4mjt3Tr6MJ5l7Q78X8KgCFudnTuiQRBhULUyBKQ==}
+  /@esbuild/linux-loong64@0.19.9:
+    resolution: {integrity: sha512-t6mN147pUIf3t6wUt3FeumoOTPfmv9Cc6DQlsVBpB7eCpLOqQDyWBP1ymXn1lDw4fNUSb/gBcKAmvTP49oIkaA==}
     engines: {node: '>=12'}
     cpu: [loong64]
     os: [linux]
@@ -801,8 +794,8 @@ packages:
     dev: true
     optional: true
 
-  /@esbuild/linux-mips64el@0.19.8:
-    resolution: {integrity: sha512-Wy/z0EL5qZYLX66dVnEg9riiwls5IYnziwuju2oUiuxVc+/edvqXa04qNtbrs0Ukatg5HEzqT94Zs7J207dN5Q==}
+  /@esbuild/linux-mips64el@0.19.9:
+    resolution: {integrity: sha512-jg9fujJTNTQBuDXdmAg1eeJUL4Jds7BklOTkkH80ZgQIoCTdQrDaHYgbFZyeTq8zbY+axgptncko3v9p5hLZtw==}
     engines: {node: '>=12'}
     cpu: [mips64el]
     os: [linux]
@@ -819,8 +812,8 @@ packages:
     dev: true
     optional: true
 
-  /@esbuild/linux-ppc64@0.19.8:
-    resolution: {integrity: sha512-ETaW6245wK23YIEufhMQ3HSeHO7NgsLx8gygBVldRHKhOlD1oNeNy/P67mIh1zPn2Hr2HLieQrt6tWrVwuqrxg==}
+  /@esbuild/linux-ppc64@0.19.9:
+    resolution: {integrity: sha512-tkV0xUX0pUUgY4ha7z5BbDS85uI7ABw3V1d0RNTii7E9lbmV8Z37Pup2tsLV46SQWzjOeyDi1Q7Wx2+QM8WaCQ==}
     engines: {node: '>=12'}
     cpu: [ppc64]
     os: [linux]
@@ -837,8 +830,8 @@ packages:
     dev: true
     optional: true
 
-  /@esbuild/linux-riscv64@0.19.8:
-    resolution: {integrity: sha512-T2DRQk55SgoleTP+DtPlMrxi/5r9AeFgkhkZ/B0ap99zmxtxdOixOMI570VjdRCs9pE4Wdkz7JYrsPvsl7eESg==}
+  /@esbuild/linux-riscv64@0.19.9:
+    resolution: {integrity: sha512-DfLp8dj91cufgPZDXr9p3FoR++m3ZJ6uIXsXrIvJdOjXVREtXuQCjfMfvmc3LScAVmLjcfloyVtpn43D56JFHg==}
     engines: {node: '>=12'}
     cpu: [riscv64]
     os: [linux]
@@ -855,8 +848,8 @@ packages:
     dev: true
     optional: true
 
-  /@esbuild/linux-s390x@0.19.8:
-    resolution: {integrity: sha512-NPxbdmmo3Bk7mbNeHmcCd7R7fptJaczPYBaELk6NcXxy7HLNyWwCyDJ/Xx+/YcNH7Im5dHdx9gZ5xIwyliQCbg==}
+  /@esbuild/linux-s390x@0.19.9:
+    resolution: {integrity: sha512-zHbglfEdC88KMgCWpOl/zc6dDYJvWGLiUtmPRsr1OgCViu3z5GncvNVdf+6/56O2Ca8jUU+t1BW261V6kp8qdw==}
     engines: {node: '>=12'}
     cpu: [s390x]
     os: [linux]
@@ -873,8 +866,8 @@ packages:
     dev: true
     optional: true
 
-  /@esbuild/linux-x64@0.19.8:
-    resolution: {integrity: sha512-lytMAVOM3b1gPypL2TRmZ5rnXl7+6IIk8uB3eLsV1JwcizuolblXRrc5ShPrO9ls/b+RTp+E6gbsuLWHWi2zGg==}
+  /@esbuild/linux-x64@0.19.9:
+    resolution: {integrity: sha512-JUjpystGFFmNrEHQnIVG8hKwvA2DN5o7RqiO1CVX8EN/F/gkCjkUMgVn6hzScpwnJtl2mPR6I9XV1oW8k9O+0A==}
     engines: {node: '>=12'}
     cpu: [x64]
     os: [linux]
@@ -891,8 +884,8 @@ packages:
     dev: true
     optional: true
 
-  /@esbuild/netbsd-x64@0.19.8:
-    resolution: {integrity: sha512-hvWVo2VsXz/8NVt1UhLzxwAfo5sioj92uo0bCfLibB0xlOmimU/DeAEsQILlBQvkhrGjamP0/el5HU76HAitGw==}
+  /@esbuild/netbsd-x64@0.19.9:
+    resolution: {integrity: sha512-GThgZPAwOBOsheA2RUlW5UeroRfESwMq/guy8uEe3wJlAOjpOXuSevLRd70NZ37ZrpO6RHGHgEHvPg1h3S1Jug==}
     engines: {node: '>=12'}
     cpu: [x64]
     os: [netbsd]
@@ -909,8 +902,8 @@ packages:
     dev: true
     optional: true
 
-  /@esbuild/openbsd-x64@0.19.8:
-    resolution: {integrity: sha512-/7Y7u77rdvmGTxR83PgaSvSBJCC2L3Kb1M/+dmSIvRvQPXXCuC97QAwMugBNG0yGcbEGfFBH7ojPzAOxfGNkwQ==}
+  /@esbuild/openbsd-x64@0.19.9:
+    resolution: {integrity: sha512-Ki6PlzppaFVbLnD8PtlVQfsYw4S9n3eQl87cqgeIw+O3sRr9IghpfSKY62mggdt1yCSZ8QWvTZ9jo9fjDSg9uw==}
     engines: {node: '>=12'}
     cpu: [x64]
     os: [openbsd]
@@ -927,8 +920,8 @@ packages:
     dev: true
     optional: true
 
-  /@esbuild/sunos-x64@0.19.8:
-    resolution: {integrity: sha512-9Lc4s7Oi98GqFA4HzA/W2JHIYfnXbUYgekUP/Sm4BG9sfLjyv6GKKHKKVs83SMicBF2JwAX6A1PuOLMqpD001w==}
+  /@esbuild/sunos-x64@0.19.9:
+    resolution: {integrity: sha512-MLHj7k9hWh4y1ddkBpvRj2b9NCBhfgBt3VpWbHQnXRedVun/hC7sIyTGDGTfsGuXo4ebik2+3ShjcPbhtFwWDw==}
     engines: {node: '>=12'}
     cpu: [x64]
     os: [sunos]
@@ -945,8 +938,8 @@ packages:
     dev: true
     optional: true
 
-  /@esbuild/win32-arm64@0.19.8:
-    resolution: {integrity: sha512-rq6WzBGjSzihI9deW3fC2Gqiak68+b7qo5/3kmB6Gvbh/NYPA0sJhrnp7wgV4bNwjqM+R2AApXGxMO7ZoGhIJg==}
+  /@esbuild/win32-arm64@0.19.9:
+    resolution: {integrity: sha512-GQoa6OrQ8G08guMFgeXPH7yE/8Dt0IfOGWJSfSH4uafwdC7rWwrfE6P9N8AtPGIjUzdo2+7bN8Xo3qC578olhg==}
     engines: {node: '>=12'}
     cpu: [arm64]
     os: [win32]
@@ -963,8 +956,8 @@ packages:
     dev: true
     optional: true
 
-  /@esbuild/win32-ia32@0.19.8:
-    resolution: {integrity: sha512-AIAbverbg5jMvJznYiGhrd3sumfwWs8572mIJL5NQjJa06P8KfCPWZQ0NwZbPQnbQi9OWSZhFVSUWjjIrn4hSw==}
+  /@esbuild/win32-ia32@0.19.9:
+    resolution: {integrity: sha512-UOozV7Ntykvr5tSOlGCrqU3NBr3d8JqPes0QWN2WOXfvkWVGRajC+Ym0/Wj88fUgecUCLDdJPDF0Nna2UK3Qtg==}
     engines: {node: '>=12'}
     cpu: [ia32]
     os: [win32]
@@ -981,8 +974,8 @@ packages:
     dev: true
     optional: true
 
-  /@esbuild/win32-x64@0.19.8:
-    resolution: {integrity: sha512-bfZ0cQ1uZs2PqpulNL5j/3w+GDhP36k1K5c38QdQg+Swy51jFZWWeIkteNsufkQxp986wnqRRsb/bHbY1WQ7TA==}
+  /@esbuild/win32-x64@0.19.9:
+    resolution: {integrity: sha512-oxoQgglOP7RH6iasDrhY+R/3cHrfwIDvRlT4CGChflq6twk8iENeVvMJjmvBb94Ik1Z+93iGO27err7w6l54GQ==}
     engines: {node: '>=12'}
     cpu: [x64]
     os: [win32]
@@ -990,13 +983,13 @@ packages:
     dev: true
     optional: true
 
-  /@eslint-community/eslint-utils@4.4.0(eslint@8.54.0):
+  /@eslint-community/eslint-utils@4.4.0(eslint@8.55.0):
     resolution: {integrity: sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==}
     engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
     peerDependencies:
       eslint: ^6.0.0 || ^7.0.0 || >=8.0.0
     dependencies:
-      eslint: 8.54.0
+      eslint: 8.55.0
       eslint-visitor-keys: 3.4.3
     dev: true
 
@@ -1005,14 +998,14 @@ packages:
     engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0}
     dev: true
 
-  /@eslint/eslintrc@2.1.3:
-    resolution: {integrity: sha512-yZzuIG+jnVu6hNSzFEN07e8BxF3uAzYtQb6uDkaYZLo6oYZDCq454c5kB8zxnzfCYyP4MIuyBn10L0DqwujTmA==}
+  /@eslint/eslintrc@2.1.4:
+    resolution: {integrity: sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==}
     engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
     dependencies:
       ajv: 6.12.6
       debug: 4.3.4
       espree: 9.6.1
-      globals: 13.23.0
+      globals: 13.24.0
       ignore: 5.3.0
       import-fresh: 3.3.0
       js-yaml: 4.1.0
@@ -1022,8 +1015,8 @@ packages:
       - supports-color
     dev: true
 
-  /@eslint/js@8.54.0:
-    resolution: {integrity: sha512-ut5V+D+fOoWPgGGNj83GGjnntO39xDy6DWxO0wb7Jp3DcMX0TfIqdzHF85VTQkerdyGmuuMD9AKAo5KiNlf/AQ==}
+  /@eslint/js@8.55.0:
+    resolution: {integrity: sha512-qQfo2mxH5yVom1kacMtZZJFVdW+E70mqHMJvVg6WTLo+VBuQJ4TojZlfWBjK0ve5BdEeNAVxOsl/nvNMpJOaJA==}
     engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
     dev: true
 
@@ -1102,7 +1095,7 @@ packages:
       '@jest/schemas': 29.6.3
       '@types/istanbul-lib-coverage': 2.0.6
       '@types/istanbul-reports': 3.0.4
-      '@types/node': 20.10.0
+      '@types/node': 20.10.4
       '@types/yargs': 17.0.32
       chalk: 4.1.2
     dev: true
@@ -1442,16 +1435,16 @@ packages:
       '@octokit/graphql': 7.0.2
       '@octokit/request': 8.1.6
       '@octokit/request-error': 5.0.1
-      '@octokit/types': 12.3.0
+      '@octokit/types': 12.4.0
       before-after-hook: 2.2.3
       universal-user-agent: 6.0.1
     dev: true
 
-  /@octokit/endpoint@9.0.3:
-    resolution: {integrity: sha512-TXVX57fJV7SA6LvRkeXPIOBr8AKvKDlhwNVBP/26O9DjIFi+CkYZGFLP9WtPdVOicRIhqGHxBCC6Fdj5AWWGgQ==}
+  /@octokit/endpoint@9.0.4:
+    resolution: {integrity: sha512-DWPLtr1Kz3tv8L0UvXTDP1fNwM0S+z6EJpRcvH66orY6Eld4XBMCSYsaWp4xIm61jTWxK68BrR7ibO+vSDnZqw==}
     engines: {node: '>= 18'}
     dependencies:
-      '@octokit/types': 12.3.0
+      '@octokit/types': 12.4.0
       universal-user-agent: 6.0.1
     dev: true
 
@@ -1460,22 +1453,22 @@ packages:
     engines: {node: '>= 18'}
     dependencies:
       '@octokit/request': 8.1.6
-      '@octokit/types': 12.3.0
+      '@octokit/types': 12.4.0
       universal-user-agent: 6.0.1
     dev: true
 
-  /@octokit/openapi-types@19.0.2:
-    resolution: {integrity: sha512-8li32fUDUeml/ACRp/njCWTsk5t17cfTM1jp9n08pBrqs5cDFJubtjsSnuz56r5Tad6jdEPJld7LxNp9dNcyjQ==}
+  /@octokit/openapi-types@19.1.0:
+    resolution: {integrity: sha512-6G+ywGClliGQwRsjvqVYpklIfa7oRPA0vyhPQG/1Feh+B+wU0vGH1JiJ5T25d3g1JZYBHzR2qefLi9x8Gt+cpw==}
     dev: true
 
-  /@octokit/plugin-paginate-rest@9.1.4(@octokit/core@5.0.2):
-    resolution: {integrity: sha512-MvZx4WvfhBnt7PtH5XE7HORsO7bBk4er1FgRIUr1qJ89NR2I6bWjGyKsxk8z42FPQ34hFQm0Baanh4gzdZR4gQ==}
+  /@octokit/plugin-paginate-rest@9.1.5(@octokit/core@5.0.2):
+    resolution: {integrity: sha512-WKTQXxK+bu49qzwv4qKbMMRXej1DU2gq017euWyKVudA6MldaSSQuxtz+vGbhxV4CjxpUxjZu6rM2wfc1FiWVg==}
     engines: {node: '>= 18'}
     peerDependencies:
       '@octokit/core': '>=5'
     dependencies:
       '@octokit/core': 5.0.2
-      '@octokit/types': 12.3.0
+      '@octokit/types': 12.4.0
     dev: true
 
   /@octokit/plugin-request-log@4.0.0(@octokit/core@5.0.2):
@@ -1487,21 +1480,21 @@ packages:
       '@octokit/core': 5.0.2
     dev: true
 
-  /@octokit/plugin-rest-endpoint-methods@10.1.5(@octokit/core@5.0.2):
-    resolution: {integrity: sha512-LMEdsMV8TTMjMTqVoqMzV95XTbv0ZsWxCxQtjAunQOCdwoDH4BVF/Ke5JMSZEVCWGI2kzxnUNbFnK/MxwV7NjA==}
+  /@octokit/plugin-rest-endpoint-methods@10.2.0(@octokit/core@5.0.2):
+    resolution: {integrity: sha512-ePbgBMYtGoRNXDyKGvr9cyHjQ163PbwD0y1MkDJCpkO2YH4OeXX40c4wYHKikHGZcpGPbcRLuy0unPUuafco8Q==}
     engines: {node: '>= 18'}
     peerDependencies:
       '@octokit/core': '>=5'
     dependencies:
       '@octokit/core': 5.0.2
-      '@octokit/types': 12.3.0
+      '@octokit/types': 12.4.0
     dev: true
 
   /@octokit/request-error@5.0.1:
     resolution: {integrity: sha512-X7pnyTMV7MgtGmiXBwmO6M5kIPrntOXdyKZLigNfQWSEQzVxR4a4vo49vJjTWX70mPndj8KhfT4Dx+2Ng3vnBQ==}
     engines: {node: '>= 18'}
     dependencies:
-      '@octokit/types': 12.3.0
+      '@octokit/types': 12.4.0
       deprecation: 2.3.1
       once: 1.4.0
     dev: true
@@ -1510,9 +1503,9 @@ packages:
     resolution: {integrity: sha512-YhPaGml3ncZC1NfXpP3WZ7iliL1ap6tLkAp6MvbK2fTTPytzVUyUesBBogcdMm86uRYO5rHaM1xIWxigWZ17MQ==}
     engines: {node: '>= 18'}
     dependencies:
-      '@octokit/endpoint': 9.0.3
+      '@octokit/endpoint': 9.0.4
       '@octokit/request-error': 5.0.1
-      '@octokit/types': 12.3.0
+      '@octokit/types': 12.4.0
       universal-user-agent: 6.0.1
     dev: true
 
@@ -1521,15 +1514,15 @@ packages:
     engines: {node: '>= 18'}
     dependencies:
       '@octokit/core': 5.0.2
-      '@octokit/plugin-paginate-rest': 9.1.4(@octokit/core@5.0.2)
+      '@octokit/plugin-paginate-rest': 9.1.5(@octokit/core@5.0.2)
       '@octokit/plugin-request-log': 4.0.0(@octokit/core@5.0.2)
-      '@octokit/plugin-rest-endpoint-methods': 10.1.5(@octokit/core@5.0.2)
+      '@octokit/plugin-rest-endpoint-methods': 10.2.0(@octokit/core@5.0.2)
     dev: true
 
-  /@octokit/types@12.3.0:
-    resolution: {integrity: sha512-nJ8X2HRr234q3w/FcovDlA+ttUU4m1eJAourvfUUtwAWeqL8AsyRqfnLvVnYn3NFbUnsmzQCzLNdFerPwdmcDQ==}
+  /@octokit/types@12.4.0:
+    resolution: {integrity: sha512-FLWs/AvZllw/AGVs+nJ+ELCDZZJk+kY0zMen118xhL2zD0s1etIUHm1odgjP7epxYU1ln7SZxEUWYop5bhsdgQ==}
     dependencies:
-      '@octokit/openapi-types': 19.0.2
+      '@octokit/openapi-types': 19.1.0
     dev: true
 
   /@pkgjs/parseargs@0.11.0:
@@ -1572,7 +1565,7 @@ packages:
       config-chain: 1.1.13
     dev: true
 
-  /@release-it/bumper@6.0.1(release-it@17.0.0):
+  /@release-it/bumper@6.0.1(release-it@17.0.1):
     resolution: {integrity: sha512-yeQsbGNMzzN0c/5JV1awXP6UHX/kJamXCKR6/daS0YQfj98SZXAcLn3JEq+qfK/Jq/cnATnlz5r6UY0cfBkm1A==}
     engines: {node: '>=18'}
     peerDependencies:
@@ -1584,7 +1577,7 @@ packages:
       ini: 4.1.1
       js-yaml: 4.1.0
       lodash-es: 4.17.21
-      release-it: 17.0.0(typescript@5.3.2)
+      release-it: 17.0.1(typescript@5.3.3)
       semver: 7.5.4
     dev: true
 
@@ -1697,14 +1690,14 @@ packages:
   /@types/node@17.0.45:
     resolution: {integrity: sha512-w+tIMs3rq2afQdsPJlODhoUEKzFP1ayaoyl1CcnwtIlsVe7K7bA1NGm4s3PraqTLlXnbIN84zuBlxBWo1u9BLw==}
 
-  /@types/node@18.18.13:
-    resolution: {integrity: sha512-vXYZGRrSCreZmq1rEjMRLXJhiy8MrIeVasx+PCVlP414N7CJLHnMf+juVvjdprHyH+XRy3zKZLHeNueOpJCn0g==}
+  /@types/node@18.19.3:
+    resolution: {integrity: sha512-k5fggr14DwAytoA/t8rPrIz++lXK7/DqckthCmoZOKNsEbJkId4Z//BqgApXBUGrGddrigYa1oqheo/7YmW4rg==}
     dependencies:
       undici-types: 5.26.5
     dev: true
 
-  /@types/node@20.10.0:
-    resolution: {integrity: sha512-D0WfRmU9TQ8I9PFx9Yc+EBHw+vSpIub4IDvQivcp26PtPrdMGAq5SDcpXEo/epqa/DXotVpekHiLNTg3iaKXBQ==}
+  /@types/node@20.10.4:
+    resolution: {integrity: sha512-D08YG6rr8X90YB56tSIuBaddy/UXAA9RKJoFvrsnogAum/0pmjkgi4+2nx96A330FmioegBWmEYQ+syqCFaveg==}
     dependencies:
       undici-types: 5.26.5
     dev: true
@@ -1732,7 +1725,7 @@ packages:
   /@types/tar@6.1.10:
     resolution: {integrity: sha512-60ZO+W0tRKJ3ggdzJKp75xKVlNogKYMqGvr2bMH/+k3T0BagfYTnbmVDFMJB1BFttz6yRgP5MDGP27eh7brrqw==}
     dependencies:
-      '@types/node': 20.10.0
+      '@types/node': 20.10.4
       minipass: 4.2.8
     dev: true
 
@@ -1757,7 +1750,7 @@ packages:
   /@types/ws@8.5.10:
     resolution: {integrity: sha512-vmQSUcfalpIq0R9q7uTo2lXs6eGIpt9wtnLdMv9LVpIjCA/+ufZRozlVoVelIYixx1ugCBKDhn89vnsEGOCx9A==}
     dependencies:
-      '@types/node': 20.10.0
+      '@types/node': 20.10.4
     dev: true
 
   /@types/yargs-parser@21.0.3:
@@ -1770,8 +1763,8 @@ packages:
       '@types/yargs-parser': 21.0.3
     dev: true
 
-  /@typescript-eslint/eslint-plugin@6.13.0(@typescript-eslint/parser@6.13.0)(eslint@8.54.0)(typescript@5.3.2):
-    resolution: {integrity: sha512-HTvbSd0JceI2GW5DHS3R9zbarOqjkM9XDR7zL8eCsBUO/eSiHcoNE7kSL5sjGXmVa9fjH5LCfHDXNnH4QLp7tQ==}
+  /@typescript-eslint/eslint-plugin@6.14.0(@typescript-eslint/parser@6.14.0)(eslint@8.55.0)(typescript@5.3.3):
+    resolution: {integrity: sha512-1ZJBykBCXaSHG94vMMKmiHoL0MhNHKSVlcHVYZNw+BKxufhqQVTOawNpwwI1P5nIFZ/4jLVop0mcY6mJJDFNaw==}
     engines: {node: ^16.0.0 || >=18.0.0}
     peerDependencies:
       '@typescript-eslint/parser': ^6.0.0 || ^6.0.0-alpha
@@ -1782,25 +1775,25 @@ packages:
         optional: true
     dependencies:
       '@eslint-community/regexpp': 4.10.0
-      '@typescript-eslint/parser': 6.13.0(eslint@8.54.0)(typescript@5.3.2)
-      '@typescript-eslint/scope-manager': 6.13.0
-      '@typescript-eslint/type-utils': 6.13.0(eslint@8.54.0)(typescript@5.3.2)
-      '@typescript-eslint/utils': 6.13.0(eslint@8.54.0)(typescript@5.3.2)
-      '@typescript-eslint/visitor-keys': 6.13.0
+      '@typescript-eslint/parser': 6.14.0(eslint@8.55.0)(typescript@5.3.3)
+      '@typescript-eslint/scope-manager': 6.14.0
+      '@typescript-eslint/type-utils': 6.14.0(eslint@8.55.0)(typescript@5.3.3)
+      '@typescript-eslint/utils': 6.14.0(eslint@8.55.0)(typescript@5.3.3)
+      '@typescript-eslint/visitor-keys': 6.14.0
       debug: 4.3.4
-      eslint: 8.54.0
+      eslint: 8.55.0
       graphemer: 1.4.0
       ignore: 5.3.0
       natural-compare: 1.4.0
       semver: 7.5.4
-      ts-api-utils: 1.0.3(typescript@5.3.2)
-      typescript: 5.3.2
+      ts-api-utils: 1.0.3(typescript@5.3.3)
+      typescript: 5.3.3
     transitivePeerDependencies:
       - supports-color
     dev: true
 
-  /@typescript-eslint/parser@6.13.0(eslint@8.54.0)(typescript@5.3.2):
-    resolution: {integrity: sha512-VpG+M7GNhHLI/aTDctqAV0XbzB16vf+qDX9DXuMZSe/0bahzDA9AKZB15NDbd+D9M4cDsJvfkbGOA7qiZ/bWJw==}
+  /@typescript-eslint/parser@6.14.0(eslint@8.55.0)(typescript@5.3.3):
+    resolution: {integrity: sha512-QjToC14CKacd4Pa7JK4GeB/vHmWFJckec49FR4hmIRf97+KXole0T97xxu9IFiPxVQ1DBWrQ5wreLwAGwWAVQA==}
     engines: {node: ^16.0.0 || >=18.0.0}
     peerDependencies:
       eslint: ^7.0.0 || ^8.0.0
@@ -1809,27 +1802,27 @@ packages:
       typescript:
         optional: true
     dependencies:
-      '@typescript-eslint/scope-manager': 6.13.0
-      '@typescript-eslint/types': 6.13.0
-      '@typescript-eslint/typescript-estree': 6.13.0(typescript@5.3.2)
-      '@typescript-eslint/visitor-keys': 6.13.0
+      '@typescript-eslint/scope-manager': 6.14.0
+      '@typescript-eslint/types': 6.14.0
+      '@typescript-eslint/typescript-estree': 6.14.0(typescript@5.3.3)
+      '@typescript-eslint/visitor-keys': 6.14.0
       debug: 4.3.4
-      eslint: 8.54.0
-      typescript: 5.3.2
+      eslint: 8.55.0
+      typescript: 5.3.3
     transitivePeerDependencies:
       - supports-color
     dev: true
 
-  /@typescript-eslint/scope-manager@6.13.0:
-    resolution: {integrity: sha512-2x0K2/CujsokIv+LN2T0l5FVDMtsCjkUyYtlcY4xxnxLAW+x41LXr16duoicHpGtLhmtN7kqvuFJ3zbz00Ikhw==}
+  /@typescript-eslint/scope-manager@6.14.0:
+    resolution: {integrity: sha512-VT7CFWHbZipPncAZtuALr9y3EuzY1b1t1AEkIq2bTXUPKw+pHoXflGNG5L+Gv6nKul1cz1VH8fz16IThIU0tdg==}
     engines: {node: ^16.0.0 || >=18.0.0}
     dependencies:
-      '@typescript-eslint/types': 6.13.0
-      '@typescript-eslint/visitor-keys': 6.13.0
+      '@typescript-eslint/types': 6.14.0
+      '@typescript-eslint/visitor-keys': 6.14.0
     dev: true
 
-  /@typescript-eslint/type-utils@6.13.0(eslint@8.54.0)(typescript@5.3.2):
-    resolution: {integrity: sha512-YHufAmZd/yP2XdoD3YeFEjq+/Tl+myhzv+GJHSOz+ro/NFGS84mIIuLU3pVwUcauSmwlCrVXbBclkn1HfjY0qQ==}
+  /@typescript-eslint/type-utils@6.14.0(eslint@8.55.0)(typescript@5.3.3):
+    resolution: {integrity: sha512-x6OC9Q7HfYKqjnuNu5a7kffIYs3No30isapRBJl1iCHLitD8O0lFbRcVGiOcuyN837fqXzPZ1NS10maQzZMKqw==}
     engines: {node: ^16.0.0 || >=18.0.0}
     peerDependencies:
       eslint: ^7.0.0 || ^8.0.0
@@ -1838,23 +1831,23 @@ packages:
       typescript:
         optional: true
     dependencies:
-      '@typescript-eslint/typescript-estree': 6.13.0(typescript@5.3.2)
-      '@typescript-eslint/utils': 6.13.0(eslint@8.54.0)(typescript@5.3.2)
+      '@typescript-eslint/typescript-estree': 6.14.0(typescript@5.3.3)
+      '@typescript-eslint/utils': 6.14.0(eslint@8.55.0)(typescript@5.3.3)
       debug: 4.3.4
-      eslint: 8.54.0
-      ts-api-utils: 1.0.3(typescript@5.3.2)
-      typescript: 5.3.2
+      eslint: 8.55.0
+      ts-api-utils: 1.0.3(typescript@5.3.3)
+      typescript: 5.3.3
     transitivePeerDependencies:
       - supports-color
     dev: true
 
-  /@typescript-eslint/types@6.13.0:
-    resolution: {integrity: sha512-oXg7DFxx/GmTrKXKKLSoR2rwiutOC7jCQ5nDH5p5VS6cmHE1TcPTaYQ0VPSSUvj7BnNqCgQ/NXcTBxn59pfPTQ==}
+  /@typescript-eslint/types@6.14.0:
+    resolution: {integrity: sha512-uty9H2K4Xs8E47z3SnXEPRNDfsis8JO27amp2GNCnzGETEW3yTqEIVg5+AI7U276oGF/tw6ZA+UesxeQ104ceA==}
     engines: {node: ^16.0.0 || >=18.0.0}
     dev: true
 
-  /@typescript-eslint/typescript-estree@6.13.0(typescript@5.3.2):
-    resolution: {integrity: sha512-IT4O/YKJDoiy/mPEDsfOfp+473A9GVqXlBKckfrAOuVbTqM8xbc0LuqyFCcgeFWpqu3WjQexolgqN2CuWBYbog==}
+  /@typescript-eslint/typescript-estree@6.14.0(typescript@5.3.3):
+    resolution: {integrity: sha512-yPkaLwK0yH2mZKFE/bXkPAkkFgOv15GJAUzgUVonAbv0Hr4PK/N2yaA/4XQbTZQdygiDkpt5DkxPELqHguNvyw==}
     engines: {node: ^16.0.0 || >=18.0.0}
     peerDependencies:
       typescript: '*'
@@ -1862,42 +1855,42 @@ packages:
       typescript:
         optional: true
     dependencies:
-      '@typescript-eslint/types': 6.13.0
-      '@typescript-eslint/visitor-keys': 6.13.0
+      '@typescript-eslint/types': 6.14.0
+      '@typescript-eslint/visitor-keys': 6.14.0
       debug: 4.3.4
       globby: 11.1.0
       is-glob: 4.0.3
       semver: 7.5.4
-      ts-api-utils: 1.0.3(typescript@5.3.2)
-      typescript: 5.3.2
+      ts-api-utils: 1.0.3(typescript@5.3.3)
+      typescript: 5.3.3
     transitivePeerDependencies:
       - supports-color
     dev: true
 
-  /@typescript-eslint/utils@6.13.0(eslint@8.54.0)(typescript@5.3.2):
-    resolution: {integrity: sha512-V+txaxARI8yznDkcQ6FNRXxG+T37qT3+2NsDTZ/nKLxv6VfGrRhTnuvxPUxpVuWWr+eVeIxU53PioOXbz8ratQ==}
+  /@typescript-eslint/utils@6.14.0(eslint@8.55.0)(typescript@5.3.3):
+    resolution: {integrity: sha512-XwRTnbvRr7Ey9a1NT6jqdKX8y/atWG+8fAIu3z73HSP8h06i3r/ClMhmaF/RGWGW1tHJEwij1uEg2GbEmPYvYg==}
     engines: {node: ^16.0.0 || >=18.0.0}
     peerDependencies:
       eslint: ^7.0.0 || ^8.0.0
     dependencies:
-      '@eslint-community/eslint-utils': 4.4.0(eslint@8.54.0)
+      '@eslint-community/eslint-utils': 4.4.0(eslint@8.55.0)
       '@types/json-schema': 7.0.15
       '@types/semver': 7.5.6
-      '@typescript-eslint/scope-manager': 6.13.0
-      '@typescript-eslint/types': 6.13.0
-      '@typescript-eslint/typescript-estree': 6.13.0(typescript@5.3.2)
-      eslint: 8.54.0
+      '@typescript-eslint/scope-manager': 6.14.0
+      '@typescript-eslint/types': 6.14.0
+      '@typescript-eslint/typescript-estree': 6.14.0(typescript@5.3.3)
+      eslint: 8.55.0
       semver: 7.5.4
     transitivePeerDependencies:
       - supports-color
       - typescript
     dev: true
 
-  /@typescript-eslint/visitor-keys@6.13.0:
-    resolution: {integrity: sha512-UQklteCEMCRoq/1UhKFZsHv5E4dN1wQSzJoxTfABasWk1HgJRdg1xNUve/Kv/Sdymt4x+iEzpESOqRFlQr/9Aw==}
+  /@typescript-eslint/visitor-keys@6.14.0:
+    resolution: {integrity: sha512-fB5cw6GRhJUz03MrROVuj5Zm/Q+XWlVdIsFj+Zb1Hvqouc8t+XP2H5y53QYU/MGtd2dPg6/vJJlhoX3xc2ehfw==}
     engines: {node: ^16.0.0 || >=18.0.0}
     dependencies:
-      '@typescript-eslint/types': 6.13.0
+      '@typescript-eslint/types': 6.14.0
       eslint-visitor-keys: 3.4.3
     dev: true
 
@@ -2047,11 +2040,11 @@ packages:
       type-fest: 0.21.3
     dev: true
 
-  /ansi-escapes@5.0.0:
-    resolution: {integrity: sha512-5GFMVX8HqE/TB+FuBJGuO5XG0WrsA6ptUqoODaT/n9mmUaZFkqnBueB4leqGBCmrUHnCnC4PCZTCd0E7QQ83bA==}
-    engines: {node: '>=12'}
+  /ansi-escapes@6.2.0:
+    resolution: {integrity: sha512-kzRaCqXnpzWs+3z5ABPQiVke+iq0KXkHo8xiWV4RPTi5Yli0l97BEQuhXV1s7+aSU/fu1kUuxgS4MsQ0fRuygw==}
+    engines: {node: '>=14.16'}
     dependencies:
-      type-fest: 1.4.0
+      type-fest: 3.13.1
     dev: true
 
   /ansi-regex@2.1.1:
@@ -2265,7 +2258,7 @@ packages:
   /assert@1.5.1:
     resolution: {integrity: sha512-zzw1uCAgLbsKwBfFc8CX78DDg+xZeBksSO3vwVIDDN5i94eOrPsSSyiVhmsSABFDM/OcpE2aagCat9dnWQLG1A==}
     dependencies:
-      object.assign: 4.1.4
+      object.assign: 4.1.5
       util: 0.10.4
     dev: true
 
@@ -2938,12 +2931,12 @@ packages:
       '@colors/colors': 1.5.0
     dev: true
 
-  /cli-truncate@3.1.0:
-    resolution: {integrity: sha512-wfOBkjXteqSnI59oPcJkcPl/ZmwvMMOj340qUIY1SKZCv0B9Cf4D4fAucRkIKQmsIuYK3x1rrgU7MeGRruiuiA==}
-    engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
+  /cli-truncate@4.0.0:
+    resolution: {integrity: sha512-nPdaFdQ0h/GEigbPClz11D0v/ZJEwxmeVZGeMo3Z5StPtUTkA9o1lD6QwoirYiSDzbcwn2XcjwmCp68W1IS4TA==}
+    engines: {node: '>=18'}
     dependencies:
       slice-ansi: 5.0.0
-      string-width: 5.1.2
+      string-width: 7.0.0
     dev: true
 
   /cli-width@2.2.1:
@@ -3254,7 +3247,7 @@ packages:
     resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==}
     dev: true
 
-  /cosmiconfig-typescript-loader@5.0.0(@types/node@18.18.13)(cosmiconfig@8.3.6)(typescript@5.3.2):
+  /cosmiconfig-typescript-loader@5.0.0(@types/node@18.19.3)(cosmiconfig@8.3.6)(typescript@5.3.3):
     resolution: {integrity: sha512-+8cK7jRAReYkMwMiG+bxhcNKiHJDM6bR9FD/nGBXOWdMLuYawjF5cGrtLilJ+LGd3ZjCXnJjR5DkfWPoIVlqJA==}
     engines: {node: '>=v16'}
     peerDependencies:
@@ -3262,13 +3255,13 @@ packages:
       cosmiconfig: '>=8.2'
       typescript: '>=4'
     dependencies:
-      '@types/node': 18.18.13
-      cosmiconfig: 8.3.6(typescript@5.3.2)
+      '@types/node': 18.19.3
+      cosmiconfig: 8.3.6(typescript@5.3.3)
       jiti: 1.21.0
-      typescript: 5.3.2
+      typescript: 5.3.3
     dev: true
 
-  /cosmiconfig@8.3.6(typescript@5.3.2):
+  /cosmiconfig@8.3.6(typescript@5.3.3):
     resolution: {integrity: sha512-kcZ6+W5QzcJ3P1Mt+83OUv/oHFqZHIx8DuxG6eZ5RGMERoLqp4BuGjhHLYGK+Kf5XVkQvqBSmAy/nGWN3qDgEA==}
     engines: {node: '>=14'}
     peerDependencies:
@@ -3281,7 +3274,7 @@ packages:
       js-yaml: 4.1.0
       parse-json: 5.2.0
       path-type: 4.0.0
-      typescript: 5.3.2
+      typescript: 5.3.3
     dev: true
 
   /create-ecdh@4.0.4:
@@ -3531,11 +3524,8 @@ packages:
     engines: {node: '>= 14'}
     dev: true
 
-  /date-fns@2.30.0:
-    resolution: {integrity: sha512-fnULvOpxnC5/Vg3NCiWelDsLiUc9bRwAPs/+LfTLNvetFCtCTN+yQz15C/fs4AwX1R9K5GLtLfn8QW+dWisaAw==}
-    engines: {node: '>=0.11'}
-    dependencies:
-      '@babel/runtime': 7.23.4
+  /date-fns@3.0.0-rc.2:
+    resolution: {integrity: sha512-3MAy/Mc7i7LVIayaPnHCNhah7Zaj9/9G9v4pmdJNvMJ+mPahQtrQ4DWm6YxkQjvhRB4gBnjV5UB1ll5ZQxE31w==}
     dev: false
 
   /debounce-fn@4.0.0:
@@ -3931,7 +3921,7 @@ packages:
       is-weakref: 1.0.2
       object-inspect: 1.13.1
       object-keys: 1.1.1
-      object.assign: 4.1.4
+      object.assign: 4.1.5
       regexp.prototype.flags: 1.5.1
       safe-array-concat: 1.0.1
       safe-regex-test: 1.0.0
@@ -4036,24 +4026,24 @@ packages:
       ext: 1.7.0
     dev: true
 
-  /esbuild-plugin-clean@1.0.1(esbuild@0.19.8):
+  /esbuild-plugin-clean@1.0.1(esbuild@0.19.9):
     resolution: {integrity: sha512-ul606g0wX6oeobBgi3EqpZtCBCwNwCDivvnshsNS5pUsRylKoxUnDqK0ZIyPinlMbP6s8Opc9y2zOeY1Plhe8Q==}
     peerDependencies:
       esbuild: '>= 0.14.0'
     dependencies:
       chalk: 4.1.2
       del: 6.1.1
-      esbuild: 0.19.8
+      esbuild: 0.19.9
     dev: true
 
-  /esbuild-plugin-copy@2.1.1(esbuild@0.19.8):
+  /esbuild-plugin-copy@2.1.1(esbuild@0.19.9):
     resolution: {integrity: sha512-Bk66jpevTcV8KMFzZI1P7MZKZ+uDcrZm2G2egZ2jNIvVnivDpodZI+/KnpL3Jnap0PBdIHU7HwFGB8r+vV5CVw==}
     peerDependencies:
       esbuild: '>= 0.14.0'
     dependencies:
       chalk: 4.1.2
       chokidar: 3.5.3
-      esbuild: 0.19.8
+      esbuild: 0.19.9
       fs-extra: 10.1.0
       globby: 11.1.0
     dev: true
@@ -4088,34 +4078,34 @@ packages:
       '@esbuild/win32-x64': 0.18.20
     dev: true
 
-  /esbuild@0.19.8:
-    resolution: {integrity: sha512-l7iffQpT2OrZfH2rXIp7/FkmaeZM0vxbxN9KfiCwGYuZqzMg/JdvX26R31Zxn/Pxvsrg3Y9N6XTcnknqDyyv4w==}
+  /esbuild@0.19.9:
+    resolution: {integrity: sha512-U9CHtKSy+EpPsEBa+/A2gMs/h3ylBC0H0KSqIg7tpztHerLi6nrrcoUJAkNCEPumx8yJ+Byic4BVwHgRbN0TBg==}
     engines: {node: '>=12'}
     hasBin: true
     requiresBuild: true
     optionalDependencies:
-      '@esbuild/android-arm': 0.19.8
-      '@esbuild/android-arm64': 0.19.8
-      '@esbuild/android-x64': 0.19.8
-      '@esbuild/darwin-arm64': 0.19.8
-      '@esbuild/darwin-x64': 0.19.8
-      '@esbuild/freebsd-arm64': 0.19.8
-      '@esbuild/freebsd-x64': 0.19.8
-      '@esbuild/linux-arm': 0.19.8
-      '@esbuild/linux-arm64': 0.19.8
-      '@esbuild/linux-ia32': 0.19.8
-      '@esbuild/linux-loong64': 0.19.8
-      '@esbuild/linux-mips64el': 0.19.8
-      '@esbuild/linux-ppc64': 0.19.8
-      '@esbuild/linux-riscv64': 0.19.8
-      '@esbuild/linux-s390x': 0.19.8
-      '@esbuild/linux-x64': 0.19.8
-      '@esbuild/netbsd-x64': 0.19.8
-      '@esbuild/openbsd-x64': 0.19.8
-      '@esbuild/sunos-x64': 0.19.8
-      '@esbuild/win32-arm64': 0.19.8
-      '@esbuild/win32-ia32': 0.19.8
-      '@esbuild/win32-x64': 0.19.8
+      '@esbuild/android-arm': 0.19.9
+      '@esbuild/android-arm64': 0.19.9
+      '@esbuild/android-x64': 0.19.9
+      '@esbuild/darwin-arm64': 0.19.9
+      '@esbuild/darwin-x64': 0.19.9
+      '@esbuild/freebsd-arm64': 0.19.9
+      '@esbuild/freebsd-x64': 0.19.9
+      '@esbuild/linux-arm': 0.19.9
+      '@esbuild/linux-arm64': 0.19.9
+      '@esbuild/linux-ia32': 0.19.9
+      '@esbuild/linux-loong64': 0.19.9
+      '@esbuild/linux-mips64el': 0.19.9
+      '@esbuild/linux-ppc64': 0.19.9
+      '@esbuild/linux-riscv64': 0.19.9
+      '@esbuild/linux-s390x': 0.19.9
+      '@esbuild/linux-x64': 0.19.9
+      '@esbuild/netbsd-x64': 0.19.9
+      '@esbuild/openbsd-x64': 0.19.9
+      '@esbuild/sunos-x64': 0.19.9
+      '@esbuild/win32-arm64': 0.19.9
+      '@esbuild/win32-ia32': 0.19.9
+      '@esbuild/win32-x64': 0.19.9
     dev: true
 
   /escalade@3.1.1:
@@ -4177,22 +4167,22 @@ packages:
       source-map: 0.6.1
     dev: true
 
-  /eslint-compat-utils@0.1.2(eslint@8.54.0):
+  /eslint-compat-utils@0.1.2(eslint@8.55.0):
     resolution: {integrity: sha512-Jia4JDldWnFNIru1Ehx1H5s9/yxiRHY/TimCuUc0jNexew3cF1gI6CYZil1ociakfWO3rRqFjl1mskBblB3RYg==}
     engines: {node: '>=12'}
     peerDependencies:
       eslint: '>=6.0.0'
     dependencies:
-      eslint: 8.54.0
+      eslint: 8.55.0
     dev: true
 
-  /eslint-config-prettier@9.0.0(eslint@8.54.0):
-    resolution: {integrity: sha512-IcJsTkJae2S35pRsRAwoCE+925rJJStOdkKnLVgtE+tEpqU0EVVM7OqrwxqgptKdX29NUwC82I5pXsGFIgSevw==}
+  /eslint-config-prettier@9.1.0(eslint@8.55.0):
+    resolution: {integrity: sha512-NSWl5BFQWEPi1j4TjVNItzYV7dZXZ+wP6I6ZhrBGpChQhZRUaElihE9uRRkcbRnNb76UMKDF3r+WTmNcGPKsqw==}
     hasBin: true
     peerDependencies:
       eslint: '>=7.0.0'
     dependencies:
-      eslint: 8.54.0
+      eslint: 8.55.0
     dev: true
 
   /eslint-import-resolver-node@0.3.9:
@@ -4205,7 +4195,7 @@ packages:
       - supports-color
     dev: true
 
-  /eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@6.13.0)(eslint-plugin-import@2.29.0)(eslint@8.54.0):
+  /eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@6.14.0)(eslint-plugin-import@2.29.0)(eslint@8.55.0):
     resolution: {integrity: sha512-xgdptdoi5W3niYeuQxKmzVDTATvLYqhpwmykwsh7f6HIOStGWEIL9iqZgQDF9u9OEzrRwR8no5q2VT+bjAujTg==}
     engines: {node: ^14.18.0 || >=16.0.0}
     peerDependencies:
@@ -4214,9 +4204,9 @@ packages:
     dependencies:
       debug: 4.3.4
       enhanced-resolve: 5.15.0
-      eslint: 8.54.0
-      eslint-module-utils: 2.8.0(@typescript-eslint/parser@6.13.0)(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1)(eslint@8.54.0)
-      eslint-plugin-import: 2.29.0(@typescript-eslint/parser@6.13.0)(eslint-import-resolver-typescript@3.6.1)(eslint@8.54.0)
+      eslint: 8.55.0
+      eslint-module-utils: 2.8.0(@typescript-eslint/parser@6.14.0)(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1)(eslint@8.55.0)
+      eslint-plugin-import: 2.29.0(@typescript-eslint/parser@6.14.0)(eslint-import-resolver-typescript@3.6.1)(eslint@8.55.0)
       fast-glob: 3.3.2
       get-tsconfig: 4.7.2
       is-core-module: 2.13.1
@@ -4228,7 +4218,7 @@ packages:
       - supports-color
     dev: true
 
-  /eslint-module-utils@2.8.0(@typescript-eslint/parser@6.13.0)(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1)(eslint@8.54.0):
+  /eslint-module-utils@2.8.0(@typescript-eslint/parser@6.14.0)(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1)(eslint@8.55.0):
     resolution: {integrity: sha512-aWajIYfsqCKRDgUfjEXNN/JlrzauMuSEy5sbd7WXbtW3EH6A6MpwEh42c7qD+MqQo9QMJ6fWLAeIJynx0g6OAw==}
     engines: {node: '>=4'}
     peerDependencies:
@@ -4249,28 +4239,28 @@ packages:
       eslint-import-resolver-webpack:
         optional: true
     dependencies:
-      '@typescript-eslint/parser': 6.13.0(eslint@8.54.0)(typescript@5.3.2)
+      '@typescript-eslint/parser': 6.14.0(eslint@8.55.0)(typescript@5.3.3)
       debug: 3.2.7
-      eslint: 8.54.0
+      eslint: 8.55.0
       eslint-import-resolver-node: 0.3.9
-      eslint-import-resolver-typescript: 3.6.1(@typescript-eslint/parser@6.13.0)(eslint-plugin-import@2.29.0)(eslint@8.54.0)
+      eslint-import-resolver-typescript: 3.6.1(@typescript-eslint/parser@6.14.0)(eslint-plugin-import@2.29.0)(eslint@8.55.0)
     transitivePeerDependencies:
       - supports-color
     dev: true
 
-  /eslint-plugin-es-x@7.4.0(eslint@8.54.0):
-    resolution: {integrity: sha512-WJa3RhYzBtl8I37ebY9p76s61UhZyi4KaFOnX2A5r32RPazkXj5yoT6PGnD02dhwzEUj0KwsUdqfKDd/OuvGsw==}
+  /eslint-plugin-es-x@7.5.0(eslint@8.55.0):
+    resolution: {integrity: sha512-ODswlDSO0HJDzXU0XvgZ3lF3lS3XAZEossh15Q2UHjwrJggWeBoKqqEsLTZLXl+dh5eOAozG0zRcYtuE35oTuQ==}
     engines: {node: ^14.18.0 || >=16.0.0}
     peerDependencies:
       eslint: '>=8'
     dependencies:
-      '@eslint-community/eslint-utils': 4.4.0(eslint@8.54.0)
+      '@eslint-community/eslint-utils': 4.4.0(eslint@8.55.0)
       '@eslint-community/regexpp': 4.10.0
-      eslint: 8.54.0
-      eslint-compat-utils: 0.1.2(eslint@8.54.0)
+      eslint: 8.55.0
+      eslint-compat-utils: 0.1.2(eslint@8.55.0)
     dev: true
 
-  /eslint-plugin-import@2.29.0(@typescript-eslint/parser@6.13.0)(eslint-import-resolver-typescript@3.6.1)(eslint@8.54.0):
+  /eslint-plugin-import@2.29.0(@typescript-eslint/parser@6.14.0)(eslint-import-resolver-typescript@3.6.1)(eslint@8.55.0):
     resolution: {integrity: sha512-QPOO5NO6Odv5lpoTkddtutccQjysJuFxoPS7fAHO+9m9udNHvTCPSAMW9zGAYj8lAIdr40I8yPCdUYrncXtrwg==}
     engines: {node: '>=4'}
     peerDependencies:
@@ -4280,16 +4270,16 @@ packages:
       '@typescript-eslint/parser':
         optional: true
     dependencies:
-      '@typescript-eslint/parser': 6.13.0(eslint@8.54.0)(typescript@5.3.2)
+      '@typescript-eslint/parser': 6.14.0(eslint@8.55.0)(typescript@5.3.3)
       array-includes: 3.1.7
       array.prototype.findlastindex: 1.2.3
       array.prototype.flat: 1.3.2
       array.prototype.flatmap: 1.3.2
       debug: 3.2.7
       doctrine: 2.1.0
-      eslint: 8.54.0
+      eslint: 8.55.0
       eslint-import-resolver-node: 0.3.9
-      eslint-module-utils: 2.8.0(@typescript-eslint/parser@6.13.0)(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1)(eslint@8.54.0)
+      eslint-module-utils: 2.8.0(@typescript-eslint/parser@6.14.0)(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1)(eslint@8.55.0)
       hasown: 2.0.0
       is-core-module: 2.13.1
       is-glob: 4.0.3
@@ -4305,7 +4295,7 @@ packages:
       - supports-color
     dev: true
 
-  /eslint-plugin-jsdoc@46.9.0(eslint@8.54.0):
+  /eslint-plugin-jsdoc@46.9.0(eslint@8.55.0):
     resolution: {integrity: sha512-UQuEtbqLNkPf5Nr/6PPRCtr9xypXY+g8y/Q7gPa0YK7eDhh0y2lWprXRnaYbW7ACgIUvpDKy9X2bZqxtGzBG9Q==}
     engines: {node: '>=16'}
     peerDependencies:
@@ -4316,7 +4306,7 @@ packages:
       comment-parser: 1.4.1
       debug: 4.3.4
       escape-string-regexp: 4.0.0
-      eslint: 8.54.0
+      eslint: 8.55.0
       esquery: 1.5.0
       is-builtin-module: 3.2.1
       semver: 7.5.4
@@ -4325,16 +4315,16 @@ packages:
       - supports-color
     dev: true
 
-  /eslint-plugin-n@16.3.1(eslint@8.54.0):
-    resolution: {integrity: sha512-w46eDIkxQ2FaTHcey7G40eD+FhTXOdKudDXPUO2n9WNcslze/i/HT2qJ3GXjHngYSGDISIgPNhwGtgoix4zeOw==}
+  /eslint-plugin-n@16.4.0(eslint@8.55.0):
+    resolution: {integrity: sha512-IkqJjGoWYGskVaJA7WQuN8PINIxc0N/Pk/jLeYT4ees6Fo5lAhpwGsYek6gS9tCUxgDC4zJ+OwY2bY/6/9OMKQ==}
     engines: {node: '>=16.0.0'}
     peerDependencies:
       eslint: '>=7.0.0'
     dependencies:
-      '@eslint-community/eslint-utils': 4.4.0(eslint@8.54.0)
+      '@eslint-community/eslint-utils': 4.4.0(eslint@8.55.0)
       builtins: 5.0.1
-      eslint: 8.54.0
-      eslint-plugin-es-x: 7.4.0(eslint@8.54.0)
+      eslint: 8.55.0
+      eslint-plugin-es-x: 7.5.0(eslint@8.55.0)
       get-tsconfig: 4.7.2
       ignore: 5.3.0
       is-builtin-module: 3.2.1
@@ -4344,7 +4334,7 @@ packages:
       semver: 7.5.4
     dev: true
 
-  /eslint-plugin-prettier@5.0.1(eslint-config-prettier@9.0.0)(eslint@8.54.0)(prettier@3.1.0):
+  /eslint-plugin-prettier@5.0.1(eslint-config-prettier@9.1.0)(eslint@8.55.0)(prettier@3.1.1):
     resolution: {integrity: sha512-m3u5RnR56asrwV/lDC4GHorlW75DsFfmUcjfCYylTUs85dBRnB7VM6xG8eCMJdeDRnppzmxZVf1GEPJvl1JmNg==}
     engines: {node: ^14.18.0 || >=16.0.0}
     peerDependencies:
@@ -4358,11 +4348,11 @@ packages:
       eslint-config-prettier:
         optional: true
     dependencies:
-      eslint: 8.54.0
-      eslint-config-prettier: 9.0.0(eslint@8.54.0)
-      prettier: 3.1.0
+      eslint: 8.55.0
+      eslint-config-prettier: 9.1.0(eslint@8.55.0)
+      prettier: 3.1.1
       prettier-linter-helpers: 1.0.0
-      synckit: 0.8.5
+      synckit: 0.8.6
     dev: true
 
   /eslint-plugin-tsdoc@0.2.17:
@@ -4385,15 +4375,15 @@ packages:
     engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
     dev: true
 
-  /eslint@8.54.0:
-    resolution: {integrity: sha512-NY0DfAkM8BIZDVl6PgSa1ttZbx3xHgJzSNJKYcQglem6CppHyMhRIQkBVSSMaSRnLhig3jsDbEzOjwCVt4AmmA==}
+  /eslint@8.55.0:
+    resolution: {integrity: sha512-iyUUAM0PCKj5QpwGfmCAG9XXbZCWsqP/eWAWrG/W0umvjuLRBECwSFdt+rCntju0xEH7teIABPwXpahftIaTdA==}
     engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
     hasBin: true
     dependencies:
-      '@eslint-community/eslint-utils': 4.4.0(eslint@8.54.0)
+      '@eslint-community/eslint-utils': 4.4.0(eslint@8.55.0)
       '@eslint-community/regexpp': 4.10.0
-      '@eslint/eslintrc': 2.1.3
-      '@eslint/js': 8.54.0
+      '@eslint/eslintrc': 2.1.4
+      '@eslint/js': 8.55.0
       '@humanwhocodes/config-array': 0.11.13
       '@humanwhocodes/module-importer': 1.0.1
       '@nodelib/fs.walk': 1.2.8
@@ -4413,7 +4403,7 @@ packages:
       file-entry-cache: 6.0.1
       find-up: 5.0.0
       glob-parent: 6.0.2
-      globals: 13.23.0
+      globals: 13.24.0
       graphemer: 1.4.0
       ignore: 5.3.0
       imurmurhash: 0.1.4
@@ -4839,6 +4829,15 @@ packages:
       jsonfile: 6.1.0
       universalify: 2.0.1
 
+  /fs-extra@11.2.0:
+    resolution: {integrity: sha512-PmDi3uwK5nFuXh7XDTlVnS17xJS7vW36is2+w3xcv8SVxiB4NyATf4ctkVY5bkSjX0Y4nbvZCq1/EjtEyr9ktw==}
+    engines: {node: '>=14.14'}
+    dependencies:
+      graceful-fs: 4.2.11
+      jsonfile: 6.1.0
+      universalify: 2.0.1
+    dev: true
+
   /fs-extra@8.1.0:
     resolution: {integrity: sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==}
     engines: {node: '>=6 <7 || >=8'}
@@ -4933,6 +4932,11 @@ packages:
     engines: {node: 6.* || 8.* || >= 10.*}
     dev: true
 
+  /get-east-asian-width@1.2.0:
+    resolution: {integrity: sha512-2nk+7SIVb14QrgXFHcm84tD4bKQz0RxPuMT8Ag5KPOq7J5fEmAg0UbXdTOSHqNuHSU28k55qnceesxXRZGzKWA==}
+    engines: {node: '>=18'}
+    dev: true
+
   /get-intrinsic@1.2.2:
     resolution: {integrity: sha512-0gSo4ml/0j98Y3lngkFEot/zhiCeWsbYIlZ+uZOVgzLyLaUw7wxUL+nCTP0XJvJg1AXulJRI3UJi8GsbDuxdGA==}
     dependencies:
@@ -5072,8 +5076,8 @@ packages:
       ini: 2.0.0
     dev: true
 
-  /globals@13.23.0:
-    resolution: {integrity: sha512-XAmF0RjlrjY23MA51q3HltdlGxUpXPvg0GioKiD9X6HD28iMjo2dKC8Vqwm7lne4GNr78+RHTfliktR6ZH09wA==}
+  /globals@13.24.0:
+    resolution: {integrity: sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==}
     engines: {node: '>=8'}
     dependencies:
       type-fest: 0.20.2
@@ -5770,6 +5774,13 @@ packages:
     engines: {node: '>=12'}
     dev: true
 
+  /is-fullwidth-code-point@5.0.0:
+    resolution: {integrity: sha512-OVa3u9kkBbw7b8Xw5F9P+D/T9X+Z4+JruYVNapTjPYZYUznQ5YfWeFkOj606XYYW8yugTfC8Pj0hYqvi4ryAhA==}
+    engines: {node: '>=18'}
+    dependencies:
+      get-east-asian-width: 1.2.0
+    dev: true
+
   /is-generator-function@1.0.10:
     resolution: {integrity: sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==}
     engines: {node: '>= 0.4'}
@@ -6069,7 +6080,7 @@ packages:
     resolution: {integrity: sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w==}
     engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
     dependencies:
-      '@babel/code-frame': 7.23.4
+      '@babel/code-frame': 7.23.5
       '@jest/types': 29.6.3
       '@types/stack-utils': 2.0.3
       chalk: 4.1.2
@@ -6085,7 +6096,7 @@ packages:
     engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
     dependencies:
       '@jest/types': 29.6.3
-      '@types/node': 20.10.0
+      '@types/node': 20.10.4
       chalk: 4.1.2
       ci-info: 3.9.0
       graceful-fs: 4.2.11
@@ -6310,17 +6321,17 @@ packages:
       type-check: 0.4.0
     dev: true
 
-  /lilconfig@2.1.0:
-    resolution: {integrity: sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==}
-    engines: {node: '>=10'}
+  /lilconfig@3.0.0:
+    resolution: {integrity: sha512-K2U4W2Ff5ibV7j7ydLr+zLAkIg5JJ4lPn1Ltsdt+Tz/IjQ8buJ55pZAxoP34lqIiwtF9iAvtLv3JGv7CAyAg+g==}
+    engines: {node: '>=14'}
     dev: true
 
   /lines-and-columns@1.2.4:
     resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==}
     dev: true
 
-  /lint-staged@15.1.0:
-    resolution: {integrity: sha512-ZPKXWHVlL7uwVpy8OZ7YQjYDAuO5X4kMh0XgZvPNxLcCCngd0PO5jKQyy3+s4TL2EnHoIXIzP1422f/l3nZKMw==}
+  /lint-staged@15.2.0:
+    resolution: {integrity: sha512-TFZzUEV00f+2YLaVPWBWGAMq7So6yQx+GG8YRMDeOEIf95Zn5RyiLMsEiX4KTNl9vq/w+NqRJkLA1kPIo15ufQ==}
     engines: {node: '>=18.12.0'}
     hasBin: true
     dependencies:
@@ -6328,8 +6339,8 @@ packages:
       commander: 11.1.0
       debug: 4.3.4
       execa: 8.0.1
-      lilconfig: 2.1.0
-      listr2: 7.0.2
+      lilconfig: 3.0.0
+      listr2: 8.0.0
       micromatch: 4.0.5
       pidtree: 0.6.0
       string-argv: 0.3.2
@@ -6338,16 +6349,16 @@ packages:
       - supports-color
     dev: true
 
-  /listr2@7.0.2:
-    resolution: {integrity: sha512-rJysbR9GKIalhTbVL2tYbF2hVyDnrf7pFUZBwjPaMIdadYHmeT+EVi/Bu3qd7ETQPahTotg2WRCatXwRBW554g==}
-    engines: {node: '>=16.0.0'}
+  /listr2@8.0.0:
+    resolution: {integrity: sha512-u8cusxAcyqAiQ2RhYvV7kRKNLgUvtObIbhOX2NCXqvp1UU32xIg5CT22ykS2TPKJXZWJwtK3IKLiqAGlGNE+Zg==}
+    engines: {node: '>=18.0.0'}
     dependencies:
-      cli-truncate: 3.1.0
+      cli-truncate: 4.0.0
       colorette: 2.0.20
       eventemitter3: 5.0.1
-      log-update: 5.0.1
+      log-update: 6.0.0
       rfdc: 1.3.0
-      wrap-ansi: 8.1.0
+      wrap-ansi: 9.0.0
     dev: true
 
   /locate-path@3.0.0:
@@ -6471,15 +6482,15 @@ packages:
       is-unicode-supported: 1.3.0
     dev: true
 
-  /log-update@5.0.1:
-    resolution: {integrity: sha512-5UtUDQ/6edw4ofyljDNcOVJQ4c7OjDro4h3y8e1GQL5iYElYclVHJ3zeWchylvMaKnDbDilC8irOVyexnA/Slw==}
-    engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
+  /log-update@6.0.0:
+    resolution: {integrity: sha512-niTvB4gqvtof056rRIrTZvjNYE4rCUzO6X/X+kYjd7WFxXeJ0NwEFnRxX6ehkvv3jTwrXnNdtAak5XYZuIyPFw==}
+    engines: {node: '>=18'}
     dependencies:
-      ansi-escapes: 5.0.0
+      ansi-escapes: 6.2.0
       cli-cursor: 4.0.0
-      slice-ansi: 5.0.0
+      slice-ansi: 7.1.0
       strip-ansi: 7.1.0
-      wrap-ansi: 8.1.0
+      wrap-ansi: 9.0.0
     dev: true
 
   /logform@2.6.0:
@@ -6930,8 +6941,8 @@ packages:
     resolution: {integrity: sha512-VoAYUqmPRmzKbbqRejjqceGFp3VF81Qe8XXFGU0UXLxB7Mf4GGvyGq5Qn3k4AiQgDEV6WzobqlPOd+j0+m6IrA==}
     dev: true
 
-  /mnemonist@0.39.5:
-    resolution: {integrity: sha512-FPUtkhtJ0efmEFGpU14x7jGbTB+s18LrzRL2KgoWz9YvcY3cPomz8tih01GbHwnGk/OmkOKfqd/RAQoc8Lm7DQ==}
+  /mnemonist@0.39.6:
+    resolution: {integrity: sha512-A/0v5Z59y63US00cRSLiloEIw3t5G+MiKz4BhX21FI+YBJXBOGW0ohFxTxO08dsOYlzxo87T7vGfZKYp2bcAWA==}
     dependencies:
       obliterator: 2.0.4
     dev: false
@@ -7336,8 +7347,8 @@ packages:
     engines: {node: '>= 0.4'}
     dev: true
 
-  /object.assign@4.1.4:
-    resolution: {integrity: sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==}
+  /object.assign@4.1.5:
+    resolution: {integrity: sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ==}
     engines: {node: '>= 0.4'}
     dependencies:
       call-bind: 1.0.5
@@ -7657,7 +7668,7 @@ packages:
     resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==}
     engines: {node: '>=8'}
     dependencies:
-      '@babel/code-frame': 7.23.4
+      '@babel/code-frame': 7.23.5
       error-ex: 1.3.2
       json-parse-even-better-errors: 2.3.1
       lines-and-columns: 1.2.4
@@ -7776,19 +7787,19 @@ packages:
     dependencies:
       semver-compare: 1.0.0
 
-  /poolifier@3.0.9:
-    resolution: {integrity: sha512-Ky6KC8D8h6xn8z1AsgAdw8n8bra6i6uzT7bJ5jsUauW0VSZatk3SV3Rm/qi710V8Dkbg2p0qg4aRI1a+BDp1MA==}
+  /poolifier@3.0.14:
+    resolution: {integrity: sha512-bER0wR3NADyvQpexHY6fbVd+rikk4hxt1tzIhKkwOcoJcqkoD+eAtN+2sVbAIUYFqwhNdeaZQwmpxcDlZ2jv3Q==}
     engines: {node: '>=18.0.0', pnpm: '>=8.6.0'}
     requiresBuild: true
     dev: false
 
-  /postcss-import@13.0.0(postcss@8.4.31):
+  /postcss-import@13.0.0(postcss@8.4.32):
     resolution: {integrity: sha512-LPUbm3ytpYopwQQjqgUH4S3EM/Gb9QsaSPP/5vnoi+oKVy3/mIk2sc0Paqw7RL57GpScm9MdIMUypw2znWiBpg==}
     engines: {node: '>=10.0.0'}
     peerDependencies:
       postcss: ^8.0.0
     dependencies:
-      postcss: 8.4.31
+      postcss: 8.4.32
       postcss-value-parser: 4.2.0
       read-cache: 1.0.0
       resolve: 1.22.8
@@ -7798,8 +7809,8 @@ packages:
     resolution: {integrity: sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==}
     dev: true
 
-  /postcss@8.4.31:
-    resolution: {integrity: sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==}
+  /postcss@8.4.32:
+    resolution: {integrity: sha512-D/kj5JNu6oo2EIy+XL/26JEDTlIbB8hw85G8StOE6L74RQAVVP5rej6wxCNqyMbR4RkPfqvezVbPw81Ngd6Kcw==}
     engines: {node: ^10 || ^12 || >=14}
     dependencies:
       nanoid: 3.3.7
@@ -7824,8 +7835,8 @@ packages:
       fast-diff: 1.3.0
     dev: true
 
-  /prettier@3.1.0:
-    resolution: {integrity: sha512-TQLvXjq5IAibjh8EpBIkNKxO749UEWABoiIZehEPiY4GNpVdhaFKqSTu+QrlU6D2dPAfubRmtJTi4K4YkQ5eXw==}
+  /prettier@3.1.1:
+    resolution: {integrity: sha512-22UbSzg8luF4UuZtzgiUOfcGM8s4tjBv6dJRT7j275NXsy2jb4aJa4NNveul5x4eqlF1wuhuR2RElK71RvmVaw==}
     engines: {node: '>=14'}
     hasBin: true
     dev: true
@@ -8154,10 +8165,6 @@ packages:
   /reflect-metadata@0.1.13:
     resolution: {integrity: sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg==}
 
-  /regenerator-runtime@0.14.0:
-    resolution: {integrity: sha512-srw17NI0TUWHuGa5CFGGmhfNIeja30WMBfbslPNhf6JrqQlLN5gcrvig1oqPxiVaXb0oW0XRKtH6Nngs5lKCIA==}
-    dev: false
-
   /regexp.prototype.flags@1.5.1:
     resolution: {integrity: sha512-sy6TXMN+hnP/wMy+ISxg3krXx7BAtWVO4UouuCN/ziM9UEne0euamVNafDfvC83bRNr95y0V5iijeDQFUNpvrg==}
     engines: {node: '>= 0.4'}
@@ -8199,8 +8206,8 @@ packages:
     resolution: {integrity: sha512-QIRet3SYrGp0HUHO88jVskiG6seqUGC5iAG7AwI/BV4ypGcuqk9Du6YQBUOUqm9c8pw1eyLoIaONifRua1lsEQ==}
     dev: true
 
-  /release-it@17.0.0(typescript@5.3.2):
-    resolution: {integrity: sha512-1A1sSQy8VXuAJcslZGhKtOD/LVBuf1sH4XqhKsQuh+2EIksC2STx/MdKmVE86jFd/zorHTXOpl7Lr/isD0dDrg==}
+  /release-it@17.0.1(typescript@5.3.3):
+    resolution: {integrity: sha512-XHeirIW8ptkkrH1+uCg+ditclZJbSKeovrtIb42v3s2S/icF2xCTwFHpbvAKQGqBVJ5Zm49If8bwsryi247KdQ==}
     engines: {node: '>=18'}
     hasBin: true
     dependencies:
@@ -8208,7 +8215,7 @@ packages:
       '@octokit/rest': 20.0.2
       async-retry: 1.3.3
       chalk: 5.3.0
-      cosmiconfig: 8.3.6(typescript@5.3.2)
+      cosmiconfig: 8.3.6(typescript@5.3.3)
       execa: 8.0.1
       git-url-parse: 13.1.1
       globby: 14.0.0
@@ -8634,6 +8641,14 @@ packages:
       is-fullwidth-code-point: 4.0.0
     dev: true
 
+  /slice-ansi@7.1.0:
+    resolution: {integrity: sha512-bSiSngZ/jWeX93BqeIAbImyTbEihizcwNjFoRUIY/T1wWQsfsm2Vw1agPKylXvQTU7iASGdHhyqRlqQzfz+Htg==}
+    engines: {node: '>=18'}
+    dependencies:
+      ansi-styles: 6.2.1
+      is-fullwidth-code-point: 5.0.0
+    dev: true
+
   /smart-buffer@4.2.0:
     resolution: {integrity: sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==}
     engines: {node: '>= 6.0.0', npm: '>= 3.0.0'}
@@ -8954,6 +8969,15 @@ packages:
       strip-ansi: 7.1.0
     dev: true
 
+  /string-width@7.0.0:
+    resolution: {integrity: sha512-GPQHj7row82Hjo9hKZieKcHIhaAIKOJvFSIZXuCU9OASVZrMNUaZuz++SPVrBjnLsnk4k+z9f2EIypgxf2vNFw==}
+    engines: {node: '>=18'}
+    dependencies:
+      emoji-regex: 10.3.0
+      get-east-asian-width: 1.2.0
+      strip-ansi: 7.1.0
+    dev: true
+
   /string.prototype.trim@1.2.8:
     resolution: {integrity: sha512-lfjY4HcixfQXOfaqCvcBuOIapyaroTXhbkfJN3gcB1OtyupngWK4sEET9Knd0cXd28kTUqu/kHoV4HKSJdnjiQ==}
     engines: {node: '>= 0.4'}
@@ -9089,8 +9113,8 @@ packages:
     resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==}
     engines: {node: '>= 0.4'}
 
-  /synckit@0.8.5:
-    resolution: {integrity: sha512-L1dapNV6vu2s/4Sputv8xGsCdAVlb5nRDMFU/E27D44l5U6cw1g0dGd45uLc+OXjNMmF4ntiMdCimzcjFKQI8Q==}
+  /synckit@0.8.6:
+    resolution: {integrity: sha512-laHF2savN6sMeHCjLRkheIU4wo3Zg9Ln5YOjOo7sZ5dVQW8yF5pPE5SIw1dsPhq3TRp1jisKRCdPhfs/1WMqDA==}
     engines: {node: ^14.18.0 || >=16.0.0}
     dependencies:
       '@pkgr/utils': 2.4.2
@@ -9264,13 +9288,13 @@ packages:
     engines: {node: '>= 14.0.0'}
     dev: false
 
-  /ts-api-utils@1.0.3(typescript@5.3.2):
+  /ts-api-utils@1.0.3(typescript@5.3.3):
     resolution: {integrity: sha512-wNMeqtMz5NtwpT/UZGY5alT+VoKdSsOOP/kqHFcUW1P/VRhH2wJ48+DN2WwUliNbQ976ETwDL0Ifd2VVvgonvg==}
     engines: {node: '>=16.13.0'}
     peerDependencies:
       typescript: '>=4.2.0'
     dependencies:
-      typescript: 5.3.2
+      typescript: 5.3.3
     dev: true
 
   /ts-morph@20.0.0:
@@ -9305,8 +9329,8 @@ packages:
   /tslib@2.6.2:
     resolution: {integrity: sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==}
 
-  /tsx@4.5.0:
-    resolution: {integrity: sha512-hgxdziy9KLaHh9KE+a6tIZFP6kb0MLq/1D0sJVifbGP4QVEYhy6+2FNn7MyCm1pMc63p9CW/L1OzdqTNPxs6rg==}
+  /tsx@4.6.2:
+    resolution: {integrity: sha512-QPpBdJo+ZDtqZgAnq86iY/PD2KYCUPSUGIunHdGwyII99GKH+f3z3FZ8XNFLSGQIA4I365ui8wnQpl8OKLqcsg==}
     engines: {node: '>=18.0.0'}
     hasBin: true
     dependencies:
@@ -9396,6 +9420,11 @@ packages:
     engines: {node: '>=12.20'}
     dev: true
 
+  /type-fest@3.13.1:
+    resolution: {integrity: sha512-tLq3bSNx+xSpwvAJnzrK0Ep5CLNWjvFTOp71URMaAEWBfRb9nnJiBoUe0tF8bI4ZFO3omgBR6NvnbzVUT3Ly4g==}
+    engines: {node: '>=14.16'}
+    dev: true
+
   /type@1.2.0:
     resolution: {integrity: sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg==}
     dev: true
@@ -9459,8 +9488,8 @@ packages:
     resolution: {integrity: sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==}
     dev: true
 
-  /typescript@5.3.2:
-    resolution: {integrity: sha512-6l+RyNy7oAHDfxC4FzSJcz9vnjTKxrLpDG5M2Vu4SHRVNg6xzqZp6LYSR9zjqQTu8DU/f5xwxUdADOkbrIX2gQ==}
+  /typescript@5.3.3:
+    resolution: {integrity: sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==}
     engines: {node: '>=14.17'}
     hasBin: true
     dev: true
@@ -9895,6 +9924,15 @@ packages:
       strip-ansi: 7.1.0
     dev: true
 
+  /wrap-ansi@9.0.0:
+    resolution: {integrity: sha512-G8ura3S+3Z2G+mkgNRq8dqaFZAuxfsxpBB8OCTGRTCtp+l/v9nbFNmCUP1BZMts3G1142MsZfn6eeUKrr4PD1Q==}
+    engines: {node: '>=18'}
+    dependencies:
+      ansi-styles: 6.2.1
+      string-width: 7.0.0
+      strip-ansi: 7.1.0
+    dev: true
+
   /wrappy@1.0.2:
     resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==}
     requiresBuild: true
@@ -9908,8 +9946,8 @@ packages:
       typedarray-to-buffer: 3.1.5
     dev: true
 
-  /ws@8.14.2(bufferutil@4.0.8)(utf-8-validate@6.0.3):
-    resolution: {integrity: sha512-wEBG1ftX4jcglPxgFCMJmZ2PLtSbJ2Peg6TmpJFTbe9GZYOQCDPdMYu/Tm0/bGZkw8paZnJY45J4K2PZrLYq8g==}
+  /ws@8.15.1(bufferutil@4.0.8)(utf-8-validate@6.0.3):
+    resolution: {integrity: sha512-W5OZiCjXEmk0yZ66ZN82beM5Sz7l7coYxpRkzS+p9PP+ToQry8szKh+61eNktr7EA9DOwvFGhfC605jDHbP6QQ==}
     engines: {node: '>=10.0.0'}
     peerDependencies:
       bufferutil: ^4.0.1
index 231dc11388faba43b5c8911ad3c68f8ce32b231e..2c7b79045bfc9e77dfd8f65a415ce68346087b9b 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.2.26
+sonar.projectVersion=1.2.29
 
 # Path is relative to the sonar-project.properties file. Replace "\" by "/" on Windows.
 sonar.sources=src
index efc3769ac45b273c65cefbc2f5beea549dc3224d..95b2c67800a59fbe18146001e81c29e95965535c 100644 (file)
@@ -1,13 +1,11 @@
 // Partial Copyright Jerome Benoit. 2021-2023. All Rights Reserved.
 
-import { AsyncResource } from 'node:async_hooks';
-
 import { hoursToMilliseconds, secondsToMilliseconds } from 'date-fns';
 
 import type { ChargingStation } from './ChargingStation';
 import { checkChargingStation } from './Helpers';
 import { IdTagsCache } from './IdTagsCache';
-import { OCPPServiceUtils } from './ocpp';
+import { isIdTagAuthorized } from './ocpp';
 import { BaseError } from '../exception';
 import { PerformanceStatistics } from '../performance';
 import {
@@ -31,9 +29,7 @@ import {
   sleep,
 } from '../utils';
 
-const moduleName = 'AutomaticTransactionGenerator';
-
-export class AutomaticTransactionGenerator extends AsyncResource {
+export class AutomaticTransactionGenerator {
   private static readonly instances: Map<string, AutomaticTransactionGenerator> = new Map<
     string,
     AutomaticTransactionGenerator
@@ -46,7 +42,6 @@ export class AutomaticTransactionGenerator extends AsyncResource {
   private readonly chargingStation: ChargingStation;
 
   private constructor(chargingStation: ChargingStation) {
-    super(moduleName);
     this.started = false;
     this.starting = false;
     this.stopping = false;
@@ -109,14 +104,7 @@ export class AutomaticTransactionGenerator extends AsyncResource {
       throw new BaseError(`Connector ${connectorId} does not exist`);
     }
     if (this.connectorsStatus.get(connectorId)?.start === false) {
-      this.runInAsyncScope(
-        this.internalStartConnector.bind(this) as (
-          this: AutomaticTransactionGenerator,
-          ...args: unknown[]
-        ) => Promise<void>,
-        this,
-        connectorId,
-      ).catch(Constants.EMPTY_FUNCTION);
+      this.internalStartConnector(connectorId).catch(Constants.EMPTY_FUNCTION);
     } else if (this.connectorsStatus.get(connectorId)?.start === true) {
       logger.warn(`${this.logPrefix(connectorId)} is already started on connector`);
     }
@@ -398,16 +386,19 @@ export class AutomaticTransactionGenerator extends AsyncResource {
   }
 
   private resetConnectorStatus(connectorStatus: Status | undefined): void {
+    if (connectorStatus === undefined) {
+      return;
+    }
     delete connectorStatus?.startDate;
     delete connectorStatus?.lastRunDate;
     delete connectorStatus?.stopDate;
     delete connectorStatus?.stoppedDate;
     if (
       !this.started &&
-      (connectorStatus?.start === true ||
+      (connectorStatus.start === true ||
         this.chargingStation.getAutomaticTransactionGeneratorConfiguration().enable === false)
     ) {
-      connectorStatus!.start = false;
+      connectorStatus.start = false;
     }
   }
 
@@ -428,7 +419,7 @@ export class AutomaticTransactionGenerator extends AsyncResource {
       )} start transaction with an idTag '${idTag}'`;
       if (this.getRequireAuthorize()) {
         ++this.connectorsStatus.get(connectorId)!.authorizeRequests!;
-        if (await OCPPServiceUtils.isIdTagAuthorized(this.chargingStation, connectorId, idTag)) {
+        if (await isIdTagAuthorized(this.chargingStation, connectorId, idTag)) {
           ++this.connectorsStatus.get(connectorId)!.acceptedAuthorizeRequests!;
           logger.info(startTransactionLogMsg);
           // Start transaction
index 710d2c894d485b4abcb4193f3721df58bbad4264..503dfb0b7301f3f9e553e21c2a03a3f0ed34ad73 100644 (file)
@@ -55,7 +55,6 @@ export class Bootstrap extends EventEmitter {
   private static instance: Bootstrap | null = null;
   public numberOfChargingStations!: number;
   public numberOfChargingStationTemplates!: number;
-  private workerConfiguration?: WorkerConfiguration;
   private workerImplementation?: WorkerAbstract<ChargingStationWorkerData>;
   private readonly uiServer?: AbstractUIServer;
   private storage?: Storage;
@@ -82,13 +81,6 @@ export class Bootstrap extends EventEmitter {
     this.uiServer = UIServerFactory.getUIServerImplementation(
       Configuration.getConfigurationSection<UIServerConfiguration>(ConfigurationSection.uiServer),
     );
-    this.on(ChargingStationWorkerMessageEvents.started, this.workerEventStarted);
-    this.on(ChargingStationWorkerMessageEvents.stopped, this.workerEventStopped);
-    this.on(ChargingStationWorkerMessageEvents.updated, this.workerEventUpdated);
-    this.on(
-      ChargingStationWorkerMessageEvents.performanceStatistics,
-      this.workerEventPerformanceStatistics,
-    );
     Configuration.configurationChangeCallback = async () => Bootstrap.getInstance().restart(false);
   }
 
@@ -103,11 +95,18 @@ export class Bootstrap extends EventEmitter {
     if (this.started === false) {
       if (this.starting === false) {
         this.starting = true;
+        this.on(ChargingStationWorkerMessageEvents.started, this.workerEventStarted);
+        this.on(ChargingStationWorkerMessageEvents.stopped, this.workerEventStopped);
+        this.on(ChargingStationWorkerMessageEvents.updated, this.workerEventUpdated);
+        this.on(
+          ChargingStationWorkerMessageEvents.performanceStatistics,
+          this.workerEventPerformanceStatistics,
+        );
         this.initializeCounters();
-        this.workerConfiguration = Configuration.getConfigurationSection<WorkerConfiguration>(
+        const workerConfiguration = Configuration.getConfigurationSection<WorkerConfiguration>(
           ConfigurationSection.worker,
         );
-        this.initializeWorkerImplementation(this.workerConfiguration);
+        this.initializeWorkerImplementation(workerConfiguration);
         await this.workerImplementation?.start();
         const performanceStorageConfiguration =
           Configuration.getConfigurationSection<StorageConfiguration>(
@@ -145,13 +144,13 @@ export class Bootstrap extends EventEmitter {
               this.version
             } started with ${this.numberOfChargingStations.toString()} charging station(s) from ${this.numberOfChargingStationTemplates.toString()} configured charging station template(s) and ${
               Configuration.workerDynamicPoolInUse()
-                ? `${this.workerConfiguration.poolMinSize?.toString()}/`
+                ? `${workerConfiguration.poolMinSize?.toString()}/`
                 : ''
             }${this.workerImplementation?.size}${
               Configuration.workerPoolInUse()
-                ? `/${this.workerConfiguration.poolMaxSize?.toString()}`
+                ? `/${workerConfiguration.poolMaxSize?.toString()}`
                 : ''
-            } worker(s) concurrently running in '${this.workerConfiguration.processType}' mode${
+            } worker(s) concurrently running in '${workerConfiguration.processType}' mode${
               !isNullOrUndefined(this.workerImplementation?.maxElementsPerWorker)
                 ? ` (${this.workerImplementation?.maxElementsPerWorker} charging station(s) per worker)`
                 : ''
@@ -195,8 +194,7 @@ export class Bootstrap extends EventEmitter {
         }
         await this.workerImplementation?.stop();
         delete this.workerImplementation;
-        delete this.workerConfiguration;
-        this.uiServer?.stop();
+        this.removeAllListeners();
         await this.storage?.close();
         delete this.storage;
         this.resetCounters();
@@ -213,6 +211,8 @@ export class Bootstrap extends EventEmitter {
 
   public async restart(stopChargingStations?: boolean): Promise<void> {
     await this.stop(stopChargingStations);
+    Configuration.getConfigurationSection<UIServerConfiguration>(ConfigurationSection.uiServer)
+      .enabled === false && this.uiServer?.stop();
     await this.start();
   }
 
@@ -242,11 +242,16 @@ export class Bootstrap extends EventEmitter {
 
   private initializeWorkerImplementation(workerConfiguration: WorkerConfiguration): void {
     let elementsPerWorker: number | undefined;
-    if (workerConfiguration?.elementsPerWorker === 'auto') {
-      elementsPerWorker =
-        this.numberOfChargingStations > availableParallelism()
-          ? Math.round(this.numberOfChargingStations / (availableParallelism() * 1.5))
-          : 1;
+    switch (workerConfiguration?.elementsPerWorker) {
+      case 'auto':
+        elementsPerWorker =
+          this.numberOfChargingStations > availableParallelism()
+            ? Math.round(this.numberOfChargingStations / (availableParallelism() * 1.5))
+            : 1;
+        break;
+      case 'all':
+        elementsPerWorker = this.numberOfChargingStations;
+        break;
     }
     this.workerImplementation = WorkerFactory.getWorkerImplementation<ChargingStationWorkerData>(
       join(
@@ -262,6 +267,7 @@ export class Bootstrap extends EventEmitter {
         elementsPerWorker: elementsPerWorker ?? (workerConfiguration.elementsPerWorker as number),
         poolOptions: {
           messageHandler: this.messageHandler.bind(this) as (message: unknown) => void,
+          workerOptions: { resourceLimits: workerConfiguration.resourceLimits },
         },
       },
     );
@@ -402,6 +408,7 @@ export class Bootstrap extends EventEmitter {
     this.stop()
       .then(() => {
         console.info(`${chalk.green('Graceful shutdown')}`);
+        this.uiServer?.stop();
         // stop() asks for charging stations to stop by default
         this.waitChargingStationsStopped()
           .then(() => {
index ba430878d4947641da61c72548fc58e437e75914..5bc0ec9ad24d8ae76f486f388eb86d03a2cad0b8 100644 (file)
@@ -22,6 +22,7 @@ import {
 import {
   buildConnectorsMap,
   checkChargingStation,
+  checkConfiguration,
   checkConnectorsConfiguration,
   checkStationInfoConnectorStatus,
   checkTemplate,
@@ -48,13 +49,16 @@ import {
   OCPP16IncomingRequestService,
   OCPP16RequestService,
   OCPP16ResponseService,
-  OCPP16ServiceUtils,
   OCPP20IncomingRequestService,
   OCPP20RequestService,
   OCPP20ResponseService,
   type OCPPIncomingRequestService,
   type OCPPRequestService,
-  OCPPServiceUtils,
+  buildMeterValue,
+  buildStatusNotificationRequest,
+  buildTransactionEndMeterValue,
+  getMessageTypeString,
+  sendAndSetConnectorStatus,
 } from './ocpp';
 import { SharedLRUCache } from './SharedLRUCache';
 import { BaseError, OCPPError } from '../exception';
@@ -87,9 +91,7 @@ import {
   type HeartbeatResponse,
   type IncomingRequest,
   type IncomingRequestCommand,
-  type JsonType,
   MessageType,
-  type MeterValue,
   MeterValueMeasurand,
   type MeterValuesRequest,
   type MeterValuesResponse,
@@ -111,7 +113,6 @@ import {
   type StopTransactionResponse,
   SupervisionUrlDistribution,
   SupportedFeatureProfiles,
-  VendorParametersKey,
   Voltage,
   type WSError,
   WebSocketCloseEventStatusCode,
@@ -497,7 +498,7 @@ export class ChargingStation extends EventEmitter {
   }
 
   public startHeartbeat(): void {
-    if (this.getHeartbeatInterval() > 0 && !this.heartbeatSetInterval) {
+    if (this.getHeartbeatInterval() > 0 && this.heartbeatSetInterval === undefined) {
       this.heartbeatSetInterval = setInterval(() => {
         this.ocppRequestService
           .requestHandler<HeartbeatRequest, HeartbeatResponse>(this, RequestCommand.HEARTBEAT)
@@ -513,7 +514,7 @@ export class ChargingStation extends EventEmitter {
           this.getHeartbeatInterval(),
         )}`,
       );
-    } else if (this.heartbeatSetInterval) {
+    } else if (this.heartbeatSetInterval !== undefined) {
       logger.info(
         `${this.logPrefix()} Heartbeat already started every ${formatDurationMilliSeconds(
           this.getHeartbeatInterval(),
@@ -570,8 +571,7 @@ export class ChargingStation extends EventEmitter {
     }
     if (interval > 0) {
       this.getConnectorStatus(connectorId)!.transactionSetInterval = setInterval(() => {
-        // FIXME: Implement OCPP version agnostic helpers
-        const meterValue: MeterValue = OCPP16ServiceUtils.buildMeterValue(
+        const meterValue = buildMeterValue(
           this,
           connectorId,
           this.getConnectorStatus(connectorId)!.transactionId!,
@@ -604,7 +604,7 @@ export class ChargingStation extends EventEmitter {
   }
 
   public stopMeterValues(connectorId: number) {
-    if (this.getConnectorStatus(connectorId)?.transactionSetInterval) {
+    if (this.getConnectorStatus(connectorId)?.transactionSetInterval !== undefined) {
       clearInterval(this.getConnectorStatus(connectorId)?.transactionSetInterval);
     }
   }
@@ -707,17 +707,7 @@ export class ChargingStation extends EventEmitter {
 
   public bufferMessage(message: string): void {
     this.messageBuffer.add(message);
-    if (this.flushMessageBufferSetInterval === undefined) {
-      this.flushMessageBufferSetInterval = setInterval(() => {
-        if (this.isWebSocketConnectionOpened() === true && this.inAcceptedState() === true) {
-          this.flushMessageBuffer();
-        }
-        if (this.flushMessageBufferSetInterval !== undefined && this.messageBuffer.size === 0) {
-          clearInterval(this.flushMessageBufferSetInterval);
-          delete this.flushMessageBufferSetInterval;
-        }
-      }, Constants.DEFAULT_MESSAGE_BUFFER_FLUSH_INTERVAL);
-    }
+    this.setIntervalFlushMessageBuffer();
   }
 
   public openWSConnection(
@@ -857,8 +847,7 @@ export class ChargingStation extends EventEmitter {
       this.stationInfo?.ocppStrictCompliance === true &&
       this.stationInfo?.outOfOrderEndMeterValues === false
     ) {
-      // FIXME: Implement OCPP version agnostic helpers
-      const transactionEndMeterValue = OCPP16ServiceUtils.buildTransactionEndMeterValue(
+      const transactionEndMeterValue = buildTransactionEndMeterValue(
         this,
         connectorId,
         this.getEnergyActiveImportRegisterByTransactionId(transactionId!),
@@ -896,7 +885,7 @@ export class ChargingStation extends EventEmitter {
       await this.removeReservation(reservationFound, ReservationTerminationReason.REPLACE_EXISTING);
     }
     this.getConnectorStatus(reservation.connectorId)!.reservation = reservation;
-    await OCPPServiceUtils.sendAndSetConnectorStatus(
+    await sendAndSetConnectorStatus(
       this,
       reservation.connectorId,
       ConnectorStatusEnum.Reserved,
@@ -918,7 +907,7 @@ export class ChargingStation extends EventEmitter {
       case ReservationTerminationReason.RESERVATION_CANCELED:
       case ReservationTerminationReason.REPLACE_EXISTING:
       case ReservationTerminationReason.EXPIRED:
-        await OCPPServiceUtils.sendAndSetConnectorStatus(
+        await sendAndSetConnectorStatus(
           this,
           reservation.connectorId,
           ConnectorStatusEnum.Available,
@@ -978,6 +967,26 @@ export class ChargingStation extends EventEmitter {
     return false;
   }
 
+  private setIntervalFlushMessageBuffer(): void {
+    if (this.flushMessageBufferSetInterval === undefined) {
+      this.flushMessageBufferSetInterval = setInterval(() => {
+        if (this.isWebSocketConnectionOpened() === true && this.inAcceptedState() === true) {
+          this.flushMessageBuffer();
+        }
+        if (this.messageBuffer.size === 0) {
+          this.clearIntervalFlushMessageBuffer();
+        }
+      }, Constants.DEFAULT_MESSAGE_BUFFER_FLUSH_INTERVAL);
+    }
+  }
+
+  private clearIntervalFlushMessageBuffer() {
+    if (this.flushMessageBufferSetInterval !== undefined) {
+      clearInterval(this.flushMessageBufferSetInterval);
+      delete this.flushMessageBufferSetInterval;
+    }
+  }
+
   private getNumberOfReservableConnectors(): number {
     let numberOfReservableConnectors = 0;
     if (this.hasEvses) {
@@ -1016,11 +1025,18 @@ export class ChargingStation extends EventEmitter {
           isRequest && PerformanceStatistics.endMeasure(commandName!, beginId!);
           if (isNullOrUndefined(error)) {
             logger.debug(
-              `${this.logPrefix()} >> Buffered ${OCPPServiceUtils.getMessageTypeString(
+              `${this.logPrefix()} >> Buffered ${getMessageTypeString(
                 messageType,
-              )} payload sent: ${message}`,
+              )} OCPP message sent '${JSON.stringify(message)}'`,
             );
             this.messageBuffer.delete(message);
+          } else {
+            logger.debug(
+              `${this.logPrefix()} >> Buffered ${getMessageTypeString(
+                messageType,
+              )} OCPP message '${JSON.stringify(message)}' send failed:`,
+              error,
+            );
           }
         });
       }
@@ -1124,29 +1140,7 @@ export class ChargingStation extends EventEmitter {
   }
 
   private getStationInfo(): ChargingStationInfo {
-    const defaultStationInfo: Partial<ChargingStationInfo> = {
-      enableStatistics: false,
-      remoteAuthorization: true,
-      currentOutType: CurrentType.AC,
-      mainVoltageMeterValues: true,
-      phaseLineToLineVoltageMeterValues: false,
-      customValueLimitationMeterValues: true,
-      ocppStrictCompliance: true,
-      outOfOrderEndMeterValues: false,
-      beginEndMeterValues: false,
-      meteringPerTransaction: true,
-      transactionDataMeterValues: false,
-      supervisionUrlOcppConfiguration: false,
-      supervisionUrlOcppKey: VendorParametersKey.ConnectionUrl,
-      ocppVersion: OCPPVersion.VERSION_16,
-      ocppPersistentConfiguration: true,
-      stationInfoPersistentConfiguration: true,
-      automaticTransactionGeneratorPersistentConfiguration: true,
-      autoReconnectMaxRetries: -1,
-      registrationMaxRetries: -1,
-      reconnectExponentialDelay: false,
-      stopTransactionsOnStopped: true,
-    };
+    const defaultStationInfo = Constants.DEFAULT_STATION_INFO;
     const stationInfoFromTemplate: ChargingStationInfo = this.getStationInfoFromTemplate();
     const stationInfoFromFile: ChargingStationInfo | undefined = this.getStationInfoFromFile(
       stationInfoFromTemplate?.stationInfoPersistentConfiguration,
@@ -1191,6 +1185,7 @@ export class ChargingStation extends EventEmitter {
       // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
       (stationConfiguration?.connectorsStatus || stationConfiguration?.evsesStatus)
     ) {
+      checkConfiguration(stationConfiguration, this.logPrefix(), this.configurationFile);
       this.initializeConnectorsOrEvsesFromFile(stationConfiguration);
     } else {
       this.initializeConnectorsOrEvsesFromTemplate(stationTemplate);
@@ -1204,15 +1199,17 @@ export class ChargingStation extends EventEmitter {
       const patternGroup: number | undefined =
         this.stationInfo.firmwareUpgrade?.versionUpgrade?.patternGroup ??
         this.stationInfo.firmwareVersion?.split('.').length;
-      const match = this.stationInfo
-        .firmwareVersion!.match(new RegExp(this.stationInfo.firmwareVersionPattern!))!
-        .slice(1, patternGroup! + 1);
-      const patchLevelIndex = match.length - 1;
-      match[patchLevelIndex] = (
-        convertToInt(match[patchLevelIndex]) +
-        this.stationInfo.firmwareUpgrade!.versionUpgrade!.step!
-      ).toString();
-      this.stationInfo.firmwareVersion = match?.join('.');
+      const match = new RegExp(this.stationInfo.firmwareVersionPattern!)
+        .exec(this.stationInfo.firmwareVersion!)
+        ?.slice(1, patternGroup! + 1);
+      if (!isNullOrUndefined(match)) {
+        const patchLevelIndex = match!.length - 1;
+        match![patchLevelIndex] = (
+          convertToInt(match![patchLevelIndex]) +
+          this.stationInfo.firmwareUpgrade!.versionUpgrade!.step!
+        ).toString();
+        this.stationInfo.firmwareVersion = match!.join('.');
+      }
     }
     this.saveStationInfo();
     this.configuredSupervisionUrl = this.getConfiguredSupervisionUrl();
@@ -1804,11 +1801,11 @@ export class ChargingStation extends EventEmitter {
     }
     throw new OCPPError(
       ErrorType.PROTOCOL_ERROR,
-      `Cached request for message id ${messageId} ${OCPPServiceUtils.getMessageTypeString(
+      `Cached request for message id ${messageId} ${getMessageTypeString(
         messageType,
       )} is not an array`,
       undefined,
-      cachedRequest as JsonType,
+      cachedRequest,
     );
   }
 
@@ -2091,12 +2088,7 @@ export class ChargingStation extends EventEmitter {
         if (evseId > 0) {
           for (const [connectorId, connectorStatus] of evseStatus.connectors) {
             const connectorBootStatus = getBootConnectorStatus(this, connectorId, connectorStatus);
-            await OCPPServiceUtils.sendAndSetConnectorStatus(
-              this,
-              connectorId,
-              connectorBootStatus,
-              evseId,
-            );
+            await sendAndSetConnectorStatus(this, connectorId, connectorBootStatus, evseId);
           }
         }
       }
@@ -2108,7 +2100,7 @@ export class ChargingStation extends EventEmitter {
             connectorId,
             this.getConnectorStatus(connectorId)!,
           );
-          await OCPPServiceUtils.sendAndSetConnectorStatus(this, connectorId, connectorBootStatus);
+          await sendAndSetConnectorStatus(this, connectorId, connectorBootStatus);
         }
       }
     }
@@ -2153,7 +2145,7 @@ export class ChargingStation extends EventEmitter {
             >(
               this,
               RequestCommand.STATUS_NOTIFICATION,
-              OCPPServiceUtils.buildStatusNotificationRequest(
+              buildStatusNotificationRequest(
                 this,
                 connectorId,
                 ConnectorStatusEnum.Unavailable,
@@ -2173,11 +2165,7 @@ export class ChargingStation extends EventEmitter {
           >(
             this,
             RequestCommand.STATUS_NOTIFICATION,
-            OCPPServiceUtils.buildStatusNotificationRequest(
-              this,
-              connectorId,
-              ConnectorStatusEnum.Unavailable,
-            ),
+            buildStatusNotificationRequest(this, connectorId, ConnectorStatusEnum.Unavailable),
           );
           delete this.getConnectorStatus(connectorId)?.status;
         }
@@ -2262,7 +2250,7 @@ export class ChargingStation extends EventEmitter {
   }
 
   private stopHeartbeat(): void {
-    if (this.heartbeatSetInterval) {
+    if (this.heartbeatSetInterval !== undefined) {
       clearInterval(this.heartbeatSetInterval);
       delete this.heartbeatSetInterval;
     }
index 955ce933b5ffb27d4e6315bd4206cd7373b101f3..d9e462d064967b75255dc333f3926f28b14b4cf4 100644 (file)
@@ -1,6 +1,5 @@
 // Partial Copyright Jerome Benoit. 2021-2023. All Rights Reserved.
 
-import { AsyncResource } from 'node:async_hooks';
 import { parentPort } from 'node:worker_threads';
 
 import { ThreadWorker } from 'poolifier';
@@ -9,9 +8,7 @@ import { ChargingStation } from './ChargingStation';
 import { BaseError } from '../exception';
 import type { ChargingStationWorkerData } from '../types';
 import { Configuration } from '../utils';
-import { type WorkerData, type WorkerMessage, WorkerMessageEvents } from '../worker';
-
-const moduleName = 'ChargingStationWorker';
+import { type WorkerMessage, WorkerMessageEvents } from '../worker';
 
 /**
  * Creates and starts a charging station instance
@@ -22,19 +19,14 @@ const startChargingStation = (data?: ChargingStationWorkerData): void => {
   new ChargingStation(data!.index, data!.templateFile).start();
 };
 
-class ChargingStationWorker<Data extends WorkerData> extends AsyncResource {
+class ChargingStationWorker<Data extends ChargingStationWorkerData> {
   constructor() {
-    super(moduleName);
     // Add message listener to create and start charging station from the main thread
     parentPort?.on('message', (message: WorkerMessage<Data>) => {
       switch (message.event) {
         case WorkerMessageEvents.startWorkerElement:
           try {
-            this.runInAsyncScope(
-              startChargingStation.bind(this) as (data?: Data) => void,
-              this,
-              message.data,
-            );
+            startChargingStation(message.data);
             parentPort?.postMessage({
               event: WorkerMessageEvents.startedWorkerElement,
             });
index 13721bd6cd04975c601c25a229ffb3a1bd98d199..492d26aa10dbeb5a5d028e1a7d6d111c291ac368 100644 (file)
@@ -6,6 +6,7 @@ import { fileURLToPath } from 'node:url';
 
 import chalk from 'chalk';
 import {
+  type Interval,
   addDays,
   addSeconds,
   addWeeks,
@@ -17,9 +18,9 @@ import {
   isDate,
   isPast,
   isWithinInterval,
-  maxTime,
   toDate,
 } from 'date-fns';
+import { maxTime } from 'date-fns/constants';
 
 import type { ChargingStation } from './ChargingStation';
 import { getConfigurationKey } from './ConfigurationKeyUtils';
@@ -33,6 +34,7 @@ import {
   ChargingProfileKindType,
   ChargingRateUnitType,
   type ChargingSchedulePeriod,
+  type ChargingStationConfiguration,
   type ChargingStationInfo,
   type ChargingStationTemplate,
   ChargingStationWorkerMessageEvents,
@@ -253,6 +255,23 @@ export const checkTemplate = (
   }
 };
 
+export const checkConfiguration = (
+  stationConfiguration: ChargingStationConfiguration | undefined,
+  logPrefix: string,
+  configurationFile: string,
+): void => {
+  if (isNullOrUndefined(stationConfiguration)) {
+    const errorMsg = `Failed to read charging station configuration file ${configurationFile}`;
+    logger.error(`${logPrefix} ${errorMsg}`);
+    throw new BaseError(errorMsg);
+  }
+  if (isEmptyObject(stationConfiguration!)) {
+    const errorMsg = `Empty charging station configuration from file ${configurationFile}`;
+    logger.error(`${logPrefix} ${errorMsg}`);
+    throw new BaseError(errorMsg);
+  }
+};
+
 export const checkConnectorsConfiguration = (
   stationTemplate: ChargingStationTemplate,
   logPrefix: string,
index a8d9b045abde5b93728ab16548a3a4e91fec8511..2697397a6b7e6bcebed8fd47cd34a548bb471c6e 100644 (file)
@@ -40,7 +40,7 @@ import {
 import { Constants, convertToInt, isEmptyObject, isNullOrUndefined, logger } from '../../utils';
 import type { ChargingStation } from '../ChargingStation';
 import { getConfigurationKey } from '../ConfigurationKeyUtils';
-import { OCPP16ServiceUtils } from '../ocpp';
+import { buildMeterValue } from '../ocpp';
 
 const moduleName = 'ChargingStationWorkerBroadcastChannel';
 
@@ -188,8 +188,7 @@ export class ChargingStationWorkerBroadcastChannel extends WorkerBroadcastChanne
             RequestCommand.METER_VALUES,
             {
               meterValue: [
-                // FIXME: Implement OCPP version agnostic helpers
-                OCPP16ServiceUtils.buildMeterValue(
+                buildMeterValue(
                   this.chargingStation,
                   requestPayload!.connectorId!,
                   this.chargingStation.getConnectorStatus(requestPayload!.connectorId!)!
index b385be7fc47aae52e67eaac792dc4f59256c81a1..d328291636ac8da6f37ce6fc1eebca288e67d339 100644 (file)
@@ -70,31 +70,31 @@ export class UIServiceWorkerBroadcastChannel extends WorkerBroadcastChannel {
       status: responsesStatus,
       hashIdsSucceeded: this.responses
         .get(uuid)
-        ?.responses.filter(({ hashId }) => !isNullOrUndefined(hashId))
-        .map(({ status, hashId }) => {
-          if (status === ResponseStatus.SUCCESS) {
+        ?.responses.map(({ status, hashId }) => {
+          if (hashId !== undefined && status === ResponseStatus.SUCCESS) {
             return hashId;
           }
-        }) as string[],
+        })
+        .filter((hashId) => !isNullOrUndefined(hashId)) as string[],
       ...(responsesStatus === ResponseStatus.FAILURE && {
         hashIdsFailed: this.responses
           .get(uuid)
-          ?.responses.filter(({ hashId }) => !isNullOrUndefined(hashId))
-          .map(({ status, hashId }) => {
-            if (status === ResponseStatus.FAILURE) {
+          ?.responses.map(({ status, hashId }) => {
+            if (hashId !== undefined && status === ResponseStatus.FAILURE) {
               return hashId;
             }
-          }) as string[],
+          })
+          .filter((hashId) => !isNullOrUndefined(hashId)) as string[],
       }),
       ...(responsesStatus === ResponseStatus.FAILURE && {
         responsesFailed: this.responses
           .get(uuid)
-          ?.responses.filter((response) => !isNullOrUndefined(response))
-          .map((response) => {
-            if (response.status === ResponseStatus.FAILURE) {
+          ?.responses.map((response) => {
+            if (response !== undefined && response.status === ResponseStatus.FAILURE) {
               return response;
             }
-          }) as BroadcastChannelResponsePayload[],
+          })
+          .filter((response) => !isNullOrUndefined(response)) as BroadcastChannelResponsePayload[],
       }),
     };
   }
index 2b34342e105ec2264f5f076d2a20062ca06910e4..6dae5c8ad51c17f66f332906bd44c0067d7720de 100644 (file)
@@ -6,7 +6,14 @@ import { URL, fileURLToPath } from 'node:url';
 
 import type { JSONSchemaType } from 'ajv';
 import { Client, type FTPResponse } from 'basic-ftp';
-import { addSeconds, differenceInSeconds, isDate, maxTime, secondsToMilliseconds } from 'date-fns';
+import {
+  type Interval,
+  addSeconds,
+  differenceInSeconds,
+  isDate,
+  secondsToMilliseconds,
+} from 'date-fns';
+import { maxTime } from 'date-fns/constants';
 import { create } from 'tar';
 
 import { OCPP16Constants } from './OCPP16Constants';
@@ -25,8 +32,6 @@ import { OCPPError } from '../../../exception';
 import {
   type ChangeConfigurationRequest,
   type ChangeConfigurationResponse,
-  type ClearChargingProfileRequest,
-  type ClearChargingProfileResponse,
   ErrorType,
   type GenericResponse,
   GenericStatus,
@@ -49,6 +54,8 @@ import {
   OCPP16ChargingProfilePurposeType,
   type OCPP16ChargingSchedule,
   type OCPP16ClearCacheRequest,
+  type OCPP16ClearChargingProfileRequest,
+  type OCPP16ClearChargingProfileResponse,
   type OCPP16DataTransferRequest,
   type OCPP16DataTransferResponse,
   OCPP16DataTransferVendorId,
@@ -253,7 +260,7 @@ export class OCPP16IncomingRequestService extends OCPPIncomingRequestService {
       ],
       [
         OCPP16IncomingRequestCommand.CLEAR_CHARGING_PROFILE,
-        OCPP16ServiceUtils.parseJsonSchemaFile<ClearChargingProfileRequest>(
+        OCPP16ServiceUtils.parseJsonSchemaFile<OCPP16ClearChargingProfileRequest>(
           'assets/json-schemas/ocpp/1.6/ClearChargingProfile.json',
           moduleName,
           'constructor',
@@ -438,14 +445,9 @@ export class OCPP16IncomingRequestService extends OCPPIncomingRequestService {
     commandPayload: ResetRequest,
   ): GenericResponse {
     const { type } = commandPayload;
-    this.runInAsyncScope(
-      chargingStation.reset.bind(chargingStation) as (
-        this: ChargingStation,
-        ...args: unknown[]
-      ) => Promise<void>,
-      chargingStation,
-      `${type}Reset` as OCPP16StopTransactionReason,
-    ).catch(Constants.EMPTY_FUNCTION);
+    chargingStation
+      .reset(`${type}Reset` as OCPP16StopTransactionReason)
+      .catch(Constants.EMPTY_FUNCTION);
     logger.info(
       `${chargingStation.logPrefix()} ${type} reset command received, simulating it. The station will be back online in ${formatDurationMilliSeconds(
         chargingStation.stationInfo.resetTime!,
@@ -791,8 +793,8 @@ export class OCPP16IncomingRequestService extends OCPPIncomingRequestService {
 
   private handleRequestClearChargingProfile(
     chargingStation: ChargingStation,
-    commandPayload: ClearChargingProfileRequest,
-  ): ClearChargingProfileResponse {
+    commandPayload: OCPP16ClearChargingProfileRequest,
+  ): OCPP16ClearChargingProfileResponse {
     if (
       OCPP16ServiceUtils.checkFeatureProfile(
         chargingStation,
@@ -1115,25 +1117,11 @@ export class OCPP16IncomingRequestService extends OCPPIncomingRequestService {
     retrieveDate = convertToDate(retrieveDate)!;
     const now = Date.now();
     if (retrieveDate?.getTime() <= now) {
-      this.runInAsyncScope(
-        this.updateFirmwareSimulation.bind(this) as (
-          this: OCPP16IncomingRequestService,
-          ...args: unknown[]
-        ) => Promise<void>,
-        this,
-        chargingStation,
-      ).catch(Constants.EMPTY_FUNCTION);
+      this.updateFirmwareSimulation(chargingStation).catch(Constants.EMPTY_FUNCTION);
     } else {
       setTimeout(
         () => {
-          this.runInAsyncScope(
-            this.updateFirmwareSimulation.bind(this) as (
-              this: OCPP16IncomingRequestService,
-              ...args: unknown[]
-            ) => Promise<void>,
-            this,
-            chargingStation,
-          ).catch(Constants.EMPTY_FUNCTION);
+          this.updateFirmwareSimulation(chargingStation).catch(Constants.EMPTY_FUNCTION);
         },
         retrieveDate?.getTime() - now,
       );
index 146778141abdbcc3c72b7860d2fde9b5d8792c8e..7c331b6c79d70c328276c8b196ca9e552591d19e 100644 (file)
@@ -14,7 +14,6 @@ import {
 import { OCPPError } from '../../../exception';
 import {
   type ChangeConfigurationResponse,
-  type ClearChargingProfileResponse,
   ErrorType,
   type GenericResponse,
   type GetConfigurationResponse,
@@ -26,6 +25,7 @@ import {
   type OCPP16BootNotificationResponse,
   type OCPP16ChangeAvailabilityResponse,
   OCPP16ChargePointStatus,
+  type OCPP16ClearChargingProfileResponse,
   type OCPP16DataTransferResponse,
   type OCPP16DiagnosticsStatusNotificationResponse,
   type OCPP16FirmwareStatusNotificationResponse,
@@ -249,7 +249,7 @@ export class OCPP16ResponseService extends OCPPResponseService {
       ],
       [
         OCPP16IncomingRequestCommand.CLEAR_CHARGING_PROFILE,
-        OCPP16ServiceUtils.parseJsonSchemaFile<ClearChargingProfileResponse>(
+        OCPP16ServiceUtils.parseJsonSchemaFile<OCPP16ClearChargingProfileResponse>(
           'assets/json-schemas/ocpp/1.6/ClearChargingProfileResponse.json',
           moduleName,
           'constructor',
index 197fb6a2aeca0e924a677ee0d327f600abc1f926..4062bc0af881d3445fdfc5207983d531dbf89b2a 100644 (file)
@@ -2,6 +2,7 @@
 
 import type { JSONSchemaType } from 'ajv';
 import {
+  type Interval,
   addSeconds,
   areIntervalsOverlapping,
   differenceInSeconds,
@@ -16,52 +17,27 @@ import {
   hasFeatureProfile,
   hasReservationExpired,
 } from '../../../charging-station';
-import { OCPPError } from '../../../exception';
 import {
-  type ClearChargingProfileRequest,
-  CurrentType,
-  ErrorType,
   type GenericResponse,
   type JsonType,
-  type MeasurandPerPhaseSampledValueTemplates,
-  type MeasurandValues,
-  MeterValueContext,
-  MeterValueLocation,
-  MeterValueUnit,
   OCPP16AuthorizationStatus,
   OCPP16AvailabilityType,
   type OCPP16ChangeAvailabilityResponse,
   OCPP16ChargePointStatus,
   type OCPP16ChargingProfile,
   type OCPP16ChargingSchedule,
+  type OCPP16ClearChargingProfileRequest,
   type OCPP16IncomingRequestCommand,
   type OCPP16MeterValue,
-  OCPP16MeterValueMeasurand,
-  OCPP16MeterValuePhase,
+  OCPP16MeterValueContext,
+  OCPP16MeterValueUnit,
   OCPP16RequestCommand,
-  type OCPP16SampledValue,
   OCPP16StandardParametersKey,
   OCPP16StopTransactionReason,
   type OCPP16SupportedFeatureProfiles,
   OCPPVersion,
-  type SampledValueTemplate,
 } from '../../../types';
-import {
-  ACElectricUtils,
-  Constants,
-  DCElectricUtils,
-  convertToFloat,
-  convertToInt,
-  getRandomFloatFluctuatedRounded,
-  getRandomFloatRounded,
-  getRandomInteger,
-  isNotEmptyArray,
-  isNotEmptyString,
-  isNullOrUndefined,
-  isUndefined,
-  logger,
-  roundTo,
-} from '../../../utils';
+import { isNotEmptyArray, isNullOrUndefined, logger, roundTo } from '../../../utils';
 import { OCPPServiceUtils } from '../OCPPServiceUtils';
 
 export class OCPP16ServiceUtils extends OCPPServiceUtils {
@@ -81,764 +57,6 @@ export class OCPP16ServiceUtils extends OCPPServiceUtils {
     return true;
   }
 
-  public static buildMeterValue(
-    chargingStation: ChargingStation,
-    connectorId: number,
-    transactionId: number,
-    interval: number,
-    debug = false,
-  ): OCPP16MeterValue {
-    const meterValue: OCPP16MeterValue = {
-      timestamp: new Date(),
-      sampledValue: [],
-    };
-    const connector = chargingStation.getConnectorStatus(connectorId);
-    // SoC measurand
-    const socSampledValueTemplate = OCPP16ServiceUtils.getSampledValueTemplate(
-      chargingStation,
-      connectorId,
-      OCPP16MeterValueMeasurand.STATE_OF_CHARGE,
-    );
-    if (socSampledValueTemplate) {
-      const socMaximumValue = 100;
-      const socMinimumValue = socSampledValueTemplate.minimumValue ?? 0;
-      const socSampledValueTemplateValue = isNotEmptyString(socSampledValueTemplate.value)
-        ? getRandomFloatFluctuatedRounded(
-            parseInt(socSampledValueTemplate.value),
-            socSampledValueTemplate.fluctuationPercent ?? Constants.DEFAULT_FLUCTUATION_PERCENT,
-          )
-        : getRandomInteger(socMaximumValue, socMinimumValue);
-      meterValue.sampledValue.push(
-        OCPP16ServiceUtils.buildSampledValue(socSampledValueTemplate, socSampledValueTemplateValue),
-      );
-      const sampledValuesIndex = meterValue.sampledValue.length - 1;
-      if (
-        convertToInt(meterValue.sampledValue[sampledValuesIndex].value) > socMaximumValue ||
-        convertToInt(meterValue.sampledValue[sampledValuesIndex].value) < socMinimumValue ||
-        debug
-      ) {
-        logger.error(
-          `${chargingStation.logPrefix()} MeterValues measurand ${
-            meterValue.sampledValue[sampledValuesIndex].measurand ??
-            OCPP16MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER
-          }: connector id ${connectorId}, transaction id ${connector?.transactionId}, value: ${socMinimumValue}/${
-            meterValue.sampledValue[sampledValuesIndex].value
-          }/${socMaximumValue}`,
-        );
-      }
-    }
-    // Voltage measurand
-    const voltageSampledValueTemplate = OCPP16ServiceUtils.getSampledValueTemplate(
-      chargingStation,
-      connectorId,
-      OCPP16MeterValueMeasurand.VOLTAGE,
-    );
-    if (voltageSampledValueTemplate) {
-      const voltageSampledValueTemplateValue = isNotEmptyString(voltageSampledValueTemplate.value)
-        ? parseInt(voltageSampledValueTemplate.value)
-        : chargingStation.stationInfo.voltageOut!;
-      const fluctuationPercent =
-        voltageSampledValueTemplate.fluctuationPercent ?? Constants.DEFAULT_FLUCTUATION_PERCENT;
-      const voltageMeasurandValue = getRandomFloatFluctuatedRounded(
-        voltageSampledValueTemplateValue,
-        fluctuationPercent,
-      );
-      if (
-        chargingStation.getNumberOfPhases() !== 3 ||
-        (chargingStation.getNumberOfPhases() === 3 &&
-          chargingStation.stationInfo?.mainVoltageMeterValues)
-      ) {
-        meterValue.sampledValue.push(
-          OCPP16ServiceUtils.buildSampledValue(voltageSampledValueTemplate, voltageMeasurandValue),
-        );
-      }
-      for (
-        let phase = 1;
-        chargingStation.getNumberOfPhases() === 3 && phase <= chargingStation.getNumberOfPhases();
-        phase++
-      ) {
-        const phaseLineToNeutralValue = `L${phase}-N`;
-        const voltagePhaseLineToNeutralSampledValueTemplate =
-          OCPP16ServiceUtils.getSampledValueTemplate(
-            chargingStation,
-            connectorId,
-            OCPP16MeterValueMeasurand.VOLTAGE,
-            phaseLineToNeutralValue as OCPP16MeterValuePhase,
-          );
-        let voltagePhaseLineToNeutralMeasurandValue: number | undefined;
-        if (voltagePhaseLineToNeutralSampledValueTemplate) {
-          const voltagePhaseLineToNeutralSampledValueTemplateValue = isNotEmptyString(
-            voltagePhaseLineToNeutralSampledValueTemplate.value,
-          )
-            ? parseInt(voltagePhaseLineToNeutralSampledValueTemplate.value)
-            : chargingStation.stationInfo.voltageOut!;
-          const fluctuationPhaseToNeutralPercent =
-            voltagePhaseLineToNeutralSampledValueTemplate.fluctuationPercent ??
-            Constants.DEFAULT_FLUCTUATION_PERCENT;
-          voltagePhaseLineToNeutralMeasurandValue = getRandomFloatFluctuatedRounded(
-            voltagePhaseLineToNeutralSampledValueTemplateValue,
-            fluctuationPhaseToNeutralPercent,
-          );
-        }
-        meterValue.sampledValue.push(
-          OCPP16ServiceUtils.buildSampledValue(
-            voltagePhaseLineToNeutralSampledValueTemplate ?? voltageSampledValueTemplate,
-            voltagePhaseLineToNeutralMeasurandValue ?? voltageMeasurandValue,
-            undefined,
-            phaseLineToNeutralValue as OCPP16MeterValuePhase,
-          ),
-        );
-        if (chargingStation.stationInfo?.phaseLineToLineVoltageMeterValues) {
-          const phaseLineToLineValue = `L${phase}-L${
-            (phase + 1) % chargingStation.getNumberOfPhases() !== 0
-              ? (phase + 1) % chargingStation.getNumberOfPhases()
-              : chargingStation.getNumberOfPhases()
-          }`;
-          const voltagePhaseLineToLineValueRounded = roundTo(
-            Math.sqrt(chargingStation.getNumberOfPhases()) *
-              chargingStation.stationInfo.voltageOut!,
-            2,
-          );
-          const voltagePhaseLineToLineSampledValueTemplate =
-            OCPP16ServiceUtils.getSampledValueTemplate(
-              chargingStation,
-              connectorId,
-              OCPP16MeterValueMeasurand.VOLTAGE,
-              phaseLineToLineValue as OCPP16MeterValuePhase,
-            );
-          let voltagePhaseLineToLineMeasurandValue: number | undefined;
-          if (voltagePhaseLineToLineSampledValueTemplate) {
-            const voltagePhaseLineToLineSampledValueTemplateValue = isNotEmptyString(
-              voltagePhaseLineToLineSampledValueTemplate.value,
-            )
-              ? parseInt(voltagePhaseLineToLineSampledValueTemplate.value)
-              : voltagePhaseLineToLineValueRounded;
-            const fluctuationPhaseLineToLinePercent =
-              voltagePhaseLineToLineSampledValueTemplate.fluctuationPercent ??
-              Constants.DEFAULT_FLUCTUATION_PERCENT;
-            voltagePhaseLineToLineMeasurandValue = getRandomFloatFluctuatedRounded(
-              voltagePhaseLineToLineSampledValueTemplateValue,
-              fluctuationPhaseLineToLinePercent,
-            );
-          }
-          const defaultVoltagePhaseLineToLineMeasurandValue = getRandomFloatFluctuatedRounded(
-            voltagePhaseLineToLineValueRounded,
-            fluctuationPercent,
-          );
-          meterValue.sampledValue.push(
-            OCPP16ServiceUtils.buildSampledValue(
-              voltagePhaseLineToLineSampledValueTemplate ?? voltageSampledValueTemplate,
-              voltagePhaseLineToLineMeasurandValue ?? defaultVoltagePhaseLineToLineMeasurandValue,
-              undefined,
-              phaseLineToLineValue as OCPP16MeterValuePhase,
-            ),
-          );
-        }
-      }
-    }
-    // Power.Active.Import measurand
-    const powerSampledValueTemplate = OCPP16ServiceUtils.getSampledValueTemplate(
-      chargingStation,
-      connectorId,
-      OCPP16MeterValueMeasurand.POWER_ACTIVE_IMPORT,
-    );
-    let powerPerPhaseSampledValueTemplates: MeasurandPerPhaseSampledValueTemplates = {};
-    if (chargingStation.getNumberOfPhases() === 3) {
-      powerPerPhaseSampledValueTemplates = {
-        L1: OCPP16ServiceUtils.getSampledValueTemplate(
-          chargingStation,
-          connectorId,
-          OCPP16MeterValueMeasurand.POWER_ACTIVE_IMPORT,
-          OCPP16MeterValuePhase.L1_N,
-        ),
-        L2: OCPP16ServiceUtils.getSampledValueTemplate(
-          chargingStation,
-          connectorId,
-          OCPP16MeterValueMeasurand.POWER_ACTIVE_IMPORT,
-          OCPP16MeterValuePhase.L2_N,
-        ),
-        L3: OCPP16ServiceUtils.getSampledValueTemplate(
-          chargingStation,
-          connectorId,
-          OCPP16MeterValueMeasurand.POWER_ACTIVE_IMPORT,
-          OCPP16MeterValuePhase.L3_N,
-        ),
-      };
-    }
-    if (powerSampledValueTemplate) {
-      OCPP16ServiceUtils.checkMeasurandPowerDivider(
-        chargingStation,
-        powerSampledValueTemplate.measurand!,
-      );
-      const errMsg = `MeterValues measurand ${
-        powerSampledValueTemplate.measurand ??
-        OCPP16MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER
-      }: Unknown ${chargingStation.stationInfo?.currentOutType} currentOutType in template file ${
-        chargingStation.templateFile
-      }, cannot calculate ${
-        powerSampledValueTemplate.measurand ??
-        OCPP16MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER
-      } measurand value`;
-      const powerMeasurandValues: MeasurandValues = {} as MeasurandValues;
-      const unitDivider = powerSampledValueTemplate?.unit === MeterValueUnit.KILO_WATT ? 1000 : 1;
-      const connectorMaximumAvailablePower =
-        chargingStation.getConnectorMaximumAvailablePower(connectorId);
-      const connectorMaximumPower = Math.round(connectorMaximumAvailablePower);
-      const connectorMaximumPowerPerPhase = Math.round(
-        connectorMaximumAvailablePower / chargingStation.getNumberOfPhases(),
-      );
-      const connectorMinimumPower = Math.round(powerSampledValueTemplate.minimumValue ?? 0);
-      const connectorMinimumPowerPerPhase = Math.round(
-        connectorMinimumPower / chargingStation.getNumberOfPhases(),
-      );
-      switch (chargingStation.stationInfo?.currentOutType) {
-        case CurrentType.AC:
-          if (chargingStation.getNumberOfPhases() === 3) {
-            const defaultFluctuatedPowerPerPhase = isNotEmptyString(powerSampledValueTemplate.value)
-              ? getRandomFloatFluctuatedRounded(
-                  OCPP16ServiceUtils.getLimitFromSampledValueTemplateCustomValue(
-                    powerSampledValueTemplate.value,
-                    connectorMaximumPower / unitDivider,
-                    connectorMinimumPower / unitDivider,
-                    {
-                      limitationEnabled:
-                        chargingStation.stationInfo?.customValueLimitationMeterValues,
-                      fallbackValue: connectorMinimumPower / unitDivider,
-                    },
-                  ) / chargingStation.getNumberOfPhases(),
-                  powerSampledValueTemplate.fluctuationPercent ??
-                    Constants.DEFAULT_FLUCTUATION_PERCENT,
-                )
-              : undefined;
-            const phase1FluctuatedValue = isNotEmptyString(
-              powerPerPhaseSampledValueTemplates.L1?.value,
-            )
-              ? getRandomFloatFluctuatedRounded(
-                  OCPP16ServiceUtils.getLimitFromSampledValueTemplateCustomValue(
-                    powerPerPhaseSampledValueTemplates.L1?.value,
-                    connectorMaximumPowerPerPhase / unitDivider,
-                    connectorMinimumPowerPerPhase / unitDivider,
-                    {
-                      limitationEnabled:
-                        chargingStation.stationInfo?.customValueLimitationMeterValues,
-                      fallbackValue: connectorMinimumPowerPerPhase / unitDivider,
-                    },
-                  ),
-                  powerPerPhaseSampledValueTemplates.L1?.fluctuationPercent ??
-                    Constants.DEFAULT_FLUCTUATION_PERCENT,
-                )
-              : undefined;
-            const phase2FluctuatedValue = isNotEmptyString(
-              powerPerPhaseSampledValueTemplates.L2?.value,
-            )
-              ? getRandomFloatFluctuatedRounded(
-                  OCPP16ServiceUtils.getLimitFromSampledValueTemplateCustomValue(
-                    powerPerPhaseSampledValueTemplates.L2?.value,
-                    connectorMaximumPowerPerPhase / unitDivider,
-                    connectorMinimumPowerPerPhase / unitDivider,
-                    {
-                      limitationEnabled:
-                        chargingStation.stationInfo?.customValueLimitationMeterValues,
-                      fallbackValue: connectorMinimumPowerPerPhase / unitDivider,
-                    },
-                  ),
-                  powerPerPhaseSampledValueTemplates.L2?.fluctuationPercent ??
-                    Constants.DEFAULT_FLUCTUATION_PERCENT,
-                )
-              : undefined;
-            const phase3FluctuatedValue = isNotEmptyString(
-              powerPerPhaseSampledValueTemplates.L3?.value,
-            )
-              ? getRandomFloatFluctuatedRounded(
-                  OCPP16ServiceUtils.getLimitFromSampledValueTemplateCustomValue(
-                    powerPerPhaseSampledValueTemplates.L3?.value,
-                    connectorMaximumPowerPerPhase / unitDivider,
-                    connectorMinimumPowerPerPhase / unitDivider,
-                    {
-                      limitationEnabled:
-                        chargingStation.stationInfo?.customValueLimitationMeterValues,
-                      fallbackValue: connectorMinimumPowerPerPhase / unitDivider,
-                    },
-                  ),
-                  powerPerPhaseSampledValueTemplates.L3?.fluctuationPercent ??
-                    Constants.DEFAULT_FLUCTUATION_PERCENT,
-                )
-              : undefined;
-            powerMeasurandValues.L1 =
-              phase1FluctuatedValue ??
-              defaultFluctuatedPowerPerPhase ??
-              getRandomFloatRounded(
-                connectorMaximumPowerPerPhase / unitDivider,
-                connectorMinimumPowerPerPhase / unitDivider,
-              );
-            powerMeasurandValues.L2 =
-              phase2FluctuatedValue ??
-              defaultFluctuatedPowerPerPhase ??
-              getRandomFloatRounded(
-                connectorMaximumPowerPerPhase / unitDivider,
-                connectorMinimumPowerPerPhase / unitDivider,
-              );
-            powerMeasurandValues.L3 =
-              phase3FluctuatedValue ??
-              defaultFluctuatedPowerPerPhase ??
-              getRandomFloatRounded(
-                connectorMaximumPowerPerPhase / unitDivider,
-                connectorMinimumPowerPerPhase / unitDivider,
-              );
-          } else {
-            powerMeasurandValues.L1 = isNotEmptyString(powerSampledValueTemplate.value)
-              ? getRandomFloatFluctuatedRounded(
-                  OCPP16ServiceUtils.getLimitFromSampledValueTemplateCustomValue(
-                    powerSampledValueTemplate.value,
-                    connectorMaximumPower / unitDivider,
-                    connectorMinimumPower / unitDivider,
-                    {
-                      limitationEnabled:
-                        chargingStation.stationInfo?.customValueLimitationMeterValues,
-                      fallbackValue: connectorMinimumPower / unitDivider,
-                    },
-                  ),
-                  powerSampledValueTemplate.fluctuationPercent ??
-                    Constants.DEFAULT_FLUCTUATION_PERCENT,
-                )
-              : getRandomFloatRounded(
-                  connectorMaximumPower / unitDivider,
-                  connectorMinimumPower / unitDivider,
-                );
-            powerMeasurandValues.L2 = 0;
-            powerMeasurandValues.L3 = 0;
-          }
-          powerMeasurandValues.allPhases = roundTo(
-            powerMeasurandValues.L1 + powerMeasurandValues.L2 + powerMeasurandValues.L3,
-            2,
-          );
-          break;
-        case CurrentType.DC:
-          powerMeasurandValues.allPhases = isNotEmptyString(powerSampledValueTemplate.value)
-            ? getRandomFloatFluctuatedRounded(
-                OCPP16ServiceUtils.getLimitFromSampledValueTemplateCustomValue(
-                  powerSampledValueTemplate.value,
-                  connectorMaximumPower / unitDivider,
-                  connectorMinimumPower / unitDivider,
-                  {
-                    limitationEnabled:
-                      chargingStation.stationInfo?.customValueLimitationMeterValues,
-                    fallbackValue: connectorMinimumPower / unitDivider,
-                  },
-                ),
-                powerSampledValueTemplate.fluctuationPercent ??
-                  Constants.DEFAULT_FLUCTUATION_PERCENT,
-              )
-            : getRandomFloatRounded(
-                connectorMaximumPower / unitDivider,
-                connectorMinimumPower / unitDivider,
-              );
-          break;
-        default:
-          logger.error(`${chargingStation.logPrefix()} ${errMsg}`);
-          throw new OCPPError(ErrorType.INTERNAL_ERROR, errMsg, OCPP16RequestCommand.METER_VALUES);
-      }
-      meterValue.sampledValue.push(
-        OCPP16ServiceUtils.buildSampledValue(
-          powerSampledValueTemplate,
-          powerMeasurandValues.allPhases,
-        ),
-      );
-      const sampledValuesIndex = meterValue.sampledValue.length - 1;
-      const connectorMaximumPowerRounded = roundTo(connectorMaximumPower / unitDivider, 2);
-      const connectorMinimumPowerRounded = roundTo(connectorMinimumPower / unitDivider, 2);
-      if (
-        convertToFloat(meterValue.sampledValue[sampledValuesIndex].value) >
-          connectorMaximumPowerRounded ||
-        convertToFloat(meterValue.sampledValue[sampledValuesIndex].value) <
-          connectorMinimumPowerRounded ||
-        debug
-      ) {
-        logger.error(
-          `${chargingStation.logPrefix()} MeterValues measurand ${
-            meterValue.sampledValue[sampledValuesIndex].measurand ??
-            OCPP16MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER
-          }: connector id ${connectorId}, transaction id ${connector?.transactionId}, value: ${connectorMinimumPowerRounded}/${
-            meterValue.sampledValue[sampledValuesIndex].value
-          }/${connectorMaximumPowerRounded}`,
-        );
-      }
-      for (
-        let phase = 1;
-        chargingStation.getNumberOfPhases() === 3 && phase <= chargingStation.getNumberOfPhases();
-        phase++
-      ) {
-        const phaseValue = `L${phase}-N`;
-        meterValue.sampledValue.push(
-          OCPP16ServiceUtils.buildSampledValue(
-            powerPerPhaseSampledValueTemplates[
-              `L${phase}` as keyof MeasurandPerPhaseSampledValueTemplates
-            ] ?? powerSampledValueTemplate,
-            powerMeasurandValues[`L${phase}` as keyof MeasurandPerPhaseSampledValueTemplates],
-            undefined,
-            phaseValue as OCPP16MeterValuePhase,
-          ),
-        );
-        const sampledValuesPerPhaseIndex = meterValue.sampledValue.length - 1;
-        const connectorMaximumPowerPerPhaseRounded = roundTo(
-          connectorMaximumPowerPerPhase / unitDivider,
-          2,
-        );
-        const connectorMinimumPowerPerPhaseRounded = roundTo(
-          connectorMinimumPowerPerPhase / unitDivider,
-          2,
-        );
-        if (
-          convertToFloat(meterValue.sampledValue[sampledValuesPerPhaseIndex].value) >
-            connectorMaximumPowerPerPhaseRounded ||
-          convertToFloat(meterValue.sampledValue[sampledValuesPerPhaseIndex].value) <
-            connectorMinimumPowerPerPhaseRounded ||
-          debug
-        ) {
-          logger.error(
-            `${chargingStation.logPrefix()} MeterValues measurand ${
-              meterValue.sampledValue[sampledValuesPerPhaseIndex].measurand ??
-              OCPP16MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER
-            }: phase ${
-              meterValue.sampledValue[sampledValuesPerPhaseIndex].phase
-            }, connector id ${connectorId}, transaction id ${connector?.transactionId}, value: ${connectorMinimumPowerPerPhaseRounded}/${
-              meterValue.sampledValue[sampledValuesPerPhaseIndex].value
-            }/${connectorMaximumPowerPerPhaseRounded}`,
-          );
-        }
-      }
-    }
-    // Current.Import measurand
-    const currentSampledValueTemplate = OCPP16ServiceUtils.getSampledValueTemplate(
-      chargingStation,
-      connectorId,
-      OCPP16MeterValueMeasurand.CURRENT_IMPORT,
-    );
-    let currentPerPhaseSampledValueTemplates: MeasurandPerPhaseSampledValueTemplates = {};
-    if (chargingStation.getNumberOfPhases() === 3) {
-      currentPerPhaseSampledValueTemplates = {
-        L1: OCPP16ServiceUtils.getSampledValueTemplate(
-          chargingStation,
-          connectorId,
-          OCPP16MeterValueMeasurand.CURRENT_IMPORT,
-          OCPP16MeterValuePhase.L1,
-        ),
-        L2: OCPP16ServiceUtils.getSampledValueTemplate(
-          chargingStation,
-          connectorId,
-          OCPP16MeterValueMeasurand.CURRENT_IMPORT,
-          OCPP16MeterValuePhase.L2,
-        ),
-        L3: OCPP16ServiceUtils.getSampledValueTemplate(
-          chargingStation,
-          connectorId,
-          OCPP16MeterValueMeasurand.CURRENT_IMPORT,
-          OCPP16MeterValuePhase.L3,
-        ),
-      };
-    }
-    if (currentSampledValueTemplate) {
-      OCPP16ServiceUtils.checkMeasurandPowerDivider(
-        chargingStation,
-        currentSampledValueTemplate.measurand!,
-      );
-      const errMsg = `MeterValues measurand ${
-        currentSampledValueTemplate.measurand ??
-        OCPP16MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER
-      }: Unknown ${chargingStation.stationInfo?.currentOutType} currentOutType in template file ${
-        chargingStation.templateFile
-      }, cannot calculate ${
-        currentSampledValueTemplate.measurand ??
-        OCPP16MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER
-      } measurand value`;
-      const currentMeasurandValues: MeasurandValues = {} as MeasurandValues;
-      const connectorMaximumAvailablePower =
-        chargingStation.getConnectorMaximumAvailablePower(connectorId);
-      const connectorMinimumAmperage = currentSampledValueTemplate.minimumValue ?? 0;
-      let connectorMaximumAmperage: number;
-      switch (chargingStation.stationInfo?.currentOutType) {
-        case CurrentType.AC:
-          connectorMaximumAmperage = ACElectricUtils.amperagePerPhaseFromPower(
-            chargingStation.getNumberOfPhases(),
-            connectorMaximumAvailablePower,
-            chargingStation.stationInfo.voltageOut!,
-          );
-          if (chargingStation.getNumberOfPhases() === 3) {
-            const defaultFluctuatedAmperagePerPhase = isNotEmptyString(
-              currentSampledValueTemplate.value,
-            )
-              ? getRandomFloatFluctuatedRounded(
-                  OCPP16ServiceUtils.getLimitFromSampledValueTemplateCustomValue(
-                    currentSampledValueTemplate.value,
-                    connectorMaximumAmperage,
-                    connectorMinimumAmperage,
-                    {
-                      limitationEnabled:
-                        chargingStation.stationInfo?.customValueLimitationMeterValues,
-                      fallbackValue: connectorMinimumAmperage,
-                    },
-                  ),
-                  currentSampledValueTemplate.fluctuationPercent ??
-                    Constants.DEFAULT_FLUCTUATION_PERCENT,
-                )
-              : undefined;
-            const phase1FluctuatedValue = isNotEmptyString(
-              currentPerPhaseSampledValueTemplates.L1?.value,
-            )
-              ? getRandomFloatFluctuatedRounded(
-                  OCPP16ServiceUtils.getLimitFromSampledValueTemplateCustomValue(
-                    currentPerPhaseSampledValueTemplates.L1?.value,
-                    connectorMaximumAmperage,
-                    connectorMinimumAmperage,
-                    {
-                      limitationEnabled:
-                        chargingStation.stationInfo?.customValueLimitationMeterValues,
-                      fallbackValue: connectorMinimumAmperage,
-                    },
-                  ),
-                  currentPerPhaseSampledValueTemplates.L1?.fluctuationPercent ??
-                    Constants.DEFAULT_FLUCTUATION_PERCENT,
-                )
-              : undefined;
-            const phase2FluctuatedValue = isNotEmptyString(
-              currentPerPhaseSampledValueTemplates.L2?.value,
-            )
-              ? getRandomFloatFluctuatedRounded(
-                  OCPP16ServiceUtils.getLimitFromSampledValueTemplateCustomValue(
-                    currentPerPhaseSampledValueTemplates.L2?.value,
-                    connectorMaximumAmperage,
-                    connectorMinimumAmperage,
-                    {
-                      limitationEnabled:
-                        chargingStation.stationInfo?.customValueLimitationMeterValues,
-                      fallbackValue: connectorMinimumAmperage,
-                    },
-                  ),
-                  currentPerPhaseSampledValueTemplates.L2?.fluctuationPercent ??
-                    Constants.DEFAULT_FLUCTUATION_PERCENT,
-                )
-              : undefined;
-            const phase3FluctuatedValue = isNotEmptyString(
-              currentPerPhaseSampledValueTemplates.L3?.value,
-            )
-              ? getRandomFloatFluctuatedRounded(
-                  OCPP16ServiceUtils.getLimitFromSampledValueTemplateCustomValue(
-                    currentPerPhaseSampledValueTemplates.L3?.value,
-                    connectorMaximumAmperage,
-                    connectorMinimumAmperage,
-                    {
-                      limitationEnabled:
-                        chargingStation.stationInfo?.customValueLimitationMeterValues,
-                      fallbackValue: connectorMinimumAmperage,
-                    },
-                  ),
-                  currentPerPhaseSampledValueTemplates.L3?.fluctuationPercent ??
-                    Constants.DEFAULT_FLUCTUATION_PERCENT,
-                )
-              : undefined;
-            currentMeasurandValues.L1 =
-              phase1FluctuatedValue ??
-              defaultFluctuatedAmperagePerPhase ??
-              getRandomFloatRounded(connectorMaximumAmperage, connectorMinimumAmperage);
-            currentMeasurandValues.L2 =
-              phase2FluctuatedValue ??
-              defaultFluctuatedAmperagePerPhase ??
-              getRandomFloatRounded(connectorMaximumAmperage, connectorMinimumAmperage);
-            currentMeasurandValues.L3 =
-              phase3FluctuatedValue ??
-              defaultFluctuatedAmperagePerPhase ??
-              getRandomFloatRounded(connectorMaximumAmperage, connectorMinimumAmperage);
-          } else {
-            currentMeasurandValues.L1 = isNotEmptyString(currentSampledValueTemplate.value)
-              ? getRandomFloatFluctuatedRounded(
-                  OCPP16ServiceUtils.getLimitFromSampledValueTemplateCustomValue(
-                    currentSampledValueTemplate.value,
-                    connectorMaximumAmperage,
-                    connectorMinimumAmperage,
-                    {
-                      limitationEnabled:
-                        chargingStation.stationInfo?.customValueLimitationMeterValues,
-                      fallbackValue: connectorMinimumAmperage,
-                    },
-                  ),
-                  currentSampledValueTemplate.fluctuationPercent ??
-                    Constants.DEFAULT_FLUCTUATION_PERCENT,
-                )
-              : getRandomFloatRounded(connectorMaximumAmperage, connectorMinimumAmperage);
-            currentMeasurandValues.L2 = 0;
-            currentMeasurandValues.L3 = 0;
-          }
-          currentMeasurandValues.allPhases = roundTo(
-            (currentMeasurandValues.L1 + currentMeasurandValues.L2 + currentMeasurandValues.L3) /
-              chargingStation.getNumberOfPhases(),
-            2,
-          );
-          break;
-        case CurrentType.DC:
-          connectorMaximumAmperage = DCElectricUtils.amperage(
-            connectorMaximumAvailablePower,
-            chargingStation.stationInfo.voltageOut!,
-          );
-          currentMeasurandValues.allPhases = isNotEmptyString(currentSampledValueTemplate.value)
-            ? getRandomFloatFluctuatedRounded(
-                OCPP16ServiceUtils.getLimitFromSampledValueTemplateCustomValue(
-                  currentSampledValueTemplate.value,
-                  connectorMaximumAmperage,
-                  connectorMinimumAmperage,
-                  {
-                    limitationEnabled:
-                      chargingStation.stationInfo?.customValueLimitationMeterValues,
-                    fallbackValue: connectorMinimumAmperage,
-                  },
-                ),
-                currentSampledValueTemplate.fluctuationPercent ??
-                  Constants.DEFAULT_FLUCTUATION_PERCENT,
-              )
-            : getRandomFloatRounded(connectorMaximumAmperage, connectorMinimumAmperage);
-          break;
-        default:
-          logger.error(`${chargingStation.logPrefix()} ${errMsg}`);
-          throw new OCPPError(ErrorType.INTERNAL_ERROR, errMsg, OCPP16RequestCommand.METER_VALUES);
-      }
-      meterValue.sampledValue.push(
-        OCPP16ServiceUtils.buildSampledValue(
-          currentSampledValueTemplate,
-          currentMeasurandValues.allPhases,
-        ),
-      );
-      const sampledValuesIndex = meterValue.sampledValue.length - 1;
-      if (
-        convertToFloat(meterValue.sampledValue[sampledValuesIndex].value) >
-          connectorMaximumAmperage ||
-        convertToFloat(meterValue.sampledValue[sampledValuesIndex].value) <
-          connectorMinimumAmperage ||
-        debug
-      ) {
-        logger.error(
-          `${chargingStation.logPrefix()} MeterValues measurand ${
-            meterValue.sampledValue[sampledValuesIndex].measurand ??
-            OCPP16MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER
-          }: connector id ${connectorId}, transaction id ${connector?.transactionId}, value: ${connectorMinimumAmperage}/${
-            meterValue.sampledValue[sampledValuesIndex].value
-          }/${connectorMaximumAmperage}`,
-        );
-      }
-      for (
-        let phase = 1;
-        chargingStation.getNumberOfPhases() === 3 && phase <= chargingStation.getNumberOfPhases();
-        phase++
-      ) {
-        const phaseValue = `L${phase}`;
-        meterValue.sampledValue.push(
-          OCPP16ServiceUtils.buildSampledValue(
-            currentPerPhaseSampledValueTemplates[
-              phaseValue as keyof MeasurandPerPhaseSampledValueTemplates
-            ] ?? currentSampledValueTemplate,
-            currentMeasurandValues[phaseValue as keyof MeasurandPerPhaseSampledValueTemplates],
-            undefined,
-            phaseValue as OCPP16MeterValuePhase,
-          ),
-        );
-        const sampledValuesPerPhaseIndex = meterValue.sampledValue.length - 1;
-        if (
-          convertToFloat(meterValue.sampledValue[sampledValuesPerPhaseIndex].value) >
-            connectorMaximumAmperage ||
-          convertToFloat(meterValue.sampledValue[sampledValuesPerPhaseIndex].value) <
-            connectorMinimumAmperage ||
-          debug
-        ) {
-          logger.error(
-            `${chargingStation.logPrefix()} MeterValues measurand ${
-              meterValue.sampledValue[sampledValuesPerPhaseIndex].measurand ??
-              OCPP16MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER
-            }: phase ${
-              meterValue.sampledValue[sampledValuesPerPhaseIndex].phase
-            }, connector id ${connectorId}, transaction id ${connector?.transactionId}, value: ${connectorMinimumAmperage}/${
-              meterValue.sampledValue[sampledValuesPerPhaseIndex].value
-            }/${connectorMaximumAmperage}`,
-          );
-        }
-      }
-    }
-    // Energy.Active.Import.Register measurand (default)
-    const energySampledValueTemplate = OCPP16ServiceUtils.getSampledValueTemplate(
-      chargingStation,
-      connectorId,
-    );
-    if (energySampledValueTemplate) {
-      OCPP16ServiceUtils.checkMeasurandPowerDivider(
-        chargingStation,
-        energySampledValueTemplate.measurand!,
-      );
-      const unitDivider =
-        energySampledValueTemplate?.unit === MeterValueUnit.KILO_WATT_HOUR ? 1000 : 1;
-      const connectorMaximumAvailablePower =
-        chargingStation.getConnectorMaximumAvailablePower(connectorId);
-      const connectorMaximumEnergyRounded = roundTo(
-        (connectorMaximumAvailablePower * interval) / (3600 * 1000),
-        2,
-      );
-      const connectorMinimumEnergyRounded = roundTo(
-        energySampledValueTemplate.minimumValue ?? 0,
-        2,
-      );
-      const energyValueRounded = isNotEmptyString(energySampledValueTemplate.value)
-        ? getRandomFloatFluctuatedRounded(
-            OCPP16ServiceUtils.getLimitFromSampledValueTemplateCustomValue(
-              energySampledValueTemplate.value,
-              connectorMaximumEnergyRounded,
-              connectorMinimumEnergyRounded,
-              {
-                limitationEnabled: chargingStation.stationInfo?.customValueLimitationMeterValues,
-                fallbackValue: connectorMinimumEnergyRounded,
-                unitMultiplier: unitDivider,
-              },
-            ),
-            energySampledValueTemplate.fluctuationPercent ?? Constants.DEFAULT_FLUCTUATION_PERCENT,
-          )
-        : getRandomFloatRounded(connectorMaximumEnergyRounded, connectorMinimumEnergyRounded);
-      // Persist previous value on connector
-      if (connector) {
-        if (
-          isNullOrUndefined(connector.energyActiveImportRegisterValue) === false &&
-          connector.energyActiveImportRegisterValue! >= 0 &&
-          isNullOrUndefined(connector.transactionEnergyActiveImportRegisterValue) === false &&
-          connector.transactionEnergyActiveImportRegisterValue! >= 0
-        ) {
-          connector.energyActiveImportRegisterValue! += energyValueRounded;
-          connector.transactionEnergyActiveImportRegisterValue! += energyValueRounded;
-        } else {
-          connector.energyActiveImportRegisterValue = 0;
-          connector.transactionEnergyActiveImportRegisterValue = 0;
-        }
-      }
-      meterValue.sampledValue.push(
-        OCPP16ServiceUtils.buildSampledValue(
-          energySampledValueTemplate,
-          roundTo(
-            chargingStation.getEnergyActiveImportRegisterByTransactionId(transactionId) /
-              unitDivider,
-            2,
-          ),
-        ),
-      );
-      const sampledValuesIndex = meterValue.sampledValue.length - 1;
-      if (
-        energyValueRounded > connectorMaximumEnergyRounded ||
-        energyValueRounded < connectorMinimumEnergyRounded ||
-        debug
-      ) {
-        logger.error(
-          `${chargingStation.logPrefix()} MeterValues measurand ${
-            meterValue.sampledValue[sampledValuesIndex].measurand ??
-            OCPP16MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER
-          }: connector id ${connectorId}, transaction id ${connector?.transactionId}, value: ${connectorMinimumEnergyRounded}/${energyValueRounded}/${connectorMaximumEnergyRounded}, duration: ${interval}ms`,
-        );
-      }
-    }
-    return meterValue;
-  }
-
   public static buildTransactionBeginMeterValue(
     chargingStation: ChargingStation,
     connectorId: number,
@@ -853,37 +71,13 @@ export class OCPP16ServiceUtils extends OCPPServiceUtils {
       chargingStation,
       connectorId,
     );
-    const unitDivider = sampledValueTemplate?.unit === MeterValueUnit.KILO_WATT_HOUR ? 1000 : 1;
+    const unitDivider =
+      sampledValueTemplate?.unit === OCPP16MeterValueUnit.KILO_WATT_HOUR ? 1000 : 1;
     meterValue.sampledValue.push(
       OCPP16ServiceUtils.buildSampledValue(
         sampledValueTemplate!,
         roundTo((meterStart ?? 0) / unitDivider, 4),
-        MeterValueContext.TRANSACTION_BEGIN,
-      ),
-    );
-    return meterValue;
-  }
-
-  public static buildTransactionEndMeterValue(
-    chargingStation: ChargingStation,
-    connectorId: number,
-    meterStop: number,
-  ): OCPP16MeterValue {
-    const meterValue: OCPP16MeterValue = {
-      timestamp: new Date(),
-      sampledValue: [],
-    };
-    // Energy.Active.Import.Register measurand (default)
-    const sampledValueTemplate = OCPP16ServiceUtils.getSampledValueTemplate(
-      chargingStation,
-      connectorId,
-    );
-    const unitDivider = sampledValueTemplate?.unit === MeterValueUnit.KILO_WATT_HOUR ? 1000 : 1;
-    meterValue.sampledValue.push(
-      OCPP16ServiceUtils.buildSampledValue(
-        sampledValueTemplate!,
-        roundTo((meterStop ?? 0) / unitDivider, 4),
-        MeterValueContext.TRANSACTION_END,
+        OCPP16MeterValueContext.TRANSACTION_BEGIN,
       ),
     );
     return meterValue;
@@ -987,7 +181,7 @@ export class OCPP16ServiceUtils extends OCPPServiceUtils {
 
   public static clearChargingProfiles = (
     chargingStation: ChargingStation,
-    commandPayload: ClearChargingProfileRequest,
+    commandPayload: OCPP16ClearChargingProfileRequest,
     chargingProfiles: OCPP16ChargingProfile[] | undefined,
   ): boolean => {
     const { id, chargingProfilePurpose, stackLevel } = commandPayload;
@@ -1328,79 +522,4 @@ export class OCPP16ServiceUtils extends OCPPServiceUtils {
       return chargingSchedule;
     }
   };
-
-  private static buildSampledValue(
-    sampledValueTemplate: SampledValueTemplate,
-    value: number,
-    context?: MeterValueContext,
-    phase?: OCPP16MeterValuePhase,
-  ): OCPP16SampledValue {
-    const sampledValueContext = context ?? sampledValueTemplate?.context;
-    const sampledValueLocation =
-      sampledValueTemplate?.location ??
-      OCPP16ServiceUtils.getMeasurandDefaultLocation(sampledValueTemplate.measurand!);
-    const sampledValuePhase = phase ?? sampledValueTemplate?.phase;
-    return {
-      ...(!isNullOrUndefined(sampledValueTemplate.unit) && {
-        unit: sampledValueTemplate.unit,
-      }),
-      ...(!isNullOrUndefined(sampledValueContext) && { context: sampledValueContext }),
-      ...(!isNullOrUndefined(sampledValueTemplate.measurand) && {
-        measurand: sampledValueTemplate.measurand,
-      }),
-      ...(!isNullOrUndefined(sampledValueLocation) && { location: sampledValueLocation }),
-      ...(!isNullOrUndefined(value) && { value: value.toString() }),
-      ...(!isNullOrUndefined(sampledValuePhase) && { phase: sampledValuePhase }),
-    } as OCPP16SampledValue;
-  }
-
-  private static checkMeasurandPowerDivider(
-    chargingStation: ChargingStation,
-    measurandType: OCPP16MeterValueMeasurand,
-  ): void {
-    if (isUndefined(chargingStation.powerDivider)) {
-      const errMsg = `MeterValues measurand ${
-        measurandType ?? OCPP16MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER
-      }: powerDivider is undefined`;
-      logger.error(`${chargingStation.logPrefix()} ${errMsg}`);
-      throw new OCPPError(ErrorType.INTERNAL_ERROR, errMsg, OCPP16RequestCommand.METER_VALUES);
-    } else if (chargingStation?.powerDivider <= 0) {
-      const errMsg = `MeterValues measurand ${
-        measurandType ?? OCPP16MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER
-      }: powerDivider have zero or below value ${chargingStation.powerDivider}`;
-      logger.error(`${chargingStation.logPrefix()} ${errMsg}`);
-      throw new OCPPError(ErrorType.INTERNAL_ERROR, errMsg, OCPP16RequestCommand.METER_VALUES);
-    }
-  }
-
-  private static getMeasurandDefaultLocation(
-    measurandType: OCPP16MeterValueMeasurand,
-  ): MeterValueLocation | undefined {
-    switch (measurandType) {
-      case OCPP16MeterValueMeasurand.STATE_OF_CHARGE:
-        return MeterValueLocation.EV;
-    }
-  }
-
-  // private static getMeasurandDefaultUnit(
-  //   measurandType: OCPP16MeterValueMeasurand,
-  // ): MeterValueUnit | undefined {
-  //   switch (measurandType) {
-  //     case OCPP16MeterValueMeasurand.CURRENT_EXPORT:
-  //     case OCPP16MeterValueMeasurand.CURRENT_IMPORT:
-  //     case OCPP16MeterValueMeasurand.CURRENT_OFFERED:
-  //       return MeterValueUnit.AMP;
-  //     case OCPP16MeterValueMeasurand.ENERGY_ACTIVE_EXPORT_REGISTER:
-  //     case OCPP16MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER:
-  //       return MeterValueUnit.WATT_HOUR;
-  //     case OCPP16MeterValueMeasurand.POWER_ACTIVE_EXPORT:
-  //     case OCPP16MeterValueMeasurand.POWER_ACTIVE_IMPORT:
-  //     case OCPP16MeterValueMeasurand.POWER_OFFERED:
-  //       return MeterValueUnit.WATT;
-  //     case OCPP16MeterValueMeasurand.STATE_OF_CHARGE:
-  //       return MeterValueUnit.PERCENT;
-  //     case OCPP16MeterValueMeasurand.VOLTAGE:
-  //       return MeterValueUnit.VOLT;
-  //   }
-  // }
 }
index 4b27f9d82f8de91b38bd1a19c4a826ebe6800d6b..c93129bcfadbca7e1d0e0c3454e5ed7b8c092885 100644 (file)
@@ -1,5 +1,3 @@
-import { AsyncResource } from 'node:async_hooks';
-
 import Ajv, { type JSONSchemaType, type ValidateFunction } from 'ajv';
 import ajvFormats from 'ajv-formats';
 
@@ -18,7 +16,7 @@ import { logger, setDefaultErrorParams } from '../../utils';
 
 const moduleName = 'OCPPIncomingRequestService';
 
-export abstract class OCPPIncomingRequestService extends AsyncResource {
+export abstract class OCPPIncomingRequestService {
   private static instance: OCPPIncomingRequestService | null = null;
   private readonly version: OCPPVersion;
   private readonly ajv: Ajv;
@@ -26,7 +24,6 @@ export abstract class OCPPIncomingRequestService extends AsyncResource {
   protected abstract jsonSchemas: Map<IncomingRequestCommand, JSONSchemaType<JsonType>>;
 
   protected constructor(version: OCPPVersion) {
-    super(moduleName);
     this.version = version;
     this.ajv = new Ajv({
       keywords: ['javaType'],
index d9d712981c816790cb4e2b6f1c09fa6cd10e7dac..275494057a4500517ef4618f96a06268e527e0ac 100644 (file)
@@ -9,7 +9,7 @@ import { OCPP16Constants } from './1.6/OCPP16Constants';
 import { OCPP20Constants } from './2.0/OCPP20Constants';
 import { OCPPConstants } from './OCPPConstants';
 import { type ChargingStation, getConfigurationKey, getIdTagsFile } from '../../charging-station';
-import { BaseError } from '../../exception';
+import { BaseError, OCPPError } from '../../exception';
 import {
   AuthorizationStatus,
   type AuthorizeRequest,
@@ -18,34 +18,1203 @@ import {
   ChargingStationEvents,
   type ConnectorStatus,
   type ConnectorStatusEnum,
+  CurrentType,
   ErrorType,
   FileType,
   IncomingRequestCommand,
   type JsonType,
+  type MeasurandPerPhaseSampledValueTemplates,
+  type MeasurandValues,
   MessageTrigger,
   MessageType,
+  type MeterValue,
+  MeterValueContext,
+  MeterValueLocation,
   MeterValueMeasurand,
-  type MeterValuePhase,
+  MeterValuePhase,
+  MeterValueUnit,
   type OCPP16StatusNotificationRequest,
   type OCPP20StatusNotificationRequest,
   OCPPVersion,
   RequestCommand,
+  type SampledValue,
   type SampledValueTemplate,
   StandardParametersKey,
   type StatusNotificationRequest,
   type StatusNotificationResponse,
 } from '../../types';
 import {
+  ACElectricUtils,
+  Constants,
+  DCElectricUtils,
+  convertToFloat,
+  convertToInt,
+  getRandomFloatFluctuatedRounded,
+  getRandomFloatRounded,
+  getRandomInteger,
   handleFileException,
   isNotEmptyArray,
   isNotEmptyString,
+  isNullOrUndefined,
+  isUndefined,
   logPrefix,
   logger,
   max,
   min,
+  roundTo,
 } from '../../utils';
 
+export const getMessageTypeString = (messageType: MessageType): string => {
+  switch (messageType) {
+    case MessageType.CALL_MESSAGE:
+      return 'request';
+    case MessageType.CALL_RESULT_MESSAGE:
+      return 'response';
+    case MessageType.CALL_ERROR_MESSAGE:
+      return 'error';
+    default:
+      return 'unknown';
+  }
+};
+
+export const buildStatusNotificationRequest = (
+  chargingStation: ChargingStation,
+  connectorId: number,
+  status: ConnectorStatusEnum,
+  evseId?: number,
+): StatusNotificationRequest => {
+  switch (chargingStation.stationInfo?.ocppVersion) {
+    case OCPPVersion.VERSION_16:
+      return {
+        connectorId,
+        status,
+        errorCode: ChargePointErrorCode.NO_ERROR,
+      } as OCPP16StatusNotificationRequest;
+    case OCPPVersion.VERSION_20:
+    case OCPPVersion.VERSION_201:
+      return {
+        timestamp: new Date(),
+        connectorStatus: status,
+        connectorId,
+        evseId,
+      } as OCPP20StatusNotificationRequest;
+    default:
+      throw new BaseError('Cannot build status notification payload: OCPP version not supported');
+  }
+};
+
+export const isIdTagAuthorized = async (
+  chargingStation: ChargingStation,
+  connectorId: number,
+  idTag: string,
+): Promise<boolean> => {
+  if (
+    !chargingStation.getLocalAuthListEnabled() &&
+    !chargingStation.stationInfo?.remoteAuthorization
+  ) {
+    logger.warn(
+      `${chargingStation.logPrefix()} The charging station expects to authorize RFID tags but nor local authorization nor remote authorization are enabled. Misbehavior may occur`,
+    );
+  }
+  if (
+    chargingStation.getLocalAuthListEnabled() === true &&
+    isIdTagLocalAuthorized(chargingStation, idTag)
+  ) {
+    const connectorStatus: ConnectorStatus = chargingStation.getConnectorStatus(connectorId)!;
+    connectorStatus.localAuthorizeIdTag = idTag;
+    connectorStatus.idTagLocalAuthorized = true;
+    return true;
+  } else if (chargingStation.stationInfo?.remoteAuthorization) {
+    return await isIdTagRemoteAuthorized(chargingStation, connectorId, idTag);
+  }
+  return false;
+};
+
+const isIdTagLocalAuthorized = (chargingStation: ChargingStation, idTag: string): boolean => {
+  return (
+    chargingStation.hasIdTags() === true &&
+    isNotEmptyString(
+      chargingStation.idTagsCache
+        .getIdTags(getIdTagsFile(chargingStation.stationInfo)!)
+        ?.find((tag) => tag === idTag),
+    )
+  );
+};
+
+const isIdTagRemoteAuthorized = async (
+  chargingStation: ChargingStation,
+  connectorId: number,
+  idTag: string,
+): Promise<boolean> => {
+  chargingStation.getConnectorStatus(connectorId)!.authorizeIdTag = idTag;
+  return (
+    (
+      await chargingStation.ocppRequestService.requestHandler<AuthorizeRequest, AuthorizeResponse>(
+        chargingStation,
+        RequestCommand.AUTHORIZE,
+        {
+          idTag,
+        },
+      )
+    )?.idTagInfo?.status === AuthorizationStatus.ACCEPTED
+  );
+};
+
+export const sendAndSetConnectorStatus = async (
+  chargingStation: ChargingStation,
+  connectorId: number,
+  status: ConnectorStatusEnum,
+  evseId?: number,
+  options?: { send: boolean },
+): Promise<void> => {
+  options = { send: true, ...options };
+  if (options.send) {
+    checkConnectorStatusTransition(chargingStation, connectorId, status);
+    await chargingStation.ocppRequestService.requestHandler<
+      StatusNotificationRequest,
+      StatusNotificationResponse
+    >(
+      chargingStation,
+      RequestCommand.STATUS_NOTIFICATION,
+      buildStatusNotificationRequest(chargingStation, connectorId, status, evseId),
+    );
+  }
+  chargingStation.getConnectorStatus(connectorId)!.status = status;
+  chargingStation.emit(ChargingStationEvents.connectorStatusChanged, {
+    connectorId,
+    ...chargingStation.getConnectorStatus(connectorId),
+  });
+};
+
+const checkConnectorStatusTransition = (
+  chargingStation: ChargingStation,
+  connectorId: number,
+  status: ConnectorStatusEnum,
+): boolean => {
+  const fromStatus = chargingStation.getConnectorStatus(connectorId)!.status;
+  let transitionAllowed = false;
+  switch (chargingStation.stationInfo?.ocppVersion) {
+    case OCPPVersion.VERSION_16:
+      if (
+        (connectorId === 0 &&
+          OCPP16Constants.ChargePointStatusChargingStationTransitions.findIndex(
+            (transition) => transition.from === fromStatus && transition.to === status,
+          ) !== -1) ||
+        (connectorId > 0 &&
+          OCPP16Constants.ChargePointStatusConnectorTransitions.findIndex(
+            (transition) => transition.from === fromStatus && transition.to === status,
+          ) !== -1)
+      ) {
+        transitionAllowed = true;
+      }
+      break;
+    case OCPPVersion.VERSION_20:
+    case OCPPVersion.VERSION_201:
+      if (
+        (connectorId === 0 &&
+          OCPP20Constants.ChargingStationStatusTransitions.findIndex(
+            (transition) => transition.from === fromStatus && transition.to === status,
+          ) !== -1) ||
+        (connectorId > 0 &&
+          OCPP20Constants.ConnectorStatusTransitions.findIndex(
+            (transition) => transition.from === fromStatus && transition.to === status,
+          ) !== -1)
+      ) {
+        transitionAllowed = true;
+      }
+      break;
+    default:
+      throw new BaseError(
+        // eslint-disable-next-line @typescript-eslint/restrict-template-expressions
+        `Cannot check connector status transition: OCPP version ${chargingStation.stationInfo?.ocppVersion} not supported`,
+      );
+  }
+  if (transitionAllowed === false) {
+    logger.warn(
+      `${chargingStation.logPrefix()} OCPP ${chargingStation.stationInfo
+        ?.ocppVersion} connector id ${connectorId} status transition from '${
+        chargingStation.getConnectorStatus(connectorId)!.status
+      }' to '${status}' is not allowed`,
+    );
+  }
+  return transitionAllowed;
+};
+
+export const buildMeterValue = (
+  chargingStation: ChargingStation,
+  connectorId: number,
+  transactionId: number,
+  interval: number,
+  debug = false,
+): MeterValue => {
+  const connector = chargingStation.getConnectorStatus(connectorId);
+  let meterValue: MeterValue;
+  let socSampledValueTemplate: SampledValueTemplate | undefined;
+  let voltageSampledValueTemplate: SampledValueTemplate | undefined;
+  let powerSampledValueTemplate: SampledValueTemplate | undefined;
+  let powerPerPhaseSampledValueTemplates: MeasurandPerPhaseSampledValueTemplates = {};
+  let currentSampledValueTemplate: SampledValueTemplate | undefined;
+  let currentPerPhaseSampledValueTemplates: MeasurandPerPhaseSampledValueTemplates = {};
+  let energySampledValueTemplate: SampledValueTemplate | undefined;
+  switch (chargingStation.stationInfo?.ocppVersion) {
+    case OCPPVersion.VERSION_16:
+      meterValue = {
+        timestamp: new Date(),
+        sampledValue: [],
+      };
+      // SoC measurand
+      socSampledValueTemplate = getSampledValueTemplate(
+        chargingStation,
+        connectorId,
+        MeterValueMeasurand.STATE_OF_CHARGE,
+      );
+      if (socSampledValueTemplate) {
+        const socMaximumValue = 100;
+        const socMinimumValue = socSampledValueTemplate.minimumValue ?? 0;
+        const socSampledValueTemplateValue = isNotEmptyString(socSampledValueTemplate.value)
+          ? getRandomFloatFluctuatedRounded(
+              parseInt(socSampledValueTemplate.value),
+              socSampledValueTemplate.fluctuationPercent ?? Constants.DEFAULT_FLUCTUATION_PERCENT,
+            )
+          : getRandomInteger(socMaximumValue, socMinimumValue);
+        meterValue.sampledValue.push(
+          buildSampledValue(socSampledValueTemplate, socSampledValueTemplateValue),
+        );
+        const sampledValuesIndex = meterValue.sampledValue.length - 1;
+        if (
+          convertToInt(meterValue.sampledValue[sampledValuesIndex].value) > socMaximumValue ||
+          convertToInt(meterValue.sampledValue[sampledValuesIndex].value) < socMinimumValue ||
+          debug
+        ) {
+          logger.error(
+            `${chargingStation.logPrefix()} MeterValues measurand ${
+              meterValue.sampledValue[sampledValuesIndex].measurand ??
+              MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER
+            }: connector id ${connectorId}, transaction id ${connector?.transactionId}, value: ${socMinimumValue}/${
+              meterValue.sampledValue[sampledValuesIndex].value
+            }/${socMaximumValue}`,
+          );
+        }
+      }
+      // Voltage measurand
+      voltageSampledValueTemplate = getSampledValueTemplate(
+        chargingStation,
+        connectorId,
+        MeterValueMeasurand.VOLTAGE,
+      );
+      if (voltageSampledValueTemplate) {
+        const voltageSampledValueTemplateValue = isNotEmptyString(voltageSampledValueTemplate.value)
+          ? parseInt(voltageSampledValueTemplate.value)
+          : chargingStation.stationInfo.voltageOut!;
+        const fluctuationPercent =
+          voltageSampledValueTemplate.fluctuationPercent ?? Constants.DEFAULT_FLUCTUATION_PERCENT;
+        const voltageMeasurandValue = getRandomFloatFluctuatedRounded(
+          voltageSampledValueTemplateValue,
+          fluctuationPercent,
+        );
+        if (
+          chargingStation.getNumberOfPhases() !== 3 ||
+          (chargingStation.getNumberOfPhases() === 3 &&
+            chargingStation.stationInfo?.mainVoltageMeterValues)
+        ) {
+          meterValue.sampledValue.push(
+            buildSampledValue(voltageSampledValueTemplate, voltageMeasurandValue),
+          );
+        }
+        for (
+          let phase = 1;
+          chargingStation.getNumberOfPhases() === 3 && phase <= chargingStation.getNumberOfPhases();
+          phase++
+        ) {
+          const phaseLineToNeutralValue = `L${phase}-N`;
+          const voltagePhaseLineToNeutralSampledValueTemplate = getSampledValueTemplate(
+            chargingStation,
+            connectorId,
+            MeterValueMeasurand.VOLTAGE,
+            phaseLineToNeutralValue as MeterValuePhase,
+          );
+          let voltagePhaseLineToNeutralMeasurandValue: number | undefined;
+          if (voltagePhaseLineToNeutralSampledValueTemplate) {
+            const voltagePhaseLineToNeutralSampledValueTemplateValue = isNotEmptyString(
+              voltagePhaseLineToNeutralSampledValueTemplate.value,
+            )
+              ? parseInt(voltagePhaseLineToNeutralSampledValueTemplate.value)
+              : chargingStation.stationInfo.voltageOut!;
+            const fluctuationPhaseToNeutralPercent =
+              voltagePhaseLineToNeutralSampledValueTemplate.fluctuationPercent ??
+              Constants.DEFAULT_FLUCTUATION_PERCENT;
+            voltagePhaseLineToNeutralMeasurandValue = getRandomFloatFluctuatedRounded(
+              voltagePhaseLineToNeutralSampledValueTemplateValue,
+              fluctuationPhaseToNeutralPercent,
+            );
+          }
+          meterValue.sampledValue.push(
+            buildSampledValue(
+              voltagePhaseLineToNeutralSampledValueTemplate ?? voltageSampledValueTemplate,
+              voltagePhaseLineToNeutralMeasurandValue ?? voltageMeasurandValue,
+              undefined,
+              phaseLineToNeutralValue as MeterValuePhase,
+            ),
+          );
+          if (chargingStation.stationInfo?.phaseLineToLineVoltageMeterValues) {
+            const phaseLineToLineValue = `L${phase}-L${
+              (phase + 1) % chargingStation.getNumberOfPhases() !== 0
+                ? (phase + 1) % chargingStation.getNumberOfPhases()
+                : chargingStation.getNumberOfPhases()
+            }`;
+            const voltagePhaseLineToLineValueRounded = roundTo(
+              Math.sqrt(chargingStation.getNumberOfPhases()) *
+                chargingStation.stationInfo.voltageOut!,
+              2,
+            );
+            const voltagePhaseLineToLineSampledValueTemplate = getSampledValueTemplate(
+              chargingStation,
+              connectorId,
+              MeterValueMeasurand.VOLTAGE,
+              phaseLineToLineValue as MeterValuePhase,
+            );
+            let voltagePhaseLineToLineMeasurandValue: number | undefined;
+            if (voltagePhaseLineToLineSampledValueTemplate) {
+              const voltagePhaseLineToLineSampledValueTemplateValue = isNotEmptyString(
+                voltagePhaseLineToLineSampledValueTemplate.value,
+              )
+                ? parseInt(voltagePhaseLineToLineSampledValueTemplate.value)
+                : voltagePhaseLineToLineValueRounded;
+              const fluctuationPhaseLineToLinePercent =
+                voltagePhaseLineToLineSampledValueTemplate.fluctuationPercent ??
+                Constants.DEFAULT_FLUCTUATION_PERCENT;
+              voltagePhaseLineToLineMeasurandValue = getRandomFloatFluctuatedRounded(
+                voltagePhaseLineToLineSampledValueTemplateValue,
+                fluctuationPhaseLineToLinePercent,
+              );
+            }
+            const defaultVoltagePhaseLineToLineMeasurandValue = getRandomFloatFluctuatedRounded(
+              voltagePhaseLineToLineValueRounded,
+              fluctuationPercent,
+            );
+            meterValue.sampledValue.push(
+              buildSampledValue(
+                voltagePhaseLineToLineSampledValueTemplate ?? voltageSampledValueTemplate,
+                voltagePhaseLineToLineMeasurandValue ?? defaultVoltagePhaseLineToLineMeasurandValue,
+                undefined,
+                phaseLineToLineValue as MeterValuePhase,
+              ),
+            );
+          }
+        }
+      }
+      // Power.Active.Import measurand
+      powerSampledValueTemplate = getSampledValueTemplate(
+        chargingStation,
+        connectorId,
+        MeterValueMeasurand.POWER_ACTIVE_IMPORT,
+      );
+      if (chargingStation.getNumberOfPhases() === 3) {
+        powerPerPhaseSampledValueTemplates = {
+          L1: getSampledValueTemplate(
+            chargingStation,
+            connectorId,
+            MeterValueMeasurand.POWER_ACTIVE_IMPORT,
+            MeterValuePhase.L1_N,
+          ),
+          L2: getSampledValueTemplate(
+            chargingStation,
+            connectorId,
+            MeterValueMeasurand.POWER_ACTIVE_IMPORT,
+            MeterValuePhase.L2_N,
+          ),
+          L3: getSampledValueTemplate(
+            chargingStation,
+            connectorId,
+            MeterValueMeasurand.POWER_ACTIVE_IMPORT,
+            MeterValuePhase.L3_N,
+          ),
+        };
+      }
+      if (powerSampledValueTemplate) {
+        checkMeasurandPowerDivider(chargingStation, powerSampledValueTemplate.measurand!);
+        const errMsg = `MeterValues measurand ${
+          powerSampledValueTemplate.measurand ?? MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER
+        }: Unknown ${chargingStation.stationInfo?.currentOutType} currentOutType in template file ${
+          chargingStation.templateFile
+        }, cannot calculate ${
+          powerSampledValueTemplate.measurand ?? MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER
+        } measurand value`;
+        const powerMeasurandValues: MeasurandValues = {} as MeasurandValues;
+        const unitDivider = powerSampledValueTemplate?.unit === MeterValueUnit.KILO_WATT ? 1000 : 1;
+        const connectorMaximumAvailablePower =
+          chargingStation.getConnectorMaximumAvailablePower(connectorId);
+        const connectorMaximumPower = Math.round(connectorMaximumAvailablePower);
+        const connectorMaximumPowerPerPhase = Math.round(
+          connectorMaximumAvailablePower / chargingStation.getNumberOfPhases(),
+        );
+        const connectorMinimumPower = Math.round(powerSampledValueTemplate.minimumValue ?? 0);
+        const connectorMinimumPowerPerPhase = Math.round(
+          connectorMinimumPower / chargingStation.getNumberOfPhases(),
+        );
+        switch (chargingStation.stationInfo?.currentOutType) {
+          case CurrentType.AC:
+            if (chargingStation.getNumberOfPhases() === 3) {
+              const defaultFluctuatedPowerPerPhase = isNotEmptyString(
+                powerSampledValueTemplate.value,
+              )
+                ? getRandomFloatFluctuatedRounded(
+                    getLimitFromSampledValueTemplateCustomValue(
+                      powerSampledValueTemplate.value,
+                      connectorMaximumPower / unitDivider,
+                      connectorMinimumPower / unitDivider,
+                      {
+                        limitationEnabled:
+                          chargingStation.stationInfo?.customValueLimitationMeterValues,
+                        fallbackValue: connectorMinimumPower / unitDivider,
+                      },
+                    ) / chargingStation.getNumberOfPhases(),
+                    powerSampledValueTemplate.fluctuationPercent ??
+                      Constants.DEFAULT_FLUCTUATION_PERCENT,
+                  )
+                : undefined;
+              const phase1FluctuatedValue = isNotEmptyString(
+                powerPerPhaseSampledValueTemplates.L1?.value,
+              )
+                ? getRandomFloatFluctuatedRounded(
+                    getLimitFromSampledValueTemplateCustomValue(
+                      powerPerPhaseSampledValueTemplates.L1?.value,
+                      connectorMaximumPowerPerPhase / unitDivider,
+                      connectorMinimumPowerPerPhase / unitDivider,
+                      {
+                        limitationEnabled:
+                          chargingStation.stationInfo?.customValueLimitationMeterValues,
+                        fallbackValue: connectorMinimumPowerPerPhase / unitDivider,
+                      },
+                    ),
+                    powerPerPhaseSampledValueTemplates.L1?.fluctuationPercent ??
+                      Constants.DEFAULT_FLUCTUATION_PERCENT,
+                  )
+                : undefined;
+              const phase2FluctuatedValue = isNotEmptyString(
+                powerPerPhaseSampledValueTemplates.L2?.value,
+              )
+                ? getRandomFloatFluctuatedRounded(
+                    getLimitFromSampledValueTemplateCustomValue(
+                      powerPerPhaseSampledValueTemplates.L2?.value,
+                      connectorMaximumPowerPerPhase / unitDivider,
+                      connectorMinimumPowerPerPhase / unitDivider,
+                      {
+                        limitationEnabled:
+                          chargingStation.stationInfo?.customValueLimitationMeterValues,
+                        fallbackValue: connectorMinimumPowerPerPhase / unitDivider,
+                      },
+                    ),
+                    powerPerPhaseSampledValueTemplates.L2?.fluctuationPercent ??
+                      Constants.DEFAULT_FLUCTUATION_PERCENT,
+                  )
+                : undefined;
+              const phase3FluctuatedValue = isNotEmptyString(
+                powerPerPhaseSampledValueTemplates.L3?.value,
+              )
+                ? getRandomFloatFluctuatedRounded(
+                    getLimitFromSampledValueTemplateCustomValue(
+                      powerPerPhaseSampledValueTemplates.L3?.value,
+                      connectorMaximumPowerPerPhase / unitDivider,
+                      connectorMinimumPowerPerPhase / unitDivider,
+                      {
+                        limitationEnabled:
+                          chargingStation.stationInfo?.customValueLimitationMeterValues,
+                        fallbackValue: connectorMinimumPowerPerPhase / unitDivider,
+                      },
+                    ),
+                    powerPerPhaseSampledValueTemplates.L3?.fluctuationPercent ??
+                      Constants.DEFAULT_FLUCTUATION_PERCENT,
+                  )
+                : undefined;
+              powerMeasurandValues.L1 =
+                phase1FluctuatedValue ??
+                defaultFluctuatedPowerPerPhase ??
+                getRandomFloatRounded(
+                  connectorMaximumPowerPerPhase / unitDivider,
+                  connectorMinimumPowerPerPhase / unitDivider,
+                );
+              powerMeasurandValues.L2 =
+                phase2FluctuatedValue ??
+                defaultFluctuatedPowerPerPhase ??
+                getRandomFloatRounded(
+                  connectorMaximumPowerPerPhase / unitDivider,
+                  connectorMinimumPowerPerPhase / unitDivider,
+                );
+              powerMeasurandValues.L3 =
+                phase3FluctuatedValue ??
+                defaultFluctuatedPowerPerPhase ??
+                getRandomFloatRounded(
+                  connectorMaximumPowerPerPhase / unitDivider,
+                  connectorMinimumPowerPerPhase / unitDivider,
+                );
+            } else {
+              powerMeasurandValues.L1 = isNotEmptyString(powerSampledValueTemplate.value)
+                ? getRandomFloatFluctuatedRounded(
+                    getLimitFromSampledValueTemplateCustomValue(
+                      powerSampledValueTemplate.value,
+                      connectorMaximumPower / unitDivider,
+                      connectorMinimumPower / unitDivider,
+                      {
+                        limitationEnabled:
+                          chargingStation.stationInfo?.customValueLimitationMeterValues,
+                        fallbackValue: connectorMinimumPower / unitDivider,
+                      },
+                    ),
+                    powerSampledValueTemplate.fluctuationPercent ??
+                      Constants.DEFAULT_FLUCTUATION_PERCENT,
+                  )
+                : getRandomFloatRounded(
+                    connectorMaximumPower / unitDivider,
+                    connectorMinimumPower / unitDivider,
+                  );
+              powerMeasurandValues.L2 = 0;
+              powerMeasurandValues.L3 = 0;
+            }
+            powerMeasurandValues.allPhases = roundTo(
+              powerMeasurandValues.L1 + powerMeasurandValues.L2 + powerMeasurandValues.L3,
+              2,
+            );
+            break;
+          case CurrentType.DC:
+            powerMeasurandValues.allPhases = isNotEmptyString(powerSampledValueTemplate.value)
+              ? getRandomFloatFluctuatedRounded(
+                  getLimitFromSampledValueTemplateCustomValue(
+                    powerSampledValueTemplate.value,
+                    connectorMaximumPower / unitDivider,
+                    connectorMinimumPower / unitDivider,
+                    {
+                      limitationEnabled:
+                        chargingStation.stationInfo?.customValueLimitationMeterValues,
+                      fallbackValue: connectorMinimumPower / unitDivider,
+                    },
+                  ),
+                  powerSampledValueTemplate.fluctuationPercent ??
+                    Constants.DEFAULT_FLUCTUATION_PERCENT,
+                )
+              : getRandomFloatRounded(
+                  connectorMaximumPower / unitDivider,
+                  connectorMinimumPower / unitDivider,
+                );
+            break;
+          default:
+            logger.error(`${chargingStation.logPrefix()} ${errMsg}`);
+            throw new OCPPError(ErrorType.INTERNAL_ERROR, errMsg, RequestCommand.METER_VALUES);
+        }
+        meterValue.sampledValue.push(
+          buildSampledValue(powerSampledValueTemplate, powerMeasurandValues.allPhases),
+        );
+        const sampledValuesIndex = meterValue.sampledValue.length - 1;
+        const connectorMaximumPowerRounded = roundTo(connectorMaximumPower / unitDivider, 2);
+        const connectorMinimumPowerRounded = roundTo(connectorMinimumPower / unitDivider, 2);
+        if (
+          convertToFloat(meterValue.sampledValue[sampledValuesIndex].value) >
+            connectorMaximumPowerRounded ||
+          convertToFloat(meterValue.sampledValue[sampledValuesIndex].value) <
+            connectorMinimumPowerRounded ||
+          debug
+        ) {
+          logger.error(
+            `${chargingStation.logPrefix()} MeterValues measurand ${
+              meterValue.sampledValue[sampledValuesIndex].measurand ??
+              MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER
+            }: connector id ${connectorId}, transaction id ${connector?.transactionId}, value: ${connectorMinimumPowerRounded}/${
+              meterValue.sampledValue[sampledValuesIndex].value
+            }/${connectorMaximumPowerRounded}`,
+          );
+        }
+        for (
+          let phase = 1;
+          chargingStation.getNumberOfPhases() === 3 && phase <= chargingStation.getNumberOfPhases();
+          phase++
+        ) {
+          const phaseValue = `L${phase}-N`;
+          meterValue.sampledValue.push(
+            buildSampledValue(
+              powerPerPhaseSampledValueTemplates[
+                `L${phase}` as keyof MeasurandPerPhaseSampledValueTemplates
+              ] ?? powerSampledValueTemplate,
+              powerMeasurandValues[`L${phase}` as keyof MeasurandPerPhaseSampledValueTemplates],
+              undefined,
+              phaseValue as MeterValuePhase,
+            ),
+          );
+          const sampledValuesPerPhaseIndex = meterValue.sampledValue.length - 1;
+          const connectorMaximumPowerPerPhaseRounded = roundTo(
+            connectorMaximumPowerPerPhase / unitDivider,
+            2,
+          );
+          const connectorMinimumPowerPerPhaseRounded = roundTo(
+            connectorMinimumPowerPerPhase / unitDivider,
+            2,
+          );
+          if (
+            convertToFloat(meterValue.sampledValue[sampledValuesPerPhaseIndex].value) >
+              connectorMaximumPowerPerPhaseRounded ||
+            convertToFloat(meterValue.sampledValue[sampledValuesPerPhaseIndex].value) <
+              connectorMinimumPowerPerPhaseRounded ||
+            debug
+          ) {
+            logger.error(
+              `${chargingStation.logPrefix()} MeterValues measurand ${
+                meterValue.sampledValue[sampledValuesPerPhaseIndex].measurand ??
+                MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER
+              }: phase ${
+                meterValue.sampledValue[sampledValuesPerPhaseIndex].phase
+              }, connector id ${connectorId}, transaction id ${connector?.transactionId}, value: ${connectorMinimumPowerPerPhaseRounded}/${
+                meterValue.sampledValue[sampledValuesPerPhaseIndex].value
+              }/${connectorMaximumPowerPerPhaseRounded}`,
+            );
+          }
+        }
+      }
+      // Current.Import measurand
+      currentSampledValueTemplate = getSampledValueTemplate(
+        chargingStation,
+        connectorId,
+        MeterValueMeasurand.CURRENT_IMPORT,
+      );
+      if (chargingStation.getNumberOfPhases() === 3) {
+        currentPerPhaseSampledValueTemplates = {
+          L1: getSampledValueTemplate(
+            chargingStation,
+            connectorId,
+            MeterValueMeasurand.CURRENT_IMPORT,
+            MeterValuePhase.L1,
+          ),
+          L2: getSampledValueTemplate(
+            chargingStation,
+            connectorId,
+            MeterValueMeasurand.CURRENT_IMPORT,
+            MeterValuePhase.L2,
+          ),
+          L3: getSampledValueTemplate(
+            chargingStation,
+            connectorId,
+            MeterValueMeasurand.CURRENT_IMPORT,
+            MeterValuePhase.L3,
+          ),
+        };
+      }
+      if (currentSampledValueTemplate) {
+        checkMeasurandPowerDivider(chargingStation, currentSampledValueTemplate.measurand!);
+        const errMsg = `MeterValues measurand ${
+          currentSampledValueTemplate.measurand ?? MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER
+        }: Unknown ${chargingStation.stationInfo?.currentOutType} currentOutType in template file ${
+          chargingStation.templateFile
+        }, cannot calculate ${
+          currentSampledValueTemplate.measurand ?? MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER
+        } measurand value`;
+        const currentMeasurandValues: MeasurandValues = {} as MeasurandValues;
+        const connectorMaximumAvailablePower =
+          chargingStation.getConnectorMaximumAvailablePower(connectorId);
+        const connectorMinimumAmperage = currentSampledValueTemplate.minimumValue ?? 0;
+        let connectorMaximumAmperage: number;
+        switch (chargingStation.stationInfo?.currentOutType) {
+          case CurrentType.AC:
+            connectorMaximumAmperage = ACElectricUtils.amperagePerPhaseFromPower(
+              chargingStation.getNumberOfPhases(),
+              connectorMaximumAvailablePower,
+              chargingStation.stationInfo.voltageOut!,
+            );
+            if (chargingStation.getNumberOfPhases() === 3) {
+              const defaultFluctuatedAmperagePerPhase = isNotEmptyString(
+                currentSampledValueTemplate.value,
+              )
+                ? getRandomFloatFluctuatedRounded(
+                    getLimitFromSampledValueTemplateCustomValue(
+                      currentSampledValueTemplate.value,
+                      connectorMaximumAmperage,
+                      connectorMinimumAmperage,
+                      {
+                        limitationEnabled:
+                          chargingStation.stationInfo?.customValueLimitationMeterValues,
+                        fallbackValue: connectorMinimumAmperage,
+                      },
+                    ),
+                    currentSampledValueTemplate.fluctuationPercent ??
+                      Constants.DEFAULT_FLUCTUATION_PERCENT,
+                  )
+                : undefined;
+              const phase1FluctuatedValue = isNotEmptyString(
+                currentPerPhaseSampledValueTemplates.L1?.value,
+              )
+                ? getRandomFloatFluctuatedRounded(
+                    getLimitFromSampledValueTemplateCustomValue(
+                      currentPerPhaseSampledValueTemplates.L1?.value,
+                      connectorMaximumAmperage,
+                      connectorMinimumAmperage,
+                      {
+                        limitationEnabled:
+                          chargingStation.stationInfo?.customValueLimitationMeterValues,
+                        fallbackValue: connectorMinimumAmperage,
+                      },
+                    ),
+                    currentPerPhaseSampledValueTemplates.L1?.fluctuationPercent ??
+                      Constants.DEFAULT_FLUCTUATION_PERCENT,
+                  )
+                : undefined;
+              const phase2FluctuatedValue = isNotEmptyString(
+                currentPerPhaseSampledValueTemplates.L2?.value,
+              )
+                ? getRandomFloatFluctuatedRounded(
+                    getLimitFromSampledValueTemplateCustomValue(
+                      currentPerPhaseSampledValueTemplates.L2?.value,
+                      connectorMaximumAmperage,
+                      connectorMinimumAmperage,
+                      {
+                        limitationEnabled:
+                          chargingStation.stationInfo?.customValueLimitationMeterValues,
+                        fallbackValue: connectorMinimumAmperage,
+                      },
+                    ),
+                    currentPerPhaseSampledValueTemplates.L2?.fluctuationPercent ??
+                      Constants.DEFAULT_FLUCTUATION_PERCENT,
+                  )
+                : undefined;
+              const phase3FluctuatedValue = isNotEmptyString(
+                currentPerPhaseSampledValueTemplates.L3?.value,
+              )
+                ? getRandomFloatFluctuatedRounded(
+                    getLimitFromSampledValueTemplateCustomValue(
+                      currentPerPhaseSampledValueTemplates.L3?.value,
+                      connectorMaximumAmperage,
+                      connectorMinimumAmperage,
+                      {
+                        limitationEnabled:
+                          chargingStation.stationInfo?.customValueLimitationMeterValues,
+                        fallbackValue: connectorMinimumAmperage,
+                      },
+                    ),
+                    currentPerPhaseSampledValueTemplates.L3?.fluctuationPercent ??
+                      Constants.DEFAULT_FLUCTUATION_PERCENT,
+                  )
+                : undefined;
+              currentMeasurandValues.L1 =
+                phase1FluctuatedValue ??
+                defaultFluctuatedAmperagePerPhase ??
+                getRandomFloatRounded(connectorMaximumAmperage, connectorMinimumAmperage);
+              currentMeasurandValues.L2 =
+                phase2FluctuatedValue ??
+                defaultFluctuatedAmperagePerPhase ??
+                getRandomFloatRounded(connectorMaximumAmperage, connectorMinimumAmperage);
+              currentMeasurandValues.L3 =
+                phase3FluctuatedValue ??
+                defaultFluctuatedAmperagePerPhase ??
+                getRandomFloatRounded(connectorMaximumAmperage, connectorMinimumAmperage);
+            } else {
+              currentMeasurandValues.L1 = isNotEmptyString(currentSampledValueTemplate.value)
+                ? getRandomFloatFluctuatedRounded(
+                    getLimitFromSampledValueTemplateCustomValue(
+                      currentSampledValueTemplate.value,
+                      connectorMaximumAmperage,
+                      connectorMinimumAmperage,
+                      {
+                        limitationEnabled:
+                          chargingStation.stationInfo?.customValueLimitationMeterValues,
+                        fallbackValue: connectorMinimumAmperage,
+                      },
+                    ),
+                    currentSampledValueTemplate.fluctuationPercent ??
+                      Constants.DEFAULT_FLUCTUATION_PERCENT,
+                  )
+                : getRandomFloatRounded(connectorMaximumAmperage, connectorMinimumAmperage);
+              currentMeasurandValues.L2 = 0;
+              currentMeasurandValues.L3 = 0;
+            }
+            currentMeasurandValues.allPhases = roundTo(
+              (currentMeasurandValues.L1 + currentMeasurandValues.L2 + currentMeasurandValues.L3) /
+                chargingStation.getNumberOfPhases(),
+              2,
+            );
+            break;
+          case CurrentType.DC:
+            connectorMaximumAmperage = DCElectricUtils.amperage(
+              connectorMaximumAvailablePower,
+              chargingStation.stationInfo.voltageOut!,
+            );
+            currentMeasurandValues.allPhases = isNotEmptyString(currentSampledValueTemplate.value)
+              ? getRandomFloatFluctuatedRounded(
+                  getLimitFromSampledValueTemplateCustomValue(
+                    currentSampledValueTemplate.value,
+                    connectorMaximumAmperage,
+                    connectorMinimumAmperage,
+                    {
+                      limitationEnabled:
+                        chargingStation.stationInfo?.customValueLimitationMeterValues,
+                      fallbackValue: connectorMinimumAmperage,
+                    },
+                  ),
+                  currentSampledValueTemplate.fluctuationPercent ??
+                    Constants.DEFAULT_FLUCTUATION_PERCENT,
+                )
+              : getRandomFloatRounded(connectorMaximumAmperage, connectorMinimumAmperage);
+            break;
+          default:
+            logger.error(`${chargingStation.logPrefix()} ${errMsg}`);
+            throw new OCPPError(ErrorType.INTERNAL_ERROR, errMsg, RequestCommand.METER_VALUES);
+        }
+        meterValue.sampledValue.push(
+          buildSampledValue(currentSampledValueTemplate, currentMeasurandValues.allPhases),
+        );
+        const sampledValuesIndex = meterValue.sampledValue.length - 1;
+        if (
+          convertToFloat(meterValue.sampledValue[sampledValuesIndex].value) >
+            connectorMaximumAmperage ||
+          convertToFloat(meterValue.sampledValue[sampledValuesIndex].value) <
+            connectorMinimumAmperage ||
+          debug
+        ) {
+          logger.error(
+            `${chargingStation.logPrefix()} MeterValues measurand ${
+              meterValue.sampledValue[sampledValuesIndex].measurand ??
+              MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER
+            }: connector id ${connectorId}, transaction id ${connector?.transactionId}, value: ${connectorMinimumAmperage}/${
+              meterValue.sampledValue[sampledValuesIndex].value
+            }/${connectorMaximumAmperage}`,
+          );
+        }
+        for (
+          let phase = 1;
+          chargingStation.getNumberOfPhases() === 3 && phase <= chargingStation.getNumberOfPhases();
+          phase++
+        ) {
+          const phaseValue = `L${phase}`;
+          meterValue.sampledValue.push(
+            buildSampledValue(
+              currentPerPhaseSampledValueTemplates[
+                phaseValue as keyof MeasurandPerPhaseSampledValueTemplates
+              ] ?? currentSampledValueTemplate,
+              currentMeasurandValues[phaseValue as keyof MeasurandPerPhaseSampledValueTemplates],
+              undefined,
+              phaseValue as MeterValuePhase,
+            ),
+          );
+          const sampledValuesPerPhaseIndex = meterValue.sampledValue.length - 1;
+          if (
+            convertToFloat(meterValue.sampledValue[sampledValuesPerPhaseIndex].value) >
+              connectorMaximumAmperage ||
+            convertToFloat(meterValue.sampledValue[sampledValuesPerPhaseIndex].value) <
+              connectorMinimumAmperage ||
+            debug
+          ) {
+            logger.error(
+              `${chargingStation.logPrefix()} MeterValues measurand ${
+                meterValue.sampledValue[sampledValuesPerPhaseIndex].measurand ??
+                MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER
+              }: phase ${
+                meterValue.sampledValue[sampledValuesPerPhaseIndex].phase
+              }, connector id ${connectorId}, transaction id ${connector?.transactionId}, value: ${connectorMinimumAmperage}/${
+                meterValue.sampledValue[sampledValuesPerPhaseIndex].value
+              }/${connectorMaximumAmperage}`,
+            );
+          }
+        }
+      }
+      // Energy.Active.Import.Register measurand (default)
+      energySampledValueTemplate = getSampledValueTemplate(chargingStation, connectorId);
+      if (energySampledValueTemplate) {
+        checkMeasurandPowerDivider(chargingStation, energySampledValueTemplate.measurand!);
+        const unitDivider =
+          energySampledValueTemplate?.unit === MeterValueUnit.KILO_WATT_HOUR ? 1000 : 1;
+        const connectorMaximumAvailablePower =
+          chargingStation.getConnectorMaximumAvailablePower(connectorId);
+        const connectorMaximumEnergyRounded = roundTo(
+          (connectorMaximumAvailablePower * interval) / (3600 * 1000),
+          2,
+        );
+        const connectorMinimumEnergyRounded = roundTo(
+          energySampledValueTemplate.minimumValue ?? 0,
+          2,
+        );
+        const energyValueRounded = isNotEmptyString(energySampledValueTemplate.value)
+          ? getRandomFloatFluctuatedRounded(
+              getLimitFromSampledValueTemplateCustomValue(
+                energySampledValueTemplate.value,
+                connectorMaximumEnergyRounded,
+                connectorMinimumEnergyRounded,
+                {
+                  limitationEnabled: chargingStation.stationInfo?.customValueLimitationMeterValues,
+                  fallbackValue: connectorMinimumEnergyRounded,
+                  unitMultiplier: unitDivider,
+                },
+              ),
+              energySampledValueTemplate.fluctuationPercent ??
+                Constants.DEFAULT_FLUCTUATION_PERCENT,
+            )
+          : getRandomFloatRounded(connectorMaximumEnergyRounded, connectorMinimumEnergyRounded);
+        // Persist previous value on connector
+        if (connector) {
+          if (
+            isNullOrUndefined(connector.energyActiveImportRegisterValue) === false &&
+            connector.energyActiveImportRegisterValue! >= 0 &&
+            isNullOrUndefined(connector.transactionEnergyActiveImportRegisterValue) === false &&
+            connector.transactionEnergyActiveImportRegisterValue! >= 0
+          ) {
+            connector.energyActiveImportRegisterValue! += energyValueRounded;
+            connector.transactionEnergyActiveImportRegisterValue! += energyValueRounded;
+          } else {
+            connector.energyActiveImportRegisterValue = 0;
+            connector.transactionEnergyActiveImportRegisterValue = 0;
+          }
+        }
+        meterValue.sampledValue.push(
+          buildSampledValue(
+            energySampledValueTemplate,
+            roundTo(
+              chargingStation.getEnergyActiveImportRegisterByTransactionId(transactionId) /
+                unitDivider,
+              2,
+            ),
+          ),
+        );
+        const sampledValuesIndex = meterValue.sampledValue.length - 1;
+        if (
+          energyValueRounded > connectorMaximumEnergyRounded ||
+          energyValueRounded < connectorMinimumEnergyRounded ||
+          debug
+        ) {
+          logger.error(
+            `${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`,
+          );
+        }
+      }
+      return meterValue;
+    case OCPPVersion.VERSION_20:
+    case OCPPVersion.VERSION_201:
+    default:
+      throw new BaseError(
+        // eslint-disable-next-line @typescript-eslint/restrict-template-expressions
+        `Cannot build meterValue: OCPP version ${chargingStation.stationInfo?.ocppVersion} not supported`,
+      );
+  }
+};
+
+export const buildTransactionEndMeterValue = (
+  chargingStation: ChargingStation,
+  connectorId: number,
+  meterStop: number,
+): MeterValue => {
+  let meterValue: MeterValue;
+  let sampledValueTemplate: SampledValueTemplate | undefined;
+  let unitDivider: number;
+  switch (chargingStation.stationInfo?.ocppVersion) {
+    case OCPPVersion.VERSION_16:
+      meterValue = {
+        timestamp: new Date(),
+        sampledValue: [],
+      };
+      // Energy.Active.Import.Register measurand (default)
+      sampledValueTemplate = getSampledValueTemplate(chargingStation, connectorId);
+      unitDivider = sampledValueTemplate?.unit === MeterValueUnit.KILO_WATT_HOUR ? 1000 : 1;
+      meterValue.sampledValue.push(
+        buildSampledValue(
+          sampledValueTemplate!,
+          roundTo((meterStop ?? 0) / unitDivider, 4),
+          MeterValueContext.TRANSACTION_END,
+        ),
+      );
+      return meterValue;
+    case OCPPVersion.VERSION_20:
+    case OCPPVersion.VERSION_201:
+    default:
+      throw new BaseError(
+        // eslint-disable-next-line @typescript-eslint/restrict-template-expressions
+        `Cannot build meterValue: OCPP version ${chargingStation.stationInfo?.ocppVersion} not supported`,
+      );
+  }
+};
+
+const checkMeasurandPowerDivider = (
+  chargingStation: ChargingStation,
+  measurandType: MeterValueMeasurand,
+): void => {
+  if (isUndefined(chargingStation.powerDivider)) {
+    const errMsg = `MeterValues measurand ${
+      measurandType ?? MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER
+    }: powerDivider is undefined`;
+    logger.error(`${chargingStation.logPrefix()} ${errMsg}`);
+    throw new OCPPError(ErrorType.INTERNAL_ERROR, errMsg, RequestCommand.METER_VALUES);
+  } else if (chargingStation?.powerDivider <= 0) {
+    const errMsg = `MeterValues measurand ${
+      measurandType ?? MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER
+    }: powerDivider have zero or below value ${chargingStation.powerDivider}`;
+    logger.error(`${chargingStation.logPrefix()} ${errMsg}`);
+    throw new OCPPError(ErrorType.INTERNAL_ERROR, errMsg, RequestCommand.METER_VALUES);
+  }
+};
+
+const getLimitFromSampledValueTemplateCustomValue = (
+  value: string | undefined,
+  maxLimit: number,
+  minLimit: number,
+  options?: { limitationEnabled?: boolean; fallbackValue?: number; unitMultiplier?: number },
+): number => {
+  options = {
+    ...{
+      limitationEnabled: false,
+      unitMultiplier: 1,
+      fallbackValue: 0,
+    },
+    ...options,
+  };
+  const parsedValue = parseInt(value ?? '');
+  if (options?.limitationEnabled) {
+    return max(
+      min((!isNaN(parsedValue) ? parsedValue : Infinity) * options.unitMultiplier!, maxLimit),
+      minLimit,
+    );
+  }
+  return (!isNaN(parsedValue) ? parsedValue : options.fallbackValue!) * options.unitMultiplier!;
+};
+
+const getSampledValueTemplate = (
+  chargingStation: ChargingStation,
+  connectorId: number,
+  measurand: MeterValueMeasurand = MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER,
+  phase?: MeterValuePhase,
+): SampledValueTemplate | undefined => {
+  const onPhaseStr = phase ? `on phase ${phase} ` : '';
+  if (OCPPConstants.OCPP_MEASURANDS_SUPPORTED.includes(measurand) === false) {
+    logger.warn(
+      `${chargingStation.logPrefix()} Trying to get unsupported MeterValues measurand '${measurand}' ${onPhaseStr}in template on connector id ${connectorId}`,
+    );
+    return;
+  }
+  if (
+    measurand !== MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER &&
+    getConfigurationKey(
+      chargingStation,
+      StandardParametersKey.MeterValuesSampledData,
+    )?.value?.includes(measurand) === false
+  ) {
+    logger.debug(
+      `${chargingStation.logPrefix()} Trying to get MeterValues measurand '${measurand}' ${onPhaseStr}in template on connector id ${connectorId} not found in '${
+        StandardParametersKey.MeterValuesSampledData
+      }' OCPP parameter`,
+    );
+    return;
+  }
+  const sampledValueTemplates: SampledValueTemplate[] =
+    chargingStation.getConnectorStatus(connectorId)!.MeterValues;
+  for (
+    let index = 0;
+    isNotEmptyArray(sampledValueTemplates) === true && index < sampledValueTemplates.length;
+    index++
+  ) {
+    if (
+      OCPPConstants.OCPP_MEASURANDS_SUPPORTED.includes(
+        sampledValueTemplates[index]?.measurand ??
+          MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER,
+      ) === false
+    ) {
+      logger.warn(
+        `${chargingStation.logPrefix()} Unsupported MeterValues measurand '${measurand}' ${onPhaseStr}in template on connector id ${connectorId}`,
+      );
+    } else if (
+      phase &&
+      sampledValueTemplates[index]?.phase === phase &&
+      sampledValueTemplates[index]?.measurand === measurand &&
+      getConfigurationKey(
+        chargingStation,
+        StandardParametersKey.MeterValuesSampledData,
+      )?.value?.includes(measurand) === true
+    ) {
+      return sampledValueTemplates[index];
+    } else if (
+      !phase &&
+      !sampledValueTemplates[index]?.phase &&
+      sampledValueTemplates[index]?.measurand === measurand &&
+      getConfigurationKey(
+        chargingStation,
+        StandardParametersKey.MeterValuesSampledData,
+      )?.value?.includes(measurand) === true
+    ) {
+      return sampledValueTemplates[index];
+    } else if (
+      measurand === MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER &&
+      (!sampledValueTemplates[index]?.measurand ||
+        sampledValueTemplates[index]?.measurand === measurand)
+    ) {
+      return sampledValueTemplates[index];
+    }
+  }
+  if (measurand === MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER) {
+    const errorMsg = `Missing MeterValues for default measurand '${measurand}' in template on connector id ${connectorId}`;
+    logger.error(`${chargingStation.logPrefix()} ${errorMsg}`);
+    throw new BaseError(errorMsg);
+  }
+  logger.debug(
+    `${chargingStation.logPrefix()} No MeterValues for measurand '${measurand}' ${onPhaseStr}in template on connector id ${connectorId}`,
+  );
+};
+
+const buildSampledValue = (
+  sampledValueTemplate: SampledValueTemplate,
+  value: number,
+  context?: MeterValueContext,
+  phase?: MeterValuePhase,
+): SampledValue => {
+  const sampledValueContext = context ?? sampledValueTemplate?.context;
+  const sampledValueLocation =
+    sampledValueTemplate?.location ?? getMeasurandDefaultLocation(sampledValueTemplate.measurand!);
+  const sampledValuePhase = phase ?? sampledValueTemplate?.phase;
+  return {
+    ...(!isNullOrUndefined(sampledValueTemplate.unit) && {
+      unit: sampledValueTemplate.unit,
+    }),
+    ...(!isNullOrUndefined(sampledValueContext) && { context: sampledValueContext }),
+    ...(!isNullOrUndefined(sampledValueTemplate.measurand) && {
+      measurand: sampledValueTemplate.measurand,
+    }),
+    ...(!isNullOrUndefined(sampledValueLocation) && { location: sampledValueLocation }),
+    ...(!isNullOrUndefined(value) && { value: value.toString() }),
+    ...(!isNullOrUndefined(sampledValuePhase) && { phase: sampledValuePhase }),
+  } as SampledValue;
+};
+
+const getMeasurandDefaultLocation = (
+  measurandType: MeterValueMeasurand,
+): MeterValueLocation | undefined => {
+  switch (measurandType) {
+    case MeterValueMeasurand.STATE_OF_CHARGE:
+      return MeterValueLocation.EV;
+  }
+};
+
+// const getMeasurandDefaultUnit = (
+//   measurandType: MeterValueMeasurand,
+// ): MeterValueUnit | undefined => {
+//   switch (measurandType) {
+//     case MeterValueMeasurand.CURRENT_EXPORT:
+//     case MeterValueMeasurand.CURRENT_IMPORT:
+//     case MeterValueMeasurand.CURRENT_OFFERED:
+//       return MeterValueUnit.AMP;
+//     case MeterValueMeasurand.ENERGY_ACTIVE_EXPORT_REGISTER:
+//     case MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER:
+//       return MeterValueUnit.WATT_HOUR;
+//     case MeterValueMeasurand.POWER_ACTIVE_EXPORT:
+//     case MeterValueMeasurand.POWER_ACTIVE_IMPORT:
+//     case MeterValueMeasurand.POWER_OFFERED:
+//       return MeterValueUnit.WATT;
+//     case MeterValueMeasurand.STATE_OF_CHARGE:
+//       return MeterValueUnit.PERCENT;
+//     case MeterValueMeasurand.VOLTAGE:
+//       return MeterValueUnit.VOLT;
+//   }
+// };
+
 export class OCPPServiceUtils {
+  public static getMessageTypeString = getMessageTypeString;
+  public static sendAndSetConnectorStatus = sendAndSetConnectorStatus;
+  public static isIdTagAuthorized = isIdTagAuthorized;
+  public static buildTransactionEndMeterValue = buildTransactionEndMeterValue;
+  protected static getSampledValueTemplate = getSampledValueTemplate;
+  protected static buildSampledValue = buildSampledValue;
+
   protected constructor() {
     // This is intentional
   }
@@ -68,19 +1237,6 @@ export class OCPPServiceUtils {
     return ErrorType.FORMAT_VIOLATION;
   }
 
-  public static getMessageTypeString(messageType: MessageType): string {
-    switch (messageType) {
-      case MessageType.CALL_MESSAGE:
-        return 'request';
-      case MessageType.CALL_RESULT_MESSAGE:
-        return 'response';
-      case MessageType.CALL_ERROR_MESSAGE:
-        return 'error';
-      default:
-        return 'unknown';
-    }
-  }
-
   public static isRequestCommandSupported(
     chargingStation: ChargingStation,
     command: RequestCommand,
@@ -169,152 +1325,14 @@ export class OCPPServiceUtils {
     }
   }
 
-  public static buildStatusNotificationRequest(
-    chargingStation: ChargingStation,
-    connectorId: number,
-    status: ConnectorStatusEnum,
-    evseId?: number,
-  ): StatusNotificationRequest {
-    switch (chargingStation.stationInfo?.ocppVersion) {
-      case OCPPVersion.VERSION_16:
-        return {
-          connectorId,
-          status,
-          errorCode: ChargePointErrorCode.NO_ERROR,
-        } as OCPP16StatusNotificationRequest;
-      case OCPPVersion.VERSION_20:
-      case OCPPVersion.VERSION_201:
-        return {
-          timestamp: new Date(),
-          connectorStatus: status,
-          connectorId,
-          evseId,
-        } as OCPP20StatusNotificationRequest;
-      default:
-        throw new BaseError('Cannot build status notification payload: OCPP version not supported');
-    }
-  }
-
   public static startHeartbeatInterval(chargingStation: ChargingStation, interval: number): void {
-    if (!chargingStation.heartbeatSetInterval) {
+    if (chargingStation.heartbeatSetInterval === undefined) {
       chargingStation.startHeartbeat();
     } else if (chargingStation.getHeartbeatInterval() !== interval) {
       chargingStation.restartHeartbeat();
     }
   }
 
-  public static async sendAndSetConnectorStatus(
-    chargingStation: ChargingStation,
-    connectorId: number,
-    status: ConnectorStatusEnum,
-    evseId?: number,
-    options?: { send: boolean },
-  ) {
-    options = { send: true, ...options };
-    if (options.send) {
-      OCPPServiceUtils.checkConnectorStatusTransition(chargingStation, connectorId, status);
-      await chargingStation.ocppRequestService.requestHandler<
-        StatusNotificationRequest,
-        StatusNotificationResponse
-      >(
-        chargingStation,
-        RequestCommand.STATUS_NOTIFICATION,
-        OCPPServiceUtils.buildStatusNotificationRequest(
-          chargingStation,
-          connectorId,
-          status,
-          evseId,
-        ),
-      );
-    }
-    chargingStation.getConnectorStatus(connectorId)!.status = status;
-    chargingStation.emit(ChargingStationEvents.connectorStatusChanged, {
-      connectorId,
-      ...chargingStation.getConnectorStatus(connectorId),
-    });
-  }
-
-  public static async isIdTagAuthorized(
-    chargingStation: ChargingStation,
-    connectorId: number,
-    idTag: string,
-  ): Promise<boolean> {
-    if (
-      !chargingStation.getLocalAuthListEnabled() &&
-      !chargingStation.stationInfo?.remoteAuthorization
-    ) {
-      logger.warn(
-        `${chargingStation.logPrefix()} The charging station expects to authorize RFID tags but nor local authorization nor remote authorization are enabled. Misbehavior may occur`,
-      );
-    }
-    if (
-      chargingStation.getLocalAuthListEnabled() === true &&
-      OCPPServiceUtils.isIdTagLocalAuthorized(chargingStation, idTag)
-    ) {
-      const connectorStatus: ConnectorStatus = chargingStation.getConnectorStatus(connectorId)!;
-      connectorStatus.localAuthorizeIdTag = idTag;
-      connectorStatus.idTagLocalAuthorized = true;
-      return true;
-    } else if (chargingStation.stationInfo?.remoteAuthorization) {
-      return await OCPPServiceUtils.isIdTagRemoteAuthorized(chargingStation, connectorId, idTag);
-    }
-    return false;
-  }
-
-  protected static checkConnectorStatusTransition(
-    chargingStation: ChargingStation,
-    connectorId: number,
-    status: ConnectorStatusEnum,
-  ): boolean {
-    const fromStatus = chargingStation.getConnectorStatus(connectorId)!.status;
-    let transitionAllowed = false;
-    switch (chargingStation.stationInfo?.ocppVersion) {
-      case OCPPVersion.VERSION_16:
-        if (
-          (connectorId === 0 &&
-            OCPP16Constants.ChargePointStatusChargingStationTransitions.findIndex(
-              (transition) => transition.from === fromStatus && transition.to === status,
-            ) !== -1) ||
-          (connectorId > 0 &&
-            OCPP16Constants.ChargePointStatusConnectorTransitions.findIndex(
-              (transition) => transition.from === fromStatus && transition.to === status,
-            ) !== -1)
-        ) {
-          transitionAllowed = true;
-        }
-        break;
-      case OCPPVersion.VERSION_20:
-      case OCPPVersion.VERSION_201:
-        if (
-          (connectorId === 0 &&
-            OCPP20Constants.ChargingStationStatusTransitions.findIndex(
-              (transition) => transition.from === fromStatus && transition.to === status,
-            ) !== -1) ||
-          (connectorId > 0 &&
-            OCPP20Constants.ConnectorStatusTransitions.findIndex(
-              (transition) => transition.from === fromStatus && transition.to === status,
-            ) !== -1)
-        ) {
-          transitionAllowed = true;
-        }
-        break;
-      default:
-        throw new BaseError(
-          // eslint-disable-next-line @typescript-eslint/restrict-template-expressions
-          `Cannot check connector status transition: OCPP version ${chargingStation.stationInfo?.ocppVersion} not supported`,
-        );
-    }
-    if (transitionAllowed === false) {
-      logger.warn(
-        `${chargingStation.logPrefix()} OCPP ${chargingStation.stationInfo
-          ?.ocppVersion} connector id ${connectorId} status transition from '${
-          chargingStation.getConnectorStatus(connectorId)!.status
-        }' to '${status}' is not allowed`,
-      );
-    }
-    return transitionAllowed;
-  }
-
   protected static parseJsonSchemaFile<T extends JsonType>(
     relativePath: string,
     ocppVersion: OCPPVersion,
@@ -336,140 +1354,6 @@ export class OCPPServiceUtils {
     }
   }
 
-  protected static getSampledValueTemplate(
-    chargingStation: ChargingStation,
-    connectorId: number,
-    measurand: MeterValueMeasurand = MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER,
-    phase?: MeterValuePhase,
-  ): SampledValueTemplate | undefined {
-    const onPhaseStr = phase ? `on phase ${phase} ` : '';
-    if (OCPPConstants.OCPP_MEASURANDS_SUPPORTED.includes(measurand) === false) {
-      logger.warn(
-        `${chargingStation.logPrefix()} Trying to get unsupported MeterValues measurand '${measurand}' ${onPhaseStr}in template on connector id ${connectorId}`,
-      );
-      return;
-    }
-    if (
-      measurand !== MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER &&
-      getConfigurationKey(
-        chargingStation,
-        StandardParametersKey.MeterValuesSampledData,
-      )?.value?.includes(measurand) === false
-    ) {
-      logger.debug(
-        `${chargingStation.logPrefix()} Trying to get MeterValues measurand '${measurand}' ${onPhaseStr}in template on connector id ${connectorId} not found in '${
-          StandardParametersKey.MeterValuesSampledData
-        }' OCPP parameter`,
-      );
-      return;
-    }
-    const sampledValueTemplates: SampledValueTemplate[] =
-      chargingStation.getConnectorStatus(connectorId)!.MeterValues;
-    for (
-      let index = 0;
-      isNotEmptyArray(sampledValueTemplates) === true && index < sampledValueTemplates.length;
-      index++
-    ) {
-      if (
-        OCPPConstants.OCPP_MEASURANDS_SUPPORTED.includes(
-          sampledValueTemplates[index]?.measurand ??
-            MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER,
-        ) === false
-      ) {
-        logger.warn(
-          `${chargingStation.logPrefix()} Unsupported MeterValues measurand '${measurand}' ${onPhaseStr}in template on connector id ${connectorId}`,
-        );
-      } else if (
-        phase &&
-        sampledValueTemplates[index]?.phase === phase &&
-        sampledValueTemplates[index]?.measurand === measurand &&
-        getConfigurationKey(
-          chargingStation,
-          StandardParametersKey.MeterValuesSampledData,
-        )?.value?.includes(measurand) === true
-      ) {
-        return sampledValueTemplates[index];
-      } else if (
-        !phase &&
-        !sampledValueTemplates[index]?.phase &&
-        sampledValueTemplates[index]?.measurand === measurand &&
-        getConfigurationKey(
-          chargingStation,
-          StandardParametersKey.MeterValuesSampledData,
-        )?.value?.includes(measurand) === true
-      ) {
-        return sampledValueTemplates[index];
-      } else if (
-        measurand === MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER &&
-        (!sampledValueTemplates[index]?.measurand ||
-          sampledValueTemplates[index]?.measurand === measurand)
-      ) {
-        return sampledValueTemplates[index];
-      }
-    }
-    if (measurand === MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER) {
-      const errorMsg = `Missing MeterValues for default measurand '${measurand}' in template on connector id ${connectorId}`;
-      logger.error(`${chargingStation.logPrefix()} ${errorMsg}`);
-      throw new BaseError(errorMsg);
-    }
-    logger.debug(
-      `${chargingStation.logPrefix()} No MeterValues for measurand '${measurand}' ${onPhaseStr}in template on connector id ${connectorId}`,
-    );
-  }
-
-  protected static getLimitFromSampledValueTemplateCustomValue(
-    value: string | undefined,
-    maxLimit: number,
-    minLimit: number,
-    options?: { limitationEnabled?: boolean; fallbackValue?: number; unitMultiplier?: number },
-  ): number {
-    options = {
-      ...{
-        limitationEnabled: false,
-        unitMultiplier: 1,
-        fallbackValue: 0,
-      },
-      ...options,
-    };
-    const parsedValue = parseInt(value ?? '');
-    if (options?.limitationEnabled) {
-      return max(
-        min((!isNaN(parsedValue) ? parsedValue : Infinity) * options.unitMultiplier!, maxLimit),
-        minLimit,
-      );
-    }
-    return (!isNaN(parsedValue) ? parsedValue : options.fallbackValue!) * options.unitMultiplier!;
-  }
-
-  private static isIdTagLocalAuthorized(chargingStation: ChargingStation, idTag: string): boolean {
-    return (
-      chargingStation.hasIdTags() === true &&
-      isNotEmptyString(
-        chargingStation.idTagsCache
-          .getIdTags(getIdTagsFile(chargingStation.stationInfo)!)
-          ?.find((tag) => tag === idTag),
-      )
-    );
-  }
-
-  private static async isIdTagRemoteAuthorized(
-    chargingStation: ChargingStation,
-    connectorId: number,
-    idTag: string,
-  ): Promise<boolean> {
-    chargingStation.getConnectorStatus(connectorId)!.authorizeIdTag = idTag;
-    return (
-      (
-        await chargingStation.ocppRequestService.requestHandler<
-          AuthorizeRequest,
-          AuthorizeResponse
-        >(chargingStation, RequestCommand.AUTHORIZE, {
-          idTag,
-        })
-      )?.idTagInfo?.status === AuthorizationStatus.ACCEPTED
-    );
-  }
-
   private static logPrefix = (
     ocppVersion: OCPPVersion,
     moduleName?: string,
index 02fadb3e24f391dac3c19599451169368a65cfaf..b5abe46446ac9c5a1d2d9a789d0568a659c163e6 100644 (file)
@@ -1,11 +1,16 @@
 export { OCPP16IncomingRequestService } from './1.6/OCPP16IncomingRequestService';
 export { OCPP16RequestService } from './1.6/OCPP16RequestService';
 export { OCPP16ResponseService } from './1.6/OCPP16ResponseService';
-// FIXME: shall not be exported
-export { OCPP16ServiceUtils } from './1.6/OCPP16ServiceUtils';
 export { OCPP20IncomingRequestService } from './2.0/OCPP20IncomingRequestService';
 export { OCPP20RequestService } from './2.0/OCPP20RequestService';
 export { OCPP20ResponseService } from './2.0/OCPP20ResponseService';
 export { OCPPIncomingRequestService } from './OCPPIncomingRequestService';
 export { OCPPRequestService } from './OCPPRequestService';
-export { OCPPServiceUtils } from './OCPPServiceUtils';
+export {
+  buildMeterValue,
+  buildStatusNotificationRequest,
+  buildTransactionEndMeterValue,
+  getMessageTypeString,
+  isIdTagAuthorized,
+  sendAndSetConnectorStatus,
+} from './OCPPServiceUtils';
index a190b60395e216f8c0a46ec6e6ad1ad0597829f5..e0078c19ff1e4d94a5cb6656d651a9013d9ad768 100644 (file)
@@ -140,7 +140,7 @@ export abstract class AbstractUIService {
   }
 
   public getBroadcastChannelExpectedResponses(uuid: string): number {
-    return this.broadcastChannelRequests.get(uuid) ?? 0;
+    return this.broadcastChannelRequests.get(uuid)!;
   }
 
   protected handleProtocolRequest(
@@ -162,9 +162,8 @@ export abstract class AbstractUIService {
   ): void {
     if (isNotEmptyArray(payload.hashIds)) {
       payload.hashIds = payload.hashIds
-        ?.filter((hashId) => !isNullOrUndefined(hashId))
         ?.map((hashId) => {
-          if (this.uiServer.chargingStations.has(hashId) === true) {
+          if (hashId !== undefined && this.uiServer.chargingStations.has(hashId) === true) {
             return hashId;
           }
           logger.warn(
@@ -173,11 +172,19 @@ export abstract class AbstractUIService {
               'sendBroadcastChannelRequest',
             )} Charging station with hashId '${hashId}' not found`,
           );
-        }) as string[];
+        })
+        ?.filter((hashId) => !isNullOrUndefined(hashId)) as string[];
+    } else {
+      delete payload.hashIds;
     }
-    const expectedNumberOfResponses = isNotEmptyArray(payload.hashIds)
-      ? payload.hashIds!.length
+    const expectedNumberOfResponses = Array.isArray(payload.hashIds)
+      ? payload.hashIds.length
       : this.uiServer.chargingStations.size;
+    if (expectedNumberOfResponses === 0) {
+      throw new BaseError(
+        'hashIds array in the request payload does not contain any valid charging station hashId',
+      );
+    }
     this.uiServiceWorkerBroadcastChannel.sendRequest([uuid, procedureName, payload]);
     this.broadcastChannelRequests.set(uuid, expectedNumberOfResponses);
   }
index b7bc5d27f894c27c9984571e90a4b07187ed8fed..94c189e4d3e6251a7bf8bfa7022a13b1fc4d07f7 100644 (file)
@@ -78,7 +78,15 @@ export class PerformanceStatistics {
   }
 
   public static endMeasure(name: string, markId: string): void {
-    performance.measure(name, markId);
+    try {
+      performance.measure(name, markId);
+    } catch (error) {
+      if (error instanceof Error && error.message.includes('performance mark has not been set')) {
+        /** Ignore */
+      } else {
+        throw error;
+      }
+    }
     performance.clearMarks(markId);
     performance.clearMeasures(name);
   }
index 622b125974d951531012740a719935a5ec1e9815..d1948921660b0da42774c813686405c2baf4d74c 100644 (file)
@@ -1,4 +1,5 @@
 import type { ListenOptions } from 'node:net';
+import type { ResourceLimits } from 'node:worker_threads';
 
 import type { WorkerChoiceStrategy } from 'poolifier';
 
@@ -63,15 +64,16 @@ export interface StorageConfiguration {
   uri?: string;
 }
 
+export type ElementsPerWorkerType = number | 'auto' | 'all';
+
 export interface WorkerConfiguration {
   processType?: WorkerProcessType;
   startDelay?: number;
-  elementsPerWorker?: number | 'auto';
+  elementsPerWorker?: ElementsPerWorkerType;
   elementStartDelay?: number;
   poolMinSize?: number;
   poolMaxSize?: number;
-  /** @deprecated Not publicly exposed to end users. */
-  poolStrategy?: WorkerChoiceStrategy;
+  resourceLimits?: ResourceLimits;
 }
 
 export interface ConfigurationData {
index a28d51148dc596aa05454b5f6632b218e56feb64..cc80f527c8ed699f5b9d06442dd8074eb1738325 100644 (file)
@@ -81,7 +81,6 @@ export {
 } from './WorkerBroadcastChannel';
 export {
   type ChangeConfigurationRequest,
-  type ClearChargingProfileRequest,
   type GetConfigurationRequest,
   type GetDiagnosticsRequest,
   OCPP16AvailabilityType,
@@ -89,6 +88,7 @@ export {
   type OCPP16CancelReservationRequest,
   type OCPP16ChangeAvailabilityRequest,
   type OCPP16ClearCacheRequest,
+  type OCPP16ClearChargingProfileRequest,
   type OCPP16DataTransferRequest,
   OCPP16DataTransferVendorId,
   type OCPP16DiagnosticsStatusNotificationRequest,
@@ -111,11 +111,11 @@ export {
 } from './ocpp/1.6/Requests';
 export {
   type ChangeConfigurationResponse,
-  type ClearChargingProfileResponse,
   type GetConfigurationResponse,
   type GetDiagnosticsResponse,
   type OCPP16BootNotificationResponse,
   type OCPP16ChangeAvailabilityResponse,
+  type OCPP16ClearChargingProfileResponse,
   type OCPP16DataTransferResponse,
   OCPP16DataTransferStatus,
   type OCPP16DiagnosticsStatusNotificationResponse,
@@ -167,6 +167,7 @@ export {
   ApplicationProtocolVersion,
   type ConfigurationData,
   ConfigurationSection,
+  type ElementsPerWorkerType,
   type LogConfiguration,
   type StationTemplateUrl,
   type StorageConfiguration,
@@ -197,14 +198,22 @@ export type {
 } from './MeasurandPerPhaseSampledValueTemplates';
 export type { MeasurandValues } from './MeasurandValues';
 export { MessageType } from './ocpp/MessageType';
-export { type MeterValue, MeterValueMeasurand, MeterValuePhase } from './ocpp/MeterValues';
 export {
+  type MeterValue,
   MeterValueContext,
   MeterValueLocation,
+  MeterValueMeasurand,
+  MeterValuePhase,
   MeterValueUnit,
+  type SampledValue,
+} from './ocpp/MeterValues';
+export {
   type OCPP16MeterValue,
+  OCPP16MeterValueContext,
+  OCPP16MeterValueLocation,
   OCPP16MeterValueMeasurand,
   OCPP16MeterValuePhase,
+  OCPP16MeterValueUnit,
   type OCPP16MeterValuesRequest,
   type OCPP16MeterValuesResponse,
   type OCPP16SampledValue,
index 74698284e2c6d2a6d70fd5af2345d9fff16fe96b..6d102b8809edb0eaba896036bb243ea0636eea9e 100644 (file)
@@ -1,7 +1,7 @@
 import type { EmptyObject } from '../../EmptyObject';
 import type { JsonObject } from '../../JsonType';
 
-export enum MeterValueUnit {
+export enum OCPP16MeterValueUnit {
   WATT_HOUR = 'Wh',
   KILO_WATT_HOUR = 'kWh',
   VAR_HOUR = 'varh',
@@ -20,7 +20,7 @@ export enum MeterValueUnit {
   PERCENT = 'Percent',
 }
 
-export enum MeterValueContext {
+export enum OCPP16MeterValueContext {
   INTERRUPTION_BEGIN = 'Interruption.Begin',
   INTERRUPTION_END = 'Interruption.End',
   OTHER = 'Other',
@@ -56,7 +56,7 @@ export enum OCPP16MeterValueMeasurand {
   VOLTAGE = 'Voltage',
 }
 
-export enum MeterValueLocation {
+export enum OCPP16MeterValueLocation {
   BODY = 'Body',
   CABLE = 'Cable',
   EV = 'EV',
@@ -77,19 +77,19 @@ export enum OCPP16MeterValuePhase {
   L3_L1 = 'L3-L1',
 }
 
-enum MeterValueFormat {
+enum OCPP16MeterValueFormat {
   RAW = 'Raw',
   SIGNED_DATA = 'SignedData',
 }
 
 export interface OCPP16SampledValue extends JsonObject {
   value: string;
-  unit?: MeterValueUnit;
-  context?: MeterValueContext;
+  unit?: OCPP16MeterValueUnit;
+  context?: OCPP16MeterValueContext;
   measurand?: OCPP16MeterValueMeasurand;
   phase?: OCPP16MeterValuePhase;
-  location?: MeterValueLocation;
-  format?: MeterValueFormat;
+  location?: OCPP16MeterValueLocation;
+  format?: OCPP16MeterValueFormat;
 }
 
 export interface OCPP16MeterValue extends JsonObject {
index c6f041e58581e40c7d92ad81b43dccaeb16f48b0..b14583f08d63a8342c26438edd7c8e5a6a4a9240 100644 (file)
@@ -124,7 +124,7 @@ export interface OCPP16ChangeAvailabilityRequest extends JsonObject {
   type: OCPP16AvailabilityType;
 }
 
-export interface ClearChargingProfileRequest extends JsonObject {
+export interface OCPP16ClearChargingProfileRequest extends JsonObject {
   id?: number;
   connectorId?: number;
   chargingProfilePurpose?: OCPP16ChargingProfilePurposeType;
index c98c03a36b13210e0b448ff68f32b1e862401291..a42733e8a2244721451bf109b395f20331898bcc 100644 (file)
@@ -74,7 +74,7 @@ export enum OCPP16ClearChargingProfileStatus {
   UNKNOWN = 'Unknown',
 }
 
-export interface ClearChargingProfileResponse extends JsonObject {
+export interface OCPP16ClearChargingProfileResponse extends JsonObject {
   status: OCPP16ClearChargingProfileStatus;
 }
 
index f34a8c176fd3cf711ee158bad3f9ac2e0f950c3e..78cc9af9b02905c44e810c3e95eed1c351ecf681 100644 (file)
@@ -1,15 +1,33 @@
 import {
   type OCPP16MeterValue,
+  OCPP16MeterValueContext,
+  OCPP16MeterValueLocation,
   OCPP16MeterValueMeasurand,
   OCPP16MeterValuePhase,
+  OCPP16MeterValueUnit,
   type OCPP16SampledValue,
 } from './1.6/MeterValues';
 
+export const MeterValueUnit = {
+  ...OCPP16MeterValueUnit,
+} as const;
+export type MeterValueUnit = OCPP16MeterValueUnit;
+
+export const MeterValueContext = {
+  ...OCPP16MeterValueContext,
+} as const;
+export type MeterValueContext = OCPP16MeterValueContext;
+
 export const MeterValueMeasurand = {
   ...OCPP16MeterValueMeasurand,
 } as const;
 export type MeterValueMeasurand = OCPP16MeterValueMeasurand;
 
+export const MeterValueLocation = {
+  ...OCPP16MeterValueLocation,
+} as const;
+export type MeterValueLocation = OCPP16MeterValueLocation;
+
 export const MeterValuePhase = {
   ...OCPP16MeterValuePhase,
 } as const;
index 1f370480d4d1b6fc47828792ccbf8271cfb81724..31d994f58eee2c29d18cacee21ac3a565f708c57 100644 (file)
@@ -1,20 +1,21 @@
 import { type FSWatcher, readFileSync, watch } from 'node:fs';
-import { dirname, join, resolve } from 'node:path';
+import { dirname, join } from 'node:path';
 import { env } from 'node:process';
 import { fileURLToPath } from 'node:url';
 
 import chalk from 'chalk';
 import merge from 'just-merge';
 
-import { Constants } from './Constants';
 import {
-  hasOwnProp,
-  isCFEnvironment,
-  isNotEmptyString,
-  isUndefined,
+  buildPerformanceUriFilePath,
+  checkWorkerElementsPerWorker,
+  checkWorkerProcessType,
+  getDefaultPerformanceStorageUri,
+  handleFileException,
   logPrefix,
-  once,
-} from './Utils';
+} from './ConfigurationUtils';
+import { Constants } from './Constants';
+import { hasOwnProp, isCFEnvironment, isUndefined, once } from './Utils';
 import {
   ApplicationProtocol,
   type ConfigurationData,
@@ -42,11 +43,6 @@ type ConfigurationSectionType =
   | WorkerConfiguration
   | UIServerConfiguration;
 
-// Avoid ESM race condition at class initialization
-const configurationLogPrefix = (): string => {
-  return logPrefix(' Simulator configuration |');
-};
-
 export class Configuration {
   public static configurationChangeCallback: () => Promise<void>;
 
@@ -183,7 +179,7 @@ export class Configuration {
     let storageConfiguration: StorageConfiguration = {
       enabled: false,
       type: StorageType.JSON_FILE,
-      uri: Configuration.getDefaultPerformanceStorageUri(StorageType.JSON_FILE),
+      uri: getDefaultPerformanceStorageUri(StorageType.JSON_FILE),
     };
     if (hasOwnProp(Configuration.getConfigurationData(), ConfigurationSection.performanceStorage)) {
       storageConfiguration = {
@@ -192,7 +188,7 @@ export class Configuration {
         ...(Configuration.getConfigurationData()?.performanceStorage?.type ===
           StorageType.JSON_FILE &&
           Configuration.getConfigurationData()?.performanceStorage?.uri && {
-            uri: Configuration.buildPerformanceUriFilePath(
+            uri: buildPerformanceUriFilePath(
               new URL(Configuration.getConfigurationData()!.performanceStorage!.uri!).pathname,
             ),
           }),
@@ -289,11 +285,8 @@ export class Configuration {
       ...(hasOwnProp(Configuration.getConfigurationData(), ConfigurationSection.worker) &&
         Configuration.getConfigurationData()?.worker),
     };
-    if (!Object.values(WorkerProcessType).includes(workerConfiguration.processType!)) {
-      throw new SyntaxError(
-        `Invalid worker process type '${workerConfiguration.processType}' defined in configuration`,
-      );
-    }
+    checkWorkerProcessType(workerConfiguration.processType!);
+    checkWorkerElementsPerWorker(workerConfiguration.elementsPerWorker);
     return workerConfiguration;
   }
 
@@ -332,7 +325,7 @@ export class Configuration {
       (stationTemplateUrl: StationTemplateUrl) => {
         if (!isUndefined(stationTemplateUrl?.['numberOfStation' as keyof StationTemplateUrl])) {
           console.error(
-            `${chalk.green(configurationLogPrefix())} ${chalk.red(
+            `${chalk.green(logPrefix())} ${chalk.red(
               `Deprecated configuration key 'numberOfStation' usage for template file '${stationTemplateUrl.file}' in 'stationTemplateUrls'. Use 'numberOfStations' instead`,
             )}`,
           );
@@ -412,7 +405,7 @@ export class Configuration {
       ('staticPool' as WorkerProcessType)
     ) {
       console.error(
-        `${chalk.green(configurationLogPrefix())} ${chalk.red(
+        `${chalk.green(logPrefix())} ${chalk.red(
           `Deprecated configuration 'staticPool' value usage in worker section 'processType' field. Use '${WorkerProcessType.fixedPool}' value instead`,
         )}`,
       );
@@ -477,7 +470,7 @@ export class Configuration {
     // uiServer section
     if (hasOwnProp(Configuration.getConfigurationData(), 'uiWebSocketServer')) {
       console.error(
-        `${chalk.green(configurationLogPrefix())} ${chalk.red(
+        `${chalk.green(logPrefix())} ${chalk.red(
           `Deprecated configuration section 'uiWebSocketServer' usage. Use '${ConfigurationSection.uiServer}' instead`,
         )}`,
       );
@@ -504,7 +497,7 @@ export class Configuration {
       )
     ) {
       console.error(
-        `${chalk.green(configurationLogPrefix())} ${chalk.red(
+        `${chalk.green(logPrefix())} ${chalk.red(
           `Deprecated configuration key '${key}' usage in section '${sectionName}'${
             logMsgToAppend.trim().length > 0 ? `. ${logMsgToAppend}` : ''
           }`,
@@ -514,7 +507,7 @@ export class Configuration {
       !isUndefined(Configuration.getConfigurationData()?.[key as keyof ConfigurationData])
     ) {
       console.error(
-        `${chalk.green(configurationLogPrefix())} ${chalk.red(
+        `${chalk.green(logPrefix())} ${chalk.red(
           `Deprecated configuration key '${key}' usage${
             logMsgToAppend.trim().length > 0 ? `. ${logMsgToAppend}` : ''
           }`,
@@ -533,11 +526,11 @@ export class Configuration {
           Configuration.configurationFileWatcher = Configuration.getConfigurationFileWatcher();
         }
       } catch (error) {
-        Configuration.handleFileException(
+        handleFileException(
           Configuration.configurationFile,
           FileType.Configuration,
           error as NodeJS.ErrnoException,
-          configurationLogPrefix(),
+          logPrefix(),
         );
       }
     }
@@ -555,7 +548,7 @@ export class Configuration {
           Configuration.configurationFileReloading = true;
           const consoleWarnOnce = once(console.warn, this);
           consoleWarnOnce(
-            `${chalk.green(configurationLogPrefix())} ${chalk.yellow(
+            `${chalk.green(logPrefix())} ${chalk.yellow(
               `${FileType.Configuration} ${this.configurationFile} file have changed, reload`,
             )}`,
           );
@@ -575,59 +568,12 @@ export class Configuration {
         }
       });
     } catch (error) {
-      Configuration.handleFileException(
+      handleFileException(
         Configuration.configurationFile,
         FileType.Configuration,
         error as NodeJS.ErrnoException,
-        configurationLogPrefix(),
+        logPrefix(),
       );
     }
   }
-
-  private static handleFileException(
-    file: string,
-    fileType: FileType,
-    error: NodeJS.ErrnoException,
-    logPfx: string,
-  ): void {
-    const prefix = isNotEmptyString(logPfx) ? `${logPfx} ` : '';
-    let logMsg: string;
-    switch (error.code) {
-      case 'ENOENT':
-        logMsg = `${fileType} file ${file} not found: `;
-        break;
-      case 'EEXIST':
-        logMsg = `${fileType} file ${file} already exists: `;
-        break;
-      case 'EACCES':
-        logMsg = `${fileType} file ${file} access denied: `;
-        break;
-      case 'EPERM':
-        logMsg = `${fileType} file ${file} permission denied: `;
-        break;
-      default:
-        logMsg = `${fileType} file ${file} error: `;
-    }
-    console.error(`${chalk.green(prefix)}${chalk.red(logMsg)}`, error);
-    throw error;
-  }
-
-  private static getDefaultPerformanceStorageUri(storageType: StorageType) {
-    switch (storageType) {
-      case StorageType.JSON_FILE:
-        return Configuration.buildPerformanceUriFilePath(
-          `${Constants.DEFAULT_PERFORMANCE_DIRECTORY}/${Constants.DEFAULT_PERFORMANCE_RECORDS_FILENAME}`,
-        );
-      case StorageType.SQLITE:
-        return Configuration.buildPerformanceUriFilePath(
-          `${Constants.DEFAULT_PERFORMANCE_DIRECTORY}/${Constants.DEFAULT_PERFORMANCE_RECORDS_DB_NAME}.db`,
-        );
-      default:
-        throw new Error(`Unsupported storage type '${storageType}'`);
-    }
-  }
-
-  private static buildPerformanceUriFilePath(file: string) {
-    return `file://${join(resolve(dirname(fileURLToPath(import.meta.url)), '../'), file)}`;
-  }
 }
diff --git a/src/utils/ConfigurationUtils.ts b/src/utils/ConfigurationUtils.ts
new file mode 100644 (file)
index 0000000..73bd9ce
--- /dev/null
@@ -0,0 +1,88 @@
+import { dirname, join, resolve } from 'node:path';
+import { fileURLToPath } from 'node:url';
+
+import chalk from 'chalk';
+
+import { Constants } from './Constants';
+import { isNotEmptyString, logPrefix as utilsLogPrefix } from './Utils';
+import { type ElementsPerWorkerType, FileType, StorageType } from '../types';
+import { WorkerProcessType } from '../worker';
+
+export const logPrefix = (): string => {
+  return utilsLogPrefix(' Simulator configuration |');
+};
+
+export const buildPerformanceUriFilePath = (file: string) => {
+  return `file://${join(resolve(dirname(fileURLToPath(import.meta.url)), '../'), file)}`;
+};
+
+export const getDefaultPerformanceStorageUri = (storageType: StorageType) => {
+  switch (storageType) {
+    case StorageType.JSON_FILE:
+      return buildPerformanceUriFilePath(
+        `${Constants.DEFAULT_PERFORMANCE_DIRECTORY}/${Constants.DEFAULT_PERFORMANCE_RECORDS_FILENAME}`,
+      );
+    case StorageType.SQLITE:
+      return buildPerformanceUriFilePath(
+        `${Constants.DEFAULT_PERFORMANCE_DIRECTORY}/${Constants.DEFAULT_PERFORMANCE_RECORDS_DB_NAME}.db`,
+      );
+    default:
+      throw new Error(`Unsupported storage type '${storageType}'`);
+  }
+};
+
+export const handleFileException = (
+  file: string,
+  fileType: FileType,
+  error: NodeJS.ErrnoException,
+  logPfx: string,
+): void => {
+  const prefix = isNotEmptyString(logPfx) ? `${logPfx} ` : '';
+  let logMsg: string;
+  switch (error.code) {
+    case 'ENOENT':
+      logMsg = `${fileType} file ${file} not found: `;
+      break;
+    case 'EEXIST':
+      logMsg = `${fileType} file ${file} already exists: `;
+      break;
+    case 'EACCES':
+      logMsg = `${fileType} file ${file} access denied: `;
+      break;
+    case 'EPERM':
+      logMsg = `${fileType} file ${file} permission denied: `;
+      break;
+    default:
+      logMsg = `${fileType} file ${file} error: `;
+  }
+  console.error(`${chalk.green(prefix)}${chalk.red(logMsg)}`, error);
+  throw error;
+};
+
+export const checkWorkerProcessType = (workerProcessType: WorkerProcessType): void => {
+  if (!Object.values(WorkerProcessType).includes(workerProcessType)) {
+    throw new SyntaxError(
+      `Invalid worker process type '${workerProcessType}' defined in configuration`,
+    );
+  }
+};
+
+export const checkWorkerElementsPerWorker = (
+  elementsPerWorker: ElementsPerWorkerType | undefined,
+): void => {
+  if (
+    elementsPerWorker !== undefined &&
+    elementsPerWorker !== 'auto' &&
+    elementsPerWorker !== 'all' &&
+    !Number.isSafeInteger(elementsPerWorker)
+  ) {
+    throw new SyntaxError(
+      `Invalid number of elements per worker '${elementsPerWorker}' defined in configuration`,
+    );
+  }
+  if (Number.isSafeInteger(elementsPerWorker) && (elementsPerWorker as number) <= 0) {
+    throw RangeError(
+      `Invalid negative or zero number of elements per worker '${elementsPerWorker}' defined in configuration`,
+    );
+  }
+};
index a17b56a8b644b938c29a0f9eef68cfd1d53b1458..d704c15ddff2a377c9d39a6ca553f5a0409b85c9 100644 (file)
@@ -1,6 +1,36 @@
-import type { AutomaticTransactionGeneratorConfiguration } from '../types';
+import {
+  type AutomaticTransactionGeneratorConfiguration,
+  type ChargingStationInfo,
+  CurrentType,
+  OCPPVersion,
+  VendorParametersKey,
+} from '../types';
 
 export class Constants {
+  static readonly DEFAULT_STATION_INFO: Partial<ChargingStationInfo> = Object.freeze({
+    enableStatistics: false,
+    remoteAuthorization: true,
+    currentOutType: CurrentType.AC,
+    mainVoltageMeterValues: true,
+    phaseLineToLineVoltageMeterValues: false,
+    customValueLimitationMeterValues: true,
+    ocppStrictCompliance: true,
+    outOfOrderEndMeterValues: false,
+    beginEndMeterValues: false,
+    meteringPerTransaction: true,
+    transactionDataMeterValues: false,
+    supervisionUrlOcppConfiguration: false,
+    supervisionUrlOcppKey: VendorParametersKey.ConnectionUrl,
+    ocppVersion: OCPPVersion.VERSION_16,
+    ocppPersistentConfiguration: true,
+    stationInfoPersistentConfiguration: true,
+    automaticTransactionGeneratorPersistentConfiguration: true,
+    autoReconnectMaxRetries: -1,
+    registrationMaxRetries: -1,
+    reconnectExponentialDelay: false,
+    stopTransactionsOnStopped: true,
+  });
+
   static readonly DEFAULT_BOOT_NOTIFICATION_INTERVAL = 60000; // Ms
   static readonly DEFAULT_HEARTBEAT_INTERVAL = 60000; // Ms
   static readonly DEFAULT_METER_VALUES_INTERVAL = 60000; // Ms
index f0bd1f28bbc789500e3b0ae41c966dbf9f3ac241..2ff71b0acb2ffa897a5d07f0e7bcd18719314903 100644 (file)
@@ -64,12 +64,27 @@ export const nthPercentile = (dataSet: number[], percentile: number): number =>
   return sortedDataSet[percentileIndexInteger];
 };
 
+/**
+ * Computes the sample standard deviation of the given data set.
+ *
+ * @param dataSet - Data set.
+ * @param dataSetAverage - Average of the data set.
+ * @returns The sample standard deviation of the given data set.
+ * @see https://en.wikipedia.org/wiki/Unbiased_estimation_of_standard_deviation
+ * @internal
+ */
 export const stdDeviation = (
   dataSet: number[],
   dataSetAverage: number = average(dataSet),
 ): number => {
+  if (isEmptyArray(dataSet)) {
+    return 0;
+  }
+  if (Array.isArray(dataSet) && dataSet.length === 1) {
+    return 0;
+  }
   return Math.sqrt(
     dataSet.reduce((accumulator, num) => accumulator + Math.pow(num - dataSetAverage, 2), 0) /
-      dataSet.length,
+      (dataSet.length - 1),
   );
 };
index efdffc2f2bdc5b59b12acaf55a425a200982b86f..366ccf98a96d182f55c67b9c2448d076be94e674 100644 (file)
@@ -1,4 +1,4 @@
-import { randomBytes, randomInt, randomUUID, webcrypto } from 'node:crypto';
+import { getRandomValues, randomBytes, randomInt, randomUUID } from 'node:crypto';
 import { env, nextTick } from 'node:process';
 
 import {
@@ -70,22 +70,24 @@ export const isValidTime = (date: unknown): boolean => {
   if (typeof date === 'number') {
     return !isNaN(date);
   } else if (isDate(date)) {
-    return !isNaN((date as Date).getTime());
+    return !isNaN(date.getTime());
   }
   return false;
 };
 
-export const convertToDate = (value: Date | string | number | undefined): Date | undefined => {
+export const convertToDate = (
+  value: Date | string | number | null | undefined,
+): Date | null | undefined => {
   if (isNullOrUndefined(value)) {
-    return value as undefined;
+    return value as null | undefined;
   }
   if (isDate(value)) {
-    return value as Date;
+    return value;
   }
   if (isString(value) || typeof value === 'number') {
-    const valueToDate = new Date(value as string | number);
+    const valueToDate = new Date(value!);
     if (isNaN(valueToDate.getTime())) {
-      throw new Error(`Cannot convert to date: '${value as string | number}'`);
+      throw new Error(`Cannot convert to date: '${value!}'`);
     }
     return valueToDate;
   }
@@ -127,7 +129,7 @@ export const convertToFloat = (value: unknown): number => {
 
 export const convertToBoolean = (value: unknown): boolean => {
   let result = false;
-  if (value) {
+  if (value != null) {
     // Check the type
     if (typeof value === 'boolean') {
       return value;
@@ -290,7 +292,6 @@ export const isUndefined = (value: unknown): boolean => {
 };
 
 export const isNullOrUndefined = (value: unknown): boolean => {
-  // eslint-disable-next-line eqeqeq, no-eq-null
   return value == null;
 };
 
@@ -336,7 +337,7 @@ export const exponentialDelay = (retryNumber = 0, delayFactor = 100): number =>
  * @returns A number in the [0,1[ range
  */
 export const secureRandom = (): number => {
-  return webcrypto.getRandomValues(new Uint32Array(1))[0] / 0x100000000;
+  return getRandomValues(new Uint32Array(1))[0] / 0x100000000;
 };
 
 export const JSONStringifyWithMapSupport = (
index 912f5256575bb2ca9a5b486bb8ed0cce8cd5bd9e..5e5e6fdbea05e01415415a852599e3a8ccb8ea27 100644 (file)
@@ -21,7 +21,7 @@ export abstract class WorkerAbstract<T extends WorkerData> {
    * @param workerOptions -
    */
   constructor(workerScript: string, workerOptions: WorkerOptions) {
-    if (workerScript === null || workerScript === undefined) {
+    if (workerScript == null) {
       throw new Error('Worker script is not defined');
     }
     if (typeof workerScript === 'string' && workerScript.trim().length === 0) {
index c5df860ced4fc85b16e7067c805605b05db75e04..17b5b6dde201c85f4c0af0cbaf3574d33968fb03 100644 (file)
@@ -95,6 +95,7 @@ export class WorkerSet extends WorkerAbstract<WorkerData> {
       await waitWorkerExit;
       this.emitter?.emit(WorkerSetEvents.stopped, this.info);
       this.emitter?.emitDestroy();
+      this.emitter?.removeAllListeners();
       this.started = false;
     }
   }
@@ -104,7 +105,7 @@ export class WorkerSet extends WorkerAbstract<WorkerData> {
     if (!this.started) {
       throw new Error('Cannot add a WorkerSet element: not started');
     }
-    if (!this.workerSet) {
+    if (this.workerSet == null) {
       throw new Error("Cannot add a WorkerSet element: 'workerSet' property does not exist");
     }
     const workerSetElement = await this.getWorkerSetElement();
index 1874767370a1a5d438993fd6ec2dba1b9f1318d1..776d7174c664f24a8d1e8bcb8ab59b5d3ee5706b 100644 (file)
@@ -1,4 +1,4 @@
-import { webcrypto } from 'node:crypto';
+import { getRandomValues } from 'node:crypto';
 
 import chalk from 'chalk';
 
@@ -34,5 +34,5 @@ export const randomizeDelay = (delay: number): number => {
  * @internal
  */
 const secureRandom = (): number => {
-  return webcrypto.getRandomValues(new Uint32Array(1))[0] / 0x100000000;
+  return getRandomValues(new Uint32Array(1))[0] / 0x100000000;
 };
index d9aadf0c5e77426f6170104799048ba79533c426..38963dbe97d2c69b27f18766f5be335351d12280 100644 (file)
@@ -33,6 +33,6 @@ await describe('StatisticUtils test suite', async () => {
   });
 
   await it('Verify stdDeviation()', () => {
-    expect(stdDeviation([0.25, 4.75, 3.05, 6.04, 1.01, 2.02, 5.03])).toBe(2.0256064851429216);
+    expect(stdDeviation([0.25, 4.75, 3.05, 6.04, 1.01, 2.02, 5.03])).toBe(2.1879050645374383);
   });
 });
index 82964803b87e0f4913a9929dc8125dc7e04d4420..615f76fa01f057c9bad1a1b60a7a0d16b4df54d4 100644 (file)
@@ -91,6 +91,7 @@ await describe('Utils test suite', async () => {
 
   await it('Verify convertToDate()', () => {
     expect(convertToDate(undefined)).toBe(undefined);
+    expect(convertToDate(null)).toBe(null);
     expect(() => convertToDate('')).toThrow(new Error("Cannot convert to date: ''"));
     expect(() => convertToDate('00:70:61')).toThrow(
       new Error("Cannot convert to date: '00:70:61'"),
index 1ed0e28881dcfcbaacd45120cc38d350c8d36ba1..a7d331b22d023e8593cb0294274644c84c0a5c9a 100644 (file)
@@ -1,6 +1,6 @@
 {
   "editor.codeActionsOnSave": {
-    "source.fixAll": true
+    "source.fixAll": "explicit"
   },
   "cSpell.words": [
     "Avenir",
index d0e40af1119b91f2ae723c8bdc416a0b71962fa7..d447d2fb8ff0e4bfdd9c6e96da2e58ea71ceb465 100644 (file)
@@ -9,7 +9,7 @@
   },
   "volta": {
     "node": "20.10.0",
-    "pnpm": "8.11.0"
+    "pnpm": "8.12.1"
   },
   "pnpm": {
     "overrides": {
   "dependencies": {
     "finalhandler": "^1.2.0",
     "serve-static": "^1.15.0",
-    "vue": "^3.3.9",
+    "vue": "^3.3.11",
     "vue-router": "^4.2.5"
   },
   "devDependencies": {
     "@tsconfig/node20": "^20.1.2",
     "@types/jsdom": "^21.1.6",
-    "@types/node": "^20.10.0",
-    "@typescript-eslint/eslint-plugin": "^6.13.0",
-    "@typescript-eslint/parser": "^6.13.0",
-    "@vitejs/plugin-vue": "^4.5.0",
+    "@types/node": "^20.10.4",
+    "@typescript-eslint/eslint-plugin": "^6.14.0",
+    "@typescript-eslint/parser": "^6.14.0",
+    "@vitejs/plugin-vue": "^4.5.2",
     "@vitejs/plugin-vue-jsx": "^3.1.0",
-    "@vitest/coverage-v8": "^0.34.6",
+    "@vitest/coverage-v8": "^1.0.4",
     "@vue/eslint-config-prettier": "^8.0.0",
     "@vue/eslint-config-typescript": "^12.0.0",
-    "@vue/test-utils": "^2.4.2",
+    "@vue/test-utils": "^2.4.3",
     "@vue/tsconfig": "^0.4.0",
     "cross-env": "^7.0.3",
-    "eslint": "^8.54.0",
+    "eslint": "^8.55.0",
     "eslint-define-config": "^2.0.0",
     "eslint-import-resolver-typescript": "^3.6.1",
     "eslint-plugin-import": "^2.29.0",
-    "eslint-plugin-vue": "^9.18.1",
-    "jsdom": "^23.0.0",
-    "prettier": "^3.1.0",
+    "eslint-plugin-vue": "^9.19.2",
+    "jsdom": "^23.0.1",
+    "prettier": "^3.1.1",
     "rimraf": "^5.0.5",
-    "typescript": "~5.3.2",
-    "vite": "^5.0.2",
-    "vitest": "^0.34.6"
+    "typescript": "~5.3.3",
+    "vite": "^5.0.9",
+    "vitest": "^1.0.4"
   },
   "_id": "webui@0.1.1"
 }
index 9cb73326e2776059eaf71130bcb5bae32f87c9ad..b093c690b7bc0f37248602fb9e23a702b467bc68 100644 (file)
@@ -15,11 +15,11 @@ dependencies:
     specifier: ^1.15.0
     version: 1.15.0
   vue:
-    specifier: ^3.3.9
-    version: 3.3.9(typescript@5.3.2)
+    specifier: ^3.3.11
+    version: 3.3.11(typescript@5.3.3)
   vue-router:
     specifier: ^4.2.5
-    version: 4.2.5(vue@3.3.9)
+    version: 4.2.5(vue@3.3.11)
 
 devDependencies:
   '@tsconfig/node20':
@@ -29,32 +29,32 @@ devDependencies:
     specifier: ^21.1.6
     version: 21.1.6
   '@types/node':
-    specifier: ^20.10.0
-    version: 20.10.0
+    specifier: ^20.10.4
+    version: 20.10.4
   '@typescript-eslint/eslint-plugin':
-    specifier: ^6.13.0
-    version: 6.13.0(@typescript-eslint/parser@6.13.0)(eslint@8.54.0)(typescript@5.3.2)
+    specifier: ^6.14.0
+    version: 6.14.0(@typescript-eslint/parser@6.14.0)(eslint@8.55.0)(typescript@5.3.3)
   '@typescript-eslint/parser':
-    specifier: ^6.13.0
-    version: 6.13.0(eslint@8.54.0)(typescript@5.3.2)
+    specifier: ^6.14.0
+    version: 6.14.0(eslint@8.55.0)(typescript@5.3.3)
   '@vitejs/plugin-vue':
-    specifier: ^4.5.0
-    version: 4.5.0(vite@5.0.2)(vue@3.3.9)
+    specifier: ^4.5.2
+    version: 4.5.2(vite@5.0.9)(vue@3.3.11)
   '@vitejs/plugin-vue-jsx':
     specifier: ^3.1.0
-    version: 3.1.0(vite@5.0.2)(vue@3.3.9)
+    version: 3.1.0(vite@5.0.9)(vue@3.3.11)
   '@vitest/coverage-v8':
-    specifier: ^0.34.6
-    version: 0.34.6(vitest@0.34.6)
+    specifier: ^1.0.4
+    version: 1.0.4(vitest@1.0.4)
   '@vue/eslint-config-prettier':
     specifier: ^8.0.0
-    version: 8.0.0(eslint@8.54.0)(prettier@3.1.0)
+    version: 8.0.0(eslint@8.55.0)(prettier@3.1.1)
   '@vue/eslint-config-typescript':
     specifier: ^12.0.0
-    version: 12.0.0(eslint-plugin-vue@9.18.1)(eslint@8.54.0)(typescript@5.3.2)
+    version: 12.0.0(eslint-plugin-vue@9.19.2)(eslint@8.55.0)(typescript@5.3.3)
   '@vue/test-utils':
-    specifier: ^2.4.2
-    version: 2.4.2(vue@3.3.9)
+    specifier: ^2.4.3
+    version: 2.4.3(vue@3.3.11)
   '@vue/tsconfig':
     specifier: ^0.4.0
     version: 0.4.0
@@ -62,38 +62,38 @@ devDependencies:
     specifier: ^7.0.3
     version: 7.0.3
   eslint:
-    specifier: ^8.54.0
-    version: 8.54.0
+    specifier: ^8.55.0
+    version: 8.55.0
   eslint-define-config:
     specifier: ^2.0.0
     version: 2.0.0
   eslint-import-resolver-typescript:
     specifier: ^3.6.1
-    version: 3.6.1(@typescript-eslint/parser@6.13.0)(eslint-plugin-import@2.29.0)(eslint@8.54.0)
+    version: 3.6.1(@typescript-eslint/parser@6.14.0)(eslint-plugin-import@2.29.0)(eslint@8.55.0)
   eslint-plugin-import:
     specifier: ^2.29.0
-    version: 2.29.0(@typescript-eslint/parser@6.13.0)(eslint-import-resolver-typescript@3.6.1)(eslint@8.54.0)
+    version: 2.29.0(@typescript-eslint/parser@6.14.0)(eslint-import-resolver-typescript@3.6.1)(eslint@8.55.0)
   eslint-plugin-vue:
-    specifier: ^9.18.1
-    version: 9.18.1(eslint@8.54.0)
+    specifier: ^9.19.2
+    version: 9.19.2(eslint@8.55.0)
   jsdom:
-    specifier: ^23.0.0
-    version: 23.0.0
+    specifier: ^23.0.1
+    version: 23.0.1
   prettier:
-    specifier: ^3.1.0
-    version: 3.1.0
+    specifier: ^3.1.1
+    version: 3.1.1
   rimraf:
     specifier: ^5.0.5
     version: 5.0.5
   typescript:
-    specifier: ~5.3.2
-    version: 5.3.2
+    specifier: ~5.3.3
+    version: 5.3.3
   vite:
-    specifier: ^5.0.2
-    version: 5.0.2(@types/node@20.10.0)
+    specifier: ^5.0.9
+    version: 5.0.9(@types/node@20.10.4)
   vitest:
-    specifier: ^0.34.6
-    version: 0.34.6(jsdom@23.0.0)
+    specifier: ^1.0.4
+    version: 1.0.4(@types/node@20.10.4)(jsdom@23.0.1)
 
 packages:
 
@@ -110,33 +110,33 @@ packages:
       '@jridgewell/trace-mapping': 0.3.20
     dev: true
 
-  /@babel/code-frame@7.23.4:
-    resolution: {integrity: sha512-r1IONyb6Ia+jYR2vvIDhdWdlTGhqbBoFqLTQidzZ4kepUFH15ejXvFHxCVbtl7BOXIudsIubf4E81xeA3h3IXA==}
+  /@babel/code-frame@7.23.5:
+    resolution: {integrity: sha512-CgH3s1a96LipHCmSUmYFPwY7MNx8C3avkq7i4Wl3cfa662ldtUe4VM1TPXX70pfmrlWTb6jLqTYrZyT2ZTJBgA==}
     engines: {node: '>=6.9.0'}
     dependencies:
       '@babel/highlight': 7.23.4
       chalk: 2.4.2
     dev: true
 
-  /@babel/compat-data@7.23.3:
-    resolution: {integrity: sha512-BmR4bWbDIoFJmJ9z2cZ8Gmm2MXgEDgjdWgpKmKWUt54UGFJdlj31ECtbaDvCG/qVdG3AQ1SfpZEs01lUFbzLOQ==}
+  /@babel/compat-data@7.23.5:
+    resolution: {integrity: sha512-uU27kfDRlhfKl+w1U6vp16IuvSLtjAxdArVXPa9BvLkrr7CYIsxH5adpHObeAGY/41+syctUWOZ140a2Rvkgjw==}
     engines: {node: '>=6.9.0'}
     dev: true
 
-  /@babel/core@7.23.3:
-    resolution: {integrity: sha512-Jg+msLuNuCJDyBvFv5+OKOUjWMZgd85bKjbICd3zWrKAo+bJ49HJufi7CQE0q0uR8NGyO6xkCACScNqyjHSZew==}
+  /@babel/core@7.23.6:
+    resolution: {integrity: sha512-FxpRyGjrMJXh7X3wGLGhNDCRiwpWEF74sKjTLDJSG5Kyvow3QZaG0Adbqzi9ZrVjTWpsX+2cxWXD71NMg93kdw==}
     engines: {node: '>=6.9.0'}
     dependencies:
       '@ampproject/remapping': 2.2.1
-      '@babel/code-frame': 7.23.4
-      '@babel/generator': 7.23.4
-      '@babel/helper-compilation-targets': 7.22.15
-      '@babel/helper-module-transforms': 7.23.3(@babel/core@7.23.3)
-      '@babel/helpers': 7.23.4
-      '@babel/parser': 7.23.4
+      '@babel/code-frame': 7.23.5
+      '@babel/generator': 7.23.6
+      '@babel/helper-compilation-targets': 7.23.6
+      '@babel/helper-module-transforms': 7.23.3(@babel/core@7.23.6)
+      '@babel/helpers': 7.23.6
+      '@babel/parser': 7.23.6
       '@babel/template': 7.22.15
-      '@babel/traverse': 7.23.4
-      '@babel/types': 7.23.4
+      '@babel/traverse': 7.23.6
+      '@babel/types': 7.23.6
       convert-source-map: 2.0.0
       debug: 4.3.4
       gensync: 1.0.0-beta.2
@@ -146,11 +146,11 @@ packages:
       - supports-color
     dev: true
 
-  /@babel/generator@7.23.4:
-    resolution: {integrity: sha512-esuS49Cga3HcThFNebGhlgsrVLkvhqvYDTzgjfFFlHJcIfLe5jFmRRfCQ1KuBfc4Jrtn3ndLgKWAKjBE+IraYQ==}
+  /@babel/generator@7.23.6:
+    resolution: {integrity: sha512-qrSfCYxYQB5owCmGLbl8XRpX1ytXlpueOb0N0UmQwA073KZxejgQTzAmJezxvpwQD9uGtK2shHdi55QT+MbjIw==}
     engines: {node: '>=6.9.0'}
     dependencies:
-      '@babel/types': 7.23.4
+      '@babel/types': 7.23.6
       '@jridgewell/gen-mapping': 0.3.3
       '@jridgewell/trace-mapping': 0.3.20
       jsesc: 2.5.2
@@ -160,33 +160,33 @@ packages:
     resolution: {integrity: sha512-LvBTxu8bQSQkcyKOU+a1btnNFQ1dMAd0R6PyW3arXes06F6QLWLIrd681bxRPIXlrMGR3XYnW9JyML7dP3qgxg==}
     engines: {node: '>=6.9.0'}
     dependencies:
-      '@babel/types': 7.23.4
+      '@babel/types': 7.23.6
     dev: true
 
-  /@babel/helper-compilation-targets@7.22.15:
-    resolution: {integrity: sha512-y6EEzULok0Qvz8yyLkCvVX+02ic+By2UdOhylwUOvOn9dvYc9mKICJuuU1n1XBI02YWsNsnrY1kc6DVbjcXbtw==}
+  /@babel/helper-compilation-targets@7.23.6:
+    resolution: {integrity: sha512-9JB548GZoQVmzrFgp8o7KxdgkTGm6xs9DW0o/Pim72UDjzr5ObUQ6ZzYPqA+g9OTS2bBQoctLJrky0RDCAWRgQ==}
     engines: {node: '>=6.9.0'}
     dependencies:
-      '@babel/compat-data': 7.23.3
-      '@babel/helper-validator-option': 7.22.15
-      browserslist: 4.22.1
+      '@babel/compat-data': 7.23.5
+      '@babel/helper-validator-option': 7.23.5
+      browserslist: 4.22.2
       lru-cache: 5.1.1
       semver: 7.5.4
     dev: true
 
-  /@babel/helper-create-class-features-plugin@7.22.15(@babel/core@7.23.3):
-    resolution: {integrity: sha512-jKkwA59IXcvSaiK2UN45kKwSC9o+KuoXsBDvHvU/7BecYIp8GQ2UwrVvFgJASUT+hBnwJx6MhvMCuMzwZZ7jlg==}
+  /@babel/helper-create-class-features-plugin@7.23.6(@babel/core@7.23.6):
+    resolution: {integrity: sha512-cBXU1vZni/CpGF29iTu4YRbOZt3Wat6zCoMDxRF1MayiEc4URxOj31tT65HUM0CRpMowA3HCJaAOVOUnMf96cw==}
     engines: {node: '>=6.9.0'}
     peerDependencies:
       '@babel/core': ^7.0.0
     dependencies:
-      '@babel/core': 7.23.3
+      '@babel/core': 7.23.6
       '@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.23.0
       '@babel/helper-optimise-call-expression': 7.22.5
-      '@babel/helper-replace-supers': 7.22.20(@babel/core@7.23.3)
+      '@babel/helper-replace-supers': 7.22.20(@babel/core@7.23.6)
       '@babel/helper-skip-transparent-expression-wrappers': 7.22.5
       '@babel/helper-split-export-declaration': 7.22.6
       semver: 7.5.4
@@ -202,37 +202,37 @@ packages:
     engines: {node: '>=6.9.0'}
     dependencies:
       '@babel/template': 7.22.15
-      '@babel/types': 7.23.4
+      '@babel/types': 7.23.6
     dev: true
 
   /@babel/helper-hoist-variables@7.22.5:
     resolution: {integrity: sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==}
     engines: {node: '>=6.9.0'}
     dependencies:
-      '@babel/types': 7.23.4
+      '@babel/types': 7.23.6
     dev: true
 
   /@babel/helper-member-expression-to-functions@7.23.0:
     resolution: {integrity: sha512-6gfrPwh7OuT6gZyJZvd6WbTfrqAo7vm4xCzAXOusKqq/vWdKXphTpj5klHKNmRUU6/QRGlBsyU9mAIPaWHlqJA==}
     engines: {node: '>=6.9.0'}
     dependencies:
-      '@babel/types': 7.23.4
+      '@babel/types': 7.23.6
     dev: true
 
   /@babel/helper-module-imports@7.22.15:
     resolution: {integrity: sha512-0pYVBnDKZO2fnSPCrgM/6WMc7eS20Fbok+0r88fp+YtWVLZrp4CkafFGIp+W0VKw4a22sgebPT99y+FDNMdP4w==}
     engines: {node: '>=6.9.0'}
     dependencies:
-      '@babel/types': 7.23.4
+      '@babel/types': 7.23.6
     dev: true
 
-  /@babel/helper-module-transforms@7.23.3(@babel/core@7.23.3):
+  /@babel/helper-module-transforms@7.23.3(@babel/core@7.23.6):
     resolution: {integrity: sha512-7bBs4ED9OmswdfDzpz4MpWgSrV7FXlc3zIagvLFjS5H+Mk7Snr21vQ6QwrsoCGMfNC4e4LQPdoULEt4ykz0SRQ==}
     engines: {node: '>=6.9.0'}
     peerDependencies:
       '@babel/core': ^7.0.0
     dependencies:
-      '@babel/core': 7.23.3
+      '@babel/core': 7.23.6
       '@babel/helper-environment-visitor': 7.22.20
       '@babel/helper-module-imports': 7.22.15
       '@babel/helper-simple-access': 7.22.5
@@ -244,7 +244,7 @@ packages:
     resolution: {integrity: sha512-HBwaojN0xFRx4yIvpwGqxiV2tUfl7401jlok564NgB9EHS1y6QT17FmKWm4ztqjeVdXLuC4fSvHc5ePpQjoTbw==}
     engines: {node: '>=6.9.0'}
     dependencies:
-      '@babel/types': 7.23.4
+      '@babel/types': 7.23.6
     dev: true
 
   /@babel/helper-plugin-utils@7.22.5:
@@ -252,13 +252,13 @@ packages:
     engines: {node: '>=6.9.0'}
     dev: true
 
-  /@babel/helper-replace-supers@7.22.20(@babel/core@7.23.3):
+  /@babel/helper-replace-supers@7.22.20(@babel/core@7.23.6):
     resolution: {integrity: sha512-qsW0In3dbwQUbK8kejJ4R7IHVGwHJlV6lpG6UA7a9hSa2YEiAib+N1T2kr6PEeUT+Fl7najmSOS6SmAwCHK6Tw==}
     engines: {node: '>=6.9.0'}
     peerDependencies:
       '@babel/core': ^7.0.0
     dependencies:
-      '@babel/core': 7.23.3
+      '@babel/core': 7.23.6
       '@babel/helper-environment-visitor': 7.22.20
       '@babel/helper-member-expression-to-functions': 7.23.0
       '@babel/helper-optimise-call-expression': 7.22.5
@@ -268,21 +268,21 @@ packages:
     resolution: {integrity: sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==}
     engines: {node: '>=6.9.0'}
     dependencies:
-      '@babel/types': 7.23.4
+      '@babel/types': 7.23.6
     dev: true
 
   /@babel/helper-skip-transparent-expression-wrappers@7.22.5:
     resolution: {integrity: sha512-tK14r66JZKiC43p8Ki33yLBVJKlQDFoA8GYN67lWCDCqoL6EMMSuM9b+Iff2jHaM/RRFYl7K+iiru7hbRqNx8Q==}
     engines: {node: '>=6.9.0'}
     dependencies:
-      '@babel/types': 7.23.4
+      '@babel/types': 7.23.6
     dev: true
 
   /@babel/helper-split-export-declaration@7.22.6:
     resolution: {integrity: sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==}
     engines: {node: '>=6.9.0'}
     dependencies:
-      '@babel/types': 7.23.4
+      '@babel/types': 7.23.6
     dev: true
 
   /@babel/helper-string-parser@7.23.4:
@@ -293,18 +293,18 @@ packages:
     resolution: {integrity: sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==}
     engines: {node: '>=6.9.0'}
 
-  /@babel/helper-validator-option@7.22.15:
-    resolution: {integrity: sha512-bMn7RmyFjY/mdECUbgn9eoSY4vqvacUnS9i9vGAGttgFWesO6B4CYWA7XlpbWgBt71iv/hfbPlynohStqnu5hA==}
+  /@babel/helper-validator-option@7.23.5:
+    resolution: {integrity: sha512-85ttAOMLsr53VgXkTbkx8oA6YTfT4q7/HzXSLEYmjcSTJPMPQtvq1BD79Byep5xMUYbGRzEpDsjUf3dyp54IKw==}
     engines: {node: '>=6.9.0'}
     dev: true
 
-  /@babel/helpers@7.23.4:
-    resolution: {integrity: sha512-HfcMizYz10cr3h29VqyfGL6ZWIjTwWfvYBMsBVGwpcbhNGe3wQ1ZXZRPzZoAHhd9OqHadHqjQ89iVKINXnbzuw==}
+  /@babel/helpers@7.23.6:
+    resolution: {integrity: sha512-wCfsbN4nBidDRhpDhvcKlzHWCTlgJYUUdSJfzXb2NuBssDSIjc3xcb+znA7l+zYsFljAcGM0aFkN40cR3lXiGA==}
     engines: {node: '>=6.9.0'}
     dependencies:
       '@babel/template': 7.22.15
-      '@babel/traverse': 7.23.4
-      '@babel/types': 7.23.4
+      '@babel/traverse': 7.23.6
+      '@babel/types': 7.23.6
     transitivePeerDependencies:
       - supports-color
     dev: true
@@ -318,75 +318,75 @@ packages:
       js-tokens: 4.0.0
     dev: true
 
-  /@babel/parser@7.23.4:
-    resolution: {integrity: sha512-vf3Xna6UEprW+7t6EtOmFpHNAuxw3xqPZghy+brsnusscJRW5BMUzzHZc5ICjULee81WeUV2jjakG09MDglJXQ==}
+  /@babel/parser@7.23.6:
+    resolution: {integrity: sha512-Z2uID7YJ7oNvAI20O9X0bblw7Qqs8Q2hFy0R9tAfnfLkp5MW0UH9eUvnDSnFwKZ0AvgS1ucqR4KzvVHgnke1VQ==}
     engines: {node: '>=6.0.0'}
     hasBin: true
     dependencies:
-      '@babel/types': 7.23.4
+      '@babel/types': 7.23.6
 
-  /@babel/plugin-syntax-jsx@7.23.3(@babel/core@7.23.3):
+  /@babel/plugin-syntax-jsx@7.23.3(@babel/core@7.23.6):
     resolution: {integrity: sha512-EB2MELswq55OHUoRZLGg/zC7QWUKfNLpE57m/S2yr1uEneIgsTgrSzXP3NXEsMkVn76OlaVVnzN+ugObuYGwhg==}
     engines: {node: '>=6.9.0'}
     peerDependencies:
       '@babel/core': ^7.0.0-0
     dependencies:
-      '@babel/core': 7.23.3
+      '@babel/core': 7.23.6
       '@babel/helper-plugin-utils': 7.22.5
     dev: true
 
-  /@babel/plugin-syntax-typescript@7.23.3(@babel/core@7.23.3):
+  /@babel/plugin-syntax-typescript@7.23.3(@babel/core@7.23.6):
     resolution: {integrity: sha512-9EiNjVJOMwCO+43TqoTrgQ8jMwcAd0sWyXi9RPfIsLTj4R2MADDDQXELhffaUx/uJv2AYcxBgPwH6j4TIA4ytQ==}
     engines: {node: '>=6.9.0'}
     peerDependencies:
       '@babel/core': ^7.0.0-0
     dependencies:
-      '@babel/core': 7.23.3
+      '@babel/core': 7.23.6
       '@babel/helper-plugin-utils': 7.22.5
     dev: true
 
-  /@babel/plugin-transform-typescript@7.23.4(@babel/core@7.23.3):
-    resolution: {integrity: sha512-39hCCOl+YUAyMOu6B9SmUTiHUU0t/CxJNUmY3qRdJujbqi+lrQcL11ysYUsAvFWPBdhihrv1z0oRG84Yr3dODQ==}
+  /@babel/plugin-transform-typescript@7.23.6(@babel/core@7.23.6):
+    resolution: {integrity: sha512-6cBG5mBvUu4VUD04OHKnYzbuHNP8huDsD3EDqqpIpsswTDoqHCjLoHb6+QgsV1WsT2nipRqCPgxD3LXnEO7XfA==}
     engines: {node: '>=6.9.0'}
     peerDependencies:
       '@babel/core': ^7.0.0-0
     dependencies:
-      '@babel/core': 7.23.3
+      '@babel/core': 7.23.6
       '@babel/helper-annotate-as-pure': 7.22.5
-      '@babel/helper-create-class-features-plugin': 7.22.15(@babel/core@7.23.3)
+      '@babel/helper-create-class-features-plugin': 7.23.6(@babel/core@7.23.6)
       '@babel/helper-plugin-utils': 7.22.5
-      '@babel/plugin-syntax-typescript': 7.23.3(@babel/core@7.23.3)
+      '@babel/plugin-syntax-typescript': 7.23.3(@babel/core@7.23.6)
     dev: true
 
   /@babel/template@7.22.15:
     resolution: {integrity: sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==}
     engines: {node: '>=6.9.0'}
     dependencies:
-      '@babel/code-frame': 7.23.4
-      '@babel/parser': 7.23.4
-      '@babel/types': 7.23.4
+      '@babel/code-frame': 7.23.5
+      '@babel/parser': 7.23.6
+      '@babel/types': 7.23.6
     dev: true
 
-  /@babel/traverse@7.23.4:
-    resolution: {integrity: sha512-IYM8wSUwunWTB6tFC2dkKZhxbIjHoWemdK+3f8/wq8aKhbUscxD5MX72ubd90fxvFknaLPeGw5ycU84V1obHJg==}
+  /@babel/traverse@7.23.6:
+    resolution: {integrity: sha512-czastdK1e8YByZqezMPFiZ8ahwVMh/ESl9vPgvgdB9AmFMGP5jfpFax74AQgl5zj4XHzqeYAg2l8PuUeRS1MgQ==}
     engines: {node: '>=6.9.0'}
     dependencies:
-      '@babel/code-frame': 7.23.4
-      '@babel/generator': 7.23.4
+      '@babel/code-frame': 7.23.5
+      '@babel/generator': 7.23.6
       '@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.22.6
-      '@babel/parser': 7.23.4
-      '@babel/types': 7.23.4
+      '@babel/parser': 7.23.6
+      '@babel/types': 7.23.6
       debug: 4.3.4
       globals: 11.12.0
     transitivePeerDependencies:
       - supports-color
     dev: true
 
-  /@babel/types@7.23.4:
-    resolution: {integrity: sha512-7uIFwVYpoplT5jp/kVv6EF93VaJ8H+Yn5IczYiaAi98ajzjfoZfslet/e0sLh+wVBjb2qqIut1b0S26VSafsSQ==}
+  /@babel/types@7.23.6:
+    resolution: {integrity: sha512-+uarb83brBzPKN38NX1MkB6vb6+mwvR6amUulqAE7ccQw1pEl+bCia9TbdG1lsnFP7lZySvUn37CHyXQdfTwzg==}
     engines: {node: '>=6.9.0'}
     dependencies:
       '@babel/helper-string-parser': 7.23.4
@@ -397,8 +397,8 @@ packages:
     resolution: {integrity: sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==}
     dev: true
 
-  /@esbuild/android-arm64@0.19.8:
-    resolution: {integrity: sha512-B8JbS61bEunhfx8kasogFENgQfr/dIp+ggYXwTqdbMAgGDhRa3AaPpQMuQU0rNxDLECj6FhDzk1cF9WHMVwrtA==}
+  /@esbuild/android-arm64@0.19.9:
+    resolution: {integrity: sha512-q4cR+6ZD0938R19MyEW3jEsMzbb/1rulLXiNAJQADD/XYp7pT+rOS5JGxvpRW8dFDEfjW4wLgC/3FXIw4zYglQ==}
     engines: {node: '>=12'}
     cpu: [arm64]
     os: [android]
@@ -406,8 +406,8 @@ packages:
     dev: true
     optional: true
 
-  /@esbuild/android-arm@0.19.8:
-    resolution: {integrity: sha512-31E2lxlGM1KEfivQl8Yf5aYU/mflz9g06H6S15ITUFQueMFtFjESRMoDSkvMo8thYvLBax+VKTPlpnx+sPicOA==}
+  /@esbuild/android-arm@0.19.9:
+    resolution: {integrity: sha512-jkYjjq7SdsWuNI6b5quymW0oC83NN5FdRPuCbs9HZ02mfVdAP8B8eeqLSYU3gb6OJEaY5CQabtTFbqBf26H3GA==}
     engines: {node: '>=12'}
     cpu: [arm]
     os: [android]
@@ -415,8 +415,8 @@ packages:
     dev: true
     optional: true
 
-  /@esbuild/android-x64@0.19.8:
-    resolution: {integrity: sha512-rdqqYfRIn4jWOp+lzQttYMa2Xar3OK9Yt2fhOhzFXqg0rVWEfSclJvZq5fZslnz6ypHvVf3CT7qyf0A5pM682A==}
+  /@esbuild/android-x64@0.19.9:
+    resolution: {integrity: sha512-KOqoPntWAH6ZxDwx1D6mRntIgZh9KodzgNOy5Ebt9ghzffOk9X2c1sPwtM9P+0eXbefnDhqYfkh5PLP5ULtWFA==}
     engines: {node: '>=12'}
     cpu: [x64]
     os: [android]
@@ -424,8 +424,8 @@ packages:
     dev: true
     optional: true
 
-  /@esbuild/darwin-arm64@0.19.8:
-    resolution: {integrity: sha512-RQw9DemMbIq35Bprbboyf8SmOr4UXsRVxJ97LgB55VKKeJOOdvsIPy0nFyF2l8U+h4PtBx/1kRf0BelOYCiQcw==}
+  /@esbuild/darwin-arm64@0.19.9:
+    resolution: {integrity: sha512-KBJ9S0AFyLVx2E5D8W0vExqRW01WqRtczUZ8NRu+Pi+87opZn5tL4Y0xT0mA4FtHctd0ZgwNoN639fUUGlNIWw==}
     engines: {node: '>=12'}
     cpu: [arm64]
     os: [darwin]
@@ -433,8 +433,8 @@ packages:
     dev: true
     optional: true
 
-  /@esbuild/darwin-x64@0.19.8:
-    resolution: {integrity: sha512-3sur80OT9YdeZwIVgERAysAbwncom7b4bCI2XKLjMfPymTud7e/oY4y+ci1XVp5TfQp/bppn7xLw1n/oSQY3/Q==}
+  /@esbuild/darwin-x64@0.19.9:
+    resolution: {integrity: sha512-vE0VotmNTQaTdX0Q9dOHmMTao6ObjyPm58CHZr1UK7qpNleQyxlFlNCaHsHx6Uqv86VgPmR4o2wdNq3dP1qyDQ==}
     engines: {node: '>=12'}
     cpu: [x64]
     os: [darwin]
@@ -442,8 +442,8 @@ packages:
     dev: true
     optional: true
 
-  /@esbuild/freebsd-arm64@0.19.8:
-    resolution: {integrity: sha512-WAnPJSDattvS/XtPCTj1tPoTxERjcTpH6HsMr6ujTT+X6rylVe8ggxk8pVxzf5U1wh5sPODpawNicF5ta/9Tmw==}
+  /@esbuild/freebsd-arm64@0.19.9:
+    resolution: {integrity: sha512-uFQyd/o1IjiEk3rUHSwUKkqZwqdvuD8GevWF065eqgYfexcVkxh+IJgwTaGZVu59XczZGcN/YMh9uF1fWD8j1g==}
     engines: {node: '>=12'}
     cpu: [arm64]
     os: [freebsd]
@@ -451,8 +451,8 @@ packages:
     dev: true
     optional: true
 
-  /@esbuild/freebsd-x64@0.19.8:
-    resolution: {integrity: sha512-ICvZyOplIjmmhjd6mxi+zxSdpPTKFfyPPQMQTK/w+8eNK6WV01AjIztJALDtwNNfFhfZLux0tZLC+U9nSyA5Zg==}
+  /@esbuild/freebsd-x64@0.19.9:
+    resolution: {integrity: sha512-WMLgWAtkdTbTu1AWacY7uoj/YtHthgqrqhf1OaEWnZb7PQgpt8eaA/F3LkV0E6K/Lc0cUr/uaVP/49iE4M4asA==}
     engines: {node: '>=12'}
     cpu: [x64]
     os: [freebsd]
@@ -460,8 +460,8 @@ packages:
     dev: true
     optional: true
 
-  /@esbuild/linux-arm64@0.19.8:
-    resolution: {integrity: sha512-z1zMZivxDLHWnyGOctT9JP70h0beY54xDDDJt4VpTX+iwA77IFsE1vCXWmprajJGa+ZYSqkSbRQ4eyLCpCmiCQ==}
+  /@esbuild/linux-arm64@0.19.9:
+    resolution: {integrity: sha512-PiPblfe1BjK7WDAKR1Cr9O7VVPqVNpwFcPWgfn4xu0eMemzRp442hXyzF/fSwgrufI66FpHOEJk0yYdPInsmyQ==}
     engines: {node: '>=12'}
     cpu: [arm64]
     os: [linux]
@@ -469,8 +469,8 @@ packages:
     dev: true
     optional: true
 
-  /@esbuild/linux-arm@0.19.8:
-    resolution: {integrity: sha512-H4vmI5PYqSvosPaTJuEppU9oz1dq2A7Mr2vyg5TF9Ga+3+MGgBdGzcyBP7qK9MrwFQZlvNyJrvz6GuCaj3OukQ==}
+  /@esbuild/linux-arm@0.19.9:
+    resolution: {integrity: sha512-C/ChPohUYoyUaqn1h17m/6yt6OB14hbXvT8EgM1ZWaiiTYz7nWZR0SYmMnB5BzQA4GXl3BgBO1l8MYqL/He3qw==}
     engines: {node: '>=12'}
     cpu: [arm]
     os: [linux]
@@ -478,8 +478,8 @@ packages:
     dev: true
     optional: true
 
-  /@esbuild/linux-ia32@0.19.8:
-    resolution: {integrity: sha512-1a8suQiFJmZz1khm/rDglOc8lavtzEMRo0v6WhPgxkrjcU0LkHj+TwBrALwoz/OtMExvsqbbMI0ChyelKabSvQ==}
+  /@esbuild/linux-ia32@0.19.9:
+    resolution: {integrity: sha512-f37i/0zE0MjDxijkPSQw1CO/7C27Eojqb+r3BbHVxMLkj8GCa78TrBZzvPyA/FNLUMzP3eyHCVkAopkKVja+6Q==}
     engines: {node: '>=12'}
     cpu: [ia32]
     os: [linux]
@@ -487,8 +487,8 @@ packages:
     dev: true
     optional: true
 
-  /@esbuild/linux-loong64@0.19.8:
-    resolution: {integrity: sha512-fHZWS2JJxnXt1uYJsDv9+b60WCc2RlvVAy1F76qOLtXRO+H4mjt3Tr6MJ5l7Q78X8KgCFudnTuiQRBhULUyBKQ==}
+  /@esbuild/linux-loong64@0.19.9:
+    resolution: {integrity: sha512-t6mN147pUIf3t6wUt3FeumoOTPfmv9Cc6DQlsVBpB7eCpLOqQDyWBP1ymXn1lDw4fNUSb/gBcKAmvTP49oIkaA==}
     engines: {node: '>=12'}
     cpu: [loong64]
     os: [linux]
@@ -496,8 +496,8 @@ packages:
     dev: true
     optional: true
 
-  /@esbuild/linux-mips64el@0.19.8:
-    resolution: {integrity: sha512-Wy/z0EL5qZYLX66dVnEg9riiwls5IYnziwuju2oUiuxVc+/edvqXa04qNtbrs0Ukatg5HEzqT94Zs7J207dN5Q==}
+  /@esbuild/linux-mips64el@0.19.9:
+    resolution: {integrity: sha512-jg9fujJTNTQBuDXdmAg1eeJUL4Jds7BklOTkkH80ZgQIoCTdQrDaHYgbFZyeTq8zbY+axgptncko3v9p5hLZtw==}
     engines: {node: '>=12'}
     cpu: [mips64el]
     os: [linux]
@@ -505,8 +505,8 @@ packages:
     dev: true
     optional: true
 
-  /@esbuild/linux-ppc64@0.19.8:
-    resolution: {integrity: sha512-ETaW6245wK23YIEufhMQ3HSeHO7NgsLx8gygBVldRHKhOlD1oNeNy/P67mIh1zPn2Hr2HLieQrt6tWrVwuqrxg==}
+  /@esbuild/linux-ppc64@0.19.9:
+    resolution: {integrity: sha512-tkV0xUX0pUUgY4ha7z5BbDS85uI7ABw3V1d0RNTii7E9lbmV8Z37Pup2tsLV46SQWzjOeyDi1Q7Wx2+QM8WaCQ==}
     engines: {node: '>=12'}
     cpu: [ppc64]
     os: [linux]
@@ -514,8 +514,8 @@ packages:
     dev: true
     optional: true
 
-  /@esbuild/linux-riscv64@0.19.8:
-    resolution: {integrity: sha512-T2DRQk55SgoleTP+DtPlMrxi/5r9AeFgkhkZ/B0ap99zmxtxdOixOMI570VjdRCs9pE4Wdkz7JYrsPvsl7eESg==}
+  /@esbuild/linux-riscv64@0.19.9:
+    resolution: {integrity: sha512-DfLp8dj91cufgPZDXr9p3FoR++m3ZJ6uIXsXrIvJdOjXVREtXuQCjfMfvmc3LScAVmLjcfloyVtpn43D56JFHg==}
     engines: {node: '>=12'}
     cpu: [riscv64]
     os: [linux]
@@ -523,8 +523,8 @@ packages:
     dev: true
     optional: true
 
-  /@esbuild/linux-s390x@0.19.8:
-    resolution: {integrity: sha512-NPxbdmmo3Bk7mbNeHmcCd7R7fptJaczPYBaELk6NcXxy7HLNyWwCyDJ/Xx+/YcNH7Im5dHdx9gZ5xIwyliQCbg==}
+  /@esbuild/linux-s390x@0.19.9:
+    resolution: {integrity: sha512-zHbglfEdC88KMgCWpOl/zc6dDYJvWGLiUtmPRsr1OgCViu3z5GncvNVdf+6/56O2Ca8jUU+t1BW261V6kp8qdw==}
     engines: {node: '>=12'}
     cpu: [s390x]
     os: [linux]
@@ -532,8 +532,8 @@ packages:
     dev: true
     optional: true
 
-  /@esbuild/linux-x64@0.19.8:
-    resolution: {integrity: sha512-lytMAVOM3b1gPypL2TRmZ5rnXl7+6IIk8uB3eLsV1JwcizuolblXRrc5ShPrO9ls/b+RTp+E6gbsuLWHWi2zGg==}
+  /@esbuild/linux-x64@0.19.9:
+    resolution: {integrity: sha512-JUjpystGFFmNrEHQnIVG8hKwvA2DN5o7RqiO1CVX8EN/F/gkCjkUMgVn6hzScpwnJtl2mPR6I9XV1oW8k9O+0A==}
     engines: {node: '>=12'}
     cpu: [x64]
     os: [linux]
@@ -541,8 +541,8 @@ packages:
     dev: true
     optional: true
 
-  /@esbuild/netbsd-x64@0.19.8:
-    resolution: {integrity: sha512-hvWVo2VsXz/8NVt1UhLzxwAfo5sioj92uo0bCfLibB0xlOmimU/DeAEsQILlBQvkhrGjamP0/el5HU76HAitGw==}
+  /@esbuild/netbsd-x64@0.19.9:
+    resolution: {integrity: sha512-GThgZPAwOBOsheA2RUlW5UeroRfESwMq/guy8uEe3wJlAOjpOXuSevLRd70NZ37ZrpO6RHGHgEHvPg1h3S1Jug==}
     engines: {node: '>=12'}
     cpu: [x64]
     os: [netbsd]
@@ -550,8 +550,8 @@ packages:
     dev: true
     optional: true
 
-  /@esbuild/openbsd-x64@0.19.8:
-    resolution: {integrity: sha512-/7Y7u77rdvmGTxR83PgaSvSBJCC2L3Kb1M/+dmSIvRvQPXXCuC97QAwMugBNG0yGcbEGfFBH7ojPzAOxfGNkwQ==}
+  /@esbuild/openbsd-x64@0.19.9:
+    resolution: {integrity: sha512-Ki6PlzppaFVbLnD8PtlVQfsYw4S9n3eQl87cqgeIw+O3sRr9IghpfSKY62mggdt1yCSZ8QWvTZ9jo9fjDSg9uw==}
     engines: {node: '>=12'}
     cpu: [x64]
     os: [openbsd]
@@ -559,8 +559,8 @@ packages:
     dev: true
     optional: true
 
-  /@esbuild/sunos-x64@0.19.8:
-    resolution: {integrity: sha512-9Lc4s7Oi98GqFA4HzA/W2JHIYfnXbUYgekUP/Sm4BG9sfLjyv6GKKHKKVs83SMicBF2JwAX6A1PuOLMqpD001w==}
+  /@esbuild/sunos-x64@0.19.9:
+    resolution: {integrity: sha512-MLHj7k9hWh4y1ddkBpvRj2b9NCBhfgBt3VpWbHQnXRedVun/hC7sIyTGDGTfsGuXo4ebik2+3ShjcPbhtFwWDw==}
     engines: {node: '>=12'}
     cpu: [x64]
     os: [sunos]
@@ -568,8 +568,8 @@ packages:
     dev: true
     optional: true
 
-  /@esbuild/win32-arm64@0.19.8:
-    resolution: {integrity: sha512-rq6WzBGjSzihI9deW3fC2Gqiak68+b7qo5/3kmB6Gvbh/NYPA0sJhrnp7wgV4bNwjqM+R2AApXGxMO7ZoGhIJg==}
+  /@esbuild/win32-arm64@0.19.9:
+    resolution: {integrity: sha512-GQoa6OrQ8G08guMFgeXPH7yE/8Dt0IfOGWJSfSH4uafwdC7rWwrfE6P9N8AtPGIjUzdo2+7bN8Xo3qC578olhg==}
     engines: {node: '>=12'}
     cpu: [arm64]
     os: [win32]
@@ -577,8 +577,8 @@ packages:
     dev: true
     optional: true
 
-  /@esbuild/win32-ia32@0.19.8:
-    resolution: {integrity: sha512-AIAbverbg5jMvJznYiGhrd3sumfwWs8572mIJL5NQjJa06P8KfCPWZQ0NwZbPQnbQi9OWSZhFVSUWjjIrn4hSw==}
+  /@esbuild/win32-ia32@0.19.9:
+    resolution: {integrity: sha512-UOozV7Ntykvr5tSOlGCrqU3NBr3d8JqPes0QWN2WOXfvkWVGRajC+Ym0/Wj88fUgecUCLDdJPDF0Nna2UK3Qtg==}
     engines: {node: '>=12'}
     cpu: [ia32]
     os: [win32]
@@ -586,8 +586,8 @@ packages:
     dev: true
     optional: true
 
-  /@esbuild/win32-x64@0.19.8:
-    resolution: {integrity: sha512-bfZ0cQ1uZs2PqpulNL5j/3w+GDhP36k1K5c38QdQg+Swy51jFZWWeIkteNsufkQxp986wnqRRsb/bHbY1WQ7TA==}
+  /@esbuild/win32-x64@0.19.9:
+    resolution: {integrity: sha512-oxoQgglOP7RH6iasDrhY+R/3cHrfwIDvRlT4CGChflq6twk8iENeVvMJjmvBb94Ik1Z+93iGO27err7w6l54GQ==}
     engines: {node: '>=12'}
     cpu: [x64]
     os: [win32]
@@ -595,13 +595,13 @@ packages:
     dev: true
     optional: true
 
-  /@eslint-community/eslint-utils@4.4.0(eslint@8.54.0):
+  /@eslint-community/eslint-utils@4.4.0(eslint@8.55.0):
     resolution: {integrity: sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==}
     engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
     peerDependencies:
       eslint: ^6.0.0 || ^7.0.0 || >=8.0.0
     dependencies:
-      eslint: 8.54.0
+      eslint: 8.55.0
       eslint-visitor-keys: 3.4.3
     dev: true
 
@@ -610,14 +610,14 @@ packages:
     engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0}
     dev: true
 
-  /@eslint/eslintrc@2.1.3:
-    resolution: {integrity: sha512-yZzuIG+jnVu6hNSzFEN07e8BxF3uAzYtQb6uDkaYZLo6oYZDCq454c5kB8zxnzfCYyP4MIuyBn10L0DqwujTmA==}
+  /@eslint/eslintrc@2.1.4:
+    resolution: {integrity: sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==}
     engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
     dependencies:
       ajv: 6.12.6
       debug: 4.3.4
       espree: 9.6.1
-      globals: 13.23.0
+      globals: 13.24.0
       ignore: 5.3.0
       import-fresh: 3.3.0
       js-yaml: 4.1.0
@@ -627,8 +627,8 @@ packages:
       - supports-color
     dev: true
 
-  /@eslint/js@8.54.0:
-    resolution: {integrity: sha512-ut5V+D+fOoWPgGGNj83GGjnntO39xDy6DWxO0wb7Jp3DcMX0TfIqdzHF85VTQkerdyGmuuMD9AKAo5KiNlf/AQ==}
+  /@eslint/js@8.55.0:
+    resolution: {integrity: sha512-qQfo2mxH5yVom1kacMtZZJFVdW+E70mqHMJvVg6WTLo+VBuQJ4TojZlfWBjK0ve5BdEeNAVxOsl/nvNMpJOaJA==}
     engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
     dev: true
 
@@ -749,96 +749,104 @@ packages:
       tslib: 2.6.2
     dev: true
 
-  /@rollup/rollup-android-arm-eabi@4.6.0:
-    resolution: {integrity: sha512-keHkkWAe7OtdALGoutLY3utvthkGF+Y17ws9LYT8pxMBYXaCoH/8dXS2uzo6e8+sEhY7y/zi5RFo22Dy2lFpDw==}
+  /@rollup/rollup-android-arm-eabi@4.9.0:
+    resolution: {integrity: sha512-+1ge/xmaJpm1KVBuIH38Z94zj9fBD+hp+/5WLaHgyY8XLq1ibxk/zj6dTXaqM2cAbYKq8jYlhHd6k05If1W5xA==}
     cpu: [arm]
     os: [android]
     requiresBuild: true
     dev: true
     optional: true
 
-  /@rollup/rollup-android-arm64@4.6.0:
-    resolution: {integrity: sha512-y3Kt+34smKQNWilicPbBz/MXEY7QwDzMFNgwEWeYiOhUt9MTWKjHqe3EVkXwT2fR7izOvHpDWZ0o2IyD9SWX7A==}
+  /@rollup/rollup-android-arm64@4.9.0:
+    resolution: {integrity: sha512-im6hUEyQ7ZfoZdNvtwgEJvBWZYauC9KVKq1w58LG2Zfz6zMd8gRrbN+xCVoqA2hv/v6fm9lp5LFGJ3za8EQH3A==}
     cpu: [arm64]
     os: [android]
     requiresBuild: true
     dev: true
     optional: true
 
-  /@rollup/rollup-darwin-arm64@4.6.0:
-    resolution: {integrity: sha512-oLzzxcUIHltHxOCmaXl+pkIlU+uhSxef5HfntW7RsLh1eHm+vJzjD9Oo4oUKso4YuP4PpbFJNlZjJuOrxo8dPg==}
+  /@rollup/rollup-darwin-arm64@4.9.0:
+    resolution: {integrity: sha512-u7aTMskN6Dmg1lCT0QJ+tINRt+ntUrvVkhbPfFz4bCwRZvjItx2nJtwJnJRlKMMaQCHRjrNqHRDYvE4mBm3DlQ==}
     cpu: [arm64]
     os: [darwin]
     requiresBuild: true
     dev: true
     optional: true
 
-  /@rollup/rollup-darwin-x64@4.6.0:
-    resolution: {integrity: sha512-+ANnmjkcOBaV25n0+M0Bere3roeVAnwlKW65qagtuAfIxXF9YxUneRyAn/RDcIdRa7QrjRNJL3jR7T43ObGe8Q==}
+  /@rollup/rollup-darwin-x64@4.9.0:
+    resolution: {integrity: sha512-8FvEl3w2ExmpcOmX5RJD0yqXcVSOqAJJUJ29Lca29Ik+3zPS1yFimr2fr5JSZ4Z5gt8/d7WqycpgkX9nocijSw==}
     cpu: [x64]
     os: [darwin]
     requiresBuild: true
     dev: true
     optional: true
 
-  /@rollup/rollup-linux-arm-gnueabihf@4.6.0:
-    resolution: {integrity: sha512-tBTSIkjSVUyrekddpkAqKOosnj1Fc0ZY0rJL2bIEWPKqlEQk0paORL9pUIlt7lcGJi3LzMIlUGXvtNi1Z6MOCQ==}
+  /@rollup/rollup-linux-arm-gnueabihf@4.9.0:
+    resolution: {integrity: sha512-lHoKYaRwd4gge+IpqJHCY+8Vc3hhdJfU6ukFnnrJasEBUvVlydP8PuwndbWfGkdgSvZhHfSEw6urrlBj0TSSfg==}
     cpu: [arm]
     os: [linux]
     requiresBuild: true
     dev: true
     optional: true
 
-  /@rollup/rollup-linux-arm64-gnu@4.6.0:
-    resolution: {integrity: sha512-Ed8uJI3kM11de9S0j67wAV07JUNhbAqIrDYhQBrQW42jGopgheyk/cdcshgGO4fW5Wjq97COCY/BHogdGvKVNQ==}
+  /@rollup/rollup-linux-arm64-gnu@4.9.0:
+    resolution: {integrity: sha512-JbEPfhndYeWHfOSeh4DOFvNXrj7ls9S/2omijVsao+LBPTPayT1uKcK3dHW3MwDJ7KO11t9m2cVTqXnTKpeaiw==}
     cpu: [arm64]
     os: [linux]
     requiresBuild: true
     dev: true
     optional: true
 
-  /@rollup/rollup-linux-arm64-musl@4.6.0:
-    resolution: {integrity: sha512-mZoNQ/qK4D7SSY8v6kEsAAyDgznzLLuSFCA3aBHZTmf3HP/dW4tNLTtWh9+LfyO0Z1aUn+ecpT7IQ3WtIg3ViQ==}
+  /@rollup/rollup-linux-arm64-musl@4.9.0:
+    resolution: {integrity: sha512-ahqcSXLlcV2XUBM3/f/C6cRoh7NxYA/W7Yzuv4bDU1YscTFw7ay4LmD7l6OS8EMhTNvcrWGkEettL1Bhjf+B+w==}
     cpu: [arm64]
     os: [linux]
     requiresBuild: true
     dev: true
     optional: true
 
-  /@rollup/rollup-linux-x64-gnu@4.6.0:
-    resolution: {integrity: sha512-rouezFHpwCqdEXsqAfNsTgSWO0FoZ5hKv5p+TGO5KFhyN/dvYXNMqMolOb8BkyKcPqjYRBeT+Z6V3aM26rPaYg==}
+  /@rollup/rollup-linux-riscv64-gnu@4.9.0:
+    resolution: {integrity: sha512-uwvOYNtLw8gVtrExKhdFsYHA/kotURUmZYlinH2VcQxNCQJeJXnkmWgw2hI9Xgzhgu7J9QvWiq9TtTVwWMDa+w==}
+    cpu: [riscv64]
+    os: [linux]
+    requiresBuild: true
+    dev: true
+    optional: true
+
+  /@rollup/rollup-linux-x64-gnu@4.9.0:
+    resolution: {integrity: sha512-m6pkSwcZZD2LCFHZX/zW2aLIISyzWLU3hrLLzQKMI12+OLEzgruTovAxY5sCZJkipklaZqPy/2bEEBNjp+Y7xg==}
     cpu: [x64]
     os: [linux]
     requiresBuild: true
     dev: true
     optional: true
 
-  /@rollup/rollup-linux-x64-musl@4.6.0:
-    resolution: {integrity: sha512-Bbm+fyn3S6u51urfj3YnqBXg5vI2jQPncRRELaucmhBVyZkbWClQ1fEsRmdnCPpQOQfkpg9gZArvtMVkOMsh1w==}
+  /@rollup/rollup-linux-x64-musl@4.9.0:
+    resolution: {integrity: sha512-VFAC1RDRSbU3iOF98X42KaVicAfKf0m0OvIu8dbnqhTe26Kh6Ym9JrDulz7Hbk7/9zGc41JkV02g+p3BivOdAg==}
     cpu: [x64]
     os: [linux]
     requiresBuild: true
     dev: true
     optional: true
 
-  /@rollup/rollup-win32-arm64-msvc@4.6.0:
-    resolution: {integrity: sha512-+MRMcyx9L2kTrTUzYmR61+XVsliMG4odFb5UmqtiT8xOfEicfYAGEuF/D1Pww1+uZkYhBqAHpvju7VN+GnC3ng==}
+  /@rollup/rollup-win32-arm64-msvc@4.9.0:
+    resolution: {integrity: sha512-9jPgMvTKXARz4inw6jezMLA2ihDBvgIU9Ml01hjdVpOcMKyxFBJrn83KVQINnbeqDv0+HdO1c09hgZ8N0s820Q==}
     cpu: [arm64]
     os: [win32]
     requiresBuild: true
     dev: true
     optional: true
 
-  /@rollup/rollup-win32-ia32-msvc@4.6.0:
-    resolution: {integrity: sha512-rxfeE6K6s/Xl2HGeK6cO8SiQq3k/3BYpw7cfhW5Bk2euXNEpuzi2cc7llxx1si1QgwfjNtdRNTGqdBzGlFZGFw==}
+  /@rollup/rollup-win32-ia32-msvc@4.9.0:
+    resolution: {integrity: sha512-WE4pT2kTXQN2bAv40Uog0AsV7/s9nT9HBWXAou8+++MBCnY51QS02KYtm6dQxxosKi1VIz/wZIrTQO5UP2EW+Q==}
     cpu: [ia32]
     os: [win32]
     requiresBuild: true
     dev: true
     optional: true
 
-  /@rollup/rollup-win32-x64-msvc@4.6.0:
-    resolution: {integrity: sha512-QqmCsydHS172Y0Kc13bkMXvipbJSvzeglBncJG3LsYJSiPlxYACz7MmJBs4A8l1oU+jfhYEIC/+AUSlvjmiX/g==}
+  /@rollup/rollup-win32-x64-msvc@4.9.0:
+    resolution: {integrity: sha512-aPP5Q5AqNGuT0tnuEkK/g4mnt3ZhheiXrDIiSVIHN9mcN21OyXDVbEMqmXPE7e2OplNLDkcvV+ZoGJa2ZImFgw==}
     cpu: [x64]
     os: [win32]
     requiresBuild: true
@@ -853,16 +861,6 @@ packages:
     resolution: {integrity: sha512-madaWq2k+LYMEhmcp0fs+OGaLFk0OenpHa4gmI4VEmCKX4PJntQ6fnnGADVFrVkBj0wIdAlQnK/MrlYTHsa1gQ==}
     dev: true
 
-  /@types/chai-subset@1.3.5:
-    resolution: {integrity: sha512-c2mPnw+xHtXDoHmdtcCXGwyLMiauiAyxWMzhGpqHC4nqI/Y5G2XhTampslK2rb59kpcuHon03UH8W6iYUzw88A==}
-    dependencies:
-      '@types/chai': 4.3.11
-    dev: true
-
-  /@types/chai@4.3.11:
-    resolution: {integrity: sha512-qQR1dr2rGIHYlJulmr8Ioq3De0Le9E4MJ5AiaeAETJJpndT1uUNHsGFK3L/UIu+rbkQSdj8J/w2bCsBZc/Y5fQ==}
-    dev: true
-
   /@types/istanbul-lib-coverage@2.0.6:
     resolution: {integrity: sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==}
     dev: true
@@ -870,7 +868,7 @@ packages:
   /@types/jsdom@21.1.6:
     resolution: {integrity: sha512-/7kkMsC+/kMs7gAYmmBR9P0vGTnOoLhQhyhQJSlXGI5bzTHp6xdo0TtKWQAsz6pmSAeVqKSbqeyP6hytqr9FDw==}
     dependencies:
-      '@types/node': 20.10.0
+      '@types/node': 20.10.4
       '@types/tough-cookie': 4.0.5
       parse5: 7.1.2
     dev: true
@@ -883,8 +881,8 @@ packages:
     resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==}
     dev: true
 
-  /@types/node@20.10.0:
-    resolution: {integrity: sha512-D0WfRmU9TQ8I9PFx9Yc+EBHw+vSpIub4IDvQivcp26PtPrdMGAq5SDcpXEo/epqa/DXotVpekHiLNTg3iaKXBQ==}
+  /@types/node@20.10.4:
+    resolution: {integrity: sha512-D08YG6rr8X90YB56tSIuBaddy/UXAA9RKJoFvrsnogAum/0pmjkgi4+2nx96A330FmioegBWmEYQ+syqCFaveg==}
     dependencies:
       undici-types: 5.26.5
     dev: true
@@ -897,8 +895,8 @@ packages:
     resolution: {integrity: sha512-/Ad8+nIOV7Rl++6f1BdKxFSMgmoqEoYbHRpPcx3JEfv8VRsQe9Z4mCXeJBzxs7mbHY/XOZZuXlRNfhpVPbs6ZA==}
     dev: true
 
-  /@typescript-eslint/eslint-plugin@6.13.0(@typescript-eslint/parser@6.13.0)(eslint@8.54.0)(typescript@5.3.2):
-    resolution: {integrity: sha512-HTvbSd0JceI2GW5DHS3R9zbarOqjkM9XDR7zL8eCsBUO/eSiHcoNE7kSL5sjGXmVa9fjH5LCfHDXNnH4QLp7tQ==}
+  /@typescript-eslint/eslint-plugin@6.14.0(@typescript-eslint/parser@6.14.0)(eslint@8.55.0)(typescript@5.3.3):
+    resolution: {integrity: sha512-1ZJBykBCXaSHG94vMMKmiHoL0MhNHKSVlcHVYZNw+BKxufhqQVTOawNpwwI1P5nIFZ/4jLVop0mcY6mJJDFNaw==}
     engines: {node: ^16.0.0 || >=18.0.0}
     peerDependencies:
       '@typescript-eslint/parser': ^6.0.0 || ^6.0.0-alpha
@@ -909,25 +907,25 @@ packages:
         optional: true
     dependencies:
       '@eslint-community/regexpp': 4.10.0
-      '@typescript-eslint/parser': 6.13.0(eslint@8.54.0)(typescript@5.3.2)
-      '@typescript-eslint/scope-manager': 6.13.0
-      '@typescript-eslint/type-utils': 6.13.0(eslint@8.54.0)(typescript@5.3.2)
-      '@typescript-eslint/utils': 6.13.0(eslint@8.54.0)(typescript@5.3.2)
-      '@typescript-eslint/visitor-keys': 6.13.0
+      '@typescript-eslint/parser': 6.14.0(eslint@8.55.0)(typescript@5.3.3)
+      '@typescript-eslint/scope-manager': 6.14.0
+      '@typescript-eslint/type-utils': 6.14.0(eslint@8.55.0)(typescript@5.3.3)
+      '@typescript-eslint/utils': 6.14.0(eslint@8.55.0)(typescript@5.3.3)
+      '@typescript-eslint/visitor-keys': 6.14.0
       debug: 4.3.4
-      eslint: 8.54.0
+      eslint: 8.55.0
       graphemer: 1.4.0
       ignore: 5.3.0
       natural-compare: 1.4.0
       semver: 7.5.4
-      ts-api-utils: 1.0.3(typescript@5.3.2)
-      typescript: 5.3.2
+      ts-api-utils: 1.0.3(typescript@5.3.3)
+      typescript: 5.3.3
     transitivePeerDependencies:
       - supports-color
     dev: true
 
-  /@typescript-eslint/parser@6.13.0(eslint@8.54.0)(typescript@5.3.2):
-    resolution: {integrity: sha512-VpG+M7GNhHLI/aTDctqAV0XbzB16vf+qDX9DXuMZSe/0bahzDA9AKZB15NDbd+D9M4cDsJvfkbGOA7qiZ/bWJw==}
+  /@typescript-eslint/parser@6.14.0(eslint@8.55.0)(typescript@5.3.3):
+    resolution: {integrity: sha512-QjToC14CKacd4Pa7JK4GeB/vHmWFJckec49FR4hmIRf97+KXole0T97xxu9IFiPxVQ1DBWrQ5wreLwAGwWAVQA==}
     engines: {node: ^16.0.0 || >=18.0.0}
     peerDependencies:
       eslint: ^7.0.0 || ^8.0.0
@@ -936,27 +934,27 @@ packages:
       typescript:
         optional: true
     dependencies:
-      '@typescript-eslint/scope-manager': 6.13.0
-      '@typescript-eslint/types': 6.13.0
-      '@typescript-eslint/typescript-estree': 6.13.0(typescript@5.3.2)
-      '@typescript-eslint/visitor-keys': 6.13.0
+      '@typescript-eslint/scope-manager': 6.14.0
+      '@typescript-eslint/types': 6.14.0
+      '@typescript-eslint/typescript-estree': 6.14.0(typescript@5.3.3)
+      '@typescript-eslint/visitor-keys': 6.14.0
       debug: 4.3.4
-      eslint: 8.54.0
-      typescript: 5.3.2
+      eslint: 8.55.0
+      typescript: 5.3.3
     transitivePeerDependencies:
       - supports-color
     dev: true
 
-  /@typescript-eslint/scope-manager@6.13.0:
-    resolution: {integrity: sha512-2x0K2/CujsokIv+LN2T0l5FVDMtsCjkUyYtlcY4xxnxLAW+x41LXr16duoicHpGtLhmtN7kqvuFJ3zbz00Ikhw==}
+  /@typescript-eslint/scope-manager@6.14.0:
+    resolution: {integrity: sha512-VT7CFWHbZipPncAZtuALr9y3EuzY1b1t1AEkIq2bTXUPKw+pHoXflGNG5L+Gv6nKul1cz1VH8fz16IThIU0tdg==}
     engines: {node: ^16.0.0 || >=18.0.0}
     dependencies:
-      '@typescript-eslint/types': 6.13.0
-      '@typescript-eslint/visitor-keys': 6.13.0
+      '@typescript-eslint/types': 6.14.0
+      '@typescript-eslint/visitor-keys': 6.14.0
     dev: true
 
-  /@typescript-eslint/type-utils@6.13.0(eslint@8.54.0)(typescript@5.3.2):
-    resolution: {integrity: sha512-YHufAmZd/yP2XdoD3YeFEjq+/Tl+myhzv+GJHSOz+ro/NFGS84mIIuLU3pVwUcauSmwlCrVXbBclkn1HfjY0qQ==}
+  /@typescript-eslint/type-utils@6.14.0(eslint@8.55.0)(typescript@5.3.3):
+    resolution: {integrity: sha512-x6OC9Q7HfYKqjnuNu5a7kffIYs3No30isapRBJl1iCHLitD8O0lFbRcVGiOcuyN837fqXzPZ1NS10maQzZMKqw==}
     engines: {node: ^16.0.0 || >=18.0.0}
     peerDependencies:
       eslint: ^7.0.0 || ^8.0.0
@@ -965,23 +963,23 @@ packages:
       typescript:
         optional: true
     dependencies:
-      '@typescript-eslint/typescript-estree': 6.13.0(typescript@5.3.2)
-      '@typescript-eslint/utils': 6.13.0(eslint@8.54.0)(typescript@5.3.2)
+      '@typescript-eslint/typescript-estree': 6.14.0(typescript@5.3.3)
+      '@typescript-eslint/utils': 6.14.0(eslint@8.55.0)(typescript@5.3.3)
       debug: 4.3.4
-      eslint: 8.54.0
-      ts-api-utils: 1.0.3(typescript@5.3.2)
-      typescript: 5.3.2
+      eslint: 8.55.0
+      ts-api-utils: 1.0.3(typescript@5.3.3)
+      typescript: 5.3.3
     transitivePeerDependencies:
       - supports-color
     dev: true
 
-  /@typescript-eslint/types@6.13.0:
-    resolution: {integrity: sha512-oXg7DFxx/GmTrKXKKLSoR2rwiutOC7jCQ5nDH5p5VS6cmHE1TcPTaYQ0VPSSUvj7BnNqCgQ/NXcTBxn59pfPTQ==}
+  /@typescript-eslint/types@6.14.0:
+    resolution: {integrity: sha512-uty9H2K4Xs8E47z3SnXEPRNDfsis8JO27amp2GNCnzGETEW3yTqEIVg5+AI7U276oGF/tw6ZA+UesxeQ104ceA==}
     engines: {node: ^16.0.0 || >=18.0.0}
     dev: true
 
-  /@typescript-eslint/typescript-estree@6.13.0(typescript@5.3.2):
-    resolution: {integrity: sha512-IT4O/YKJDoiy/mPEDsfOfp+473A9GVqXlBKckfrAOuVbTqM8xbc0LuqyFCcgeFWpqu3WjQexolgqN2CuWBYbog==}
+  /@typescript-eslint/typescript-estree@6.14.0(typescript@5.3.3):
+    resolution: {integrity: sha512-yPkaLwK0yH2mZKFE/bXkPAkkFgOv15GJAUzgUVonAbv0Hr4PK/N2yaA/4XQbTZQdygiDkpt5DkxPELqHguNvyw==}
     engines: {node: ^16.0.0 || >=18.0.0}
     peerDependencies:
       typescript: '*'
@@ -989,42 +987,42 @@ packages:
       typescript:
         optional: true
     dependencies:
-      '@typescript-eslint/types': 6.13.0
-      '@typescript-eslint/visitor-keys': 6.13.0
+      '@typescript-eslint/types': 6.14.0
+      '@typescript-eslint/visitor-keys': 6.14.0
       debug: 4.3.4
       globby: 11.1.0
       is-glob: 4.0.3
       semver: 7.5.4
-      ts-api-utils: 1.0.3(typescript@5.3.2)
-      typescript: 5.3.2
+      ts-api-utils: 1.0.3(typescript@5.3.3)
+      typescript: 5.3.3
     transitivePeerDependencies:
       - supports-color
     dev: true
 
-  /@typescript-eslint/utils@6.13.0(eslint@8.54.0)(typescript@5.3.2):
-    resolution: {integrity: sha512-V+txaxARI8yznDkcQ6FNRXxG+T37qT3+2NsDTZ/nKLxv6VfGrRhTnuvxPUxpVuWWr+eVeIxU53PioOXbz8ratQ==}
+  /@typescript-eslint/utils@6.14.0(eslint@8.55.0)(typescript@5.3.3):
+    resolution: {integrity: sha512-XwRTnbvRr7Ey9a1NT6jqdKX8y/atWG+8fAIu3z73HSP8h06i3r/ClMhmaF/RGWGW1tHJEwij1uEg2GbEmPYvYg==}
     engines: {node: ^16.0.0 || >=18.0.0}
     peerDependencies:
       eslint: ^7.0.0 || ^8.0.0
     dependencies:
-      '@eslint-community/eslint-utils': 4.4.0(eslint@8.54.0)
+      '@eslint-community/eslint-utils': 4.4.0(eslint@8.55.0)
       '@types/json-schema': 7.0.15
       '@types/semver': 7.5.6
-      '@typescript-eslint/scope-manager': 6.13.0
-      '@typescript-eslint/types': 6.13.0
-      '@typescript-eslint/typescript-estree': 6.13.0(typescript@5.3.2)
-      eslint: 8.54.0
+      '@typescript-eslint/scope-manager': 6.14.0
+      '@typescript-eslint/types': 6.14.0
+      '@typescript-eslint/typescript-estree': 6.14.0(typescript@5.3.3)
+      eslint: 8.55.0
       semver: 7.5.4
     transitivePeerDependencies:
       - supports-color
       - typescript
     dev: true
 
-  /@typescript-eslint/visitor-keys@6.13.0:
-    resolution: {integrity: sha512-UQklteCEMCRoq/1UhKFZsHv5E4dN1wQSzJoxTfABasWk1HgJRdg1xNUve/Kv/Sdymt4x+iEzpESOqRFlQr/9Aw==}
+  /@typescript-eslint/visitor-keys@6.14.0:
+    resolution: {integrity: sha512-fB5cw6GRhJUz03MrROVuj5Zm/Q+XWlVdIsFj+Zb1Hvqouc8t+XP2H5y53QYU/MGtd2dPg6/vJJlhoX3xc2ehfw==}
     engines: {node: ^16.0.0 || >=18.0.0}
     dependencies:
-      '@typescript-eslint/types': 6.13.0
+      '@typescript-eslint/types': 6.14.0
       eslint-visitor-keys: 3.4.3
     dev: true
 
@@ -1032,86 +1030,88 @@ packages:
     resolution: {integrity: sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==}
     dev: true
 
-  /@vitejs/plugin-vue-jsx@3.1.0(vite@5.0.2)(vue@3.3.9):
+  /@vitejs/plugin-vue-jsx@3.1.0(vite@5.0.9)(vue@3.3.11):
     resolution: {integrity: sha512-w9M6F3LSEU5kszVb9An2/MmXNxocAnUb3WhRr8bHlimhDrXNt6n6D2nJQR3UXpGlZHh/EsgouOHCsM8V3Ln+WA==}
     engines: {node: ^14.18.0 || >=16.0.0}
     peerDependencies:
       vite: ^4.0.0 || ^5.0.0
       vue: ^3.0.0
     dependencies:
-      '@babel/core': 7.23.3
-      '@babel/plugin-transform-typescript': 7.23.4(@babel/core@7.23.3)
-      '@vue/babel-plugin-jsx': 1.1.5(@babel/core@7.23.3)
-      vite: 5.0.2(@types/node@20.10.0)
-      vue: 3.3.9(typescript@5.3.2)
+      '@babel/core': 7.23.6
+      '@babel/plugin-transform-typescript': 7.23.6(@babel/core@7.23.6)
+      '@vue/babel-plugin-jsx': 1.1.5(@babel/core@7.23.6)
+      vite: 5.0.9(@types/node@20.10.4)
+      vue: 3.3.11(typescript@5.3.3)
     transitivePeerDependencies:
       - supports-color
     dev: true
 
-  /@vitejs/plugin-vue@4.5.0(vite@5.0.2)(vue@3.3.9):
-    resolution: {integrity: sha512-a2WSpP8X8HTEww/U00bU4mX1QpLINNuz/2KMNpLsdu3BzOpak3AGI1CJYBTXcc4SPhaD0eNRUp7IyQK405L5dQ==}
+  /@vitejs/plugin-vue@4.5.2(vite@5.0.9)(vue@3.3.11):
+    resolution: {integrity: sha512-UGR3DlzLi/SaVBPX0cnSyE37vqxU3O6chn8l0HJNzQzDia6/Au2A4xKv+iIJW8w2daf80G7TYHhi1pAUjdZ0bQ==}
     engines: {node: ^14.18.0 || >=16.0.0}
     peerDependencies:
       vite: ^4.0.0 || ^5.0.0
       vue: ^3.2.25
     dependencies:
-      vite: 5.0.2(@types/node@20.10.0)
-      vue: 3.3.9(typescript@5.3.2)
+      vite: 5.0.9(@types/node@20.10.4)
+      vue: 3.3.11(typescript@5.3.3)
     dev: true
 
-  /@vitest/coverage-v8@0.34.6(vitest@0.34.6):
-    resolution: {integrity: sha512-fivy/OK2d/EsJFoEoxHFEnNGTg+MmdZBAVK9Ka4qhXR2K3J0DS08vcGVwzDtXSuUMabLv4KtPcpSKkcMXFDViw==}
+  /@vitest/coverage-v8@1.0.4(vitest@1.0.4):
+    resolution: {integrity: sha512-xD6Yuql6RW0Ir/JJIs6rVrmnG2/KOWJF+IRX1oJQk5wGKGxbtdrYPbl+WTUn/4ICCQ2G20zbE1e8/nPNyAG5Vg==}
     peerDependencies:
-      vitest: '>=0.32.0 <1'
+      vitest: ^1.0.0
     dependencies:
       '@ampproject/remapping': 2.2.1
       '@bcoe/v8-coverage': 0.2.3
+      debug: 4.3.4
       istanbul-lib-coverage: 3.2.2
       istanbul-lib-report: 3.0.1
       istanbul-lib-source-maps: 4.0.1
       istanbul-reports: 3.1.6
       magic-string: 0.30.5
+      magicast: 0.3.2
       picocolors: 1.0.0
-      std-env: 3.5.0
+      std-env: 3.6.0
       test-exclude: 6.0.0
       v8-to-istanbul: 9.2.0
-      vitest: 0.34.6(jsdom@23.0.0)
+      vitest: 1.0.4(@types/node@20.10.4)(jsdom@23.0.1)
     transitivePeerDependencies:
       - supports-color
     dev: true
 
-  /@vitest/expect@0.34.6:
-    resolution: {integrity: sha512-QUzKpUQRc1qC7qdGo7rMK3AkETI7w18gTCUrsNnyjjJKYiuUB9+TQK3QnR1unhCnWRC0AbKv2omLGQDF/mIjOw==}
+  /@vitest/expect@1.0.4:
+    resolution: {integrity: sha512-/NRN9N88qjg3dkhmFcCBwhn/Ie4h064pY3iv7WLRsDJW7dXnEgeoa8W9zy7gIPluhz6CkgqiB3HmpIXgmEY5dQ==}
     dependencies:
-      '@vitest/spy': 0.34.6
-      '@vitest/utils': 0.34.6
+      '@vitest/spy': 1.0.4
+      '@vitest/utils': 1.0.4
       chai: 4.3.10
     dev: true
 
-  /@vitest/runner@0.34.6:
-    resolution: {integrity: sha512-1CUQgtJSLF47NnhN+F9X2ycxUP0kLHQ/JWvNHbeBfwW8CzEGgeskzNnHDyv1ieKTltuR6sdIHV+nmR6kPxQqzQ==}
+  /@vitest/runner@1.0.4:
+    resolution: {integrity: sha512-rhOQ9FZTEkV41JWXozFM8YgOqaG9zA7QXbhg5gy6mFOVqh4PcupirIJ+wN7QjeJt8S8nJRYuZH1OjJjsbxAXTQ==}
     dependencies:
-      '@vitest/utils': 0.34.6
-      p-limit: 4.0.0
+      '@vitest/utils': 1.0.4
+      p-limit: 5.0.0
       pathe: 1.1.1
     dev: true
 
-  /@vitest/snapshot@0.34.6:
-    resolution: {integrity: sha512-B3OZqYn6k4VaN011D+ve+AA4whM4QkcwcrwaKwAbyyvS/NB1hCWjFIBQxAQQSQir9/RtyAAGuq+4RJmbn2dH4w==}
+  /@vitest/snapshot@1.0.4:
+    resolution: {integrity: sha512-vkfXUrNyNRA/Gzsp2lpyJxh94vU2OHT1amoD6WuvUAA12n32xeVZQ0KjjQIf8F6u7bcq2A2k969fMVxEsxeKYA==}
     dependencies:
       magic-string: 0.30.5
       pathe: 1.1.1
       pretty-format: 29.7.0
     dev: true
 
-  /@vitest/spy@0.34.6:
-    resolution: {integrity: sha512-xaCvneSaeBw/cz8ySmF7ZwGvL0lBjfvqc1LpQ/vcdHEvpLn3Ff1vAvjw+CoGn0802l++5L/pxb7whwcWAw+DUQ==}
+  /@vitest/spy@1.0.4:
+    resolution: {integrity: sha512-9ojTFRL1AJVh0hvfzAQpm0QS6xIS+1HFIw94kl/1ucTfGCaj1LV/iuJU4Y6cdR03EzPDygxTHwE1JOm+5RCcvA==}
     dependencies:
       tinyspy: 2.2.0
     dev: true
 
-  /@vitest/utils@0.34.6:
-    resolution: {integrity: sha512-IG5aDD8S6zlvloDsnzHw0Ut5xczlF+kv2BOTo+iXfPr54Yhi5qbVOgGB1hZaVq4iJ4C/MZ2J0y15IlsV/ZcI0A==}
+  /@vitest/utils@1.0.4:
+    resolution: {integrity: sha512-gsswWDXxtt0QvtK/y/LWukN7sGMYmnCcv1qv05CsY6cU/Y1zpGX1QuvLs+GO1inczpE6Owixeel3ShkjhYtGfA==}
     dependencies:
       diff-sequences: 29.6.3
       loupe: 2.3.7
@@ -1122,17 +1122,17 @@ packages:
     resolution: {integrity: sha512-SgUymFpMoAyWeYWLAY+MkCK3QEROsiUnfaw5zxOVD/M64KQs8D/4oK6Q5omVA2hnvEOE0SCkH2TZxs/jnnUj7w==}
     dev: true
 
-  /@vue/babel-plugin-jsx@1.1.5(@babel/core@7.23.3):
+  /@vue/babel-plugin-jsx@1.1.5(@babel/core@7.23.6):
     resolution: {integrity: sha512-nKs1/Bg9U1n3qSWnsHhCVQtAzI6aQXqua8j/bZrau8ywT1ilXQbK4FwEJGmU8fV7tcpuFvWmmN7TMmV1OBma1g==}
     peerDependencies:
       '@babel/core': ^7.0.0-0
     dependencies:
-      '@babel/core': 7.23.3
+      '@babel/core': 7.23.6
       '@babel/helper-module-imports': 7.22.15
-      '@babel/plugin-syntax-jsx': 7.23.3(@babel/core@7.23.3)
+      '@babel/plugin-syntax-jsx': 7.23.3(@babel/core@7.23.6)
       '@babel/template': 7.22.15
-      '@babel/traverse': 7.23.4
-      '@babel/types': 7.23.4
+      '@babel/traverse': 7.23.6
+      '@babel/types': 7.23.6
       '@vue/babel-helper-vue-transform-on': 1.1.5
       camelcase: 6.3.0
       html-tags: 3.3.1
@@ -1141,59 +1141,59 @@ packages:
       - supports-color
     dev: true
 
-  /@vue/compiler-core@3.3.9:
-    resolution: {integrity: sha512-+/Lf68Vr/nFBA6ol4xOtJrW+BQWv3QWKfRwGSm70jtXwfhZNF4R/eRgyVJYoxFRhdCTk/F6g99BP0ffPgZihfQ==}
+  /@vue/compiler-core@3.3.11:
+    resolution: {integrity: sha512-h97/TGWBilnLuRaj58sxNrsUU66fwdRKLOLQ9N/5iNDfp+DZhYH9Obhe0bXxhedl8fjAgpRANpiZfbgWyruQ0w==}
     dependencies:
-      '@babel/parser': 7.23.4
-      '@vue/shared': 3.3.9
+      '@babel/parser': 7.23.6
+      '@vue/shared': 3.3.11
       estree-walker: 2.0.2
       source-map-js: 1.0.2
 
-  /@vue/compiler-dom@3.3.9:
-    resolution: {integrity: sha512-nfWubTtLXuT4iBeDSZ5J3m218MjOy42Vp2pmKVuBKo2/BLcrFUX8nCSr/bKRFiJ32R8qbdnnnBgRn9AdU5v0Sg==}
+  /@vue/compiler-dom@3.3.11:
+    resolution: {integrity: sha512-zoAiUIqSKqAJ81WhfPXYmFGwDRuO+loqLxvXmfUdR5fOitPoUiIeFI9cTTyv9MU5O1+ZZglJVTusWzy+wfk5hw==}
     dependencies:
-      '@vue/compiler-core': 3.3.9
-      '@vue/shared': 3.3.9
+      '@vue/compiler-core': 3.3.11
+      '@vue/shared': 3.3.11
 
-  /@vue/compiler-sfc@3.3.9:
-    resolution: {integrity: sha512-wy0CNc8z4ihoDzjASCOCsQuzW0A/HP27+0MDSSICMjVIFzk/rFViezkR3dzH+miS2NDEz8ywMdbjO5ylhOLI2A==}
+  /@vue/compiler-sfc@3.3.11:
+    resolution: {integrity: sha512-U4iqPlHO0KQeK1mrsxCN0vZzw43/lL8POxgpzcJweopmqtoYy9nljJzWDIQS3EfjiYhfdtdk9Gtgz7MRXnz3GA==}
     dependencies:
-      '@babel/parser': 7.23.4
-      '@vue/compiler-core': 3.3.9
-      '@vue/compiler-dom': 3.3.9
-      '@vue/compiler-ssr': 3.3.9
-      '@vue/reactivity-transform': 3.3.9
-      '@vue/shared': 3.3.9
+      '@babel/parser': 7.23.6
+      '@vue/compiler-core': 3.3.11
+      '@vue/compiler-dom': 3.3.11
+      '@vue/compiler-ssr': 3.3.11
+      '@vue/reactivity-transform': 3.3.11
+      '@vue/shared': 3.3.11
       estree-walker: 2.0.2
       magic-string: 0.30.5
-      postcss: 8.4.31
+      postcss: 8.4.32
       source-map-js: 1.0.2
 
-  /@vue/compiler-ssr@3.3.9:
-    resolution: {integrity: sha512-NO5oobAw78R0G4SODY5A502MGnDNiDjf6qvhn7zD7TJGc8XDeIEw4fg6JU705jZ/YhuokBKz0A5a/FL/XZU73g==}
+  /@vue/compiler-ssr@3.3.11:
+    resolution: {integrity: sha512-Zd66ZwMvndxRTgVPdo+muV4Rv9n9DwQ4SSgWWKWkPFebHQfVYRrVjeygmmDmPewsHyznCNvJ2P2d6iOOhdv8Qg==}
     dependencies:
-      '@vue/compiler-dom': 3.3.9
-      '@vue/shared': 3.3.9
+      '@vue/compiler-dom': 3.3.11
+      '@vue/shared': 3.3.11
 
   /@vue/devtools-api@6.5.1:
     resolution: {integrity: sha512-+KpckaAQyfbvshdDW5xQylLni1asvNSGme1JFs8I1+/H5pHEhqUKMEQD/qn3Nx5+/nycBq11qAEi8lk+LXI2dA==}
     dev: false
 
-  /@vue/eslint-config-prettier@8.0.0(eslint@8.54.0)(prettier@3.1.0):
+  /@vue/eslint-config-prettier@8.0.0(eslint@8.55.0)(prettier@3.1.1):
     resolution: {integrity: sha512-55dPqtC4PM/yBjhAr+yEw6+7KzzdkBuLmnhBrDfp4I48+wy+Giqqj9yUr5T2uD/BkBROjjmqnLZmXRdOx/VtQg==}
     peerDependencies:
       eslint: '>= 8.0.0'
       prettier: '>= 3.0.0'
     dependencies:
-      eslint: 8.54.0
-      eslint-config-prettier: 8.10.0(eslint@8.54.0)
-      eslint-plugin-prettier: 5.0.1(eslint-config-prettier@8.10.0)(eslint@8.54.0)(prettier@3.1.0)
-      prettier: 3.1.0
+      eslint: 8.55.0
+      eslint-config-prettier: 8.10.0(eslint@8.55.0)
+      eslint-plugin-prettier: 5.0.1(eslint-config-prettier@8.10.0)(eslint@8.55.0)(prettier@3.1.1)
+      prettier: 3.1.1
     transitivePeerDependencies:
       - '@types/eslint'
     dev: true
 
-  /@vue/eslint-config-typescript@12.0.0(eslint-plugin-vue@9.18.1)(eslint@8.54.0)(typescript@5.3.2):
+  /@vue/eslint-config-typescript@12.0.0(eslint-plugin-vue@9.19.2)(eslint@8.55.0)(typescript@5.3.3):
     resolution: {integrity: sha512-StxLFet2Qe97T8+7L8pGlhYBBr8Eg05LPuTDVopQV6il+SK6qqom59BA/rcFipUef2jD8P2X44Vd8tMFytfvlg==}
     engines: {node: ^14.17.0 || >=16.0.0}
     peerDependencies:
@@ -1204,57 +1204,57 @@ packages:
       typescript:
         optional: true
     dependencies:
-      '@typescript-eslint/eslint-plugin': 6.13.0(@typescript-eslint/parser@6.13.0)(eslint@8.54.0)(typescript@5.3.2)
-      '@typescript-eslint/parser': 6.13.0(eslint@8.54.0)(typescript@5.3.2)
-      eslint: 8.54.0
-      eslint-plugin-vue: 9.18.1(eslint@8.54.0)
-      typescript: 5.3.2
-      vue-eslint-parser: 9.3.2(eslint@8.54.0)
+      '@typescript-eslint/eslint-plugin': 6.14.0(@typescript-eslint/parser@6.14.0)(eslint@8.55.0)(typescript@5.3.3)
+      '@typescript-eslint/parser': 6.14.0(eslint@8.55.0)(typescript@5.3.3)
+      eslint: 8.55.0
+      eslint-plugin-vue: 9.19.2(eslint@8.55.0)
+      typescript: 5.3.3
+      vue-eslint-parser: 9.3.2(eslint@8.55.0)
     transitivePeerDependencies:
       - supports-color
     dev: true
 
-  /@vue/reactivity-transform@3.3.9:
-    resolution: {integrity: sha512-HnUFm7Ry6dFa4Lp63DAxTixUp8opMtQr6RxQCpDI1vlh12rkGIeYqMvJtK+IKyEfEOa2I9oCkD1mmsPdaGpdVg==}
+  /@vue/reactivity-transform@3.3.11:
+    resolution: {integrity: sha512-fPGjH0wqJo68A0wQ1k158utDq/cRyZNlFoxGwNScE28aUFOKFEnCBsvyD8jHn+0kd0UKVpuGuaZEQ6r9FJRqCg==}
     dependencies:
-      '@babel/parser': 7.23.4
-      '@vue/compiler-core': 3.3.9
-      '@vue/shared': 3.3.9
+      '@babel/parser': 7.23.6
+      '@vue/compiler-core': 3.3.11
+      '@vue/shared': 3.3.11
       estree-walker: 2.0.2
       magic-string: 0.30.5
 
-  /@vue/reactivity@3.3.9:
-    resolution: {integrity: sha512-VmpIqlNp+aYDg2X0xQhJqHx9YguOmz2UxuUJDckBdQCNkipJvfk9yA75woLWElCa0Jtyec3lAAt49GO0izsphw==}
+  /@vue/reactivity@3.3.11:
+    resolution: {integrity: sha512-D5tcw091f0nuu+hXq5XANofD0OXnBmaRqMYl5B3fCR+mX+cXJIGNw/VNawBqkjLNWETrFW0i+xH9NvDbTPVh7g==}
     dependencies:
-      '@vue/shared': 3.3.9
+      '@vue/shared': 3.3.11
 
-  /@vue/runtime-core@3.3.9:
-    resolution: {integrity: sha512-xxaG9KvPm3GTRuM4ZyU8Tc+pMVzcu6eeoSRQJ9IE7NmCcClW6z4B3Ij6L4EDl80sxe/arTtQ6YmgiO4UZqRc+w==}
+  /@vue/runtime-core@3.3.11:
+    resolution: {integrity: sha512-g9ztHGwEbS5RyWaOpXuyIVFTschclnwhqEbdy5AwGhYOgc7m/q3NFwr50MirZwTTzX55JY8pSkeib9BX04NIpw==}
     dependencies:
-      '@vue/reactivity': 3.3.9
-      '@vue/shared': 3.3.9
+      '@vue/reactivity': 3.3.11
+      '@vue/shared': 3.3.11
 
-  /@vue/runtime-dom@3.3.9:
-    resolution: {integrity: sha512-e7LIfcxYSWbV6BK1wQv9qJyxprC75EvSqF/kQKe6bdZEDNValzeRXEVgiX7AHI6hZ59HA4h7WT5CGvm69vzJTQ==}
+  /@vue/runtime-dom@3.3.11:
+    resolution: {integrity: sha512-OlhtV1PVpbgk+I2zl+Y5rQtDNcCDs12rsRg71XwaA2/Rbllw6mBLMi57VOn8G0AjOJ4Mdb4k56V37+g8ukShpQ==}
     dependencies:
-      '@vue/runtime-core': 3.3.9
-      '@vue/shared': 3.3.9
-      csstype: 3.1.2
+      '@vue/runtime-core': 3.3.11
+      '@vue/shared': 3.3.11
+      csstype: 3.1.3
 
-  /@vue/server-renderer@3.3.9(vue@3.3.9):
-    resolution: {integrity: sha512-w0zT/s5l3Oa3ZjtLW88eO4uV6AQFqU8X5GOgzq7SkQQu6vVr+8tfm+OI2kDBplS/W/XgCBuFXiPw6T5EdwXP0A==}
+  /@vue/server-renderer@3.3.11(vue@3.3.11):
+    resolution: {integrity: sha512-AIWk0VwwxCAm4wqtJyxBylRTXSy1wCLOKbWxHaHiu14wjsNYtiRCSgVuqEPVuDpErOlRdNnuRgipQfXRLjLN5A==}
     peerDependencies:
-      vue: 3.3.9
+      vue: 3.3.11
     dependencies:
-      '@vue/compiler-ssr': 3.3.9
-      '@vue/shared': 3.3.9
-      vue: 3.3.9(typescript@5.3.2)
+      '@vue/compiler-ssr': 3.3.11
+      '@vue/shared': 3.3.11
+      vue: 3.3.11(typescript@5.3.3)
 
-  /@vue/shared@3.3.9:
-    resolution: {integrity: sha512-ZE0VTIR0LmYgeyhurPTpy4KzKsuDyQbMSdM49eKkMnT5X4VfFBLysMzjIZhLEFQYjjOVVfbvUDHckwjDFiO2eA==}
+  /@vue/shared@3.3.11:
+    resolution: {integrity: sha512-u2G8ZQ9IhMWTMXaWqZycnK4UthG1fA238CD+DP4Dm4WJi5hdUKKLg0RMRaRpDPNMdkTwIDkp7WtD0Rd9BH9fLw==}
 
-  /@vue/test-utils@2.4.2(vue@3.3.9):
-    resolution: {integrity: sha512-07lLjpG1o9tEBoWQfVOFhDT7+WFCdDeECoeSdzOuVgIi6nxb2JDLGNNOV6+3crPpyg/jMlIocj96UROcgomiGg==}
+  /@vue/test-utils@2.4.3(vue@3.3.11):
+    resolution: {integrity: sha512-F4K7mF+ad++VlTrxMJVRnenKSJmO6fkQt2wpRDiKDesQMkfpniGWsqEi/JevxGBo2qEkwwjvTUAoiGJLNx++CA==}
     peerDependencies:
       '@vue/server-renderer': ^3.0.1
       vue: ^3.0.1
@@ -1263,8 +1263,8 @@ packages:
         optional: true
     dependencies:
       js-beautify: 1.14.11
-      vue: 3.3.9(typescript@5.3.2)
-      vue-component-type-helpers: 1.8.22
+      vue: 3.3.11(typescript@5.3.3)
+      vue-component-type-helpers: 1.8.25
     dev: true
 
   /@vue/tsconfig@0.4.0:
@@ -1284,8 +1284,8 @@ packages:
       acorn: 8.11.2
     dev: true
 
-  /acorn-walk@8.3.0:
-    resolution: {integrity: sha512-FS7hV565M5l1R08MXqo8odwMTB02C2UqzB17RVgu9EyuYFBqJZ3/ZY97sQD5FewVu1UyDFc1yztUDrAwT0EypA==}
+  /acorn-walk@8.3.1:
+    resolution: {integrity: sha512-TgUZgYvqZprrl7YldZNoa9OciCAyZR+Ejm9eXzKCmjsF5IKp/wgQ7Z/ZpjpGTIUPwrHQIcYeI8qDh4PsEwxMbw==}
     engines: {node: '>=0.4.0'}
     dev: true
 
@@ -1471,15 +1471,15 @@ packages:
       fill-range: 7.0.1
     dev: true
 
-  /browserslist@4.22.1:
-    resolution: {integrity: sha512-FEVc202+2iuClEhZhrWy6ZiAcRLvNMyYcxZ8raemul1DYVOVdFsbqckWLdsixQZCpJlwe77Z3UTalE7jsjnKfQ==}
+  /browserslist@4.22.2:
+    resolution: {integrity: sha512-0UgcrvQmBDvZHFGdYUehrCNIazki7/lUP3kkoi/r3YB2amZbFM9J43ZRkJTXBUZK4gmx56+Sqk9+Vs9mwZx9+A==}
     engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7}
     hasBin: true
     dependencies:
-      caniuse-lite: 1.0.30001565
-      electron-to-chromium: 1.4.595
-      node-releases: 2.0.13
-      update-browserslist-db: 1.0.13(browserslist@4.22.1)
+      caniuse-lite: 1.0.30001570
+      electron-to-chromium: 1.4.611
+      node-releases: 2.0.14
+      update-browserslist-db: 1.0.13(browserslist@4.22.2)
     dev: true
 
   /bundle-name@3.0.0:
@@ -1512,8 +1512,8 @@ packages:
     engines: {node: '>=10'}
     dev: true
 
-  /caniuse-lite@1.0.30001565:
-    resolution: {integrity: sha512-xrE//a3O7TP0vaJ8ikzkD2c2NgcVUvsEe2IvFTntV4Yd1Z9FVzh+gW+enX96L0psrbaFMcVcH2l90xNuGDWc8w==}
+  /caniuse-lite@1.0.30001570:
+    resolution: {integrity: sha512-+3e0ASu4sw1SWaoCtvPeyXp+5PsjigkSt8OXZbF9StH5pQWbxEjLAZE3n8Aup5udop1uRiKA7a4utUk/uoSpUw==}
     dev: true
 
   /chai@4.3.10:
@@ -1630,8 +1630,8 @@ packages:
       rrweb-cssom: 0.6.0
     dev: true
 
-  /csstype@3.1.2:
-    resolution: {integrity: sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==}
+  /csstype@3.1.3:
+    resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==}
 
   /data-urls@5.0.0:
     resolution: {integrity: sha512-ZYP5VBHshaDAiVZxjbRVcFJpc+4xGgT0bK3vzy1HLN8jTO975HEbuYzZJcHoQEY5K1a0z8YayJkyVETa08eNTg==}
@@ -1791,8 +1791,8 @@ packages:
     resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==}
     dev: false
 
-  /electron-to-chromium@1.4.595:
-    resolution: {integrity: sha512-+ozvXuamBhDOKvMNUQvecxfbyICmIAwS4GpLmR0bsiSBlGnLaOcs2Cj7J8XSbW+YEaN3Xl3ffgpm+srTUWFwFQ==}
+  /electron-to-chromium@1.4.611:
+    resolution: {integrity: sha512-ZtRpDxrjHapOwxtv+nuth5ByB8clyn8crVynmRNGO3wG3LOp8RTcyZDqwaI6Ng6y8FCK2hVZmJoqwCskKbNMaw==}
     dev: true
 
   /emoji-regex@8.0.0:
@@ -1851,7 +1851,7 @@ packages:
       is-weakref: 1.0.2
       object-inspect: 1.13.1
       object-keys: 1.1.1
-      object.assign: 4.1.4
+      object.assign: 4.1.5
       regexp.prototype.flags: 1.5.1
       safe-array-concat: 1.0.1
       safe-regex-test: 1.0.0
@@ -1890,34 +1890,34 @@ packages:
       is-symbol: 1.0.4
     dev: true
 
-  /esbuild@0.19.8:
-    resolution: {integrity: sha512-l7iffQpT2OrZfH2rXIp7/FkmaeZM0vxbxN9KfiCwGYuZqzMg/JdvX26R31Zxn/Pxvsrg3Y9N6XTcnknqDyyv4w==}
+  /esbuild@0.19.9:
+    resolution: {integrity: sha512-U9CHtKSy+EpPsEBa+/A2gMs/h3ylBC0H0KSqIg7tpztHerLi6nrrcoUJAkNCEPumx8yJ+Byic4BVwHgRbN0TBg==}
     engines: {node: '>=12'}
     hasBin: true
     requiresBuild: true
     optionalDependencies:
-      '@esbuild/android-arm': 0.19.8
-      '@esbuild/android-arm64': 0.19.8
-      '@esbuild/android-x64': 0.19.8
-      '@esbuild/darwin-arm64': 0.19.8
-      '@esbuild/darwin-x64': 0.19.8
-      '@esbuild/freebsd-arm64': 0.19.8
-      '@esbuild/freebsd-x64': 0.19.8
-      '@esbuild/linux-arm': 0.19.8
-      '@esbuild/linux-arm64': 0.19.8
-      '@esbuild/linux-ia32': 0.19.8
-      '@esbuild/linux-loong64': 0.19.8
-      '@esbuild/linux-mips64el': 0.19.8
-      '@esbuild/linux-ppc64': 0.19.8
-      '@esbuild/linux-riscv64': 0.19.8
-      '@esbuild/linux-s390x': 0.19.8
-      '@esbuild/linux-x64': 0.19.8
-      '@esbuild/netbsd-x64': 0.19.8
-      '@esbuild/openbsd-x64': 0.19.8
-      '@esbuild/sunos-x64': 0.19.8
-      '@esbuild/win32-arm64': 0.19.8
-      '@esbuild/win32-ia32': 0.19.8
-      '@esbuild/win32-x64': 0.19.8
+      '@esbuild/android-arm': 0.19.9
+      '@esbuild/android-arm64': 0.19.9
+      '@esbuild/android-x64': 0.19.9
+      '@esbuild/darwin-arm64': 0.19.9
+      '@esbuild/darwin-x64': 0.19.9
+      '@esbuild/freebsd-arm64': 0.19.9
+      '@esbuild/freebsd-x64': 0.19.9
+      '@esbuild/linux-arm': 0.19.9
+      '@esbuild/linux-arm64': 0.19.9
+      '@esbuild/linux-ia32': 0.19.9
+      '@esbuild/linux-loong64': 0.19.9
+      '@esbuild/linux-mips64el': 0.19.9
+      '@esbuild/linux-ppc64': 0.19.9
+      '@esbuild/linux-riscv64': 0.19.9
+      '@esbuild/linux-s390x': 0.19.9
+      '@esbuild/linux-x64': 0.19.9
+      '@esbuild/netbsd-x64': 0.19.9
+      '@esbuild/openbsd-x64': 0.19.9
+      '@esbuild/sunos-x64': 0.19.9
+      '@esbuild/win32-arm64': 0.19.9
+      '@esbuild/win32-ia32': 0.19.9
+      '@esbuild/win32-x64': 0.19.9
     dev: true
 
   /escalade@3.1.1:
@@ -1939,13 +1939,13 @@ packages:
     engines: {node: '>=10'}
     dev: true
 
-  /eslint-config-prettier@8.10.0(eslint@8.54.0):
+  /eslint-config-prettier@8.10.0(eslint@8.55.0):
     resolution: {integrity: sha512-SM8AMJdeQqRYT9O9zguiruQZaN7+z+E4eAP9oiLNGKMtomwaB1E9dcgUD6ZAn/eQAb52USbvezbiljfZUhbJcg==}
     hasBin: true
     peerDependencies:
       eslint: '>=7.0.0'
     dependencies:
-      eslint: 8.54.0
+      eslint: 8.55.0
     dev: true
 
   /eslint-define-config@2.0.0:
@@ -1963,7 +1963,7 @@ packages:
       - supports-color
     dev: true
 
-  /eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@6.13.0)(eslint-plugin-import@2.29.0)(eslint@8.54.0):
+  /eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@6.14.0)(eslint-plugin-import@2.29.0)(eslint@8.55.0):
     resolution: {integrity: sha512-xgdptdoi5W3niYeuQxKmzVDTATvLYqhpwmykwsh7f6HIOStGWEIL9iqZgQDF9u9OEzrRwR8no5q2VT+bjAujTg==}
     engines: {node: ^14.18.0 || >=16.0.0}
     peerDependencies:
@@ -1972,9 +1972,9 @@ packages:
     dependencies:
       debug: 4.3.4
       enhanced-resolve: 5.15.0
-      eslint: 8.54.0
-      eslint-module-utils: 2.8.0(@typescript-eslint/parser@6.13.0)(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1)(eslint@8.54.0)
-      eslint-plugin-import: 2.29.0(@typescript-eslint/parser@6.13.0)(eslint-import-resolver-typescript@3.6.1)(eslint@8.54.0)
+      eslint: 8.55.0
+      eslint-module-utils: 2.8.0(@typescript-eslint/parser@6.14.0)(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1)(eslint@8.55.0)
+      eslint-plugin-import: 2.29.0(@typescript-eslint/parser@6.14.0)(eslint-import-resolver-typescript@3.6.1)(eslint@8.55.0)
       fast-glob: 3.3.2
       get-tsconfig: 4.7.2
       is-core-module: 2.13.1
@@ -1986,7 +1986,7 @@ packages:
       - supports-color
     dev: true
 
-  /eslint-module-utils@2.8.0(@typescript-eslint/parser@6.13.0)(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1)(eslint@8.54.0):
+  /eslint-module-utils@2.8.0(@typescript-eslint/parser@6.14.0)(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1)(eslint@8.55.0):
     resolution: {integrity: sha512-aWajIYfsqCKRDgUfjEXNN/JlrzauMuSEy5sbd7WXbtW3EH6A6MpwEh42c7qD+MqQo9QMJ6fWLAeIJynx0g6OAw==}
     engines: {node: '>=4'}
     peerDependencies:
@@ -2007,16 +2007,16 @@ packages:
       eslint-import-resolver-webpack:
         optional: true
     dependencies:
-      '@typescript-eslint/parser': 6.13.0(eslint@8.54.0)(typescript@5.3.2)
+      '@typescript-eslint/parser': 6.14.0(eslint@8.55.0)(typescript@5.3.3)
       debug: 3.2.7
-      eslint: 8.54.0
+      eslint: 8.55.0
       eslint-import-resolver-node: 0.3.9
-      eslint-import-resolver-typescript: 3.6.1(@typescript-eslint/parser@6.13.0)(eslint-plugin-import@2.29.0)(eslint@8.54.0)
+      eslint-import-resolver-typescript: 3.6.1(@typescript-eslint/parser@6.14.0)(eslint-plugin-import@2.29.0)(eslint@8.55.0)
     transitivePeerDependencies:
       - supports-color
     dev: true
 
-  /eslint-plugin-import@2.29.0(@typescript-eslint/parser@6.13.0)(eslint-import-resolver-typescript@3.6.1)(eslint@8.54.0):
+  /eslint-plugin-import@2.29.0(@typescript-eslint/parser@6.14.0)(eslint-import-resolver-typescript@3.6.1)(eslint@8.55.0):
     resolution: {integrity: sha512-QPOO5NO6Odv5lpoTkddtutccQjysJuFxoPS7fAHO+9m9udNHvTCPSAMW9zGAYj8lAIdr40I8yPCdUYrncXtrwg==}
     engines: {node: '>=4'}
     peerDependencies:
@@ -2026,16 +2026,16 @@ packages:
       '@typescript-eslint/parser':
         optional: true
     dependencies:
-      '@typescript-eslint/parser': 6.13.0(eslint@8.54.0)(typescript@5.3.2)
+      '@typescript-eslint/parser': 6.14.0(eslint@8.55.0)(typescript@5.3.3)
       array-includes: 3.1.7
       array.prototype.findlastindex: 1.2.3
       array.prototype.flat: 1.3.2
       array.prototype.flatmap: 1.3.2
       debug: 3.2.7
       doctrine: 2.1.0
-      eslint: 8.54.0
+      eslint: 8.55.0
       eslint-import-resolver-node: 0.3.9
-      eslint-module-utils: 2.8.0(@typescript-eslint/parser@6.13.0)(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1)(eslint@8.54.0)
+      eslint-module-utils: 2.8.0(@typescript-eslint/parser@6.14.0)(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1)(eslint@8.55.0)
       hasown: 2.0.0
       is-core-module: 2.13.1
       is-glob: 4.0.3
@@ -2051,7 +2051,7 @@ packages:
       - supports-color
     dev: true
 
-  /eslint-plugin-prettier@5.0.1(eslint-config-prettier@8.10.0)(eslint@8.54.0)(prettier@3.1.0):
+  /eslint-plugin-prettier@5.0.1(eslint-config-prettier@8.10.0)(eslint@8.55.0)(prettier@3.1.1):
     resolution: {integrity: sha512-m3u5RnR56asrwV/lDC4GHorlW75DsFfmUcjfCYylTUs85dBRnB7VM6xG8eCMJdeDRnppzmxZVf1GEPJvl1JmNg==}
     engines: {node: ^14.18.0 || >=16.0.0}
     peerDependencies:
@@ -2065,26 +2065,26 @@ packages:
       eslint-config-prettier:
         optional: true
     dependencies:
-      eslint: 8.54.0
-      eslint-config-prettier: 8.10.0(eslint@8.54.0)
-      prettier: 3.1.0
+      eslint: 8.55.0
+      eslint-config-prettier: 8.10.0(eslint@8.55.0)
+      prettier: 3.1.1
       prettier-linter-helpers: 1.0.0
-      synckit: 0.8.5
+      synckit: 0.8.6
     dev: true
 
-  /eslint-plugin-vue@9.18.1(eslint@8.54.0):
-    resolution: {integrity: sha512-7hZFlrEgg9NIzuVik2I9xSnJA5RsmOfueYgsUGUokEDLJ1LHtxO0Pl4duje1BriZ/jDWb+44tcIlC3yi0tdlZg==}
+  /eslint-plugin-vue@9.19.2(eslint@8.55.0):
+    resolution: {integrity: sha512-CPDqTOG2K4Ni2o4J5wixkLVNwgctKXFu6oBpVJlpNq7f38lh9I80pRTouZSJ2MAebPJlINU/KTFSXyQfBUlymA==}
     engines: {node: ^14.17.0 || >=16.0.0}
     peerDependencies:
       eslint: ^6.2.0 || ^7.0.0 || ^8.0.0
     dependencies:
-      '@eslint-community/eslint-utils': 4.4.0(eslint@8.54.0)
-      eslint: 8.54.0
+      '@eslint-community/eslint-utils': 4.4.0(eslint@8.55.0)
+      eslint: 8.55.0
       natural-compare: 1.4.0
       nth-check: 2.1.1
       postcss-selector-parser: 6.0.13
       semver: 7.5.4
-      vue-eslint-parser: 9.3.2(eslint@8.54.0)
+      vue-eslint-parser: 9.3.2(eslint@8.55.0)
       xml-name-validator: 4.0.0
     transitivePeerDependencies:
       - supports-color
@@ -2103,15 +2103,15 @@ packages:
     engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
     dev: true
 
-  /eslint@8.54.0:
-    resolution: {integrity: sha512-NY0DfAkM8BIZDVl6PgSa1ttZbx3xHgJzSNJKYcQglem6CppHyMhRIQkBVSSMaSRnLhig3jsDbEzOjwCVt4AmmA==}
+  /eslint@8.55.0:
+    resolution: {integrity: sha512-iyUUAM0PCKj5QpwGfmCAG9XXbZCWsqP/eWAWrG/W0umvjuLRBECwSFdt+rCntju0xEH7teIABPwXpahftIaTdA==}
     engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
     hasBin: true
     dependencies:
-      '@eslint-community/eslint-utils': 4.4.0(eslint@8.54.0)
+      '@eslint-community/eslint-utils': 4.4.0(eslint@8.55.0)
       '@eslint-community/regexpp': 4.10.0
-      '@eslint/eslintrc': 2.1.3
-      '@eslint/js': 8.54.0
+      '@eslint/eslintrc': 2.1.4
+      '@eslint/js': 8.55.0
       '@humanwhocodes/config-array': 0.11.13
       '@humanwhocodes/module-importer': 1.0.1
       '@nodelib/fs.walk': 1.2.8
@@ -2131,7 +2131,7 @@ packages:
       file-entry-cache: 6.0.1
       find-up: 5.0.0
       glob-parent: 6.0.2
-      globals: 13.23.0
+      globals: 13.24.0
       graphemer: 1.4.0
       ignore: 5.3.0
       imurmurhash: 0.1.4
@@ -2221,6 +2221,21 @@ packages:
       strip-final-newline: 3.0.0
     dev: true
 
+  /execa@8.0.1:
+    resolution: {integrity: sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==}
+    engines: {node: '>=16.17'}
+    dependencies:
+      cross-spawn: 7.0.3
+      get-stream: 8.0.1
+      human-signals: 5.0.0
+      is-stream: 3.0.0
+      merge-stream: 2.0.0
+      npm-run-path: 5.1.0
+      onetime: 6.0.0
+      signal-exit: 4.1.0
+      strip-final-newline: 3.0.0
+    dev: true
+
   /fast-deep-equal@3.1.3:
     resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==}
     dev: true
@@ -2385,6 +2400,11 @@ packages:
     engines: {node: '>=10'}
     dev: true
 
+  /get-stream@8.0.1:
+    resolution: {integrity: sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==}
+    engines: {node: '>=16'}
+    dev: true
+
   /get-symbol-description@1.0.0:
     resolution: {integrity: sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==}
     engines: {node: '>= 0.4'}
@@ -2441,8 +2461,8 @@ packages:
     engines: {node: '>=4'}
     dev: true
 
-  /globals@13.23.0:
-    resolution: {integrity: sha512-XAmF0RjlrjY23MA51q3HltdlGxUpXPvg0GioKiD9X6HD28iMjo2dKC8Vqwm7lne4GNr78+RHTfliktR6ZH09wA==}
+  /globals@13.24.0:
+    resolution: {integrity: sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==}
     engines: {node: '>=8'}
     dependencies:
       type-fest: 0.20.2
@@ -2582,6 +2602,11 @@ packages:
     engines: {node: '>=14.18.0'}
     dev: true
 
+  /human-signals@5.0.0:
+    resolution: {integrity: sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==}
+    engines: {node: '>=16.17.0'}
+    dev: true
+
   /iconv-lite@0.6.3:
     resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==}
     engines: {node: '>=0.10.0'}
@@ -2863,11 +2888,11 @@ packages:
       argparse: 2.0.1
     dev: true
 
-  /jsdom@23.0.0:
-    resolution: {integrity: sha512-cbL/UCtohJguhFC7c2/hgW6BeZCNvP7URQGnx9tSJRYKCdnfbfWOrtuLTMfiB2VxKsx5wPHVsh/J0aBy9lIIhQ==}
+  /jsdom@23.0.1:
+    resolution: {integrity: sha512-2i27vgvlUsGEBO9+/kJQRbtqtm+191b5zAZrU/UezVmnC2dlDAFLgDYJvAEi94T4kjsRKkezEtLQTgsNEsW2lQ==}
     engines: {node: '>=18'}
     peerDependencies:
-      canvas: ^3.0.0
+      canvas: ^2.11.2
     peerDependenciesMeta:
       canvas:
         optional: true
@@ -2891,7 +2916,7 @@ packages:
       whatwg-encoding: 3.1.1
       whatwg-mimetype: 4.0.0
       whatwg-url: 14.0.0
-      ws: 8.14.2
+      ws: 8.15.1
       xml-name-validator: 5.0.0
     transitivePeerDependencies:
       - bufferutil
@@ -2948,9 +2973,12 @@ packages:
       type-check: 0.4.0
     dev: true
 
-  /local-pkg@0.4.3:
-    resolution: {integrity: sha512-SFppqq5p42fe2qcZQqqEOiVRXl+WCP1MdT6k7BDEW1j++sp5fIY+/fdRQitvKgB5BrBcmrs5m/L0v2FrU5MY1g==}
+  /local-pkg@0.5.0:
+    resolution: {integrity: sha512-ok6z3qlYyCDS4ZEU27HaU6x/xZa9Whf8jD4ptH5UZTQYZVYeb9bnZ3ojVhiJNLiXK1Hfc0GNbLXcmZ5plLDDBg==}
     engines: {node: '>=14'}
+    dependencies:
+      mlly: 1.4.2
+      pkg-types: 1.0.3
     dev: true
 
   /locate-path@6.0.0:
@@ -2998,6 +3026,14 @@ packages:
     dependencies:
       '@jridgewell/sourcemap-codec': 1.4.15
 
+  /magicast@0.3.2:
+    resolution: {integrity: sha512-Fjwkl6a0syt9TFN0JSYpOybxiMCkYNEeOTnOTNRbjphirLakznZXAqrXgj/7GG3D1dvETONNwrBfinvAbpunDg==}
+    dependencies:
+      '@babel/parser': 7.23.6
+      '@babel/types': 7.23.6
+      source-map-js: 1.0.2
+    dev: true
+
   /make-dir@4.0.0:
     resolution: {integrity: sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==}
     engines: {node: '>=10'}
@@ -3108,8 +3144,8 @@ packages:
     resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==}
     dev: true
 
-  /node-releases@2.0.13:
-    resolution: {integrity: sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ==}
+  /node-releases@2.0.14:
+    resolution: {integrity: sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==}
     dev: true
 
   /nopt@7.2.0:
@@ -3153,8 +3189,8 @@ packages:
     engines: {node: '>= 0.4'}
     dev: true
 
-  /object.assign@4.1.4:
-    resolution: {integrity: sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==}
+  /object.assign@4.1.5:
+    resolution: {integrity: sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ==}
     engines: {node: '>= 0.4'}
     dependencies:
       call-bind: 1.0.5
@@ -3246,9 +3282,9 @@ packages:
       yocto-queue: 0.1.0
     dev: true
 
-  /p-limit@4.0.0:
-    resolution: {integrity: sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ==}
-    engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
+  /p-limit@5.0.0:
+    resolution: {integrity: sha512-/Eaoq+QyLSiXQ4lyYV23f14mZRQcXnxfHrN0vCai+ak9G0pp9iEQukIIZq5NccEvwRB8PUnZT0KsOoDCINS1qQ==}
+    engines: {node: '>=18'}
     dependencies:
       yocto-queue: 1.0.0
     dev: true
@@ -3347,8 +3383,8 @@ packages:
       util-deprecate: 1.0.2
     dev: true
 
-  /postcss@8.4.31:
-    resolution: {integrity: sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==}
+  /postcss@8.4.32:
+    resolution: {integrity: sha512-D/kj5JNu6oo2EIy+XL/26JEDTlIbB8hw85G8StOE6L74RQAVVP5rej6wxCNqyMbR4RkPfqvezVbPw81Ngd6Kcw==}
     engines: {node: ^10 || ^12 || >=14}
     dependencies:
       nanoid: 3.3.7
@@ -3367,8 +3403,8 @@ packages:
       fast-diff: 1.3.0
     dev: true
 
-  /prettier@3.1.0:
-    resolution: {integrity: sha512-TQLvXjq5IAibjh8EpBIkNKxO749UEWABoiIZehEPiY4GNpVdhaFKqSTu+QrlU6D2dPAfubRmtJTi4K4YkQ5eXw==}
+  /prettier@3.1.1:
+    resolution: {integrity: sha512-22UbSzg8luF4UuZtzgiUOfcGM8s4tjBv6dJRT7j275NXsy2jb4aJa4NNveul5x4eqlF1wuhuR2RElK71RvmVaw==}
     engines: {node: '>=14'}
     hasBin: true
     dev: true
@@ -3463,23 +3499,24 @@ packages:
       glob: 10.3.10
     dev: true
 
-  /rollup@4.6.0:
-    resolution: {integrity: sha512-R8i5Her4oO1LiMQ3jKf7MUglYV/mhQ5g5OKeld5CnkmPdIGo79FDDQYqPhq/PCVuTQVuxsWgIbDy9F+zdHn80w==}
+  /rollup@4.9.0:
+    resolution: {integrity: sha512-bUHW/9N21z64gw8s6tP4c88P382Bq/L5uZDowHlHx6s/QWpjJXivIAbEw6LZthgSvlEizZBfLC4OAvWe7aoF7A==}
     engines: {node: '>=18.0.0', npm: '>=8.0.0'}
     hasBin: true
     optionalDependencies:
-      '@rollup/rollup-android-arm-eabi': 4.6.0
-      '@rollup/rollup-android-arm64': 4.6.0
-      '@rollup/rollup-darwin-arm64': 4.6.0
-      '@rollup/rollup-darwin-x64': 4.6.0
-      '@rollup/rollup-linux-arm-gnueabihf': 4.6.0
-      '@rollup/rollup-linux-arm64-gnu': 4.6.0
-      '@rollup/rollup-linux-arm64-musl': 4.6.0
-      '@rollup/rollup-linux-x64-gnu': 4.6.0
-      '@rollup/rollup-linux-x64-musl': 4.6.0
-      '@rollup/rollup-win32-arm64-msvc': 4.6.0
-      '@rollup/rollup-win32-ia32-msvc': 4.6.0
-      '@rollup/rollup-win32-x64-msvc': 4.6.0
+      '@rollup/rollup-android-arm-eabi': 4.9.0
+      '@rollup/rollup-android-arm64': 4.9.0
+      '@rollup/rollup-darwin-arm64': 4.9.0
+      '@rollup/rollup-darwin-x64': 4.9.0
+      '@rollup/rollup-linux-arm-gnueabihf': 4.9.0
+      '@rollup/rollup-linux-arm64-gnu': 4.9.0
+      '@rollup/rollup-linux-arm64-musl': 4.9.0
+      '@rollup/rollup-linux-riscv64-gnu': 4.9.0
+      '@rollup/rollup-linux-x64-gnu': 4.9.0
+      '@rollup/rollup-linux-x64-musl': 4.9.0
+      '@rollup/rollup-win32-arm64-msvc': 4.9.0
+      '@rollup/rollup-win32-ia32-msvc': 4.9.0
+      '@rollup/rollup-win32-x64-msvc': 4.9.0
       fsevents: 2.3.3
     dev: true
 
@@ -3649,8 +3686,8 @@ packages:
     engines: {node: '>= 0.8'}
     dev: false
 
-  /std-env@3.5.0:
-    resolution: {integrity: sha512-JGUEaALvL0Mf6JCfYnJOTcobY+Nc7sG/TemDRBqCA0wEr4DER7zDchaaixTlmOxAjG1uRJmX82EQcxwTQTkqVA==}
+  /std-env@3.6.0:
+    resolution: {integrity: sha512-aFZ19IgVmhdB2uX599ve2kE6BIE3YMnQ6Gp6BURhW/oIzpXGKr878TQfAQZn1+i0Flcc/UKUy1gOlcfaUBCryg==}
     dev: true
 
   /string-width@4.2.3:
@@ -3763,8 +3800,8 @@ packages:
     resolution: {integrity: sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==}
     dev: true
 
-  /synckit@0.8.5:
-    resolution: {integrity: sha512-L1dapNV6vu2s/4Sputv8xGsCdAVlb5nRDMFU/E27D44l5U6cw1g0dGd45uLc+OXjNMmF4ntiMdCimzcjFKQI8Q==}
+  /synckit@0.8.6:
+    resolution: {integrity: sha512-laHF2savN6sMeHCjLRkheIU4wo3Zg9Ln5YOjOo7sZ5dVQW8yF5pPE5SIw1dsPhq3TRp1jisKRCdPhfs/1WMqDA==}
     engines: {node: ^14.18.0 || >=16.0.0}
     dependencies:
       '@pkgr/utils': 2.4.2
@@ -3793,8 +3830,8 @@ packages:
     resolution: {integrity: sha512-65NKvSuAVDP/n4CqH+a9w2kTlLReS9vhsAP06MWx+/89nMinJyB2icyl58RIcqCmIggpojIGeuJGhjU1aGMBSg==}
     dev: true
 
-  /tinypool@0.7.0:
-    resolution: {integrity: sha512-zSYNUlYSMhJ6Zdou4cJwo/p7w5nmAH17GRfU/ui3ctvjXFErXXkruT4MWW6poDeXgCaIBlGLrfU6TbTXxyGMww==}
+  /tinypool@0.8.1:
+    resolution: {integrity: sha512-zBTCK0cCgRROxvs9c0CGK838sPkeokNGdQVUUwHAbynHFlmyJYj825f/oRs528HaIJ97lo0pLIlDUzwN+IorWg==}
     engines: {node: '>=14.0.0'}
     dev: true
 
@@ -3841,13 +3878,13 @@ packages:
       punycode: 2.3.1
     dev: true
 
-  /ts-api-utils@1.0.3(typescript@5.3.2):
+  /ts-api-utils@1.0.3(typescript@5.3.3):
     resolution: {integrity: sha512-wNMeqtMz5NtwpT/UZGY5alT+VoKdSsOOP/kqHFcUW1P/VRhH2wJ48+DN2WwUliNbQ976ETwDL0Ifd2VVvgonvg==}
     engines: {node: '>=16.13.0'}
     peerDependencies:
       typescript: '>=4.2.0'
     dependencies:
-      typescript: 5.3.2
+      typescript: 5.3.3
     dev: true
 
   /tsconfig-paths@3.14.2:
@@ -3918,8 +3955,8 @@ packages:
       is-typed-array: 1.1.12
     dev: true
 
-  /typescript@5.3.2:
-    resolution: {integrity: sha512-6l+RyNy7oAHDfxC4FzSJcz9vnjTKxrLpDG5M2Vu4SHRVNg6xzqZp6LYSR9zjqQTu8DU/f5xwxUdADOkbrIX2gQ==}
+  /typescript@5.3.3:
+    resolution: {integrity: sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==}
     engines: {node: '>=14.17'}
     hasBin: true
 
@@ -3955,13 +3992,13 @@ packages:
     engines: {node: '>=8'}
     dev: true
 
-  /update-browserslist-db@1.0.13(browserslist@4.22.1):
+  /update-browserslist-db@1.0.13(browserslist@4.22.2):
     resolution: {integrity: sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==}
     hasBin: true
     peerDependencies:
       browserslist: '>= 4.21.0'
     dependencies:
-      browserslist: 4.22.1
+      browserslist: 4.22.2
       escalade: 3.1.1
       picocolors: 1.0.0
     dev: true
@@ -3992,17 +4029,16 @@ packages:
       convert-source-map: 2.0.0
     dev: true
 
-  /vite-node@0.34.6(@types/node@20.10.0):
-    resolution: {integrity: sha512-nlBMJ9x6n7/Amaz6F3zJ97EBwR2FkzhBRxF5e+jE6LA3yi6Wtc2lyTij1OnDMIr34v5g/tVQtsVAzhT0jc5ygA==}
-    engines: {node: '>=v14.18.0'}
+  /vite-node@1.0.4(@types/node@20.10.4):
+    resolution: {integrity: sha512-9xQQtHdsz5Qn8hqbV7UKqkm8YkJhzT/zr41Dmt5N7AlD8hJXw/Z7y0QiD5I8lnTthV9Rvcvi0QW7PI0Fq83ZPg==}
+    engines: {node: ^18.0.0 || >=20.0.0}
     hasBin: true
     dependencies:
       cac: 6.7.14
       debug: 4.3.4
-      mlly: 1.4.2
       pathe: 1.1.1
       picocolors: 1.0.0
-      vite: 5.0.2(@types/node@20.10.0)
+      vite: 5.0.9(@types/node@20.10.4)
     transitivePeerDependencies:
       - '@types/node'
       - less
@@ -4014,8 +4050,8 @@ packages:
       - terser
     dev: true
 
-  /vite@5.0.2(@types/node@20.10.0):
-    resolution: {integrity: sha512-6CCq1CAJCNM1ya2ZZA7+jS2KgnhbzvxakmlIjN24cF/PXhRMzpM/z8QgsVJA/Dm5fWUWnVEsmtBoMhmerPxT0g==}
+  /vite@5.0.9(@types/node@20.10.4):
+    resolution: {integrity: sha512-wVqMd5kp28QWGgfYPDfrj771VyHTJ4UDlCteLH7bJDGDEamaz5hV8IX6h1brSGgnnyf9lI2RnzXq/JmD0c2wwg==}
     engines: {node: ^18.0.0 || >=20.0.0}
     hasBin: true
     peerDependencies:
@@ -4042,30 +4078,30 @@ packages:
       terser:
         optional: true
     dependencies:
-      '@types/node': 20.10.0
-      esbuild: 0.19.8
-      postcss: 8.4.31
-      rollup: 4.6.0
+      '@types/node': 20.10.4
+      esbuild: 0.19.9
+      postcss: 8.4.32
+      rollup: 4.9.0
     optionalDependencies:
       fsevents: 2.3.3
     dev: true
 
-  /vitest@0.34.6(jsdom@23.0.0):
-    resolution: {integrity: sha512-+5CALsOvbNKnS+ZHMXtuUC7nL8/7F1F2DnHGjSsszX8zCjWSSviphCb/NuS9Nzf4Q03KyyDRBAXhF/8lffME4Q==}
-    engines: {node: '>=v14.18.0'}
+  /vitest@1.0.4(@types/node@20.10.4)(jsdom@23.0.1):
+    resolution: {integrity: sha512-s1GQHp/UOeWEo4+aXDOeFBJwFzL6mjycbQwwKWX2QcYfh/7tIerS59hWQ20mxzupTJluA2SdwiBuWwQHH67ckg==}
+    engines: {node: ^18.0.0 || >=20.0.0}
     hasBin: true
     peerDependencies:
       '@edge-runtime/vm': '*'
-      '@vitest/browser': '*'
-      '@vitest/ui': '*'
+      '@types/node': ^18.0.0 || >=20.0.0
+      '@vitest/browser': ^1.0.0
+      '@vitest/ui': ^1.0.0
       happy-dom: '*'
       jsdom: '*'
-      playwright: '*'
-      safaridriver: '*'
-      webdriverio: '*'
     peerDependenciesMeta:
       '@edge-runtime/vm':
         optional: true
+      '@types/node':
+        optional: true
       '@vitest/browser':
         optional: true
       '@vitest/ui':
@@ -4074,37 +4110,29 @@ packages:
         optional: true
       jsdom:
         optional: true
-      playwright:
-        optional: true
-      safaridriver:
-        optional: true
-      webdriverio:
-        optional: true
     dependencies:
-      '@types/chai': 4.3.11
-      '@types/chai-subset': 1.3.5
-      '@types/node': 20.10.0
-      '@vitest/expect': 0.34.6
-      '@vitest/runner': 0.34.6
-      '@vitest/snapshot': 0.34.6
-      '@vitest/spy': 0.34.6
-      '@vitest/utils': 0.34.6
-      acorn: 8.11.2
-      acorn-walk: 8.3.0
+      '@types/node': 20.10.4
+      '@vitest/expect': 1.0.4
+      '@vitest/runner': 1.0.4
+      '@vitest/snapshot': 1.0.4
+      '@vitest/spy': 1.0.4
+      '@vitest/utils': 1.0.4
+      acorn-walk: 8.3.1
       cac: 6.7.14
       chai: 4.3.10
       debug: 4.3.4
-      jsdom: 23.0.0
-      local-pkg: 0.4.3
+      execa: 8.0.1
+      jsdom: 23.0.1
+      local-pkg: 0.5.0
       magic-string: 0.30.5
       pathe: 1.1.1
       picocolors: 1.0.0
-      std-env: 3.5.0
+      std-env: 3.6.0
       strip-literal: 1.3.0
       tinybench: 2.5.1
-      tinypool: 0.7.0
-      vite: 5.0.2(@types/node@20.10.0)
-      vite-node: 0.34.6(@types/node@20.10.0)
+      tinypool: 0.8.1
+      vite: 5.0.9(@types/node@20.10.4)
+      vite-node: 1.0.4(@types/node@20.10.4)
       why-is-node-running: 2.2.2
     transitivePeerDependencies:
       - less
@@ -4116,18 +4144,18 @@ packages:
       - terser
     dev: true
 
-  /vue-component-type-helpers@1.8.22:
-    resolution: {integrity: sha512-LK3wJHs3vJxHG292C8cnsRusgyC5SEZDCzDCD01mdE/AoREFMl2tzLRuzwyuEsOIz13tqgBcnvysN3Lxsa14Fw==}
+  /vue-component-type-helpers@1.8.25:
+    resolution: {integrity: sha512-NCA6sekiJIMnMs4DdORxATXD+/NRkQpS32UC+I1KQJUasx+Z7MZUb3Y+MsKsFmX+PgyTYSteb73JW77AibaCCw==}
     dev: true
 
-  /vue-eslint-parser@9.3.2(eslint@8.54.0):
+  /vue-eslint-parser@9.3.2(eslint@8.55.0):
     resolution: {integrity: sha512-q7tWyCVaV9f8iQyIA5Mkj/S6AoJ9KBN8IeUSf3XEmBrOtxOZnfTg5s4KClbZBCK3GtnT/+RyCLZyDHuZwTuBjg==}
     engines: {node: ^14.17.0 || >=16.0.0}
     peerDependencies:
       eslint: '>=6.0.0'
     dependencies:
       debug: 4.3.4
-      eslint: 8.54.0
+      eslint: 8.55.0
       eslint-scope: 7.2.2
       eslint-visitor-keys: 3.4.3
       espree: 9.6.1
@@ -4138,29 +4166,29 @@ packages:
       - supports-color
     dev: true
 
-  /vue-router@4.2.5(vue@3.3.9):
+  /vue-router@4.2.5(vue@3.3.11):
     resolution: {integrity: sha512-DIUpKcyg4+PTQKfFPX88UWhlagBEBEfJ5A8XDXRJLUnZOvcpMF8o/dnL90vpVkGaPbjvXazV/rC1qBKrZlFugw==}
     peerDependencies:
       vue: ^3.2.0
     dependencies:
       '@vue/devtools-api': 6.5.1
-      vue: 3.3.9(typescript@5.3.2)
+      vue: 3.3.11(typescript@5.3.3)
     dev: false
 
-  /vue@3.3.9(typescript@5.3.2):
-    resolution: {integrity: sha512-sy5sLCTR8m6tvUk1/ijri3Yqzgpdsmxgj6n6yl7GXXCXqVbmW2RCXe9atE4cEI6Iv7L89v5f35fZRRr5dChP9w==}
+  /vue@3.3.11(typescript@5.3.3):
+    resolution: {integrity: sha512-d4oBctG92CRO1cQfVBZp6WJAs0n8AK4Xf5fNjQCBeKCvMI1efGQ5E3Alt1slFJS9fZuPcFoiAiqFvQlv1X7t/w==}
     peerDependencies:
       typescript: '*'
     peerDependenciesMeta:
       typescript:
         optional: true
     dependencies:
-      '@vue/compiler-dom': 3.3.9
-      '@vue/compiler-sfc': 3.3.9
-      '@vue/runtime-dom': 3.3.9
-      '@vue/server-renderer': 3.3.9(vue@3.3.9)
-      '@vue/shared': 3.3.9
-      typescript: 5.3.2
+      '@vue/compiler-dom': 3.3.11
+      '@vue/compiler-sfc': 3.3.11
+      '@vue/runtime-dom': 3.3.11
+      '@vue/server-renderer': 3.3.11(vue@3.3.11)
+      '@vue/shared': 3.3.11
+      typescript: 5.3.3
 
   /w3c-xmlserializer@5.0.0:
     resolution: {integrity: sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==}
@@ -4254,8 +4282,8 @@ packages:
     resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==}
     dev: true
 
-  /ws@8.14.2:
-    resolution: {integrity: sha512-wEBG1ftX4jcglPxgFCMJmZ2PLtSbJ2Peg6TmpJFTbe9GZYOQCDPdMYu/Tm0/bGZkw8paZnJY45J4K2PZrLYq8g==}
+  /ws@8.15.1:
+    resolution: {integrity: sha512-W5OZiCjXEmk0yZ66ZN82beM5Sz7l7coYxpRkzS+p9PP+ToQry8szKh+61eNktr7EA9DOwvFGhfC605jDHbP6QQ==}
     engines: {node: '>=10.0.0'}
     peerDependencies:
       bufferutil: ^4.0.1