diff --git a/.gitignore b/.gitignore index b8939e3858..10ef12e4cd 100644 --- a/.gitignore +++ b/.gitignore @@ -359,9 +359,12 @@ out.yaml # helm **/Chart.lock -#Performance Tests +# npm dist +# Performance Tests +scripts/windows/dumps/dump-files + # ci .ci/package-lock.json @@ -374,4 +377,4 @@ dist !Applications/AdminUi/packages/* # Hardlinks for appsettings.override.json -Applications/**/appsettings.override.json \ No newline at end of file +Applications/**/appsettings.override.json diff --git a/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/.gitignore b/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/.gitignore new file mode 100644 index 0000000000..3f9a54c625 --- /dev/null +++ b/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/.gitignore @@ -0,0 +1 @@ +k6-outputs/ \ No newline at end of file diff --git a/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/PerformanceSnapshotCreator/Application/MessageDistributor/IMessageDistributor.cs b/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/PerformanceSnapshotCreator/Application/MessageDistributor/IMessageDistributor.cs deleted file mode 100644 index 95111d438c..0000000000 --- a/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/PerformanceSnapshotCreator/Application/MessageDistributor/IMessageDistributor.cs +++ /dev/null @@ -1,8 +0,0 @@ -using Backbone.PerformanceSnapshotCreator.PoolsFile; - -namespace Backbone.PerformanceSnapshotCreator.Application.MessageDistributor; - -public interface IMessageDistributor -{ - public void Distribute(IList pools); -} diff --git a/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/PerformanceSnapshotCreator/Application/RelationshipDistributor/IRelationshipDistributor.cs b/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/PerformanceSnapshotCreator/Application/RelationshipDistributor/IRelationshipDistributor.cs deleted file mode 100644 index 4189a5620f..0000000000 --- a/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/PerformanceSnapshotCreator/Application/RelationshipDistributor/IRelationshipDistributor.cs +++ /dev/null @@ -1,8 +0,0 @@ -using Backbone.PerformanceSnapshotCreator.PoolsFile; - -namespace Backbone.PerformanceSnapshotCreator.Application.RelationshipDistributor; - -public interface IRelationshipDistributor -{ - public void Distribute(IList pools); -} diff --git a/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/PerformanceSnapshotCreator/Properties/launchSettings.json b/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/PerformanceSnapshotCreator/Properties/launchSettings.json deleted file mode 100644 index d2a29e99b1..0000000000 --- a/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/PerformanceSnapshotCreator/Properties/launchSettings.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "profiles": { - "Pool Generator": { - "commandName": "Project", - "commandLineArgs": "GeneratePools --poolsFile pools.json" - }, - "Pool Generator Light": { - "commandName": "Project", - "commandLineArgs": "GeneratePools --poolsFile pools_light.json" - }, - "Pool Generator Test": { - "commandName": "Project", - "commandLineArgs": "GeneratePools --poolsFile pools_test.json" - }, - "Create Entities": { - "commandName": "Project", - "commandLineArgs": "CreateEntities --baseAddress http://localhost:8081 --clientId test --clientSecret test --poolsFile pools.json --ram selected-solution\\ram.csv" - }, - "Create Entities Light": { - "commandName": "Project", - "commandLineArgs": "CreateEntities --baseAddress http://localhost:8081 --clientId test --clientSecret test --poolsFile pools_light.json --ram light-solution\\ram.csv" - } - } -} diff --git a/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/README.md b/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/README.md index fd446426ef..08d0843aeb 100644 --- a/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/README.md +++ b/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/README.md @@ -6,23 +6,23 @@ The generation of a snapshot is a convoluted process which can be described in the following steps: -#### 1. Creation of a RaM distribution +#### 1. Creation of a _Relationships & Messages_ distribution -Using the `Identity.Pool.Creator` project, run the command with the arguemnts: +Run the `ConsumerApi.Tests.Performance.SnapshotCreator` project with the following arguemnts: -`GeneratePools --poolsFile ` +`GeneratePools --poolsFile ` Where `` is a pools configuration file. You can find examples of this file in this repository. This will use a mix of a manual algorithm with simulated annealing to create a solution. The time it takes to run the algorith depends mostly on the number of SA iterations. That number can be changed in code. -The execution creates a `ram.csv` file which must be passed to the next step. +The execution creates a `relationshipsAndMessages.csv` file which must be passed to the next step. #### 2. Creation of entities -Using the `Identity.Pool.Creator` project, run the command with the arguemnts: +Run the `ConsumerApi.Tests.Performance.SnapshotCreator` project with the following arguemnts: -`CreateEntities --baseAddress http://localhost:8081 --clientId test --clientSecret test --poolsFile pools.json --ram selected-solution\\ram.csv` +`CreateEntities --baseAddress --clientId --clientSecret --poolsFile --relationshipsAndMessages ` where: @@ -30,7 +30,7 @@ where: - `--clientId` is the client Id to use when addressing the API. - `--clientSecret` is the client Secret to use when addressing the API. - `--poolsFile` is the same file used in the step above. -- `--ram` the Relationships & Messages configuration created in the step above (csv file). +- `--relationshipsAndMessages` the Relationships & Messages configuration created in the step above (csv file). This command will create the following entities: @@ -54,41 +54,29 @@ The time it takes to run this command depends mostly on the number of entities t #### 3. Dumping the database -The specific way of doing this depends greatly on the way the database management system is running. This guide assumes docker is used. +Depending on which database you are using, you must run the appropriate script to dump the database to a file. -##### When using SQL Server: +When using SQL Server: ```sh -cd docker-compose -.\dump_sqlserver_bak.bat +scripts/windows/dumps/dump-sqlserver.ps1 ``` -##### When using PostgreSQL: +When using PostgreSQL: ```sh -cd docker-compose -.\dump_postgres.bat +scripts/windows/dumps/dump-postgres.ps1 ``` #### 4. Persisting the results -Now that the database has been exported to a file, you can zip it and move it to a newly created folder for the snapshot you just created. You should also put the step 2. csv files there as well (entity csv files). Don't forget to update the **list** below. +Now that the database has been exported to a file, you can zip it and move it to a newly created folder for the snapshot you just created. You should add the csv files generated in step 2 to the zip as well. Don't forget to update the **list** below. -### Usage - -In order to use a snapshot, you must: - -1. from the snapshot: - 1. extract the entity CSV files to the place where the performance tests expect to find them. - 2. recreate the database. You may need to merge split zip files. This can be done on the Powershell by running `cmd.exe /c copy /b postgres-enmeshed.zip.* postgres-enmeshed.zip` -1. start the consumer API -1. run the performance tests - -### List +### List of snapshots #### Snapshot Heavy (snapshot.heavy.zip, downloadable from file hosting) -RaM Generation: ~8h +_Relationships & Messages_ Generation: ~8h Entity Creation: ~10h @@ -101,7 +89,7 @@ Entity Creation: ~10h #### Snapshot Light (snapshot.light.zip) -RaM Generation: ~20min +_Relationships & Messages_ Generation: ~20min Entity Creation: ~1h @@ -111,3 +99,53 @@ Entity Creation: ~1h | RelationshipTemplates | 750 | | Relationships | 1747 | | Messages | 16113 | + +# How to run k6 performance tests + +In order to run the performance tests, you must load an appropriate snapshot of the database. These snapshots are bundled with the usernames and passwords of the created identities/devices, meaning you can authenticate as such users and do API calls in their stead. + +Test snapshots are currently only available for **Postgres**. For windows, make sure that you're using PowerShell 7. It can be installed by running `winget install --id Microsoft.PowerShell --source winget`. + +1. **Install k6** + + 1. You must install k6 if you haven't already. Please download it from the [official website](https://k6.io/open-source/). + +1. **Select a snapshot:** + + 1. Select one of the available snapshots. You can find more information on the available snapshots in the [scenarios README](src/scenarios/README.md) file. + +1. **Load the snapshot and the CSVs:** + + 1. `cd Applications/ConsumerApi/test/ConsumerApi.Tests.Performance` + 1. Ensure that the Postgres server where the snapshot should be loaded is running. + 1. Run the following command (the snapshot name **must not** contain the extension) + ```sh + # scripts/windows/load-snapshot.ps1 -SnapshotName "snapshot" [-Hostname "custom.hostname"] [-Username "dbuser"] [-Password "dbpass"] [-DbName "dbname"] + ``` + +1. **Run the test(s)** + + ```sh + # scripts/windows/run-test.ps1 + ``` + + where \ is for example `s01`. + + > [!NOTE] + > The command can be appended with `-- `. Extra parameters are k6 parameters, some of which are explained below. + +1. You must tweak the way the test is run to ensure it conforms with your preferences. The following CLI parameters are available: + + | Key | Default | Possible Values | + | --------------------- | ------------------- | ------------------------------------------- | + | `--duration` | depends on the test | `60m`, `4h`, etc. | + | `--address` | `localhost:8081` | any valid URL, e.g. `load-test.enmeshed.eu` | + | `--env snapshot=` | `light` | `heavy` | + | `--env clientId=` | `test` | any string | + | `--env clientSecret=` | `test` | any string | + + Example: + + ```sh + $ scripts/windows/run-test.sh s01 -- --address test.enmeshed.eu:443 --duration 4h + ``` diff --git a/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/custom-typings/k6-httpx/index.d.ts b/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/custom-typings/k6-httpx/index.d.ts index f87ab475e6..08de3e6953 100644 --- a/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/custom-typings/k6-httpx/index.d.ts +++ b/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/custom-typings/k6-httpx/index.d.ts @@ -2,26 +2,19 @@ declare module "https://jslib.k6.io/httpx/0.1.0/index.js" { export class Httpx { constructor(options: Options); - get( - url: string | HttpURL, - params?: RefinedParams | null, - ): RefinedResponse; + get(url: string | HttpURL, params?: RefinedParams | null): TypedResponse; - post( - url: string | HttpURL, - body?: RequestBody | null, - params?: RefinedParams | null, - ): RefinedResponse; + delete(url: string | HttpURL, params?: RefinedParams | null): TypedResponse; - put( - url: string | HttpURL, - body?: RequestBody | null, - params?: RefinedParams | null, - ): RefinedResponse; + post(url: string | HttpURL, body?: RequestBody | null, params?: RefinedParams | null): TypedResponse; + + put(url: string | HttpURL, body?: RequestBody | null, params?: RefinedParams | null): TypedResponse; + + patch(url: string | HttpURL, body?: RequestBody | null, params?: RefinedParams | null): TypedResponse; } - export class RefinedResponse { - json(path?: string): any; + export class TypedResponse extends Response { + json(path?: string): RT; } export interface Options { diff --git a/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/package-lock.json b/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/package-lock.json index c52c549cae..f6255c0484 100644 --- a/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/package-lock.json +++ b/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/package-lock.json @@ -15,11 +15,13 @@ "@js-soft/eslint-config-ts": "1.6.9", "@js-soft/license-check": "1.0.9", "@types/k6": "~0.54.0", + "@types/papaparse": "^5.3.14", "@types/webpack": "5.28.5", "babel-loader": "9.2.1", "clean-webpack-plugin": "4.0.0", "copy-webpack-plugin": "12.0.2", "eslint": "^8.57.0", + "papaparse": "^5.4.1", "prettier": "3.3.3", "typescript": "5.6.2", "webpack": "5.95.0", @@ -28,13 +30,13 @@ } }, "node_modules/@ampproject/remapping": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.1.tgz", - "integrity": "sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", + "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", "dev": true, "dependencies": { - "@jridgewell/gen-mapping": "^0.3.0", - "@jridgewell/trace-mapping": "^0.3.9" + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" }, "engines": { "node": ">=6.0.0" @@ -45,7 +47,6 @@ "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.7.tgz", "integrity": "sha512-BcYH1CVJBO9tvyIZ2jVeXgSIMvGZ2FDRvDdOIVQyuklNKSsx+eppDEBq/g47Ayw+RqNFE+URvOShmf+f/qwAlA==", "dev": true, - "license": "MIT", "dependencies": { "@babel/highlight": "^7.24.7", "picocolors": "^1.0.0" @@ -59,7 +60,6 @@ "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.25.4.tgz", "integrity": "sha512-+LGRog6RAsCJrrrg/IO6LGmpphNe5DiK30dGjCoxxeGv49B10/3XYGxPsAwrDlMFcFEvdAUavDT8r9k/hSyQqQ==", "dev": true, - "license": "MIT", "engines": { "node": ">=6.9.0" } @@ -69,7 +69,6 @@ "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.25.2.tgz", "integrity": "sha512-BBt3opiCOxUr9euZ5/ro/Xv8/V7yJ5bjYMqG/C1YAo8MIKAnumZalCN+msbci3Pigy4lIQfPUpfMM27HMGaYEA==", "dev": true, - "license": "MIT", "dependencies": { "@ampproject/remapping": "^2.2.0", "@babel/code-frame": "^7.24.7", @@ -100,7 +99,6 @@ "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.25.6.tgz", "integrity": "sha512-VPC82gr1seXOpkjAAKoLhP50vx4vGNlF4msF64dSFq1P8RfB+QAuJWGHPXXPc8QyfVWwwB/TNNU4+ayZmHNbZw==", "dev": true, - "license": "MIT", "dependencies": { "@babel/types": "^7.25.6", "@jridgewell/gen-mapping": "^0.3.5", @@ -116,7 +114,6 @@ "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.24.7.tgz", "integrity": "sha512-BaDeOonYvhdKw+JoMVkAixAAJzG2jVPIwWoKBPdYuY9b452e2rPuI9QPYh3KpofZ3pW2akOmwZLOiOsHMiqRAg==", "dev": true, - "license": "MIT", "dependencies": { "@babel/types": "^7.24.7" }, @@ -129,7 +126,6 @@ "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.24.7.tgz", "integrity": "sha512-xZeCVVdwb4MsDBkkyZ64tReWYrLRHlMN72vP7Bdm3OUOuyFZExhsHUUnuWnm2/XOlAJzR0LfPpB56WXZn0X/lA==", "dev": true, - "license": "MIT", "dependencies": { "@babel/traverse": "^7.24.7", "@babel/types": "^7.24.7" @@ -143,7 +139,6 @@ "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.25.2.tgz", "integrity": "sha512-U2U5LsSaZ7TAt3cfaymQ8WHh0pxvdHoEk6HVpaexxixjyEquMh0L0YNJNM6CTGKMXV1iksi0iZkGw4AcFkPaaw==", "dev": true, - "license": "MIT", "dependencies": { "@babel/compat-data": "^7.25.2", "@babel/helper-validator-option": "^7.24.8", @@ -160,7 +155,6 @@ "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.25.4.tgz", "integrity": "sha512-ro/bFs3/84MDgDmMwbcHgDa8/E6J3QKNTk4xJJnVeFtGE+tL0K26E3pNxhYz2b67fJpt7Aphw5XcploKXuCvCQ==", "dev": true, - "license": "MIT", "dependencies": { "@babel/helper-annotate-as-pure": "^7.24.7", "@babel/helper-member-expression-to-functions": "^7.24.8", @@ -182,7 +176,6 @@ "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.25.2.tgz", "integrity": "sha512-+wqVGP+DFmqwFD3EH6TMTfUNeqDehV3E/dl+Sd54eaXqm17tEUNbEIn4sVivVowbvUpOtIGxdo3GoXyDH9N/9g==", "dev": true, - "license": "MIT", "dependencies": { "@babel/helper-annotate-as-pure": "^7.24.7", "regexpu-core": "^5.3.1", @@ -200,7 +193,6 @@ "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.6.2.tgz", "integrity": "sha512-LV76g+C502biUK6AyZ3LK10vDpDyCzZnhZFXkH1L75zHPj68+qc8Zfpx2th+gzwA2MzyK+1g/3EPl62yFnVttQ==", "dev": true, - "license": "MIT", "dependencies": { "@babel/helper-compilation-targets": "^7.22.6", "@babel/helper-plugin-utils": "^7.22.5", @@ -217,7 +209,6 @@ "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.24.8.tgz", "integrity": "sha512-LABppdt+Lp/RlBxqrh4qgf1oEH/WxdzQNDJIu5gC/W1GyvPVrOBiItmmM8wan2fm4oYqFuFfkXmlGpLQhPY8CA==", "dev": true, - "license": "MIT", "dependencies": { "@babel/traverse": "^7.24.8", "@babel/types": "^7.24.8" @@ -231,7 +222,6 @@ "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.24.7.tgz", "integrity": "sha512-8AyH3C+74cgCVVXow/myrynrAGv+nTVg5vKu2nZph9x7RcRwzmh0VFallJuFTZ9mx6u4eSdXZfcOzSqTUm0HCA==", "dev": true, - "license": "MIT", "dependencies": { "@babel/traverse": "^7.24.7", "@babel/types": "^7.24.7" @@ -245,7 +235,6 @@ "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.25.2.tgz", "integrity": "sha512-BjyRAbix6j/wv83ftcVJmBt72QtHI56C7JXZoG2xATiLpmoC7dpd8WnkikExHDVPpi/3qCmO6WY1EaXOluiecQ==", "dev": true, - "license": "MIT", "dependencies": { "@babel/helper-module-imports": "^7.24.7", "@babel/helper-simple-access": "^7.24.7", @@ -264,7 +253,6 @@ "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.24.7.tgz", "integrity": "sha512-jKiTsW2xmWwxT1ixIdfXUZp+P5yURx2suzLZr5Hi64rURpDYdMW0pv+Uf17EYk2Rd428Lx4tLsnjGJzYKDM/6A==", "dev": true, - "license": "MIT", "dependencies": { "@babel/types": "^7.24.7" }, @@ -277,7 +265,6 @@ "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.24.8.tgz", "integrity": "sha512-FFWx5142D8h2Mgr/iPVGH5G7w6jDn4jUSpZTyDnQO0Yn7Ks2Kuz6Pci8H6MPCoUJegd/UZQ3tAvfLCxQSnWWwg==", "dev": true, - "license": "MIT", "engines": { "node": ">=6.9.0" } @@ -287,7 +274,6 @@ "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.25.0.tgz", "integrity": "sha512-NhavI2eWEIz/H9dbrG0TuOicDhNexze43i5z7lEqwYm0WEZVTwnPpA0EafUTP7+6/W79HWIP2cTe3Z5NiSTVpw==", "dev": true, - "license": "MIT", "dependencies": { "@babel/helper-annotate-as-pure": "^7.24.7", "@babel/helper-wrap-function": "^7.25.0", @@ -305,7 +291,6 @@ "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.25.0.tgz", "integrity": "sha512-q688zIvQVYtZu+i2PsdIu/uWGRpfxzr5WESsfpShfZECkO+d2o+WROWezCi/Q6kJ0tfPa5+pUGUlfx2HhrA3Bg==", "dev": true, - "license": "MIT", "dependencies": { "@babel/helper-member-expression-to-functions": "^7.24.8", "@babel/helper-optimise-call-expression": "^7.24.7", @@ -323,7 +308,6 @@ "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.24.7.tgz", "integrity": "sha512-zBAIvbCMh5Ts+b86r/CjU+4XGYIs+R1j951gxI3KmmxBMhCg4oQMsv6ZXQ64XOm/cvzfU1FmoCyt6+owc5QMYg==", "dev": true, - "license": "MIT", "dependencies": { "@babel/traverse": "^7.24.7", "@babel/types": "^7.24.7" @@ -337,7 +321,6 @@ "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.24.7.tgz", "integrity": "sha512-IO+DLT3LQUElMbpzlatRASEyQtfhSE0+m465v++3jyyXeBTBUjtVZg28/gHeV5mrTJqvEKhKroBGAvhW+qPHiQ==", "dev": true, - "license": "MIT", "dependencies": { "@babel/traverse": "^7.24.7", "@babel/types": "^7.24.7" @@ -351,7 +334,6 @@ "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.24.8.tgz", "integrity": "sha512-pO9KhhRcuUyGnJWwyEgnRJTSIZHiT+vMD0kPeD+so0l7mxkMT19g3pjY9GTnHySck/hDzq+dtW/4VgnMkippsQ==", "dev": true, - "license": "MIT", "engines": { "node": ">=6.9.0" } @@ -361,7 +343,6 @@ "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.7.tgz", "integrity": "sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w==", "dev": true, - "license": "MIT", "engines": { "node": ">=6.9.0" } @@ -371,7 +352,6 @@ "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.24.8.tgz", "integrity": "sha512-xb8t9tD1MHLungh/AIoWYN+gVHaB9kwlu8gffXGSt3FFEIT7RjS+xWbc2vUD1UTZdIpKj/ab3rdqJ7ufngyi2Q==", "dev": true, - "license": "MIT", "engines": { "node": ">=6.9.0" } @@ -381,7 +361,6 @@ "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.25.0.tgz", "integrity": "sha512-s6Q1ebqutSiZnEjaofc/UKDyC4SbzV5n5SrA2Gq8UawLycr3i04f1dX4OzoQVnexm6aOCh37SQNYlJ/8Ku+PMQ==", "dev": true, - "license": "MIT", "dependencies": { "@babel/template": "^7.25.0", "@babel/traverse": "^7.25.0", @@ -392,14 +371,13 @@ } }, "node_modules/@babel/helpers": { - "version": "7.25.0", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.25.0.tgz", - "integrity": "sha512-MjgLZ42aCm0oGjJj8CtSM3DB8NOOf8h2l7DCTePJs29u+v7yO/RBX9nShlKMgFnRks/Q4tBAe7Hxnov9VkGwLw==", + "version": "7.25.6", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.25.6.tgz", + "integrity": "sha512-Xg0tn4HcfTijTwfDwYlvVCl43V6h4KyVVX2aEm4qdO/PC6L2YvzLHFdmxhoeSA3eslcE6+ZVXHgWwopXYLNq4Q==", "dev": true, - "license": "MIT", "dependencies": { "@babel/template": "^7.25.0", - "@babel/types": "^7.25.0" + "@babel/types": "^7.25.6" }, "engines": { "node": ">=6.9.0" @@ -410,7 +388,6 @@ "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.7.tgz", "integrity": "sha512-EStJpq4OuY8xYfhGVXngigBJRWxftKX9ksiGDnmlY3o7B/V7KIAc9X4oiK87uPJSc/vs5L869bem5fhZa8caZw==", "dev": true, - "license": "MIT", "dependencies": { "@babel/helper-validator-identifier": "^7.24.7", "chalk": "^2.4.2", @@ -426,7 +403,6 @@ "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.25.6.tgz", "integrity": "sha512-trGdfBdbD0l1ZPmcJ83eNxB9rbEax4ALFTF7fN386TMYbeCQbyme5cOEXQhbGXKebwGaB/J52w1mrklMcbgy6Q==", "dev": true, - "license": "MIT", "dependencies": { "@babel/types": "^7.25.6" }, @@ -442,7 +418,6 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-firefox-class-in-computed-class-key/-/plugin-bugfix-firefox-class-in-computed-class-key-7.25.3.tgz", "integrity": "sha512-wUrcsxZg6rqBXG05HG1FPYgsP6EvwF4WpBbxIpWIIYnH8wG0gzx3yZY3dtEHas4sTAOGkbTsc9EGPxwff8lRoA==", "dev": true, - "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.24.8", "@babel/traverse": "^7.25.3" @@ -459,7 +434,6 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-class-field-initializer-scope/-/plugin-bugfix-safari-class-field-initializer-scope-7.25.0.tgz", "integrity": "sha512-Bm4bH2qsX880b/3ziJ8KD711LT7z4u8CFudmjqle65AZj/HNUFhEf90dqYv6O86buWvSBmeQDjv0Tn2aF/bIBA==", "dev": true, - "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.24.8" }, @@ -475,7 +449,6 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.25.0.tgz", "integrity": "sha512-lXwdNZtTmeVOOFtwM/WDe7yg1PL8sYhRk/XH0FzbR2HDQ0xC+EnQ/JHeoMYSavtU115tnUk0q9CDyq8si+LMAA==", "dev": true, - "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.24.8" }, @@ -491,7 +464,6 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.24.7.tgz", "integrity": "sha512-+izXIbke1T33mY4MSNnrqhPXDz01WYhEf3yF5NbnUtkiNnm+XBZJl3kNfoK6NKmYlz/D07+l2GWVK/QfDkNCuQ==", "dev": true, - "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.24.7", "@babel/helper-skip-transparent-expression-wrappers": "^7.24.7", @@ -509,7 +481,6 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly/-/plugin-bugfix-v8-static-class-fields-redefine-readonly-7.25.0.tgz", "integrity": "sha512-tggFrk1AIShG/RUQbEwt2Tr/E+ObkfwrPjR6BjbRvsx24+PSjK8zrq0GWPNCjo8qpRx4DuJzlcvWJqlm+0h3kw==", "dev": true, - "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.24.8", "@babel/traverse": "^7.25.0" @@ -634,13 +605,12 @@ } }, "node_modules/@babel/plugin-syntax-import-assertions": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.24.7.tgz", - "integrity": "sha512-Ec3NRUMoi8gskrkBe3fNmEQfxDvY8bgfQpz6jlk/41kX9eUjvpyqWU7PBP/pLAvMaSQjbMNKJmvX57jP+M6bPg==", + "version": "7.25.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.25.6.tgz", + "integrity": "sha512-aABl0jHw9bZ2karQ/uUD6XP4u0SG22SJrOHFoL6XB1R7dTovOP4TzTlsxOYC5yQ1pdscVK2JTUnF6QL3ARoAiQ==", "dev": true, - "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.24.8" }, "engines": { "node": ">=6.9.0" @@ -650,13 +620,12 @@ } }, "node_modules/@babel/plugin-syntax-import-attributes": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.24.7.tgz", - "integrity": "sha512-hbX+lKKeUMGihnK8nvKqmXBInriT3GVjzXKFriV3YC6APGxMbP8RZNFwy91+hocLXq90Mta+HshoB31802bb8A==", + "version": "7.25.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.25.6.tgz", + "integrity": "sha512-sXaDXaJN9SNLymBdlWFA+bjzBhFD617ZaFiY13dGt7TVslVvVgA6fkZOP7Ki3IGElC45lwHdOTrCtKZGVAWeLQ==", "dev": true, - "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.24.8" }, "engines": { "node": ">=6.9.0" @@ -694,7 +663,6 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.24.7.tgz", "integrity": "sha512-6ddciUPe/mpMnOKv/U+RSd2vvVy+Yw/JfBB0ZHYjEZt9NLHmCUylNYlsbqCCS1Bffjlb0fCwC9Vqz+sBz6PsiQ==", "dev": true, - "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.24.7" }, @@ -808,13 +776,12 @@ } }, "node_modules/@babel/plugin-syntax-typescript": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.24.7.tgz", - "integrity": "sha512-c/+fVeJBB0FeKsFvwytYiUD+LBvhHjGSI0g446PRGdSVGZLRNArBUno2PETbAly3tpiNAQR5XaZ+JslxkotsbA==", + "version": "7.25.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.25.4.tgz", + "integrity": "sha512-uMOCoHVU52BsSWxPOMVv5qKRdeSlPuImUCB2dlPuBSU+W2/ROE7/Zg8F2Kepbk+8yBa68LlRKxO+xgEVWorsDg==", "dev": true, - "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.24.8" }, "engines": { "node": ">=6.9.0" @@ -844,7 +811,6 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.24.7.tgz", "integrity": "sha512-Dt9LQs6iEY++gXUwY03DNFat5C2NbO48jj+j/bSAz6b3HgPs39qcPiYt77fDObIcFwj3/C2ICX9YMwGflUoSHQ==", "dev": true, - "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.24.7" }, @@ -860,7 +826,6 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.25.4.tgz", "integrity": "sha512-jz8cV2XDDTqjKPwVPJBIjORVEmSGYhdRa8e5k5+vN+uwcjSrSxUaebBRa4ko1jqNF2uxyg8G6XYk30Jv285xzg==", "dev": true, - "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.24.8", "@babel/helper-remap-async-to-generator": "^7.25.0", @@ -879,7 +844,6 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.24.7.tgz", "integrity": "sha512-SQY01PcJfmQ+4Ash7NE+rpbLFbmqA2GPIgqzxfFTL4t1FKRq4zTms/7htKpoCUI9OcFYgzqfmCdH53s6/jn5fA==", "dev": true, - "license": "MIT", "dependencies": { "@babel/helper-module-imports": "^7.24.7", "@babel/helper-plugin-utils": "^7.24.7", @@ -897,7 +861,6 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.24.7.tgz", "integrity": "sha512-yO7RAz6EsVQDaBH18IDJcMB1HnrUn2FJ/Jslc/WtPPWcjhpUJXU/rjbwmluzp7v/ZzWcEhTMXELnnsz8djWDwQ==", "dev": true, - "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.24.7" }, @@ -913,7 +876,6 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.25.0.tgz", "integrity": "sha512-yBQjYoOjXlFv9nlXb3f1casSHOZkWr29NX+zChVanLg5Nc157CrbEX9D7hxxtTpuFy7Q0YzmmWfJxzvps4kXrQ==", "dev": true, - "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.24.8" }, @@ -929,7 +891,6 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.25.4.tgz", "integrity": "sha512-nZeZHyCWPfjkdU5pA/uHiTaDAFUEqkpzf1YoQT2NeSynCGYq9rxfyI3XpQbfx/a0hSnFH6TGlEXvae5Vi7GD8g==", "dev": true, - "license": "MIT", "dependencies": { "@babel/helper-create-class-features-plugin": "^7.25.4", "@babel/helper-plugin-utils": "^7.24.8" @@ -946,7 +907,6 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.24.7.tgz", "integrity": "sha512-HMXK3WbBPpZQufbMG4B46A90PkuuhN9vBCb5T8+VAHqvAqvcLi+2cKoukcpmUYkszLhScU3l1iudhrks3DggRQ==", "dev": true, - "license": "MIT", "dependencies": { "@babel/helper-create-class-features-plugin": "^7.24.7", "@babel/helper-plugin-utils": "^7.24.7", @@ -964,7 +924,6 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.25.4.tgz", "integrity": "sha512-oexUfaQle2pF/b6E0dwsxQtAol9TLSO88kQvym6HHBWFliV2lGdrPieX+WgMRLSJDVzdYywk7jXbLPuO2KLTLg==", "dev": true, - "license": "MIT", "dependencies": { "@babel/helper-annotate-as-pure": "^7.24.7", "@babel/helper-compilation-targets": "^7.25.2", @@ -985,7 +944,6 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.24.7.tgz", "integrity": "sha512-25cS7v+707Gu6Ds2oY6tCkUwsJ9YIDbggd9+cu9jzzDgiNq7hR/8dkzxWfKWnTic26vsI3EsCXNd4iEB6e8esQ==", "dev": true, - "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.24.7", "@babel/template": "^7.24.7" @@ -1002,7 +960,6 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.24.8.tgz", "integrity": "sha512-36e87mfY8TnRxc7yc6M9g9gOB7rKgSahqkIKwLpz4Ppk2+zC2Cy1is0uwtuSG6AE4zlTOUa+7JGz9jCJGLqQFQ==", "dev": true, - "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.24.8" }, @@ -1018,7 +975,6 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.24.7.tgz", "integrity": "sha512-ZOA3W+1RRTSWvyqcMJDLqbchh7U4NRGqwRfFSVbOLS/ePIP4vHB5e8T8eXcuqyN1QkgKyj5wuW0lcS85v4CrSw==", "dev": true, - "license": "MIT", "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.24.7", "@babel/helper-plugin-utils": "^7.24.7" @@ -1035,7 +991,6 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.24.7.tgz", "integrity": "sha512-JdYfXyCRihAe46jUIliuL2/s0x0wObgwwiGxw/UbgJBr20gQBThrokO4nYKgWkD7uBaqM7+9x5TU7NkExZJyzw==", "dev": true, - "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.24.7" }, @@ -1051,7 +1006,6 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-named-capturing-groups-regex/-/plugin-transform-duplicate-named-capturing-groups-regex-7.25.0.tgz", "integrity": "sha512-YLpb4LlYSc3sCUa35un84poXoraOiQucUTTu8X1j18JV+gNa8E0nyUf/CjZ171IRGr4jEguF+vzJU66QZhn29g==", "dev": true, - "license": "MIT", "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.25.0", "@babel/helper-plugin-utils": "^7.24.8" @@ -1068,7 +1022,6 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.24.7.tgz", "integrity": "sha512-sc3X26PhZQDb3JhORmakcbvkeInvxz+A8oda99lj7J60QRuPZvNAk9wQlTBS1ZynelDrDmTU4pw1tyc5d5ZMUg==", "dev": true, - "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.24.7", "@babel/plugin-syntax-dynamic-import": "^7.8.3" @@ -1085,7 +1038,6 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.24.7.tgz", "integrity": "sha512-Rqe/vSc9OYgDajNIK35u7ot+KeCoetqQYFXM4Epf7M7ez3lWlOjrDjrwMei6caCVhfdw+mIKD4cgdGNy5JQotQ==", "dev": true, - "license": "MIT", "dependencies": { "@babel/helper-builder-binary-assignment-operator-visitor": "^7.24.7", "@babel/helper-plugin-utils": "^7.24.7" @@ -1102,7 +1054,6 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.24.7.tgz", "integrity": "sha512-v0K9uNYsPL3oXZ/7F9NNIbAj2jv1whUEtyA6aujhekLs56R++JDQuzRcP2/z4WX5Vg/c5lE9uWZA0/iUoFhLTA==", "dev": true, - "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.24.7", "@babel/plugin-syntax-export-namespace-from": "^7.8.3" @@ -1119,7 +1070,6 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.24.7.tgz", "integrity": "sha512-wo9ogrDG1ITTTBsy46oGiN1dS9A7MROBTcYsfS8DtsImMkHk9JXJ3EWQM6X2SUw4x80uGPlwj0o00Uoc6nEE3g==", "dev": true, - "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.24.7", "@babel/helper-skip-transparent-expression-wrappers": "^7.24.7" @@ -1136,7 +1086,6 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.25.1.tgz", "integrity": "sha512-TVVJVdW9RKMNgJJlLtHsKDTydjZAbwIsn6ySBPQaEAUU5+gVvlJt/9nRmqVbsV/IBanRjzWoaAQKLoamWVOUuA==", "dev": true, - "license": "MIT", "dependencies": { "@babel/helper-compilation-targets": "^7.24.8", "@babel/helper-plugin-utils": "^7.24.8", @@ -1154,7 +1103,6 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.24.7.tgz", "integrity": "sha512-2yFnBGDvRuxAaE/f0vfBKvtnvvqU8tGpMHqMNpTN2oWMKIR3NqFkjaAgGwawhqK/pIN2T3XdjGPdaG0vDhOBGw==", "dev": true, - "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.24.7", "@babel/plugin-syntax-json-strings": "^7.8.3" @@ -1171,7 +1119,6 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.25.2.tgz", "integrity": "sha512-HQI+HcTbm9ur3Z2DkO+jgESMAMcYLuN/A7NRw9juzxAezN9AvqvUTnpKP/9kkYANz6u7dFlAyOu44ejuGySlfw==", "dev": true, - "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.24.8" }, @@ -1187,7 +1134,6 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.24.7.tgz", "integrity": "sha512-4D2tpwlQ1odXmTEIFWy9ELJcZHqrStlzK/dAOWYyxX3zT0iXQB6banjgeOJQXzEc4S0E0a5A+hahxPaEFYftsw==", "dev": true, - "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.24.7", "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4" @@ -1204,7 +1150,6 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.24.7.tgz", "integrity": "sha512-T/hRC1uqrzXMKLQ6UCwMT85S3EvqaBXDGf0FaMf4446Qx9vKwlghvee0+uuZcDUCZU5RuNi4781UQ7R308zzBw==", "dev": true, - "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.24.7" }, @@ -1220,7 +1165,6 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.24.7.tgz", "integrity": "sha512-9+pB1qxV3vs/8Hdmz/CulFB8w2tuu6EB94JZFsjdqxQokwGa9Unap7Bo2gGBGIvPmDIVvQrom7r5m/TCDMURhg==", "dev": true, - "license": "MIT", "dependencies": { "@babel/helper-module-transforms": "^7.24.7", "@babel/helper-plugin-utils": "^7.24.7" @@ -1237,7 +1181,6 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.24.8.tgz", "integrity": "sha512-WHsk9H8XxRs3JXKWFiqtQebdh9b/pTk4EgueygFzYlTKAg0Ud985mSevdNjdXdFBATSKVJGQXP1tv6aGbssLKA==", "dev": true, - "license": "MIT", "dependencies": { "@babel/helper-module-transforms": "^7.24.8", "@babel/helper-plugin-utils": "^7.24.8", @@ -1255,7 +1198,6 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.25.0.tgz", "integrity": "sha512-YPJfjQPDXxyQWg/0+jHKj1llnY5f/R6a0p/vP4lPymxLu7Lvl4k2WMitqi08yxwQcCVUUdG9LCUj4TNEgAp3Jw==", "dev": true, - "license": "MIT", "dependencies": { "@babel/helper-module-transforms": "^7.25.0", "@babel/helper-plugin-utils": "^7.24.8", @@ -1274,7 +1216,6 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.24.7.tgz", "integrity": "sha512-3aytQvqJ/h9z4g8AsKPLvD4Zqi2qT+L3j7XoFFu1XBlZWEl2/1kWnhmAbxpLgPrHSY0M6UA02jyTiwUVtiKR6A==", "dev": true, - "license": "MIT", "dependencies": { "@babel/helper-module-transforms": "^7.24.7", "@babel/helper-plugin-utils": "^7.24.7" @@ -1291,7 +1232,6 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.24.7.tgz", "integrity": "sha512-/jr7h/EWeJtk1U/uz2jlsCioHkZk1JJZVcc8oQsJ1dUlaJD83f4/6Zeh2aHt9BIFokHIsSeDfhUmju0+1GPd6g==", "dev": true, - "license": "MIT", "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.24.7", "@babel/helper-plugin-utils": "^7.24.7" @@ -1308,7 +1248,6 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.24.7.tgz", "integrity": "sha512-RNKwfRIXg4Ls/8mMTza5oPF5RkOW8Wy/WgMAp1/F1yZ8mMbtwXW+HDoJiOsagWrAhI5f57Vncrmr9XeT4CVapA==", "dev": true, - "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.24.7" }, @@ -1324,7 +1263,6 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.24.7.tgz", "integrity": "sha512-Ts7xQVk1OEocqzm8rHMXHlxvsfZ0cEF2yomUqpKENHWMF4zKk175Y4q8H5knJes6PgYad50uuRmt3UJuhBw8pQ==", "dev": true, - "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.24.7", "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3" @@ -1341,7 +1279,6 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.24.7.tgz", "integrity": "sha512-e6q1TiVUzvH9KRvicuxdBTUj4AdKSRwzIyFFnfnezpCfP2/7Qmbb8qbU2j7GODbl4JMkblitCQjKYUaX/qkkwA==", "dev": true, - "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.24.7", "@babel/plugin-syntax-numeric-separator": "^7.10.4" @@ -1358,7 +1295,6 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.24.7.tgz", "integrity": "sha512-4QrHAr0aXQCEFni2q4DqKLD31n2DL+RxcwnNjDFkSG0eNQ/xCavnRkfCUjsyqGC2OviNJvZOF/mQqZBw7i2C5Q==", "dev": true, - "license": "MIT", "dependencies": { "@babel/helper-compilation-targets": "^7.24.7", "@babel/helper-plugin-utils": "^7.24.7", @@ -1377,7 +1313,6 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.24.7.tgz", "integrity": "sha512-A/vVLwN6lBrMFmMDmPPz0jnE6ZGx7Jq7d6sT/Ev4H65RER6pZ+kczlf1DthF5N0qaPHBsI7UXiE8Zy66nmAovg==", "dev": true, - "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.24.7", "@babel/helper-replace-supers": "^7.24.7" @@ -1394,7 +1329,6 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.24.7.tgz", "integrity": "sha512-uLEndKqP5BfBbC/5jTwPxLh9kqPWWgzN/f8w6UwAIirAEqiIVJWWY312X72Eub09g5KF9+Zn7+hT7sDxmhRuKA==", "dev": true, - "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.24.7", "@babel/plugin-syntax-optional-catch-binding": "^7.8.3" @@ -1411,7 +1345,6 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.24.8.tgz", "integrity": "sha512-5cTOLSMs9eypEy8JUVvIKOu6NgvbJMnpG62VpIHrTmROdQ+L5mDAaI40g25k5vXti55JWNX5jCkq3HZxXBQANw==", "dev": true, - "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.24.8", "@babel/helper-skip-transparent-expression-wrappers": "^7.24.7", @@ -1429,7 +1362,6 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.24.7.tgz", "integrity": "sha512-yGWW5Rr+sQOhK0Ot8hjDJuxU3XLRQGflvT4lhlSY0DFvdb3TwKaY26CJzHtYllU0vT9j58hc37ndFPsqT1SrzA==", "dev": true, - "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.24.7" }, @@ -1445,7 +1377,6 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.25.4.tgz", "integrity": "sha512-ao8BG7E2b/URaUQGqN3Tlsg+M3KlHY6rJ1O1gXAEUnZoyNQnvKyH87Kfg+FoxSeyWUB8ISZZsC91C44ZuBFytw==", "dev": true, - "license": "MIT", "dependencies": { "@babel/helper-create-class-features-plugin": "^7.25.4", "@babel/helper-plugin-utils": "^7.24.8" @@ -1462,7 +1393,6 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.24.7.tgz", "integrity": "sha512-9z76mxwnwFxMyxZWEgdgECQglF2Q7cFLm0kMf8pGwt+GSJsY0cONKj/UuO4bOH0w/uAel3ekS4ra5CEAyJRmDA==", "dev": true, - "license": "MIT", "dependencies": { "@babel/helper-annotate-as-pure": "^7.24.7", "@babel/helper-create-class-features-plugin": "^7.24.7", @@ -1481,7 +1411,6 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.24.7.tgz", "integrity": "sha512-EMi4MLQSHfd2nrCqQEWxFdha2gBCqU4ZcCng4WBGZ5CJL4bBRW0ptdqqDdeirGZcpALazVVNJqRmsO8/+oNCBA==", "dev": true, - "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.24.7" }, @@ -1497,7 +1426,6 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.24.7.tgz", "integrity": "sha512-lq3fvXPdimDrlg6LWBoqj+r/DEWgONuwjuOuQCSYgRroXDH/IdM1C0IZf59fL5cHLpjEH/O6opIRBbqv7ELnuA==", "dev": true, - "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.24.7", "regenerator-transform": "^0.15.2" @@ -1514,7 +1442,6 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.24.7.tgz", "integrity": "sha512-0DUq0pHcPKbjFZCfTss/pGkYMfy3vFWydkUBd9r0GHpIyfs2eCDENvqadMycRS9wZCXR41wucAfJHJmwA0UmoQ==", "dev": true, - "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.24.7" }, @@ -1530,7 +1457,6 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.24.7.tgz", "integrity": "sha512-KsDsevZMDsigzbA09+vacnLpmPH4aWjcZjXdyFKGzpplxhbeB4wYtury3vglQkg6KM/xEPKt73eCjPPf1PgXBA==", "dev": true, - "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.24.7" }, @@ -1546,7 +1472,6 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.24.7.tgz", "integrity": "sha512-x96oO0I09dgMDxJaANcRyD4ellXFLLiWhuwDxKZX5g2rWP1bTPkBSwCYv96VDXVT1bD9aPj8tppr5ITIh8hBng==", "dev": true, - "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.24.7", "@babel/helper-skip-transparent-expression-wrappers": "^7.24.7" @@ -1563,7 +1488,6 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.24.7.tgz", "integrity": "sha512-kHPSIJc9v24zEml5geKg9Mjx5ULpfncj0wRpYtxbvKyTtHCYDkVE3aHQ03FrpEo4gEe2vrJJS1Y9CJTaThA52g==", "dev": true, - "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.24.7" }, @@ -1579,7 +1503,6 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.24.7.tgz", "integrity": "sha512-AfDTQmClklHCOLxtGoP7HkeMw56k1/bTQjwsfhL6pppo/M4TOBSq+jjBUBLmV/4oeFg4GWMavIl44ZeCtmmZTw==", "dev": true, - "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.24.7" }, @@ -1595,7 +1518,6 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.24.8.tgz", "integrity": "sha512-adNTUpDCVnmAE58VEqKlAA6ZBlNkMnWD0ZcW76lyNFN3MJniyGFZfNwERVk8Ap56MCnXztmDr19T4mPTztcuaw==", "dev": true, - "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.24.8" }, @@ -1611,7 +1533,6 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.25.2.tgz", "integrity": "sha512-lBwRvjSmqiMYe/pS0+1gggjJleUJi7NzjvQ1Fkqtt69hBa/0t1YuW/MLQMAPixfwaQOHUXsd6jeU3Z+vdGv3+A==", "dev": true, - "license": "MIT", "dependencies": { "@babel/helper-annotate-as-pure": "^7.24.7", "@babel/helper-create-class-features-plugin": "^7.25.0", @@ -1631,7 +1552,6 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.24.7.tgz", "integrity": "sha512-U3ap1gm5+4edc2Q/P+9VrBNhGkfnf+8ZqppY71Bo/pzZmXhhLdqgaUl6cuB07O1+AQJtCLfaOmswiNbSQ9ivhw==", "dev": true, - "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.24.7" }, @@ -1647,7 +1567,6 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.24.7.tgz", "integrity": "sha512-uH2O4OV5M9FZYQrwc7NdVmMxQJOCCzFeYudlZSzUAHRFeOujQefa92E74TQDVskNHCzOXoigEuoyzHDhaEaK5w==", "dev": true, - "license": "MIT", "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.24.7", "@babel/helper-plugin-utils": "^7.24.7" @@ -1664,7 +1583,6 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.24.7.tgz", "integrity": "sha512-hlQ96MBZSAXUq7ltkjtu3FJCCSMx/j629ns3hA3pXnBXjanNP0LHi+JpPeA81zaWgVK1VGH95Xuy7u0RyQ8kMg==", "dev": true, - "license": "MIT", "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.24.7", "@babel/helper-plugin-utils": "^7.24.7" @@ -1681,7 +1599,6 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.25.4.tgz", "integrity": "sha512-qesBxiWkgN1Q+31xUE9RcMk79eOXXDCv6tfyGMRSs4RGlioSg2WVyQAm07k726cSE56pa+Kb0y9epX2qaXzTvA==", "dev": true, - "license": "MIT", "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.25.2", "@babel/helper-plugin-utils": "^7.24.8" @@ -1698,7 +1615,6 @@ "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.25.4.tgz", "integrity": "sha512-W9Gyo+KmcxjGahtt3t9fb14vFRWvPpu5pT6GBlovAK6BTBcxgjfVMSQCfJl4oi35ODrxP6xx2Wr8LNST57Mraw==", "dev": true, - "license": "MIT", "dependencies": { "@babel/compat-data": "^7.25.4", "@babel/helper-compilation-targets": "^7.25.2", @@ -1810,7 +1726,6 @@ "resolved": "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.24.7.tgz", "integrity": "sha512-SyXRe3OdWwIwalxDg5UtJnJQO+YPcTfwiIY2B0Xlddh9o7jpWLvv8X1RthIeDOxQ+O1ML5BLPCONToObyVQVuQ==", "dev": true, - "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.24.7", "@babel/helper-validator-option": "^7.24.7", @@ -1832,9 +1747,9 @@ "dev": true }, "node_modules/@babel/runtime": { - "version": "7.24.0", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.0.tgz", - "integrity": "sha512-Chk32uHMg6TnQdvw2e9IlqPpFX/6NLuK0Ys2PqLb7/gL5uFn9mXvK715FGLlOLQrcO4qIkNHkvPGktzzXexsFw==", + "version": "7.25.6", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.25.6.tgz", + "integrity": "sha512-VBj9MYyDb9tuLq7yzqjgzt6Q+IBQLrGZfdjOekyEirZPHxXWoTSGUTMrpsfi58Up73d13NfYLv8HT9vmznjzhQ==", "dev": true, "dependencies": { "regenerator-runtime": "^0.14.0" @@ -1848,7 +1763,6 @@ "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.25.0.tgz", "integrity": "sha512-aOOgh1/5XzKvg1jvVz7AVrx2piJ2XBi227DHmbY6y+bM9H2FlN+IfecYu4Xl0cNiiVejlsCri89LUsbj8vJD9Q==", "dev": true, - "license": "MIT", "dependencies": { "@babel/code-frame": "^7.24.7", "@babel/parser": "^7.25.0", @@ -1863,7 +1777,6 @@ "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.25.6.tgz", "integrity": "sha512-9Vrcx5ZW6UwK5tvqsj0nGpp/XzqthkT0dqIc9g1AdtygFToNtTF67XzYS//dm+SAK9cp3B9R4ZO/46p63SCjlQ==", "dev": true, - "license": "MIT", "dependencies": { "@babel/code-frame": "^7.24.7", "@babel/generator": "^7.25.6", @@ -1882,7 +1795,6 @@ "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.25.6.tgz", "integrity": "sha512-/l42B1qxpG6RdfYf343Uw1vmDjeNhneUXtzhojE7pDgfpEypmRhI6j1kr17XCVv4Cgl9HdAiQY2x0GwKm7rWCw==", "dev": true, - "license": "MIT", "dependencies": { "@babel/helper-string-parser": "^7.24.8", "@babel/helper-validator-identifier": "^7.24.7", @@ -1917,9 +1829,9 @@ } }, "node_modules/@eslint-community/regexpp": { - "version": "4.10.0", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.10.0.tgz", - "integrity": "sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA==", + "version": "4.11.0", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.11.0.tgz", + "integrity": "sha512-G/M/tIiMrTAxEWRfLfQJMmGNX28IxBg4PBz8XqQhqUHLFI6TL2htpIB1iQCj144V5ee/JaKyT9/WZ0MGZWfA7A==", "dev": true, "engines": { "node": "^12.0.0 || ^14.0.0 || >=16.0.0" @@ -1948,20 +1860,14 @@ "url": "https://opencollective.com/eslint" } }, - "node_modules/@eslint/eslintrc/node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "node_modules/@eslint/eslintrc/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "dev": true, "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" } }, "node_modules/@eslint/eslintrc/node_modules/globals": { @@ -1979,11 +1885,17 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@eslint/eslintrc/node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true + "node_modules/@eslint/eslintrc/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } }, "node_modules/@eslint/js": { "version": "8.57.0", @@ -1998,6 +1910,7 @@ "version": "0.11.14", "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz", "integrity": "sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==", + "deprecated": "Use @eslint/config-array instead", "dev": true, "dependencies": { "@humanwhocodes/object-schema": "^2.0.2", @@ -2008,6 +1921,28 @@ "node": ">=10.10.0" } }, + "node_modules/@humanwhocodes/config-array/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/@humanwhocodes/config-array/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, "node_modules/@humanwhocodes/module-importer": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", @@ -2025,6 +1960,7 @@ "version": "2.0.3", "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz", "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==", + "deprecated": "Use @eslint/object-schema instead", "dev": true }, "node_modules/@jridgewell/gen-mapping": { @@ -2032,7 +1968,6 @@ "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", "dev": true, - "license": "MIT", "dependencies": { "@jridgewell/set-array": "^1.2.1", "@jridgewell/sourcemap-codec": "^1.4.10", @@ -2056,25 +1991,24 @@ "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", "dev": true, - "license": "MIT", "engines": { "node": ">=6.0.0" } }, "node_modules/@jridgewell/source-map": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.5.tgz", - "integrity": "sha512-UTYAUj/wviwdsMfzoSJspJxbkH5o1snzwX0//0ENX1u/55kkZZkcTZP6u9bwKGkv+dkk9at4m1Cpt0uY80kcpQ==", + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.6.tgz", + "integrity": "sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ==", "dev": true, "dependencies": { - "@jridgewell/gen-mapping": "^0.3.0", - "@jridgewell/trace-mapping": "^0.3.9" + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25" } }, "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.4.15", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", - "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", + "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==", "dev": true }, "node_modules/@jridgewell/trace-mapping": { @@ -2082,7 +2016,6 @@ "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", "dev": true, - "license": "MIT", "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" @@ -2159,7 +2092,6 @@ "resolved": "https://registry.npmjs.org/@sindresorhus/merge-streams/-/merge-streams-2.3.0.tgz", "integrity": "sha512-LtoMMhxAlorcGhmFYI+LhPgbPZCkgP6ra1YL604EeF6U98pLlQ3iWIGMdWSC+vWmPBWBNgmDBAhnAobLROJmwg==", "dev": true, - "license": "MIT", "engines": { "node": ">=18" }, @@ -2203,12 +2135,21 @@ "dev": true }, "node_modules/@types/node": { - "version": "20.11.21", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.11.21.tgz", - "integrity": "sha512-/ySDLGscFPNasfqStUuWWPfL78jompfIoVzLJPVVAHBh6rpG68+pI2Gk+fNLeI8/f1yPYL4s46EleVIc20F1Ow==", + "version": "22.5.4", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.5.4.tgz", + "integrity": "sha512-FDuKUJQm/ju9fT/SeX/6+gBzoPzlVCzfzmGkwKvRHQVxi4BntVbyIwf6a4Xn62mrvndLiml6z/UBXIdEVjQLXg==", "dev": true, "dependencies": { - "undici-types": "~5.26.4" + "undici-types": "~6.19.2" + } + }, + "node_modules/@types/papaparse": { + "version": "5.3.14", + "resolved": "https://registry.npmjs.org/@types/papaparse/-/papaparse-5.3.14.tgz", + "integrity": "sha512-LxJ4iEFcpqc6METwp9f6BV6VVc43m6MfH0VqFosHvrUgfXiFe6ww7R3itkOQ+TCK6Y+Iv/+RnnvtRZnkc5Kc9g==", + "dev": true, + "dependencies": { + "@types/node": "*" } }, "node_modules/@types/webpack": { @@ -2227,7 +2168,6 @@ "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.18.0.tgz", "integrity": "sha512-94EQTWZ40mzBc42ATNIBimBEDltSJ9RQHCC8vc/PDbxi4k8dVwUAv4o98dk50M1zB+JGFxp43FP7f8+FP8R6Sw==", "dev": true, - "license": "MIT", "dependencies": { "@eslint-community/regexpp": "^4.10.0", "@typescript-eslint/scope-manager": "7.18.0", @@ -2261,7 +2201,6 @@ "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.18.0.tgz", "integrity": "sha512-4Z+L8I2OqhZV8qA132M4wNL30ypZGYOQVBfMgxDH/K5UX0PNqTu1c6za9ST5r9+tavvHiTWmBnKzpCJ/GlVFtg==", "dev": true, - "license": "BSD-2-Clause", "dependencies": { "@typescript-eslint/scope-manager": "7.18.0", "@typescript-eslint/types": "7.18.0", @@ -2290,7 +2229,6 @@ "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.18.0.tgz", "integrity": "sha512-jjhdIE/FPF2B7Z1uzc6i3oWKbGcHb87Qw7AWj6jmEqNOfDFbJWtjt/XfwCpvNkpGWlcJaog5vTR+VV8+w9JflA==", "dev": true, - "license": "MIT", "dependencies": { "@typescript-eslint/types": "7.18.0", "@typescript-eslint/visitor-keys": "7.18.0" @@ -2308,7 +2246,6 @@ "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.18.0.tgz", "integrity": "sha512-XL0FJXuCLaDuX2sYqZUUSOJ2sG5/i1AAze+axqmLnSkNEVMVYLF+cbwlB2w8D1tinFuSikHmFta+P+HOofrLeA==", "dev": true, - "license": "MIT", "dependencies": { "@typescript-eslint/typescript-estree": "7.18.0", "@typescript-eslint/utils": "7.18.0", @@ -2336,7 +2273,6 @@ "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.18.0.tgz", "integrity": "sha512-iZqi+Ds1y4EDYUtlOOC+aUmxnE9xS/yCigkjA7XpTKV6nCBd3Hp/PRGGmdwnfkV2ThMyYldP1wRpm/id99spTQ==", "dev": true, - "license": "MIT", "engines": { "node": "^18.18.0 || >=20.0.0" }, @@ -2350,7 +2286,6 @@ "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.18.0.tgz", "integrity": "sha512-aP1v/BSPnnyhMHts8cf1qQ6Q1IFwwRvAQGRvBFkWlo3/lH29OXA3Pts+c10nxRxIBrDnoMqzhgdwVe5f2D6OzA==", "dev": true, - "license": "BSD-2-Clause", "dependencies": { "@typescript-eslint/types": "7.18.0", "@typescript-eslint/visitor-keys": "7.18.0", @@ -2374,69 +2309,11 @@ } } }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/array-union": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", - "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/globby": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", - "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", - "dev": true, - "license": "MIT", - "dependencies": { - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.2.9", - "ignore": "^5.2.0", - "merge2": "^1.4.1", - "slash": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", - "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/@typescript-eslint/typescript-estree/node_modules/semver": { "version": "7.6.3", "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", "dev": true, - "license": "ISC", "bin": { "semver": "bin/semver.js" }, @@ -2444,22 +2321,11 @@ "node": ">=10" } }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, "node_modules/@typescript-eslint/utils": { "version": "7.18.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.18.0.tgz", "integrity": "sha512-kK0/rNa2j74XuHVcoCZxdFBMF+aq/vH83CXAOHieC+2Gis4mF8jJXT5eAfyD3K0sAxtPuwxaIOIOvhwzVDt/kw==", "dev": true, - "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", "@typescript-eslint/scope-manager": "7.18.0", @@ -2482,7 +2348,6 @@ "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.18.0.tgz", "integrity": "sha512-cDF0/Gf81QpY3xYyJKDV14Zwdmid5+uuENhjH2EqFaF0ni+yAyq/LzMaIJdhNJXZI7uLzwIlA+V7oWoyn6Curg==", "dev": true, - "license": "MIT", "dependencies": { "@typescript-eslint/types": "7.18.0", "eslint-visitor-keys": "^3.4.3" @@ -2710,9 +2575,9 @@ "dev": true }, "node_modules/acorn": { - "version": "8.11.3", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", - "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==", + "version": "8.12.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.1.tgz", + "integrity": "sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==", "dev": true, "bin": { "acorn": "bin/acorn" @@ -2740,14 +2605,14 @@ } }, "node_modules/ajv": { - "version": "8.12.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", - "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", "dev": true, "dependencies": { "fast-deep-equal": "^3.1.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", "uri-js": "^4.2.2" }, "funding": { @@ -2772,17 +2637,36 @@ } } }, - "node_modules/ajv-keywords": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", - "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "node_modules/ajv-formats/node_modules/ajv": { + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", "dev": true, "dependencies": { - "fast-deep-equal": "^3.1.3" + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" }, - "peerDependencies": { - "ajv": "^8.8.2" - } + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ajv-formats/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + }, + "node_modules/ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "dev": true, + "peerDependencies": { + "ajv": "^6.9.1" + } }, "node_modules/ansi-regex": { "version": "5.0.1", @@ -2821,15 +2705,12 @@ } }, "node_modules/array-union": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz", - "integrity": "sha512-Dxr6QJj/RdU/hCaBjOfxW+q6lyuVE6JFWIrAUpuOOhoJJoQ99cUn3igRaHVB5P9WrgFVN0FfArM3x0cueOU8ng==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", "dev": true, - "dependencies": { - "array-uniq": "^1.0.1" - }, "engines": { - "node": ">=0.10.0" + "node": ">=8" } }, "node_modules/array-uniq": { @@ -2870,7 +2751,6 @@ "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.11.tgz", "integrity": "sha512-sMEJ27L0gRHShOh5G54uAAPaiCOygY/5ratXuiyb2G46FmlSpc9eFCzYVyDiPxfNbwzA7mYahmjQc5q+CZQ09Q==", "dev": true, - "license": "MIT", "dependencies": { "@babel/compat-data": "^7.22.6", "@babel/helper-define-polyfill-provider": "^0.6.2", @@ -2885,7 +2765,6 @@ "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.10.6.tgz", "integrity": "sha512-b37+KR2i/khY5sKmWNVQAnitvquQbNdWy6lJdsr0kmquCKEEUgMKK4SboVM3HtfnZilfjr4MMQ7vY58FVWDtIA==", "dev": true, - "license": "MIT", "dependencies": { "@babel/helper-define-polyfill-provider": "^0.6.2", "core-js-compat": "^3.38.0" @@ -2899,7 +2778,6 @@ "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.6.2.tgz", "integrity": "sha512-2R25rQZWP63nGwaAswvDazbPXfrM3HwVoBXK6HcqeKrSrL/JqcC/rDcf95l4r7LXLyxDXc8uQDa064GubtCABg==", "dev": true, - "license": "MIT", "dependencies": { "@babel/helper-define-polyfill-provider": "^0.6.2" }, @@ -2914,13 +2792,12 @@ "dev": true }, "node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", "dev": true, "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "balanced-match": "^1.0.0" } }, "node_modules/braces": { @@ -2954,7 +2831,6 @@ "url": "https://github.com/sponsors/ai" } ], - "license": "MIT", "dependencies": { "caniuse-lite": "^1.0.30001646", "electron-to-chromium": "^1.5.4", @@ -2984,9 +2860,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001657", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001657.tgz", - "integrity": "sha512-DPbJAlP8/BAXy3IgiWmZKItubb3TYGP0WscQQlVGIfT4s/YlFYVuJgyOsQNP7rJRChx/qdMeLJQJP0Sgg2yjNA==", + "version": "1.0.30001659", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001659.tgz", + "integrity": "sha512-Qxxyfv3RdHAfJcXelgf0hU4DFUVXBGTjqrBUZLUh8AtlGnsDo+CnncYtTd95+ZKfnANUOzxyIQCuU/UeBZBYoA==", "dev": true, "funding": [ { @@ -3001,8 +2877,7 @@ "type": "github", "url": "https://github.com/sponsors/ai" } - ], - "license": "CC-BY-4.0" + ] }, "node_modules/chalk": { "version": "2.4.2", @@ -3019,9 +2894,9 @@ } }, "node_modules/chrome-trace-event": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz", - "integrity": "sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.4.tgz", + "integrity": "sha512-rNjApaLzuwaOTjCiT8lSDdGN1APCiqkChLMJxJPWLunPAt5fy8xgU9/jNOchV84wfIxrA0lRQB7oCT8jrn/wrQ==", "dev": true, "engines": { "node": ">=6.0" @@ -3140,12 +3015,55 @@ "webpack": "^5.1.0" } }, + "node_modules/copy-webpack-plugin/node_modules/globby": { + "version": "14.0.2", + "resolved": "https://registry.npmjs.org/globby/-/globby-14.0.2.tgz", + "integrity": "sha512-s3Fq41ZVh7vbbe2PN3nrW7yC7U7MFVc5c98/iTl9c2GawNMKx/J648KQRW6WKkuU8GIbbh2IXfIRQjOZnXcTnw==", + "dev": true, + "dependencies": { + "@sindresorhus/merge-streams": "^2.1.0", + "fast-glob": "^3.3.2", + "ignore": "^5.2.4", + "path-type": "^5.0.0", + "slash": "^5.1.0", + "unicorn-magic": "^0.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/copy-webpack-plugin/node_modules/path-type": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-5.0.0.tgz", + "integrity": "sha512-5HviZNaZcfqP95rwpv+1HDgUamezbqdSYTyzjTvwtJSnIH+3vnbmWsItli8OFEndS984VT55M3jduxZbX351gg==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/copy-webpack-plugin/node_modules/slash": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-5.1.0.tgz", + "integrity": "sha512-ZA6oR3T/pEyuqwMgAKT0/hAv8oAXckzbkmR0UkUosQ+Mc4RxGoJkRmwHgHufaenlyAgE1Mxgpdcrf75y6XcnDg==", + "dev": true, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/core-js-compat": { "version": "3.38.1", "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.38.1.tgz", "integrity": "sha512-JRH6gfXxGmrzF3tZ57lFx97YARxCXPaMzPo6jELZhv88pBH5VXpQ+y0znKGlFnzuaihqhLbefxSJxWJMPtfDzw==", "dev": true, - "license": "MIT", "dependencies": { "browserslist": "^4.23.3" }, @@ -3169,12 +3087,12 @@ } }, "node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", + "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", "dev": true, "dependencies": { - "ms": "2.1.2" + "ms": "^2.1.3" }, "engines": { "node": ">=6.0" @@ -3219,6 +3137,18 @@ "node": ">=6" } }, + "node_modules/del/node_modules/array-union": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz", + "integrity": "sha512-Dxr6QJj/RdU/hCaBjOfxW+q6lyuVE6JFWIrAUpuOOhoJJoQ99cUn3igRaHVB5P9WrgFVN0FfArM3x0cueOU8ng==", + "dev": true, + "dependencies": { + "array-uniq": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/del/node_modules/globby": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/globby/-/globby-6.1.0.tgz", @@ -3259,7 +3189,6 @@ "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", "dev": true, - "license": "MIT", "dependencies": { "path-type": "^4.0.0" }, @@ -3280,11 +3209,10 @@ } }, "node_modules/electron-to-chromium": { - "version": "1.5.15", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.15.tgz", - "integrity": "sha512-Z4rIDoImwEJW+YYKnPul4DzqsWVqYetYVN3XqDmRpgV0mjz0hYTaeeh+8/9CL1bk3AHYmF4freW/NTiVoXA2gA==", - "dev": true, - "license": "ISC" + "version": "1.5.18", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.18.tgz", + "integrity": "sha512-1OfuVACu+zKlmjsNdcJuVQuVE61sZOLbNM4JAQ1Rvh6EOj0/EUKhMJjRH73InPlXSh8HIJk1cVZ8pyOV/FMdUQ==", + "dev": true }, "node_modules/emoji-regex": { "version": "8.0.0", @@ -3306,9 +3234,9 @@ } }, "node_modules/envinfo": { - "version": "7.11.1", - "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.11.1.tgz", - "integrity": "sha512-8PiZgZNIB4q/Lw4AhOvAfB/ityHAd2bli3lESSWmWSzSsl5dKpy5N1d1Rfkd2teq/g9xN90lc6o98DOjMeYHpg==", + "version": "7.13.0", + "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.13.0.tgz", + "integrity": "sha512-cvcaMr7KqXVh4nyzGTVqTum+gAiL265x5jUWQIDLq//zOGbW+gSW/C+OWLleY/rs9Qole6AZLMXPbtIFQbqu+Q==", "dev": true, "bin": { "envinfo": "dist/cli.js" @@ -3318,15 +3246,15 @@ } }, "node_modules/es-module-lexer": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.4.1.tgz", - "integrity": "sha512-cXLGjP0c4T3flZJKQSuziYoq7MlT+rnvfZjfp7h+I7K9BNX54kP9nyWvdbwjQ4u1iWbOL4u96fgeZLToQlZC7w==", + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.5.4.tgz", + "integrity": "sha512-MVNK56NiMrOwitFB7cqDwq0CQutbw+0BvLshJSse0MUNU+y1FC3bUS/AQg7oUng+/wKrrki7JfmwtVHkVfPLlw==", "dev": true }, "node_modules/escalade": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz", - "integrity": "sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", "dev": true, "engines": { "node": ">=6" @@ -3401,7 +3329,6 @@ "resolved": "https://registry.npmjs.org/eslint-plugin-chai-expect/-/eslint-plugin-chai-expect-3.1.0.tgz", "integrity": "sha512-a9F8b38hhJsR7fgDEfyMxppZXCnCW6OOHj7cQfygsm9guXqdSzfpwrHX5FT93gSExDqD71HQglF1lLkGBwhJ+g==", "dev": true, - "license": "MIT", "engines": { "node": "10.* || 12.* || || 14.* || 16.* || >= 18.*" }, @@ -3427,12 +3354,11 @@ "resolved": "https://registry.npmjs.org/eslint-plugin-jest/-/eslint-plugin-jest-28.8.3.tgz", "integrity": "sha512-HIQ3t9hASLKm2IhIOqnu+ifw7uLZkIlR7RYNv7fMcEi/p0CIiJmfriStQS2LDkgtY4nyLbIZAD+JL347Yc2ETQ==", "dev": true, - "license": "MIT", "dependencies": { "@typescript-eslint/utils": "^6.0.0 || ^7.0.0 || ^8.0.0" }, "engines": { - "node": "^16.10.0 || ^18.12.0 || >=20.0.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" }, "peerDependencies": { "@typescript-eslint/eslint-plugin": "^6.0.0 || ^7.0.0 || ^8.0.0", @@ -3449,9 +3375,9 @@ } }, "node_modules/eslint-plugin-mocha": { - "version": "10.4.3", - "resolved": "https://registry.npmjs.org/eslint-plugin-mocha/-/eslint-plugin-mocha-10.4.3.tgz", - "integrity": "sha512-emc4TVjq5Ht0/upR+psftuz6IBG5q279p+1dSRDeHf+NS9aaerBi3lXKo1SEzwC29hFIW21gO89CEWSvRsi8IQ==", + "version": "10.5.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-mocha/-/eslint-plugin-mocha-10.5.0.tgz", + "integrity": "sha512-F2ALmQVPT1GoP27O1JTZGrV9Pqg8k79OeIuvw63UxMtQKREZtmkK1NFgkZQ2TW7L2JSSFKHFPTtHu5z8R9QNRw==", "dev": true, "dependencies": { "eslint-utils": "^3.0.0", @@ -3481,16 +3407,19 @@ } }, "node_modules/eslint-scope": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", - "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", + "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", "dev": true, "dependencies": { "esrecurse": "^4.3.0", - "estraverse": "^4.1.1" + "estraverse": "^5.2.0" }, "engines": { - "node": ">=8.0.0" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, "node_modules/eslint-utils": { @@ -3532,22 +3461,6 @@ "url": "https://opencollective.com/eslint" } }, - "node_modules/eslint/node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, "node_modules/eslint/node_modules/ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", @@ -3563,6 +3476,16 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, + "node_modules/eslint/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, "node_modules/eslint/node_modules/chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", @@ -3609,47 +3532,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/eslint/node_modules/eslint-scope": { - "version": "7.2.2", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", - "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", - "dev": true, - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint/node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/eslint/node_modules/find-up": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", - "dev": true, - "dependencies": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/eslint/node_modules/globals": { "version": "13.24.0", "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", @@ -3674,73 +3556,16 @@ "node": ">=8" } }, - "node_modules/eslint/node_modules/is-path-inside": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", - "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/eslint/node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true - }, - "node_modules/eslint/node_modules/locate-path": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", - "dev": true, - "dependencies": { - "p-locate": "^5.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint/node_modules/p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "dev": true, - "dependencies": { - "yocto-queue": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint/node_modules/p-locate": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "node_modules/eslint/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "dev": true, "dependencies": { - "p-limit": "^3.0.2" + "brace-expansion": "^1.1.7" }, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint/node_modules/path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true, - "engines": { - "node": ">=8" + "node": "*" } }, "node_modules/eslint/node_modules/supports-color": { @@ -3755,18 +3580,6 @@ "node": ">=8" } }, - "node_modules/eslint/node_modules/yocto-queue": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", - "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/espree": { "version": "9.6.1", "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", @@ -3785,9 +3598,9 @@ } }, "node_modules/esquery": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", - "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", + "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", "dev": true, "dependencies": { "estraverse": "^5.1.0" @@ -3796,15 +3609,6 @@ "node": ">=0.10" } }, - "node_modules/esquery/node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, "node_modules/esrecurse": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", @@ -3817,7 +3621,7 @@ "node": ">=4.0" } }, - "node_modules/esrecurse/node_modules/estraverse": { + "node_modules/estraverse": { "version": "5.3.0", "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", @@ -3826,15 +3630,6 @@ "node": ">=4.0" } }, - "node_modules/estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, "node_modules/esutils": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", @@ -3899,6 +3694,12 @@ "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", "dev": true }, + "node_modules/fast-uri": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.0.1.tgz", + "integrity": "sha512-MWipKbbYiYI0UC7cl8m/i/IWTqfC8YXsqjzybjddLsFjStroQzsHXkc73JutMvBiXmOvapk+axIl79ig5t55Bw==", + "dev": true + }, "node_modules/fastest-levenshtein": { "version": "1.0.16", "resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz", @@ -3958,16 +3759,16 @@ } }, "node_modules/find-up": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-6.3.0.tgz", - "integrity": "sha512-v2ZsoEuVHYy8ZIlYqwPe/39Cy+cFDzp4dXPaxNvkEuouymu+2Jbz0PxpKarJHYJTmv2HWT3O382qY8l4jMWthw==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", "dev": true, "dependencies": { - "locate-path": "^7.1.0", - "path-exists": "^5.0.0" + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" }, "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + "node": ">=10" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -4000,6 +3801,7 @@ "version": "3.0.2", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", "dev": true, "dependencies": { "glob": "^7.1.3" @@ -4054,6 +3856,7 @@ "version": "7.2.3", "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", "dev": true, "dependencies": { "fs.realpath": "^1.0.0", @@ -4088,6 +3891,28 @@ "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", "dev": true }, + "node_modules/glob/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/glob/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, "node_modules/globals": { "version": "11.12.0", "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", @@ -4098,34 +3923,20 @@ } }, "node_modules/globby": { - "version": "14.0.2", - "resolved": "https://registry.npmjs.org/globby/-/globby-14.0.2.tgz", - "integrity": "sha512-s3Fq41ZVh7vbbe2PN3nrW7yC7U7MFVc5c98/iTl9c2GawNMKx/J648KQRW6WKkuU8GIbbh2IXfIRQjOZnXcTnw==", + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", "dev": true, - "license": "MIT", "dependencies": { - "@sindresorhus/merge-streams": "^2.1.0", - "fast-glob": "^3.3.2", - "ignore": "^5.2.4", - "path-type": "^5.0.0", - "slash": "^5.1.0", - "unicorn-magic": "^0.1.0" - }, - "engines": { - "node": ">=18" + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/globby/node_modules/path-type": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-5.0.0.tgz", - "integrity": "sha512-5HviZNaZcfqP95rwpv+1HDgUamezbqdSYTyzjTvwtJSnIH+3vnbmWsItli8OFEndS984VT55M3jduxZbX351gg==", - "dev": true, - "license": "MIT", "engines": { - "node": ">=12" + "node": ">=10" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -4153,9 +3964,9 @@ } }, "node_modules/hasown": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.1.tgz", - "integrity": "sha512-1/th4MHjnwncwXsIW6QMzlvYL9kG5e/CpVvLRZe4XPa8TOUNbCELqmvhDmnkNsAjwaG4+I8gJJL0JBvTTLO9qA==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", "dev": true, "dependencies": { "function-bind": "^1.1.2" @@ -4171,9 +3982,9 @@ "dev": true }, "node_modules/ignore": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz", - "integrity": "sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==", + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", "dev": true, "engines": { "node": ">= 4" @@ -4195,19 +4006,10 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/import-fresh/node_modules/resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true, - "engines": { - "node": ">=4" - } - }, "node_modules/import-local": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz", - "integrity": "sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.2.0.tgz", + "integrity": "sha512-2SPlun1JUPWoM6t3F0dw0FkCF/jWY8kttcY4f599GLTSjh2OCuuhdTkJQsEcZzBqbXZGKMK2OqW1oZsjtf/gQA==", "dev": true, "dependencies": { "pkg-dir": "^4.2.0", @@ -4275,15 +4077,6 @@ "node": ">=8" } }, - "node_modules/import-local/node_modules/path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/import-local/node_modules/pkg-dir": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", @@ -4309,6 +4102,7 @@ "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", "dev": true, "dependencies": { "once": "^1.3.0", @@ -4331,12 +4125,15 @@ } }, "node_modules/is-core-module": { - "version": "2.13.1", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz", - "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==", + "version": "2.15.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.15.1.tgz", + "integrity": "sha512-z0vtXSwucUJtANQWldhbtbt7BnL0vxiFjIdDLAatwhDYty2bad6s+rijD6Ri4YuYJubLzIJLUidCh09e1djEVQ==", "dev": true, "dependencies": { - "hasown": "^2.0.0" + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -4402,7 +4199,7 @@ "node": ">=6" } }, - "node_modules/is-path-inside": { + "node_modules/is-path-in-cwd/node_modules/is-path-inside": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-2.1.0.tgz", "integrity": "sha512-wiyhTzfDWsvwAW53OBWF5zuvaOGlZ6PwYxAbPVDhpm+gM09xKQGjBq/8uYN12aDvMxnAnq3dxTyoSoRNmg5YFg==", @@ -4414,6 +4211,15 @@ "node": ">=6" } }, + "node_modules/is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/is-plain-object": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", @@ -4483,8 +4289,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/js-yaml": { "version": "4.1.0", @@ -4523,9 +4328,9 @@ "dev": true }, "node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", "dev": true }, "node_modules/json-stable-stringify-without-jsonify": { @@ -4626,15 +4431,15 @@ } }, "node_modules/locate-path": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-7.2.0.tgz", - "integrity": "sha512-gvVijfZvn7R+2qyPX8mAuKcFGDf6Nc61GdvGafQsHL0sBIxfKzA+usWn4GFC/bk+QdwPUD4kWFJLhElipq+0VA==", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", "dev": true, "dependencies": { - "p-locate": "^6.0.0" + "p-locate": "^5.0.0" }, "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + "node": ">=10" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -4644,8 +4449,7 @@ "version": "4.0.8", "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/lodash.merge": { "version": "4.6.2", @@ -4678,12 +4482,12 @@ } }, "node_modules/micromatch": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", - "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", "dev": true, "dependencies": { - "braces": "^3.0.2", + "braces": "^3.0.3", "picomatch": "^2.3.1" }, "engines": { @@ -4712,15 +4516,18 @@ } }, "node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", "dev": true, "dependencies": { - "brace-expansion": "^1.1.7" + "brace-expansion": "^2.0.1" }, "engines": { - "node": "*" + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, "node_modules/minimist": { @@ -4745,9 +4552,9 @@ } }, "node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", "dev": true }, "node_modules/natural-compare": { @@ -4766,8 +4573,7 @@ "version": "2.0.18", "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.18.tgz", "integrity": "sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/nopt": { "version": "4.0.3", @@ -4875,6 +4681,7 @@ "version": "0.1.5", "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz", "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==", + "deprecated": "This package is no longer supported.", "dev": true, "dependencies": { "os-homedir": "^1.0.0", @@ -4882,30 +4689,30 @@ } }, "node_modules/p-limit": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-4.0.0.tgz", - "integrity": "sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", "dev": true, "dependencies": { - "yocto-queue": "^1.0.0" + "yocto-queue": "^0.1.0" }, "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + "node": ">=10" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/p-locate": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-6.0.0.tgz", - "integrity": "sha512-wPrq66Llhl7/4AGC6I+cqxT07LhXvWL08LNXz1fENOw0Ap4sRZZ/gZpTTJ5jpurzzzfS2W/Ge9BY3LgLjCShcw==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", "dev": true, "dependencies": { - "p-limit": "^4.0.0" + "p-limit": "^3.0.2" }, "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + "node": ">=10" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -4929,6 +4736,12 @@ "node": ">=6" } }, + "node_modules/papaparse": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/papaparse/-/papaparse-5.4.1.tgz", + "integrity": "sha512-HipMsgJkZu8br23pW15uvo6sib6wne/4woLZPlFf3rpDyMe9ywEXUsuD7+6K9PRkJlVT51j/sCOYDKGGS3ZJrw==", + "dev": true + }, "node_modules/parent-module": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", @@ -4942,12 +4755,12 @@ } }, "node_modules/path-exists": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-5.0.0.tgz", - "integrity": "sha512-RjhtfwJOxzcFmNOi6ltcbcu4Iu+FL3zEj83dk4kAS+fVpTxXLO1b38RvJgT/0QwvV/L3aY9TAnyv0EOqW4GoMQ==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", "dev": true, "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + "node": ">=8" } }, "node_modules/path-is-absolute": { @@ -4985,17 +4798,15 @@ "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", "dev": true, - "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/picocolors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.1.tgz", - "integrity": "sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==", - "dev": true, - "license": "ISC" + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.0.tgz", + "integrity": "sha512-TQ92mBOW0l3LeMeyLV6mzy/kWr8lkd/hp3mTg7wYK7zJhuBStmGMBG0BdeDZS/dZx1IukaX6Bk11zcln25o1Aw==", + "dev": true }, "node_modules/picomatch": { "version": "2.3.1", @@ -5054,6 +4865,88 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/pkg-dir/node_modules/find-up": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-6.3.0.tgz", + "integrity": "sha512-v2ZsoEuVHYy8ZIlYqwPe/39Cy+cFDzp4dXPaxNvkEuouymu+2Jbz0PxpKarJHYJTmv2HWT3O382qY8l4jMWthw==", + "dev": true, + "dependencies": { + "locate-path": "^7.1.0", + "path-exists": "^5.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pkg-dir/node_modules/locate-path": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-7.2.0.tgz", + "integrity": "sha512-gvVijfZvn7R+2qyPX8mAuKcFGDf6Nc61GdvGafQsHL0sBIxfKzA+usWn4GFC/bk+QdwPUD4kWFJLhElipq+0VA==", + "dev": true, + "dependencies": { + "p-locate": "^6.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pkg-dir/node_modules/p-limit": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-4.0.0.tgz", + "integrity": "sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ==", + "dev": true, + "dependencies": { + "yocto-queue": "^1.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pkg-dir/node_modules/p-locate": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-6.0.0.tgz", + "integrity": "sha512-wPrq66Llhl7/4AGC6I+cqxT07LhXvWL08LNXz1fENOw0Ap4sRZZ/gZpTTJ5jpurzzzfS2W/Ge9BY3LgLjCShcw==", + "dev": true, + "dependencies": { + "p-limit": "^4.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pkg-dir/node_modules/path-exists": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-5.0.0.tgz", + "integrity": "sha512-RjhtfwJOxzcFmNOi6ltcbcu4Iu+FL3zEj83dk4kAS+fVpTxXLO1b38RvJgT/0QwvV/L3aY9TAnyv0EOqW4GoMQ==", + "dev": true, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + } + }, + "node_modules/pkg-dir/node_modules/yocto-queue": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.1.1.tgz", + "integrity": "sha512-b4JR1PFR10y1mKjhHY9LaGo6tmrgjit7hxVIeAmyMw3jegXR4dhYqLaQF5zMXZxY7tLpMyJeLjr1C4rLmkVe8g==", + "dev": true, + "engines": { + "node": ">=12.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/prelude-ls": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", @@ -5068,7 +4961,6 @@ "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.3.3.tgz", "integrity": "sha512-i2tDNA0O5IrMO757lfrdQZCc2jPNDVntV0m/+4whiDfWaTKfMNgR7Qz0NAeGz/nRqF4m5/6CLzbP4/liHt12Ew==", "dev": true, - "license": "MIT", "bin": { "prettier": "bin/prettier.cjs" }, @@ -5127,6 +5019,7 @@ "version": "4.0.3", "resolved": "https://registry.npmjs.org/read-installed/-/read-installed-4.0.3.tgz", "integrity": "sha512-O03wg/IYuV/VtnK2h/KXEt9VIbMUFbk3ERG0Iu4FhLZw0EP0T9znqrYDGn6ncbEsXUFaUjiVAWXHzxwt3lhRPQ==", + "deprecated": "This package is no longer supported.", "dev": true, "dependencies": { "debuglog": "^1.0.1", @@ -5153,6 +5046,7 @@ "version": "2.1.2", "resolved": "https://registry.npmjs.org/read-package-json/-/read-package-json-2.1.2.tgz", "integrity": "sha512-D1KmuLQr6ZSJS0tW8hf3WGpRlwszJOXZ3E8Yd/DNRaM5d+1wVRZdHlpGBLAuovjr28LbWvjpWkBHMxpRGGjzNA==", + "deprecated": "This package is no longer supported. Please use @npmcli/package-json instead.", "dev": true, "dependencies": { "glob": "^7.1.1", @@ -5304,7 +5198,7 @@ "node": ">=8" } }, - "node_modules/resolve-from": { + "node_modules/resolve-cwd/node_modules/resolve-from": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", @@ -5313,6 +5207,15 @@ "node": ">=8" } }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "engines": { + "node": ">=4" + } + }, "node_modules/reusify": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", @@ -5327,6 +5230,7 @@ "version": "2.7.1", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", "dev": true, "dependencies": { "glob": "^7.1.3" @@ -5397,6 +5301,40 @@ "url": "https://opencollective.com/webpack" } }, + "node_modules/schema-utils/node_modules/ajv": { + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/schema-utils/node_modules/ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.3" + }, + "peerDependencies": { + "ajv": "^8.8.2" + } + }, + "node_modules/schema-utils/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + }, "node_modules/semver": { "version": "6.3.1", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", @@ -5449,16 +5387,12 @@ } }, "node_modules/slash": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-5.1.0.tgz", - "integrity": "sha512-ZA6oR3T/pEyuqwMgAKT0/hAv8oAXckzbkmR0UkUosQ+Mc4RxGoJkRmwHgHufaenlyAgE1Mxgpdcrf75y6XcnDg==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", "dev": true, - "license": "MIT", "engines": { - "node": ">=14.16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=8" } }, "node_modules/slide": { @@ -5527,9 +5461,9 @@ } }, "node_modules/spdx-license-ids": { - "version": "3.0.17", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.17.tgz", - "integrity": "sha512-sh8PWc/ftMqAAdFiBu6Fy6JUOYjqDJBJvIhpfDMyHrr0Rbp5liZqd4TjtQ/RgfLjKFZb+LMx5hpml5qOWy0qvg==", + "version": "3.0.20", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.20.tgz", + "integrity": "sha512-jg25NiDV/1fLtSgEgyvVyDunvaNHbuwF9lfNV17gSmPFAlYzdfNBlLtLzXTevwkPj7DhGbmN9VnmJIgLnhvaBw==", "dev": true }, "node_modules/spdx-ranges": { @@ -5621,9 +5555,9 @@ } }, "node_modules/terser": { - "version": "5.28.1", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.28.1.tgz", - "integrity": "sha512-wM+bZp54v/E9eRRGXb5ZFDvinrJIOaTapx3WUokyVGZu5ucVCK55zEgGd5Dl2fSr3jUo5sDiERErUWLY6QPFyA==", + "version": "5.32.0", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.32.0.tgz", + "integrity": "sha512-v3Gtw3IzpBJ0ugkxEX8U0W6+TnPKRRCWGh1jC/iM/e3Ki5+qvO1L1EAZ56bZasc64aXHwRHNIQEzm6//i5cemQ==", "dev": true, "dependencies": { "@jridgewell/source-map": "^0.3.3", @@ -5672,37 +5606,6 @@ } } }, - "node_modules/terser-webpack-plugin/node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/terser-webpack-plugin/node_modules/ajv-keywords": { - "version": "3.5.2", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", - "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", - "dev": true, - "peerDependencies": { - "ajv": "^6.9.1" - } - }, - "node_modules/terser-webpack-plugin/node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true - }, "node_modules/terser-webpack-plugin/node_modules/schema-utils": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", @@ -5799,7 +5702,6 @@ "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.6.2.tgz", "integrity": "sha512-NW8ByodCSNCwZeghjN3o+JX5OFH0Ojg6sadjEKY4huZ52TqbJTJnDo5+Tw98lSy63NZvi4n+ez5m2u5d4PkZyw==", "dev": true, - "license": "Apache-2.0", "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -5809,9 +5711,9 @@ } }, "node_modules/undici-types": { - "version": "5.26.5", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", - "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", + "version": "6.19.8", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz", + "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==", "dev": true }, "node_modules/unicode-canonical-property-names-ecmascript": { @@ -5859,7 +5761,6 @@ "resolved": "https://registry.npmjs.org/unicorn-magic/-/unicorn-magic-0.1.0.tgz", "integrity": "sha512-lRfVq8fE8gz6QMBuDM6a+LO3IAzTi05H6gCVaUpir2E1Rwpo4ZUog45KpNXKC/Mn3Yb9UDuHumeFTo9iV/D9FQ==", "dev": true, - "license": "MIT", "engines": { "node": ">=18" }, @@ -5886,7 +5787,6 @@ "url": "https://github.com/sponsors/ai" } ], - "license": "MIT", "dependencies": { "escalade": "^3.1.2", "picocolors": "^1.0.1" @@ -6046,10 +5946,21 @@ "glob": "^5.0.15" } }, + "node_modules/webpack-glob-entries/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, "node_modules/webpack-glob-entries/node_modules/glob": { "version": "5.0.15", "resolved": "https://registry.npmjs.org/glob/-/glob-5.0.15.tgz", "integrity": "sha512-c9IPMazfRITpmAAKi22dK1VKxGDX9ehhqfABDriL/lzO92xcUKEJPQHrVA/2YHSNFB4iFlykVmWvwo48nr3OxA==", + "deprecated": "Glob versions prior to v9 are no longer supported", "dev": true, "dependencies": { "inflight": "^1.0.4", @@ -6062,6 +5973,18 @@ "node": "*" } }, + "node_modules/webpack-glob-entries/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, "node_modules/webpack-merge": { "version": "5.10.0", "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.10.0.tgz", @@ -6085,40 +6008,30 @@ "node": ">=10.13.0" } }, - "node_modules/webpack/node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "node_modules/webpack/node_modules/eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", "dev": true, "license": "MIT", "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" + "engines": { + "node": ">=8.0.0" } }, - "node_modules/webpack/node_modules/ajv-keywords": { - "version": "3.5.2", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", - "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "node_modules/webpack/node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", "dev": true, "license": "MIT", "peerDependencies": { "ajv": "^6.9.1" } }, - "node_modules/webpack/node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true, - "license": "MIT" - }, "node_modules/webpack/node_modules/schema-utils": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", @@ -6267,12 +6180,12 @@ } }, "node_modules/yocto-queue": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.0.0.tgz", - "integrity": "sha512-9bnSc/HEW2uRy67wc+T8UwauLuPJVn28jb+GtJY16iiKWyvmYJRXVT4UamsAEGQfPohgr2q4Tq0sQbQlxTfi1g==", + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", "dev": true, "engines": { - "node": ">=12.20" + "node": ">=10" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" diff --git a/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/package.json b/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/package.json index 0db1e91f30..8fdb7881ff 100644 --- a/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/package.json +++ b/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/package.json @@ -10,15 +10,20 @@ "@js-soft/eslint-config-ts": "1.6.9", "@js-soft/license-check": "1.0.9", "@types/k6": "~0.54.0", + "@types/papaparse": "^5.3.14", "@types/webpack": "5.28.5", "babel-loader": "9.2.1", "clean-webpack-plugin": "4.0.0", "copy-webpack-plugin": "12.0.2", "eslint": "^8.57.0", + "papaparse": "^5.4.1", "prettier": "3.3.3", "typescript": "5.6.2", "webpack": "5.95.0", "webpack-cli": "5.1.4", "webpack-glob-entries": "1.0.1" + }, + "scripts": { + "build": "npx webpack" } } diff --git a/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/scripts/linux/load-snapshot.sh b/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/scripts/linux/load-snapshot.sh new file mode 100644 index 0000000000..7dfadb24b2 --- /dev/null +++ b/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/scripts/linux/load-snapshot.sh @@ -0,0 +1,46 @@ +#!/bin/bash + +# Check if unzip is installed, and install it if not +if ! command -v unzip &> /dev/null; then + echo "'unzip' is not installed. Installing it now..." + sudo apt update && sudo apt install -y unzip +fi +# Default values for parameters +SNAPSHOT_NAME=$1 +HOSTNAME=${2:-"host.docker.internal"} +USERNAME=${3:-"postgres"} +PASSWORD=${4:-"admin"} +DB_NAME=${5:-"enmeshed"} + +# Prompt for the snapshot name if not provided +if [ -z "$SNAPSHOT_NAME" ]; then + read -p "Enter the snapshot name: " SNAPSHOT_NAME +fi + +# Get the current script location +SCRIPT_PATH="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" +ROOT_PATH=$(realpath "$SCRIPT_PATH/../..") +SNAPSHOTS_FOLDER="$ROOT_PATH/snapshots" +SNAPSHOT_FILE_PATH="$SNAPSHOTS_FOLDER/$SNAPSHOT_NAME.zip" +REPO_ROOT=$(realpath "$SCRIPT_PATH/../../../../../..") + +# Check if the file exists +echo "Snapshot file path: $SNAPSHOT_FILE_PATH" +if [ ! -f "$SNAPSHOT_FILE_PATH" ]; then + echo "Snapshot file '$SNAPSHOT_NAME' not found in the 'snapshots' folder." + exit 1 +fi + +# Extract the zip file +echo "Extracting '$SNAPSHOT_NAME'..." +if unzip -o "$SNAPSHOT_FILE_PATH" -d "$SNAPSHOTS_FOLDER"; then + echo "Extraction complete. Files are in '$SNAPSHOTS_FOLDER'." + mv -f "$SNAPSHOTS_FOLDER/$SNAPSHOT_NAME/enmeshed.pg" "$REPO_ROOT/scripts/dumps/dump-files/" +else + echo "An error occurred during extraction." + exit 1 +fi + +# Load Postgres +LOAD_POSTGRES="$REPO_ROOT/scripts/dumps/load_postgres.sh" +bash "$LOAD_POSTGRES" "$HOSTNAME" "$USERNAME" "$PASSWORD" "$DB_NAME" "enmeshed.pg" diff --git a/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/scripts/linux/run-test.sh b/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/scripts/linux/run-test.sh new file mode 100755 index 0000000000..10c19c3c8b --- /dev/null +++ b/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/scripts/linux/run-test.sh @@ -0,0 +1,66 @@ +#!/bin/bash + +# Get the scenario, either from the command line argument or by prompting the user +s="$1" +if [ -z "$s" ]; then + read -p "Which scenario should be executed? " s +fi + +# Capture all arguments after `--` +while [ "$1" != "--" ] && [ -n "$1" ]; do + s="$1" + shift +done + +# Shift past `--` +if [ "$1" == "--" ]; then + shift +fi + +npm install -g webpack-cli tsx webpack + +# Remaining arguments are for `k6` +k6Arguments="$@" + +# Generate a timestamp `t` in the format YYYYMMDD-HHmmSS +t=$(date +"%Y%m%d-%H%M%S") + +# Construct the file paths and commands +testFile="./dist/${s}.test.js" +outputFile="./k6-outputs/${t}-${s}.csv" +resultAnalyzerFolder="./tools/result-analyzer" + +# ensure the the result analyzer has its dependencies installed + +cd tools/result-analyzer + +npm i + +cd ../.. + +mkdir -p k6-results + +# Run the `npx webpack` command +npx webpack + +# Check the exit status of the webpack command +if [ $? -ne 0 ]; then + echo "Error: Webpack failed." + exit 1 +fi + +# Check if the test file exists +if [ ! -f "$testFile" ]; then + echo "Error: Test file '$testFile' does not exist." + exit 1 +fi + +# Run the `k6` command +k6 run "$testFile" -o "csv=$outputFile" $k6Arguments + +# Run the result analyzer script +cd $resultAnalyzerFolder + +npx tsx "src/main.js" "$outputFile" + +cd ../.. diff --git a/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/scripts/windows/load-snapshot.ps1 b/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/scripts/windows/load-snapshot.ps1 new file mode 100644 index 0000000000..e64ae2c5b7 --- /dev/null +++ b/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/scripts/windows/load-snapshot.ps1 @@ -0,0 +1,35 @@ +# PowerShell Script to Extract a Zip File from 'snapshots' Folder + +param( + [string]$SnapshotName, + [string]$Hostname = "host.docker.internal", + [string]$Username = "postgres", + [string]$Password = "admin", + [string]$DbName = "enmeshed" +) + +Add-Type -AssemblyName System.IO.Compression.FileSystem + +# Check if the snapshot is provided; if not, prompt the user +if (-not $SnapshotName) { + $SnapshotName = Read-Host "Enter the name of the zip file (without extension). The file should be present in the 'snapshots' folder" +} + +$repoRoot = git rev-parse --show-toplevel +$snapshotZipPath = "$repoRoot\Applications\ConsumerApi\test\ConsumerApi.Tests.Performance\snapshots\$SnapshotName.zip" + +if (-not (Test-Path $snapshotZipPath)) { + throw "Snapshot file '$SnapshotName' not found in the 'snapshots' folder." +} + +# Extract the zip file +try { + Write-Host "Extracting '$SnapshotName'..." + [System.IO.Compression.ZipFile]::ExtractToDirectory($snapshotZipPath, "$repoRoot\scripts\windows\dumps\dump-files", 1) + +} +catch { + Write-Host "An error occurred during extraction: $_" +} + +& "$repoRoot\scripts\windows\dumps\load-postgres.ps1" -Hostname $Hostname -Username $Username -Password $Password -DbName $DbName -Dumpfile enmeshed.pg diff --git a/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/scripts/windows/run-test.ps1 b/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/scripts/windows/run-test.ps1 new file mode 100644 index 0000000000..767c171d16 --- /dev/null +++ b/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/scripts/windows/run-test.ps1 @@ -0,0 +1,54 @@ +param ( + [string]$s +) + +# Check if the scenario is provided; if not, prompt the user +if (-not $s) { + $s = Read-Host "Enter the scenario name" +} + +# install required global packages +npm install -g webpack-cli tsx webpack + +$k6Arguments = $args + +# Generate a timestamp `t` in the format YYYYMMDD-HHmmSS +$t = Get-Date -Format "yyyyMMdd-HHmmss" + +# Construct the file paths and commands +$testFile = ".\dist\$($s).test.js" +$outputFile = "k6-outputs\$($t)-$($s).csv" +$resultAnalyzerFolder = ".\tools\result-analyzer" + +# Run the `npx webpack` command +npx webpack + +Set-Location tools\result-analyzer + +npm install + +Set-Location ..\.. + +New-Item -Path "k6-outputs" -ItemType Directory -Force + +# Check the exit code of the webpack command +if ($LASTEXITCODE -ne 0) { + Write-Host "Error: Webpack failed with exit code $LASTEXITCODE." -ForegroundColor Red + exit $LASTEXITCODE +} + +# Check if the test file exists +if (-not (Test-Path $testFile)) { + Write-Host "Error: Test file '$testFile' does not exist." -ForegroundColor Red + exit 1 +} + +try { + # Run the `k6` command with additional arguments + k6 run $testFile -v -o "csv=$outputFile" @k6Arguments +} +finally { + # Run the result analyzer script + npx tsx $resultAnalyzerFolder\src\main.js $outputFile + Write-Host "Result file can be found at '$outputFile'." +} diff --git a/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/snapshots/.gitignore b/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/snapshots/.gitignore deleted file mode 100644 index 72e8ffc0db..0000000000 --- a/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/snapshots/.gitignore +++ /dev/null @@ -1 +0,0 @@ -* diff --git a/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/snapshots/light.zip b/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/snapshots/light.zip new file mode 100644 index 0000000000..d02aa7b126 Binary files /dev/null and b/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/snapshots/light.zip differ diff --git a/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/src/libs/backbone-client/authenticated-client.ts b/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/src/libs/backbone-client/authenticated-client.ts new file mode 100644 index 0000000000..c0f66a90b1 --- /dev/null +++ b/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/src/libs/backbone-client/authenticated-client.ts @@ -0,0 +1,47 @@ +import { BaseClient } from "./base-client"; +import { HttpClientConfiguration } from "./http-client-configuration"; +import { CreateChallengeResponse, JwtResponse } from "./models"; + +export class AuthenticatedClient extends BaseClient { + private token_expires_at = new Date(); + private access_token = ""; + private readonly password: string; + private readonly username: string; + + public constructor(username: string, password: string, configuration: HttpClientConfiguration) { + super(configuration); + + this.username = username; + this.password = password; + } + + private tokenIsStillValid(): boolean { + return +this.token_expires_at - 1000 > +new Date(); + } + + private exchangeToken() { + const payload = { + client_id: this.configuration.clientId, + client_secret: this.configuration.clientSecret, + grant_type: "password", + username: this.username, + password: this.password + }; + const response = this.client.request().setEndpoint("connect/token").setHeaders({ "Content-Type": "application/x-www-form-urlencoded" }).post(payload, null); + + this.access_token = `${response.token_type} ${response.access_token}`; + this.token_expires_at = new Date(+new Date() + response.expires_in * 1000); + } + + private getAccessToken(): string { + if (!this.tokenIsStillValid()) { + this.exchangeToken(); + } + + return this.access_token; + } + + public getChallenge(): CreateChallengeResponse { + return this.client.request().setEndpoint(`api/${this.configuration.apiVersion}/Challenges`).withJsonBody().authenticate(this.getAccessToken()).post(null); + } +} diff --git a/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/src/libs/backbone-client/base-client.ts b/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/src/libs/backbone-client/base-client.ts new file mode 100644 index 0000000000..80fd3bb037 --- /dev/null +++ b/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/src/libs/backbone-client/base-client.ts @@ -0,0 +1,20 @@ +import { Httpx } from "https://jslib.k6.io/httpx/0.1.0/index.js"; +import { FluentClient } from "./fluent-client"; +import { HttpClientConfiguration } from "./http-client-configuration"; + +export class BaseClient { + protected readonly client: FluentClient; + protected readonly httpxClient: Httpx; + protected readonly configuration: HttpClientConfiguration; + + protected constructor(config: HttpClientConfiguration) { + this.httpxClient = new Httpx({ + baseURL: config.baseUrl, + timeout: config.timeoutInMilliseconds + }); + + this.configuration = config; + + this.client = new FluentClient(this.httpxClient); + } +} diff --git a/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/src/libs/backbone-client/constants.ts b/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/src/libs/backbone-client/constants.ts deleted file mode 100644 index c22852e384..0000000000 --- a/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/src/libs/backbone-client/constants.ts +++ /dev/null @@ -1,4 +0,0 @@ -export const apiVersion = "v1"; -export const clientId = "test"; -export const clientSecret = "test"; -export const defaultPassword = "Passw0rd!"; diff --git a/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/src/libs/backbone-client/fluent-client.ts b/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/src/libs/backbone-client/fluent-client.ts new file mode 100644 index 0000000000..ee11042a42 --- /dev/null +++ b/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/src/libs/backbone-client/fluent-client.ts @@ -0,0 +1,14 @@ +import { Httpx } from "https://jslib.k6.io/httpx/0.1.0/index.js"; +import { FluentRequest } from "./fluent-request"; + +export class FluentClient { + public readonly httpxClient: Httpx; + + public constructor(client: Httpx) { + this.httpxClient = client; + } + + public request(): FluentRequest { + return new FluentRequest(this); + } +} diff --git a/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/src/libs/backbone-client/fluent-request.ts b/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/src/libs/backbone-client/fluent-request.ts new file mode 100644 index 0000000000..c251d90aba --- /dev/null +++ b/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/src/libs/backbone-client/fluent-request.ts @@ -0,0 +1,81 @@ +import { TypedResponse } from "https://jslib.k6.io/httpx/0.1.0/index.js"; +import { RequestBody } from "k6/http"; +import { FluentClient } from "./fluent-client"; + +export class FluentRequest { + private readonly statelessClient: FluentClient; + private endpoint!: string; + private headers!: Record; + + public constructor(client: FluentClient) { + this.statelessClient = client; + } + + public setEndpoint(endpoint: string): this { + this.endpoint = endpoint; + return this; + } + + public setHeaders(headers: Record): this { + this.headers = headers; + return this; + } + + public authenticate(token: string): this { + this.headers = { ...this.headers, Authorization: token }; + return this; + } + + public withJsonBody(): this { + this.headers = { ...this.headers, "Content-Type": "application/json" }; + return this; + } + + public post(body: RequestBody | null, jsonRootKey: string | null = "result"): T { + const response = this.statelessClient.httpxClient.post(this.endpoint, body, { headers: this.headers }); + + this.ThrowIfResponse4or5(response, "POST"); + return this.getJson(response, jsonRootKey); + } + + public put(body: RequestBody, jsonRootKey: string | null = "result"): T { + const response = this.statelessClient.httpxClient.put(this.endpoint, body, { headers: this.headers }); + + this.ThrowIfResponse4or5(response, "PUT"); + return this.getJson(response, jsonRootKey); + } + + public get(jsonRootKey: string | null = "result"): T { + const response = this.statelessClient.httpxClient.get(this.endpoint, { headers: this.headers }); + + this.ThrowIfResponse4or5(response, "GET"); + return this.getJson(response, jsonRootKey); + } + + public delete(jsonRootKey: string | null = "result"): T { + const response = this.statelessClient.httpxClient.delete(this.endpoint, { headers: this.headers }); + + this.ThrowIfResponse4or5(response, "DELETE"); + return this.getJson(response, jsonRootKey); + } + + public patch(body: RequestBody, jsonRootKey: string | null = "result"): T { + const response = this.statelessClient.httpxClient.patch(this.endpoint, body, { headers: this.headers }); + + this.ThrowIfResponse4or5(response, "PATCH"); + return this.getJson(response, jsonRootKey); + } + + private getJson(response: TypedResponse, jsonRootKey: string | null) { + if (jsonRootKey === null) { + return response.json(); + } + return response.json(jsonRootKey); + } + + private ThrowIfResponse4or5(response: TypedResponse, type: string) { + if (response.status > 399) { + throw new Error(`Request ${type} ${this.endpoint} failed with status code ${response.status}: ${JSON.stringify(response.json())}`); + } + } +} diff --git a/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/src/libs/backbone-client/http-client-configuration.ts b/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/src/libs/backbone-client/http-client-configuration.ts new file mode 100644 index 0000000000..a9cddecd32 --- /dev/null +++ b/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/src/libs/backbone-client/http-client-configuration.ts @@ -0,0 +1,25 @@ +export class HttpClientConfiguration { + public get clientId(): string { + return this.getEnvVar("clientId") ?? "test"; + } + + public get clientSecret(): string { + return this.getEnvVar("clientSecret") ?? "test"; + } + + public get apiVersion(): string { + return this.getEnvVar("apiVersion") ?? "v1"; + } + + public get baseUrl(): string { + return this.getEnvVar("baseUrl") ?? "http://localhost:8081/"; + } + + public get timeoutInMilliseconds(): number { + return parseInt(this.getEnvVar("timeoutInMilliseconds") ?? "20000"); + } + + private getEnvVar(name: string): string | undefined { + return __ENV[name] as string | undefined; + } +} diff --git a/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/src/libs/backbone-client/identity.ts b/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/src/libs/backbone-client/identity.ts deleted file mode 100644 index 681e892f0b..0000000000 --- a/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/src/libs/backbone-client/identity.ts +++ /dev/null @@ -1,59 +0,0 @@ -import { Httpx } from "https://jslib.k6.io/httpx/0.1.0/index.js"; -import { b64encode } from "k6/encoding"; -import { Response } from "k6/http"; -import { apiVersion, clientId, clientSecret } from "."; -import { CreateChallengeResponse, CreateIdentityRequest, JwtResponse } from "../../models"; -import { ChallengeRequestPayload, CryptoHelper } from "../crypto-helper"; - -export function createIdentity(client: Httpx, clientId: string, clientSecret: string, password: string): Response { - try { - const keyPair = CryptoHelper.generateKeyPair(); - - const challenge = getChallenge(client); - - const signedChallenge = CryptoHelper.signChallenge(keyPair, challenge); - - const createIdentityRequest: CreateIdentityRequest = { - clientId: clientId, - clientSecret: clientSecret, - signedChallenge: { challenge: JSON.stringify(challenge), signature: b64encode(JSON.stringify(signedChallenge)) }, - identityPublicKey: b64encode(JSON.stringify(keyPair.pub)), - devicePassword: password, - identityVersion: 1 - }; - - const httpResponse = client.post(`api/${apiVersion}/Identities`, JSON.stringify(createIdentityRequest), { - headers: { "Content-Type": "application/json" } - }) as Response; - return httpResponse; - } catch (e) { - console.error(e); - throw e; - } -} - -export function exchangeToken(client: Httpx, username: string, password: string): JwtResponse { - const payload = { - client_id: clientId, - client_secret: clientSecret, - grant_type: "password", - username, - password - }; - return client - .post("connect/token", payload, { - headers: { - "Content-Type": "application/x-www-form-urlencoded" - } - }) - .json() as unknown as JwtResponse; -} - -function getChallenge(client: Httpx): ChallengeRequestPayload { - const receivedChallenge = client.post(`api/${apiVersion}/Challenges`).json("result") as CreateChallengeResponse; - - return { - id: receivedChallenge.id, - expiresAt: receivedChallenge.expiresAt - }; -} diff --git a/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/src/libs/backbone-client/index.ts b/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/src/libs/backbone-client/index.ts deleted file mode 100644 index 7dd1f15440..0000000000 --- a/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/src/libs/backbone-client/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from "./constants"; -export * from "./identity"; diff --git a/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/src/models/challenge.ts b/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/src/libs/backbone-client/models/challenge.ts similarity index 100% rename from Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/src/models/challenge.ts rename to Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/src/libs/backbone-client/models/challenge.ts diff --git a/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/src/models/identity.ts b/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/src/libs/backbone-client/models/identity.ts similarity index 60% rename from Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/src/models/identity.ts rename to Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/src/libs/backbone-client/models/identity.ts index c2a385915d..1af508afa2 100644 --- a/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/src/models/identity.ts +++ b/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/src/libs/backbone-client/models/identity.ts @@ -1,12 +1,10 @@ -import { JwtResponse } from "."; - export interface CreateIdentityRequest { clientId: string; clientSecret: string; - identityPublicKey: any; + identityPublicKey: unknown; devicePassword: string; identityVersion: number; - signedChallenge: any; + signedChallenge: unknown; } export interface CreateIdentityResponse { @@ -18,9 +16,3 @@ export interface CreateIdentityResponse { username: string; }; } - -export interface IdentityWithToken { - response: CreateIdentityResponse; - token: JwtResponse; - password: string; -} diff --git a/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/src/models/index.ts b/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/src/libs/backbone-client/models/index.ts similarity index 100% rename from Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/src/models/index.ts rename to Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/src/libs/backbone-client/models/index.ts diff --git a/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/src/models/jwt-response.ts b/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/src/libs/backbone-client/models/jwt-response.ts similarity index 100% rename from Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/src/models/jwt-response.ts rename to Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/src/libs/backbone-client/models/jwt-response.ts diff --git a/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/src/models/sync-run.ts b/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/src/libs/backbone-client/models/sync-run.ts similarity index 100% rename from Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/src/models/sync-run.ts rename to Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/src/libs/backbone-client/models/sync-run.ts diff --git a/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/src/libs/backbone-client/unauthenticated-client.ts b/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/src/libs/backbone-client/unauthenticated-client.ts new file mode 100644 index 0000000000..3364a28f02 --- /dev/null +++ b/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/src/libs/backbone-client/unauthenticated-client.ts @@ -0,0 +1,44 @@ +import { b64encode } from "k6/encoding"; +import { CryptoHelper } from "../crypto-helper"; +import { BaseClient } from "./base-client"; +import { apiVersion } from "./http-client-configuration"; +import { CreateChallengeResponse, CreateIdentityRequest, CreateIdentityResponse } from "./models"; + +export class UnauthenticatedClient extends BaseClient { + public constructor() { + super(); + } + + public createIdentity(clientId: string, clientSecret: string, password: string): CreateIdentityResponse { + try { + const keyPair = CryptoHelper.generateKeyPair(); + + const challenge = this.getChallenge(); + + const signedChallenge = CryptoHelper.signChallenge(keyPair, challenge); + + const createIdentityRequest: CreateIdentityRequest = { + clientId: clientId, + clientSecret: clientSecret, + signedChallenge: { challenge: JSON.stringify(challenge), signature: b64encode(JSON.stringify(signedChallenge)) }, + identityPublicKey: b64encode(JSON.stringify(keyPair.pub)), + devicePassword: password, + identityVersion: 1 + }; + + const httpResponse = this.httpxClient + .post(`api/${apiVersion}/Identities`, JSON.stringify(createIdentityRequest), { + headers: { "Content-Type": "application/json" } + }) + .json("result") as CreateIdentityResponse; + return httpResponse; + } catch (e) { + console.error(e); + throw e; + } + } + + public getChallenge(): CreateChallengeResponse { + return this.httpxClient.post(`api/${apiVersion}/Challenges`).json("result") as CreateChallengeResponse; + } +} diff --git a/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/src/libs/data-loader/models.ts b/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/src/libs/data-loader/models.ts new file mode 100644 index 0000000000..3edcd4d638 --- /dev/null +++ b/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/src/libs/data-loader/models.ts @@ -0,0 +1,87 @@ +export interface Identity { + relationships?: Relationship[]; + sentMessages?: Message[]; + address: string; + devices: Device[]; + poolAlias: string; + datawalletModifications?: DatawalletModification[]; + relationshipTemplates?: RelationshipTemplate[]; +} + +export interface Pool { + name: string; + identities: Identity[]; +} + +export interface Relationship { + relationshipId: string; + fromAddress: string; + toAddress: string; +} + +interface Device { + deviceId: string; + username: string; + password: string; +} + +interface Message { + messageId: string; + recipient: string; +} + +interface DatawalletModification { + modificationId: string; + index: number; +} + +interface RelationshipTemplate { + relationshipTemplateId: string; +} + +export class LoadedPools { + private readonly _pools: Pool[] = []; + + public constructor(pools: Pool[]) { + this._pools = pools; + } + + public get pools(): Pool[] { + return this._pools; + } + + /** + * fluent method to filter the loaded pools + * @param poolTypes the types of pools to be loaded + * @returns + */ + public ofTypes(...poolTypes: PoolTypes[]): LoadedPools { + if (poolTypes.includes(PoolTypes.All)) return new LoadedPools(this._pools); + + return new LoadedPools(this._pools.filter((pool) => poolTypes.some((type) => pool.name.startsWith(type)))); + } +} + +export enum PoolLoadOptions { + Identities, + Relationships, + Messages, + RelationshipTemplates, + DatawalletModifications +} + +export enum PoolTypes { + App = "a", + AppLight = "a1", + AppMedium = "a2", + AppHeavy = "a3", + + Connector = "c", + ConnectorLight = "c1", + ConnectorMedium = "c2", + ConnectorHeavy = "c3", + + Never = "e", + + All = "*" +} diff --git a/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/src/libs/drept/identity.ts b/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/src/libs/drept/identity.ts deleted file mode 100644 index e9af0fdbb8..0000000000 --- a/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/src/libs/drept/identity.ts +++ /dev/null @@ -1,14 +0,0 @@ -export interface Identity { - devices: Device[]; - pool: Pool; -} - -export interface Pool { - name: string; - identities: Identity[]; -} - -interface Device { - username: string; - password: string; -} diff --git a/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/src/libs/drept/index.ts b/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/src/libs/drept/index.ts deleted file mode 100644 index a2158658cb..0000000000 --- a/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/src/libs/drept/index.ts +++ /dev/null @@ -1 +0,0 @@ -// DATA REPRESENTATION FOR ENMESHED BACKBONE PERFORMANCE TESTS PROTOCOL diff --git a/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/src/libs/file-utils.ts b/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/src/libs/file-utils.ts new file mode 100644 index 0000000000..abb8eee109 --- /dev/null +++ b/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/src/libs/file-utils.ts @@ -0,0 +1,183 @@ +import { SharedArray } from "k6/data"; +import papaparse from "papaparse"; +import { Identity, LoadedPools, Pool, PoolLoadOptions } from "./data-loader/models"; + +/** + * + * @param folderName The name of the folder matching the name of the snapshot to load + * @param whatoToLoad An array of {@link PoolLoadOptions} representing the entities to be loaded + * @returns a {@link LoadedPools} populated according to {@link whatoToLoad} + */ +export function loadPools(folderName: string, whatoToLoad: PoolLoadOptions[] = [PoolLoadOptions.Identities]): LoadedPools { + const csvFilesPath = `../snapshots/${folderName}/csvs`; + let pools: Pool[]; + const identitiesMap: Map = new Map(); + + const poolsReturn = new SharedArray("pools", function () { + if (!whatoToLoad.includes(PoolLoadOptions.Identities)) { + console.warn("whatToLoad does not include Identities but they must always be loaded. Loading either way..."); + } + + console.info(`Started loading ${folderName} snapshot. Loading identities`); + const start = +new Date(); + + pools = loadPoolsWithIdentities(); + + if (whatoToLoad.includes(PoolLoadOptions.DatawalletModifications)) { + console.info("Loading datawallet modifications"); + loadDataWalletModifications(); + } + + if (whatoToLoad.includes(PoolLoadOptions.RelationshipTemplates)) { + console.info("Loading relationship templates"); + loadRelationshipTemplates(); + } + + if (whatoToLoad.includes(PoolLoadOptions.Relationships)) { + console.info("Loading relationships"); + loadRelationships(); + } + + if (whatoToLoad.includes(PoolLoadOptions.Messages)) { + console.info("Loading messages"); + loadMessages(); + } + + console.info(`Finished Loading in ${+new Date() - start}ms`); + return pools; + }); + + return new LoadedPools(poolsReturn); + + function loadDataWalletModifications() { + const DatawalletModificationsFile = open(`${csvFilesPath}/datawalletModifications.csv`); + const parsedDatawalletModifications = papaparse.parse(DatawalletModificationsFile, { header: true }).data.filter((x) => x.IdentityAddress !== ""); + + // create a map of datawalletModifications by their address + const datawalletModificationsMap = new Map(); + parsedDatawalletModifications.forEach((modification) => { + if (!datawalletModificationsMap.has(modification.IdentityAddress)) { + datawalletModificationsMap.set(modification.IdentityAddress, []); + } + datawalletModificationsMap.get(modification.IdentityAddress)!.push(modification); + }); + + // add datawalletModifications to each identity + pools.forEach((pool) => { + pool.identities.forEach((identity) => { + identity.datawalletModifications = []; + datawalletModificationsMap.get(identity.address)?.forEach((x) => { + identity.datawalletModifications!.push({ index: Number.parseInt(x.ModificationIndex), modificationId: x.ModificationId }); + }); + }); + }); + } + + function loadPoolsWithIdentities() { + const identitiesFile = open(`${csvFilesPath}/identities.csv`); + const parsedIdentities = papaparse.parse(identitiesFile, { header: true }).data.filter((x) => x.Address !== ""); + + parsedIdentities.forEach((csvIdentity) => { + const device = { deviceId: csvIdentity.DeviceId, username: csvIdentity.Username, password: csvIdentity.Password }; + const sameIdentityInPool = identitiesMap.get(csvIdentity.Address); + + if (sameIdentityInPool) { + sameIdentityInPool.devices.push(device); + } else { + identitiesMap.set(csvIdentity.Address, { + address: csvIdentity.Address, + devices: [device], + poolAlias: csvIdentity.Alias + }); + } + }); + + const result: Pool[] = []; + + parsedIdentities.forEach((csvIdentity) => { + let pool = result.find((p) => p.name === csvIdentity.Alias); + if (!pool) { + result.push({ name: csvIdentity.Alias, identities: [] }); + pool = result.find((p) => p.name === csvIdentity.Alias); + } + }); + + result.forEach((pool) => { + identitiesMap.forEach((i) => { + if (i.poolAlias === pool.name) pool.identities.push(i); + }); + }); + + return result; + } + + function loadRelationshipTemplates() { + const RelationshipTemplatesFile = open(`${csvFilesPath}/relationshipTemplates.csv`); + const parsedRelationshipTemplates = papaparse.parse(RelationshipTemplatesFile, { header: true }).data.filter((x) => x.IdentityAddress !== ""); + + parsedRelationshipTemplates.forEach((relationshipTemplate) => { + const identity = identitiesMap.get(relationshipTemplate.IdentityAddress); + if (identity !== undefined) { + if (identity.relationshipTemplates === undefined) identity.relationshipTemplates = []; + identity.relationshipTemplates.push({ relationshipTemplateId: relationshipTemplate.RelationshipTemplateId }); + } + }); + } + + function loadRelationships() { + const RelationshipsFile = open(`${csvFilesPath}/relationships.csv`); + const parsedRelationships = papaparse.parse(RelationshipsFile, { header: true }).data.filter((x) => x.RelationshipId !== ""); + parsedRelationships.forEach((relationship) => { + const identityFrom = identitiesMap.get(relationship.AddressFrom)!; + if (identityFrom.relationships === undefined) identityFrom.relationships = []; + identityFrom.relationships.push({ fromAddress: relationship.AddressFrom, toAddress: relationship.AddressTo, relationshipId: relationship.RelationshipId }); + + const identityTo = identitiesMap.get(relationship.AddressTo)!; + if (identityTo.relationships === undefined) identityTo.relationships = []; + identityTo.relationships.push({ fromAddress: relationship.AddressTo, toAddress: relationship.AddressFrom, relationshipId: relationship.RelationshipId }); + }); + } + + function loadMessages() { + const MessagesFile = open(`${csvFilesPath}/messages.csv`); + const parsedMessages = papaparse.parse(MessagesFile, { header: true }).data.filter((x) => x.AddressFrom !== ""); + parsedMessages.forEach((message) => { + const identityFrom = identitiesMap.get(message.AddressFrom); + const identityTo = identitiesMap.get(message.AddressTo); + if (identityTo && identityFrom) { + identityFrom.sentMessages ??= []; + identityFrom.sentMessages.push({ messageId: message.AddressFrom, recipient: message.AddressTo }); + } + }); + } +} + +interface CSVIdentity { + Address: string; + DeviceId: string; + Username: string; + Password: string; + Alias: string; +} + +interface CSVDatawalletModification { + IdentityAddress: string; + ModificationIndex: string; + ModificationId: string; +} + +interface CSVRelationshipTemplate { + IdentityAddress: string; + RelationshipTemplateId: string; +} + +interface CSVRelationship { + RelationshipId: string; + AddressFrom: string; + AddressTo: string; +} +interface CSVMessage { + MessageId: string; + AddressFrom: string; + AddressTo: string; +} diff --git a/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/src/scenarios/README.md b/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/src/scenarios/README.md new file mode 100644 index 0000000000..4328eaf51e --- /dev/null +++ b/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/src/scenarios/README.md @@ -0,0 +1,153 @@ +# Scenarios + +## 01. Creating Challenges + +| Property | Configuration | +| ------------- | ------------- | +| Identity Pool | i: a+c | +| Average Load | 1 per 5m | + +### Steps + +1. Create a Challenge + +## 02. Creating Identities + +| Property | Configuration | +| ------------- | -------------- | +| Identity Pool | not applicable | +| Average Load | 1 per 5m | + +### Steps + +1. Create a Challenge +2. Create an Identity + +## 03. Creating Datawallet Modifications + +| Property | Configuration | +| ------------- | ------------- | +| Identity Pool | i: a | +| Average Load | 100 per 1m | + +### Steps + +1. Create a Datawallet Modification (content size: 300B) + +## 04. Creating Tokens + +| Property | Configuration | +| ------------- | ------------- | +| Identity Pool | i: a+c | +| Average Load | 1 per 10m | + +### Steps + +1. Create a Token (content size: 1kB) + +## 05. Creating RelationshipTemplates + +| Property | Configuration | +| ------------- | ------------- | +| Identity Pool | i: c | +| Average Load | 1 per 1m | + +### Steps + +1. Create a RelationshipTemplate (content size: 8kB) + +## 06. Relationship Lifecycle + +| Property | Configuration | +| ------------- | ---------------------------------- | +| Identity Pool | i1: c, i2: a (no relationship yet) | +| Average Load | 1 every 3m | + +### Steps + +1. i1: Create a RelationshipTemplate +2. i2: Create a Relationship to i1. If a Relationship already exists, get a new i2 and try again +3. i1: Fetch Relationship +4. i1: Reject Relationship +5. i2: Fetch Relationship +6. i2: Create a Relationship to i1 +7. i1: Fetch Relationship +8. i2: Revoke Relationship +9. i1: Fetch Relationship +10. i2: Create a Relationship to i1 +11. i1: Fetch Relationship +12. i1: Accept Relationship +13. i2: Fetch Relationship +14. i1/i2: Terminate Relationship +15. i1/i2: Fetch Relationship +16. i1: Request Relationship reactivation +17. i2: Fetch Relationship +18. i2: Reject Relationship reactivation +19. i1: Fetch Relationship +20. i1: Request Relationship reactivation +21. i2: Fetch Relationship +22. i1: Revoke Relationship reactivation +23. i2: Fetch Relationship +24. i1: Request Relationship reactivation +25. i2: Fetch Relationship +26. i2: Accept Relationship reactivation +27. i1: Fetch Relationship +28. i1: Decompose Relationship +29. i2: Fetch Relationship +30. i2: Decompose Relationship + +## 07. Sending Personalized Messages + +| Property | Configuration | +| ------------- | ---------------- | +| Identity Pool | i1: a+c, i2: a+c | +| Average Load | 1 every 10s | + +### Steps + +1. i1: Send a Message to i2 + +## 08. Sending Messages to Multiple Recipients + +| Property | Configuration | +| ------------- | -------------------------------------------------- | +| Identity Pool | i1: a+c, i2...in: a+c (where i1 has relationships) | +| Average Load | 1 every 5m | + +### Steps + +1. i1: Send a Message with n-1 recipients (i2...in, n is randomly chosen between 50 and 1000) + +## 09. Connector External Event Sync + +| Property | Configuration | +| ------------- | ------------- | +| Identity Pool | i: c | +| Average Load | nc every 1s | + +### Steps + +1. Get all datawallet modifications +2. Try to create a sync run of type ExternalEventSync + - If the result does not contain a started sync run, abort + - Otherwise, continue +3. Assume the sync run contains n external events +4. Finalize the sync run by: + - Pushing n datawallet modifications + - Sending n/5 external event results with some error code + - Sending 4n/5 external event results without error code + +## 10. Device Onboarding + +| Property | Configuration | +| ------------- | ------------- | +| Identity Pool | i: a3 | +| Average Load | 1 every 10m | + +### Steps + +1. Get all Datawallet modifications starting with index 0 (CAUTION: remember to paginate the results, if necessary!) +2. Get all Messages (CAUTION: remember to paginate the results, if necessary!) +3. Get all Relationship Templates (CAUTION: remember to paginate the results, if necessary!) +4. Get all Relationships (CAUTION: remember to paginate the results, if necessary!) +5. Get all Tokens (CAUTION: remember to paginate the results, if necessary!) diff --git a/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/src/scenarios/configuration.ts b/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/src/scenarios/configuration.ts new file mode 100644 index 0000000000..1d23f56705 --- /dev/null +++ b/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/src/scenarios/configuration.ts @@ -0,0 +1,23 @@ +import { HttpClientConfiguration } from "../libs/backbone-client/http-client-configuration"; + +export class Configuration { + private constructor() { + // hide constructor to enforce use of static `load` function + } + + public get snapshot(): string { + return this.getEnvVar("snapshot") ?? "light"; + } + + private getEnvVar(name: string): string | undefined { + return __ENV[name] as string | undefined; + } + + public get httpClient(): HttpClientConfiguration { + return new HttpClientConfiguration(); + } + + public static load(): Configuration { + return new Configuration(); + } +} diff --git a/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/src/scenarios/s01.test.ts b/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/src/scenarios/s01.test.ts new file mode 100644 index 0000000000..1181c73502 --- /dev/null +++ b/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/src/scenarios/s01.test.ts @@ -0,0 +1,46 @@ +import { check } from "k6"; +import { SharedArray } from "k6/data"; +import { Options } from "k6/options"; +import { AuthenticatedClient } from "../libs/backbone-client/authenticated-client"; +import { PoolLoadOptions, PoolTypes } from "../libs/data-loader/models"; +import { loadPools } from "../libs/file-utils"; +import { Configuration } from "./configuration"; + +export const options: Options = { + scenarios: { + constantRequestRate: { + executor: "constant-arrival-rate", + rate: 1, + timeUnit: "5m", + duration: "60m", + preAllocatedVUs: 1 + } + } +}; + +const configuration = Configuration.load(); + +const pools = loadPools(configuration.snapshot, [PoolLoadOptions.Identities]).ofTypes(PoolTypes.App, PoolTypes.Connector).pools; + +const testIdentities = new SharedArray("testIdentities", function () { + return pools.flatMap((p) => p.identities); +}); + +let identityIterator = 0; + +export default function (): void { + const thisIdentityIterator = identityIterator++; + const currentIdentity = testIdentities[thisIdentityIterator]; + + const username = currentIdentity.devices[0].username; + const password = currentIdentity.devices[0].password; + const client = new AuthenticatedClient(username, password, configuration.httpClient); + + const createChallengeResult = client.getChallenge(); + + check(createChallengeResult, { + "challenge contains correct device": (r) => r.createdByDevice === currentIdentity.devices[0].deviceId, + "challenge contains correct address": (r) => r.createdBy === currentIdentity.address, + "challenge id is not empty": (r) => r.id !== "" + }); +} diff --git a/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/crypto-sidecar/README.md b/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/tools/crypto-sidecar/README.md similarity index 100% rename from Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/crypto-sidecar/README.md rename to Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/tools/crypto-sidecar/README.md diff --git a/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/crypto-sidecar/package-lock.json b/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/tools/crypto-sidecar/package-lock.json similarity index 100% rename from Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/crypto-sidecar/package-lock.json rename to Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/tools/crypto-sidecar/package-lock.json diff --git a/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/crypto-sidecar/package.json b/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/tools/crypto-sidecar/package.json similarity index 100% rename from Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/crypto-sidecar/package.json rename to Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/tools/crypto-sidecar/package.json diff --git a/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/crypto-sidecar/src/index.ts b/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/tools/crypto-sidecar/src/index.ts similarity index 100% rename from Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/crypto-sidecar/src/index.ts rename to Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/tools/crypto-sidecar/src/index.ts diff --git a/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/crypto-sidecar/tsconfig.json b/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/tools/crypto-sidecar/tsconfig.json similarity index 100% rename from Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/crypto-sidecar/tsconfig.json rename to Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/tools/crypto-sidecar/tsconfig.json diff --git a/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/tools/result-analyzer/package-lock.json b/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/tools/result-analyzer/package-lock.json new file mode 100644 index 0000000000..1761a1d204 --- /dev/null +++ b/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/tools/result-analyzer/package-lock.json @@ -0,0 +1,501 @@ +{ + "name": "k6-result-analyzer", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "k6-result-analyzer", + "version": "1.0.0", + "license": "MIT", + "dependencies": { + "csv-parse": "^5.5.6" + }, + "devDependencies": { + "tsx": "^4.19.0" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.23.1.tgz", + "integrity": "sha512-6VhYk1diRqrhBAqpJEdjASR/+WVRtfjpqKuNw11cLiaWpAT/Uu+nokB+UJnevzy/P9C/ty6AOe0dwueMrGh/iQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.23.1.tgz", + "integrity": "sha512-uz6/tEy2IFm9RYOyvKl88zdzZfwEfKZmnX9Cj1BHjeSGNuGLuMD1kR8y5bteYmwqKm1tj8m4cb/aKEorr6fHWQ==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.23.1.tgz", + "integrity": "sha512-xw50ipykXcLstLeWH7WRdQuysJqejuAGPd30vd1i5zSyKK3WE+ijzHmLKxdiCMtH1pHz78rOg0BKSYOSB/2Khw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.23.1.tgz", + "integrity": "sha512-nlN9B69St9BwUoB+jkyU090bru8L0NA3yFvAd7k8dNsVH8bi9a8cUAUSEcEEgTp2z3dbEDGJGfP6VUnkQnlReg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.23.1.tgz", + "integrity": "sha512-YsS2e3Wtgnw7Wq53XXBLcV6JhRsEq8hkfg91ESVadIrzr9wO6jJDMZnCQbHm1Guc5t/CdDiFSSfWP58FNuvT3Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.23.1.tgz", + "integrity": "sha512-aClqdgTDVPSEGgoCS8QDG37Gu8yc9lTHNAQlsztQ6ENetKEO//b8y31MMu2ZaPbn4kVsIABzVLXYLhCGekGDqw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.23.1.tgz", + "integrity": "sha512-h1k6yS8/pN/NHlMl5+v4XPfikhJulk4G+tKGFIOwURBSFzE8bixw1ebjluLOjfwtLqY0kewfjLSrO6tN2MgIhA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.23.1.tgz", + "integrity": "sha512-lK1eJeyk1ZX8UklqFd/3A60UuZ/6UVfGT2LuGo3Wp4/z7eRTRYY+0xOu2kpClP+vMTi9wKOfXi2vjUpO1Ro76g==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.23.1.tgz", + "integrity": "sha512-CXXkzgn+dXAPs3WBwE+Kvnrf4WECwBdfjfeYHpMeVxWE0EceB6vhWGShs6wi0IYEqMSIzdOF1XjQ/Mkm5d7ZdQ==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.23.1.tgz", + "integrity": "sha512-/93bf2yxencYDnItMYV/v116zff6UyTjo4EtEQjUBeGiVpMmffDNUyD9UN2zV+V3LRV3/on4xdZ26NKzn6754g==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.23.1.tgz", + "integrity": "sha512-VTN4EuOHwXEkXzX5nTvVY4s7E/Krz7COC8xkftbbKRYAl96vPiUssGkeMELQMOnLOJ8k3BY1+ZY52tttZnHcXQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.23.1.tgz", + "integrity": "sha512-Vx09LzEoBa5zDnieH8LSMRToj7ir/Jeq0Gu6qJ/1GcBq9GkfoEAoXvLiW1U9J1qE/Y/Oyaq33w5p2ZWrNNHNEw==", + "cpu": [ + "loong64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.23.1.tgz", + "integrity": "sha512-nrFzzMQ7W4WRLNUOU5dlWAqa6yVeI0P78WKGUo7lg2HShq/yx+UYkeNSE0SSfSure0SqgnsxPvmAUu/vu0E+3Q==", + "cpu": [ + "mips64el" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.23.1.tgz", + "integrity": "sha512-dKN8fgVqd0vUIjxuJI6P/9SSSe/mB9rvA98CSH2sJnlZ/OCZWO1DJvxj8jvKTfYUdGfcq2dDxoKaC6bHuTlgcw==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.23.1.tgz", + "integrity": "sha512-5AV4Pzp80fhHL83JM6LoA6pTQVWgB1HovMBsLQ9OZWLDqVY8MVobBXNSmAJi//Csh6tcY7e7Lny2Hg1tElMjIA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.23.1.tgz", + "integrity": "sha512-9ygs73tuFCe6f6m/Tb+9LtYxWR4c9yg7zjt2cYkjDbDpV/xVn+68cQxMXCjUpYwEkze2RcU/rMnfIXNRFmSoDw==", + "cpu": [ + "s390x" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.23.1.tgz", + "integrity": "sha512-EV6+ovTsEXCPAp58g2dD68LxoP/wK5pRvgy0J/HxPGB009omFPv3Yet0HiaqvrIrgPTBuC6wCH1LTOY91EO5hQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.23.1.tgz", + "integrity": "sha512-aevEkCNu7KlPRpYLjwmdcuNz6bDFiE7Z8XC4CPqExjTvrHugh28QzUXVOZtiYghciKUacNktqxdpymplil1beA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.23.1.tgz", + "integrity": "sha512-3x37szhLexNA4bXhLrCC/LImN/YtWis6WXr1VESlfVtVeoFJBRINPJ3f0a/6LV8zpikqoUg4hyXw0sFBt5Cr+Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.23.1.tgz", + "integrity": "sha512-aY2gMmKmPhxfU+0EdnN+XNtGbjfQgwZj43k8G3fyrDM/UdZww6xrWxmDkuz2eCZchqVeABjV5BpildOrUbBTqA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.23.1.tgz", + "integrity": "sha512-RBRT2gqEl0IKQABT4XTj78tpk9v7ehp+mazn2HbUeZl1YMdaGAQqhapjGTCe7uw7y0frDi4gS0uHzhvpFuI1sA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.23.1.tgz", + "integrity": "sha512-4O+gPR5rEBe2FpKOVyiJ7wNDPA8nGzDuJ6gN4okSA1gEOYZ67N8JPk58tkWtdtPeLz7lBnY6I5L3jdsr3S+A6A==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.23.1.tgz", + "integrity": "sha512-BcaL0Vn6QwCwre3Y717nVHZbAa4UBEigzFm6VdsVdT/MbZ38xoj1X9HPkZhbmaBGUD1W8vxAfffbDe8bA6AKnQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.23.1.tgz", + "integrity": "sha512-BHpFFeslkWrXWyUPnbKm+xYYVYruCinGcftSBaa8zoF9hZO4BcSCFUvHVTtzpIY6YzUnYtuEhZ+C9iEXjxnasg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/csv-parse": { + "version": "5.5.6", + "resolved": "https://registry.npmjs.org/csv-parse/-/csv-parse-5.5.6.tgz", + "integrity": "sha512-uNpm30m/AGSkLxxy7d9yRXpJQFrZzVWLFBkS+6ngPcZkw/5k3L/jjFuj7tVnEpRn+QgmiXr21nDlhCiUK4ij2A==" + }, + "node_modules/esbuild": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.23.1.tgz", + "integrity": "sha512-VVNz/9Sa0bs5SELtn3f7qhJCDPCF5oMEl5cO9/SSinpE9hbPVvxbd572HH5AKiP7WD8INO53GgfDDhRjkylHEg==", + "dev": true, + "hasInstallScript": true, + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.23.1", + "@esbuild/android-arm": "0.23.1", + "@esbuild/android-arm64": "0.23.1", + "@esbuild/android-x64": "0.23.1", + "@esbuild/darwin-arm64": "0.23.1", + "@esbuild/darwin-x64": "0.23.1", + "@esbuild/freebsd-arm64": "0.23.1", + "@esbuild/freebsd-x64": "0.23.1", + "@esbuild/linux-arm": "0.23.1", + "@esbuild/linux-arm64": "0.23.1", + "@esbuild/linux-ia32": "0.23.1", + "@esbuild/linux-loong64": "0.23.1", + "@esbuild/linux-mips64el": "0.23.1", + "@esbuild/linux-ppc64": "0.23.1", + "@esbuild/linux-riscv64": "0.23.1", + "@esbuild/linux-s390x": "0.23.1", + "@esbuild/linux-x64": "0.23.1", + "@esbuild/netbsd-x64": "0.23.1", + "@esbuild/openbsd-arm64": "0.23.1", + "@esbuild/openbsd-x64": "0.23.1", + "@esbuild/sunos-x64": "0.23.1", + "@esbuild/win32-arm64": "0.23.1", + "@esbuild/win32-ia32": "0.23.1", + "@esbuild/win32-x64": "0.23.1" + } + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/get-tsconfig": { + "version": "4.8.0", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.8.0.tgz", + "integrity": "sha512-Pgba6TExTZ0FJAn1qkJAjIeKoDJ3CsI2ChuLohJnZl/tTU8MVrq3b+2t5UOPfRa4RMsorClBjJALkJUMjG1PAw==", + "dev": true, + "dependencies": { + "resolve-pkg-maps": "^1.0.0" + }, + "funding": { + "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" + } + }, + "node_modules/resolve-pkg-maps": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", + "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", + "dev": true, + "funding": { + "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" + } + }, + "node_modules/tsx": { + "version": "4.19.0", + "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.19.0.tgz", + "integrity": "sha512-bV30kM7bsLZKZIOCHeMNVMJ32/LuJzLVajkQI/qf92J2Qr08ueLQvW00PUZGiuLPP760UINwupgUj8qrSCPUKg==", + "dev": true, + "dependencies": { + "esbuild": "~0.23.0", + "get-tsconfig": "^4.7.5" + }, + "bin": { + "tsx": "dist/cli.mjs" + }, + "engines": { + "node": ">=18.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + } + } + } +} diff --git a/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/tools/result-analyzer/package.json b/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/tools/result-analyzer/package.json new file mode 100644 index 0000000000..d93a210f16 --- /dev/null +++ b/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/tools/result-analyzer/package.json @@ -0,0 +1,18 @@ +{ + "name": "k6-result-analyzer", + "version": "1.0.0", + "description": "", + "main": "main.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1", + "start": "node src/main.js" + }, + "author": "", + "license": "MIT", + "dependencies": { + "csv-parse": "^5.5.6" + }, + "devDependencies": { + "tsx": "^4.19.0" + } +} diff --git a/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/tools/result-analyzer/src/k6-output-line.ts b/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/tools/result-analyzer/src/k6-output-line.ts new file mode 100644 index 0000000000..179eb32ddf --- /dev/null +++ b/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/tools/result-analyzer/src/k6-output-line.ts @@ -0,0 +1,21 @@ +export interface k6OutputLine { + metric_name: string; + timestamp: string; + metric_value: string; + check: string; + error: string; + error_code: string; + expected_response: string; + group: string; + method: string; + name: string; + proto: string; + scenario: string; + service: string; + status: string; + subproto: string; + tls_version: string; + url: string; + extra_tags: string; + metadata: string; +} diff --git a/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/tools/result-analyzer/src/main.ts b/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/tools/result-analyzer/src/main.ts new file mode 100644 index 0000000000..8f6525adf4 --- /dev/null +++ b/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/tools/result-analyzer/src/main.ts @@ -0,0 +1,88 @@ +import csv from "csv-parse/sync"; +import fs from "fs"; +import { k6OutputLine } from "./k6-output-line"; +import { RouteMetrics } from "./route-metrics"; + +// Function to read the CSV file +function readK6Output(filePath: string): k6OutputLine[] | null { + try { + var data = fs.readFileSync(filePath, "utf-8"); + return csv.parse(data, { delimiter: ",", columns: true }) as k6OutputLine[]; + } catch (error) { + console.error("Error reading the file:", error); + return null; + } +} + +// Function to group metrics by route +function groupMetricsByRoute(metrics: k6OutputLine[]): RouteMetrics { + const routeMetrics = {}; + + metrics.forEach((metric) => { + const route = `${metric.method} ${new URL(metric.name).pathname}`; + const type = metric.metric_name; + + if (!routeMetrics[route]) routeMetrics[route] = {}; + + if (!routeMetrics[route][type]) { + routeMetrics[route][type] = { + totalRequests: 0, + totalTime: 0.0, + statuses: {} + }; + } + + routeMetrics[route][type].totalRequests += 1; + routeMetrics[route][type].totalTime += parseFloat(metric.metric_value); + const status = parseInt(metric.status); + + if (!routeMetrics[route][type].statuses[status]) { + routeMetrics[route][type].statuses[status] = 0; + } + routeMetrics[route][type].statuses[status] += 1; + }); + + return routeMetrics; +} + +// Function to print the grouped metrics +function printMetrics(routeMetrics: RouteMetrics) { + console.log("HTTP Request Metrics Grouped by Route and timing:"); + Object.entries(routeMetrics).forEach(([route, typeMetrics]) => { + const firstMetric = Object.entries(typeMetrics)[0][1]; + console.log(`\nRoute: ${route}`); + console.log(`Total Requests: ${firstMetric.totalRequests}`); + console.log("Status Codes:"); + Object.entries(firstMetric.statuses).forEach(([status, count]) => { + console.log(` ${status}: ${count}`); + }); + console.log("Timings:"); + Object.entries(typeMetrics).forEach(([type, metrics]) => { + const averageTime = (metrics.totalTime / metrics.totalRequests).toFixed(2); + console.log(`${type}: \t ${averageTime} ms`); + }); + }); +} + +// Main function to process the K6 output +function processK6Output(filePath: string) { + const k6Data = readK6Output(filePath); + if (k6Data) { + const httpMetrics = k6Data.filter((x) => x.metric_name.indexOf("http_req_") == 0 && x.metric_name.indexOf("http_req_tls") != 0); + const groupedMetrics = groupMetricsByRoute(httpMetrics); + printMetrics(groupedMetrics); + } else { + console.error("Failed to process K6 output."); + } +} + +const args = process.argv.slice(2); +var filename = "../result.csv"; +if (args[0] === undefined) { + console.log(`Loading default file "${filename}". Pass a custom filename if you want to process it instead.`); +} else { + filename = args[0]; +} + +// Run the program +processK6Output(filename); diff --git a/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/tools/result-analyzer/src/route-metrics.ts b/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/tools/result-analyzer/src/route-metrics.ts new file mode 100644 index 0000000000..cc1559bb2f --- /dev/null +++ b/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/tools/result-analyzer/src/route-metrics.ts @@ -0,0 +1,11 @@ +export interface RouteMetrics { + [route: string]: { + [metricType: string]: { + totalRequests: number; + totalTime: number; + statuses: { + [statusCode: number]: number; + }; + }; + }; +} diff --git a/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/PerformanceSnapshotCreator/.gitignore b/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/tools/snapshot-creator/.gitignore similarity index 100% rename from Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/PerformanceSnapshotCreator/.gitignore rename to Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/tools/snapshot-creator/.gitignore diff --git a/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/tools/snapshot-creator/Application/MessageDistributor/IMessageDistributor.cs b/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/tools/snapshot-creator/Application/MessageDistributor/IMessageDistributor.cs new file mode 100644 index 0000000000..3ca88278b1 --- /dev/null +++ b/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/tools/snapshot-creator/Application/MessageDistributor/IMessageDistributor.cs @@ -0,0 +1,8 @@ +using Backbone.ConsumerApi.Tests.Performance.SnapshotCreator.PoolsFile; + +namespace Backbone.ConsumerApi.Tests.Performance.SnapshotCreator.Application.MessageDistributor; + +public interface IMessageDistributor +{ + public void Distribute(IList pools); +} diff --git a/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/PerformanceSnapshotCreator/Application/MessageDistributor/MessageDistributorV2.cs b/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/tools/snapshot-creator/Application/MessageDistributor/MessageDistributorV2.cs similarity index 83% rename from Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/PerformanceSnapshotCreator/Application/MessageDistributor/MessageDistributorV2.cs rename to Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/tools/snapshot-creator/Application/MessageDistributor/MessageDistributorV2.cs index 289ea196ea..22fc853f20 100644 --- a/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/PerformanceSnapshotCreator/Application/MessageDistributor/MessageDistributorV2.cs +++ b/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/tools/snapshot-creator/Application/MessageDistributor/MessageDistributorV2.cs @@ -1,7 +1,7 @@ -using Backbone.PerformanceSnapshotCreator.PoolsFile; -using Backbone.PerformanceSnapshotCreator.Tools; +using Backbone.ConsumerApi.Tests.Performance.SnapshotCreator.PoolsFile; +using Backbone.ConsumerApi.Tests.Performance.SnapshotCreator.Tools; -namespace Backbone.PerformanceSnapshotCreator.Application.MessageDistributor; +namespace Backbone.ConsumerApi.Tests.Performance.SnapshotCreator.Application.MessageDistributor; public class MessageDistributorV2 : IMessageDistributor { diff --git a/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/PerformanceSnapshotCreator/Application/Printer/Printer.cs b/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/tools/snapshot-creator/Application/Printer/Printer.cs similarity index 95% rename from Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/PerformanceSnapshotCreator/Application/Printer/Printer.cs rename to Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/tools/snapshot-creator/Application/Printer/Printer.cs index 19108b81f2..eb1d7f2bf2 100644 --- a/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/PerformanceSnapshotCreator/Application/Printer/Printer.cs +++ b/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/tools/snapshot-creator/Application/Printer/Printer.cs @@ -1,12 +1,12 @@ using System.Text; -using Backbone.PerformanceSnapshotCreator.PoolsFile; +using Backbone.ConsumerApi.Tests.Performance.SnapshotCreator.PoolsFile; using Backbone.Tooling; -namespace Backbone.PerformanceSnapshotCreator.Application.Printer; +namespace Backbone.ConsumerApi.Tests.Performance.SnapshotCreator.Application.Printer; public class Printer : IPrinter { - private readonly string _outputDirName = $@"{Path.GetTempPath()}\poolCreator.{SystemTime.UtcNow:yyyyMMdd-HHmmss}"; + private readonly string _outputDirName = $"{Path.GetTempPath()}poolCreator.{SystemTime.UtcNow:yyyyMMdd-HHmmss}"; public void PrintRelationships(IList pools, bool summaryOnly = false) { @@ -92,7 +92,7 @@ private static void OutputRelationshipTemplates(string outputDirName, IList pools) @@ -110,7 +110,7 @@ private static void OutputDatawalletModifications(string outputDirName, IList pools) diff --git a/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/tools/snapshot-creator/Application/RelationshipDistributor/IRelationshipDistributor.cs b/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/tools/snapshot-creator/Application/RelationshipDistributor/IRelationshipDistributor.cs new file mode 100644 index 0000000000..7236fb667b --- /dev/null +++ b/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/tools/snapshot-creator/Application/RelationshipDistributor/IRelationshipDistributor.cs @@ -0,0 +1,8 @@ +using Backbone.ConsumerApi.Tests.Performance.SnapshotCreator.PoolsFile; + +namespace Backbone.ConsumerApi.Tests.Performance.SnapshotCreator.Application.RelationshipDistributor; + +public interface IRelationshipDistributor +{ + public void Distribute(IList pools); +} diff --git a/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/PerformanceSnapshotCreator/Application/RelationshipDistributor/RelationshipDistributorV4.cs b/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/tools/snapshot-creator/Application/RelationshipDistributor/RelationshipDistributorV4.cs similarity index 94% rename from Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/PerformanceSnapshotCreator/Application/RelationshipDistributor/RelationshipDistributorV4.cs rename to Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/tools/snapshot-creator/Application/RelationshipDistributor/RelationshipDistributorV4.cs index e181656ccf..94c9266033 100644 --- a/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/PerformanceSnapshotCreator/Application/RelationshipDistributor/RelationshipDistributorV4.cs +++ b/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/tools/snapshot-creator/Application/RelationshipDistributor/RelationshipDistributorV4.cs @@ -1,7 +1,7 @@ -using Backbone.PerformanceSnapshotCreator.Domain; -using Backbone.PerformanceSnapshotCreator.PoolsFile; +using Backbone.ConsumerApi.Tests.Performance.SnapshotCreator.Domain; +using Backbone.ConsumerApi.Tests.Performance.SnapshotCreator.PoolsFile; -namespace Backbone.PerformanceSnapshotCreator.Application.RelationshipDistributor; +namespace Backbone.ConsumerApi.Tests.Performance.SnapshotCreator.Application.RelationshipDistributor; /// /// Assigns relationships based on a special heuristic called PWA (Pool Weight Affinity) diff --git a/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/PerformanceSnapshotCreator/PerformanceSnapshotCreator.csproj b/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/tools/snapshot-creator/ConsumerApi.Tests.Performance.SnapshotCreator.csproj similarity index 88% rename from Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/PerformanceSnapshotCreator/PerformanceSnapshotCreator.csproj rename to Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/tools/snapshot-creator/ConsumerApi.Tests.Performance.SnapshotCreator.csproj index aee0a5e35b..47aa83edae 100644 --- a/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/PerformanceSnapshotCreator/PerformanceSnapshotCreator.csproj +++ b/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/tools/snapshot-creator/ConsumerApi.Tests.Performance.SnapshotCreator.csproj @@ -9,7 +9,7 @@ - + diff --git a/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/PerformanceSnapshotCreator/CreateEntitiesCommand.cs b/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/tools/snapshot-creator/CreateEntitiesCommand.cs similarity index 85% rename from Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/PerformanceSnapshotCreator/CreateEntitiesCommand.cs rename to Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/tools/snapshot-creator/CreateEntitiesCommand.cs index c310b0ee8a..b97ed88b87 100644 --- a/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/PerformanceSnapshotCreator/CreateEntitiesCommand.cs +++ b/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/tools/snapshot-creator/CreateEntitiesCommand.cs @@ -1,10 +1,10 @@ using System.CommandLine; -using Backbone.PerformanceSnapshotCreator.Application.Printer; -using Backbone.PerformanceSnapshotCreator.EntityCreation; -using Backbone.PerformanceSnapshotCreator.PoolsFile; -using Backbone.PerformanceSnapshotCreator.PoolsGenerator; +using Backbone.ConsumerApi.Tests.Performance.SnapshotCreator.Application.Printer; +using Backbone.ConsumerApi.Tests.Performance.SnapshotCreator.EntityCreation; +using Backbone.ConsumerApi.Tests.Performance.SnapshotCreator.PoolsFile; +using Backbone.ConsumerApi.Tests.Performance.SnapshotCreator.PoolsGenerator; -namespace Backbone.PerformanceSnapshotCreator; +namespace Backbone.ConsumerApi.Tests.Performance.SnapshotCreator; public class CreateEntitiesCommand : Command { @@ -19,7 +19,7 @@ public class CreateEntitiesCommand : Command var clientSecret = new Option(name: "--clientSecret", description: "The corresponding client secret."); AddOption(clientSecret); - var configurationFilePath = new Option(name: "--ram", description: "The csv file with the relationships and messages configuration."); + var configurationFilePath = new Option(name: "--relationshipsAndMessages", description: "The csv file with the relationships and messages configuration."); AddOption(configurationFilePath); var poolsFilePath = new Option(name: "--poolsFile", description: "The json file with the pools' configuration."); diff --git a/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/PerformanceSnapshotCreator/Domain/Identity.cs b/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/tools/snapshot-creator/Domain/Identity.cs similarity index 96% rename from Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/PerformanceSnapshotCreator/Domain/Identity.cs rename to Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/tools/snapshot-creator/Domain/Identity.cs index 01316b9e19..9e24b5397c 100644 --- a/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/PerformanceSnapshotCreator/Domain/Identity.cs +++ b/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/tools/snapshot-creator/Domain/Identity.cs @@ -2,9 +2,9 @@ using Backbone.ConsumerApi.Sdk.Endpoints.Challenges.Types; using Backbone.ConsumerApi.Sdk.Endpoints.RelationshipTemplates.Types.Responses; using Backbone.ConsumerApi.Sdk.Endpoints.SyncRuns.Types; -using Backbone.PerformanceSnapshotCreator.PoolsFile; +using Backbone.ConsumerApi.Tests.Performance.SnapshotCreator.PoolsFile; -namespace Backbone.PerformanceSnapshotCreator.Domain; +namespace Backbone.ConsumerApi.Tests.Performance.SnapshotCreator.Domain; public class Identity { public readonly UserCredentials UserCredentials; diff --git a/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/PerformanceSnapshotCreator/EntityCreation/EntityCreator.cs b/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/tools/snapshot-creator/EntityCreation/EntityCreator.cs similarity index 96% rename from Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/PerformanceSnapshotCreator/EntityCreation/EntityCreator.cs rename to Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/tools/snapshot-creator/EntityCreation/EntityCreator.cs index a333712759..1fe2cc7f30 100644 --- a/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/PerformanceSnapshotCreator/EntityCreation/EntityCreator.cs +++ b/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/tools/snapshot-creator/EntityCreation/EntityCreator.cs @@ -7,16 +7,15 @@ using Backbone.ConsumerApi.Sdk.Endpoints.Relationships.Types.Requests; using Backbone.ConsumerApi.Sdk.Endpoints.RelationshipTemplates.Types.Requests; using Backbone.ConsumerApi.Sdk.Endpoints.SyncRuns.Types.Requests; +using Backbone.ConsumerApi.Tests.Performance.SnapshotCreator.Application.Printer; +using Backbone.ConsumerApi.Tests.Performance.SnapshotCreator.PoolsFile; +using Backbone.ConsumerApi.Tests.Performance.SnapshotCreator.PoolsGenerator; +using Backbone.ConsumerApi.Tests.Performance.SnapshotCreator.Tools; using Backbone.Crypto; -using Backbone.PerformanceSnapshotCreator.Application.Printer; -using Backbone.PerformanceSnapshotCreator.Domain; -using Backbone.PerformanceSnapshotCreator.PoolsFile; -using Backbone.PerformanceSnapshotCreator.PoolsGenerator; -using Backbone.PerformanceSnapshotCreator.Tools; using Backbone.Tooling; using Backbone.Tooling.Extensions; -namespace Backbone.PerformanceSnapshotCreator.EntityCreation; +namespace Backbone.ConsumerApi.Tests.Performance.SnapshotCreator.EntityCreation; public class EntityCreator { @@ -191,7 +190,7 @@ await Parallel.ForEachAsync(_pools, async (pool, _) => if (sdk.DeviceData is null) throw new Exception("The SDK could not be used to create a new Identity."); - var createdIdentity = new Identity(sdk.DeviceData.UserCredentials, sdk.IdentityData?.Address ?? "no address", sdk.DeviceData.DeviceId, pool, i + 1); + var createdIdentity = new Domain.Identity(sdk.DeviceData.UserCredentials, sdk.IdentityData?.Address ?? "no address", sdk.DeviceData.DeviceId, pool, i + 1); if (pool.NumberOfDevices > 1) { diff --git a/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/PerformanceSnapshotCreator/GeneratePoolsCommand.cs b/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/tools/snapshot-creator/GeneratePoolsCommand.cs similarity index 75% rename from Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/PerformanceSnapshotCreator/GeneratePoolsCommand.cs rename to Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/tools/snapshot-creator/GeneratePoolsCommand.cs index 63800cc08e..ef6a15aefe 100644 --- a/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/PerformanceSnapshotCreator/GeneratePoolsCommand.cs +++ b/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/tools/snapshot-creator/GeneratePoolsCommand.cs @@ -1,12 +1,12 @@ using System.CommandLine; -using Backbone.PerformanceSnapshotCreator.Application.MessageDistributor; -using Backbone.PerformanceSnapshotCreator.Application.Printer; -using Backbone.PerformanceSnapshotCreator.Application.RelationshipDistributor; -using Backbone.PerformanceSnapshotCreator.PoolsFile; -using Backbone.PerformanceSnapshotCreator.PoolsGenerator; +using Backbone.ConsumerApi.Tests.Performance.SnapshotCreator.Application.MessageDistributor; +using Backbone.ConsumerApi.Tests.Performance.SnapshotCreator.Application.Printer; +using Backbone.ConsumerApi.Tests.Performance.SnapshotCreator.Application.RelationshipDistributor; +using Backbone.ConsumerApi.Tests.Performance.SnapshotCreator.PoolsFile; +using Backbone.ConsumerApi.Tests.Performance.SnapshotCreator.PoolsGenerator; using Microsoft.Extensions.DependencyInjection; -namespace Backbone.PerformanceSnapshotCreator; +namespace Backbone.ConsumerApi.Tests.Performance.SnapshotCreator; public class GeneratePoolsCommand : Command { diff --git a/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/PerformanceSnapshotCreator/MainCommand.cs b/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/tools/snapshot-creator/MainCommand.cs similarity index 75% rename from Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/PerformanceSnapshotCreator/MainCommand.cs rename to Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/tools/snapshot-creator/MainCommand.cs index a41f3e2348..220ba62f88 100644 --- a/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/PerformanceSnapshotCreator/MainCommand.cs +++ b/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/tools/snapshot-creator/MainCommand.cs @@ -1,6 +1,6 @@ using System.CommandLine; -namespace Backbone.PerformanceSnapshotCreator; +namespace Backbone.ConsumerApi.Tests.Performance.SnapshotCreator; public class MainCommand : RootCommand { diff --git a/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/PerformanceSnapshotCreator/PoolsFile/PoolEntry.cs b/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/tools/snapshot-creator/PoolsFile/PoolEntry.cs similarity index 96% rename from Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/PerformanceSnapshotCreator/PoolsFile/PoolEntry.cs rename to Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/tools/snapshot-creator/PoolsFile/PoolEntry.cs index 594867801f..9df305aa72 100644 --- a/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/PerformanceSnapshotCreator/PoolsFile/PoolEntry.cs +++ b/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/tools/snapshot-creator/PoolsFile/PoolEntry.cs @@ -1,8 +1,8 @@ using System.Collections.Concurrent; using System.Text.Json.Serialization; -using Backbone.PerformanceSnapshotCreator.Domain; +using Backbone.ConsumerApi.Tests.Performance.SnapshotCreator.Domain; -namespace Backbone.PerformanceSnapshotCreator.PoolsFile; +namespace Backbone.ConsumerApi.Tests.Performance.SnapshotCreator.PoolsFile; public record PoolEntry { diff --git a/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/PerformanceSnapshotCreator/PoolsFile/PoolFileRoot.cs b/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/tools/snapshot-creator/PoolsFile/PoolFileRoot.cs similarity index 76% rename from Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/PerformanceSnapshotCreator/PoolsFile/PoolFileRoot.cs rename to Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/tools/snapshot-creator/PoolsFile/PoolFileRoot.cs index 1d190f78f5..8dd2e06bfe 100644 --- a/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/PerformanceSnapshotCreator/PoolsFile/PoolFileRoot.cs +++ b/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/tools/snapshot-creator/PoolsFile/PoolFileRoot.cs @@ -1,4 +1,4 @@ -namespace Backbone.PerformanceSnapshotCreator.PoolsFile; +namespace Backbone.ConsumerApi.Tests.Performance.SnapshotCreator.PoolsFile; public class PoolFileRoot { diff --git a/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/PerformanceSnapshotCreator/PoolsFile/PoolTypes.cs b/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/tools/snapshot-creator/PoolsFile/PoolTypes.cs similarity index 61% rename from Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/PerformanceSnapshotCreator/PoolsFile/PoolTypes.cs rename to Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/tools/snapshot-creator/PoolsFile/PoolTypes.cs index bdc1123b87..5cb70f1a7c 100644 --- a/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/PerformanceSnapshotCreator/PoolsFile/PoolTypes.cs +++ b/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/tools/snapshot-creator/PoolsFile/PoolTypes.cs @@ -1,4 +1,4 @@ -namespace Backbone.PerformanceSnapshotCreator.PoolsFile; +namespace Backbone.ConsumerApi.Tests.Performance.SnapshotCreator.PoolsFile; public class PoolTypes { public const string CONNECTOR_TYPE = "connector"; diff --git a/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/PerformanceSnapshotCreator/PoolsFile/PoolsOffset.cs b/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/tools/snapshot-creator/PoolsFile/PoolsOffset.cs similarity index 98% rename from Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/PerformanceSnapshotCreator/PoolsFile/PoolsOffset.cs rename to Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/tools/snapshot-creator/PoolsFile/PoolsOffset.cs index f3fbf4fe43..6777b8fa93 100644 --- a/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/PerformanceSnapshotCreator/PoolsFile/PoolsOffset.cs +++ b/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/tools/snapshot-creator/PoolsFile/PoolsOffset.cs @@ -1,4 +1,4 @@ -namespace Backbone.PerformanceSnapshotCreator.PoolsFile; +namespace Backbone.ConsumerApi.Tests.Performance.SnapshotCreator.PoolsFile; internal record PoolsOffset { public OffsetDirections? MessagesOffsetPendingTo { get; private set; } diff --git a/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/PerformanceSnapshotCreator/PoolsFile/Reader.cs b/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/tools/snapshot-creator/PoolsFile/Reader.cs similarity index 85% rename from Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/PerformanceSnapshotCreator/PoolsFile/Reader.cs rename to Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/tools/snapshot-creator/PoolsFile/Reader.cs index 29204310e7..c2bea1fc50 100644 --- a/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/PerformanceSnapshotCreator/PoolsFile/Reader.cs +++ b/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/tools/snapshot-creator/PoolsFile/Reader.cs @@ -1,6 +1,6 @@ using System.Text.Json; -namespace Backbone.PerformanceSnapshotCreator.PoolsFile; +namespace Backbone.ConsumerApi.Tests.Performance.SnapshotCreator.PoolsFile; public static class Reader { public static async Task ReadPools(string poolsFilePath) diff --git a/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/PerformanceSnapshotCreator/PoolsGenerator/DeterministicPoolsGenerator.cs b/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/tools/snapshot-creator/PoolsGenerator/DeterministicPoolsGenerator.cs similarity index 90% rename from Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/PerformanceSnapshotCreator/PoolsGenerator/DeterministicPoolsGenerator.cs rename to Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/tools/snapshot-creator/PoolsGenerator/DeterministicPoolsGenerator.cs index 879f710d87..e8a04781f5 100644 --- a/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/PerformanceSnapshotCreator/PoolsGenerator/DeterministicPoolsGenerator.cs +++ b/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/tools/snapshot-creator/PoolsGenerator/DeterministicPoolsGenerator.cs @@ -1,12 +1,11 @@ using Backbone.ConsumerApi.Sdk.Authentication; -using Backbone.PerformanceSnapshotCreator.Application.MessageDistributor; -using Backbone.PerformanceSnapshotCreator.Application.Printer; -using Backbone.PerformanceSnapshotCreator.Application.RelationshipDistributor; -using Backbone.PerformanceSnapshotCreator.Domain; -using Backbone.PerformanceSnapshotCreator.PoolsFile; +using Backbone.ConsumerApi.Tests.Performance.SnapshotCreator.Application.MessageDistributor; +using Backbone.ConsumerApi.Tests.Performance.SnapshotCreator.Application.Printer; +using Backbone.ConsumerApi.Tests.Performance.SnapshotCreator.Application.RelationshipDistributor; +using Backbone.ConsumerApi.Tests.Performance.SnapshotCreator.PoolsFile; using Backbone.Tooling; -namespace Backbone.PerformanceSnapshotCreator.PoolsGenerator; +namespace Backbone.ConsumerApi.Tests.Performance.SnapshotCreator.PoolsGenerator; public class DeterministicPoolsGenerator { @@ -105,7 +104,7 @@ private void CreateFakeIdentities() { for (uint i = 0; i < pool.Amount; i++) { - var createdIdentity = new Identity(new UserCredentials("USR" + PasswordHelper.GeneratePassword(8, 8), PasswordHelper.GeneratePassword(18, 24)), + var createdIdentity = new Domain.Identity(new UserCredentials("USR" + PasswordHelper.GeneratePassword(8, 8), PasswordHelper.GeneratePassword(18, 24)), "ID1" + PasswordHelper.GeneratePassword(16, 16), "DVC" + PasswordHelper.GeneratePassword(8, 8), pool, i + 1, uon++); if (pool.NumberOfDevices > 1) diff --git a/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/PerformanceSnapshotCreator/PoolsGenerator/SimulatedAnnealingGenerator.cs b/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/tools/snapshot-creator/PoolsGenerator/SimulatedAnnealingGenerator.cs similarity index 87% rename from Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/PerformanceSnapshotCreator/PoolsGenerator/SimulatedAnnealingGenerator.cs rename to Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/tools/snapshot-creator/PoolsGenerator/SimulatedAnnealingGenerator.cs index c98d1e8bd6..827cecee6b 100644 --- a/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/PerformanceSnapshotCreator/PoolsGenerator/SimulatedAnnealingGenerator.cs +++ b/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/tools/snapshot-creator/PoolsGenerator/SimulatedAnnealingGenerator.cs @@ -2,18 +2,18 @@ using System.Diagnostics; using System.Text; using Backbone.ConsumerApi.Sdk.Authentication; -using Backbone.PerformanceSnapshotCreator.Application.Printer; -using Backbone.PerformanceSnapshotCreator.PoolsFile; -using Backbone.PerformanceSnapshotCreator.Tools; +using Backbone.ConsumerApi.Tests.Performance.SnapshotCreator.Application.Printer; +using Backbone.ConsumerApi.Tests.Performance.SnapshotCreator.PoolsFile; +using Backbone.ConsumerApi.Tests.Performance.SnapshotCreator.Tools; using Backbone.Tooling; -using GeneratorIdentity = Backbone.PerformanceSnapshotCreator.Domain.Identity; +using GeneratorIdentity = Backbone.ConsumerApi.Tests.Performance.SnapshotCreator.Domain.Identity; using Math = System.Math; // ReSharper disable HeuristicUnreachableCode #pragma warning disable CS0162 // Unreachable code detected // -- used for debugging -namespace Backbone.PerformanceSnapshotCreator.PoolsGenerator; +namespace Backbone.ConsumerApi.Tests.Performance.SnapshotCreator.PoolsGenerator; /// /// We use a different approach here. Instead of creating all identities, then their relationships and lastly their messages, @@ -57,7 +57,7 @@ public SimulatedAnnealingPoolsGenerator( public void CreatePools() { - _printer.PrintStringToFile(Generate().GetAsCSV(_identitiesDictionary), "ram"); + _printer.PrintStringToFile(Generate().GetAsCSV(_identitiesDictionary), "relationshipsAndMessages"); } private SolutionRepresentation Generate(double initialTemperature = 20d, ulong maxIterations = 20000) @@ -308,15 +308,15 @@ public class SolutionRepresentation : ICloneable /// This approach ensures that messages can only be sent in the context of a relationship (a mandatory requisite). /// /// - private Dictionary<(uint a, uint b), uint> RaM { get; } = new(); + private Dictionary<(uint a, uint b), uint> RelationshipsAndMessages { get; } = new(); public ulong IterationCount { get; set; } private readonly Random _localRandom = new(); - public SolutionRepresentation(Dictionary<(uint a, uint b), uint>? ram = null, Stopwatch? createdAt = null, (ulong relationshipCount, ulong messagesCount)? counters = null) + public SolutionRepresentation(Dictionary<(uint a, uint b), uint>? relationshipsAndMessages = null, Stopwatch? createdAt = null, (ulong relationshipCount, ulong messagesCount)? counters = null) { - if (ram is not null) RaM = ram.ToDictionary(entry => entry.Key, entry => entry.Value); + if (relationshipsAndMessages is not null) RelationshipsAndMessages = relationshipsAndMessages.ToDictionary(entry => entry.Key, entry => entry.Value); if (counters.HasValue) { _relationshipCount = counters.Value.relationshipCount; @@ -328,7 +328,7 @@ public SolutionRepresentation(Dictionary<(uint a, uint b), uint>? ram = null, St public bool EstablishRelationship(uint identity1, uint identity2) { - if (RaM.ContainsKey((identity1, identity2))) + if (RelationshipsAndMessages.ContainsKey((identity1, identity2))) { // relationship already exists return false; @@ -337,8 +337,8 @@ public bool EstablishRelationship(uint identity1, uint identity2) if (identity1 == identity2) return false; - RaM[(identity1, identity2)] = 0; - RaM[(identity2, identity1)] = 0; + RelationshipsAndMessages[(identity1, identity2)] = 0; + RelationshipsAndMessages[(identity2, identity1)] = 0; _relationshipCount++; return true; @@ -354,13 +354,13 @@ public bool EstablishRelationship(uint identity1, uint identity2) /// private int RemoveRelationship(uint identity1, uint identity2) { - if (_relationshipCount <= 0 || !RaM.ContainsKey((identity1, identity2))) + if (_relationshipCount <= 0 || !RelationshipsAndMessages.ContainsKey((identity1, identity2))) return -1; - var messageCount = RaM[(identity1, identity2)] + RaM[(identity2, identity1)]; + var messageCount = RelationshipsAndMessages[(identity1, identity2)] + RelationshipsAndMessages[(identity2, identity1)]; - RaM.Remove((identity1, identity2)); - RaM.Remove((identity2, identity1)); + RelationshipsAndMessages.Remove((identity1, identity2)); + RelationshipsAndMessages.Remove((identity2, identity1)); _messagesCount -= messageCount; _relationshipCount--; return Convert.ToInt32(messageCount); @@ -369,22 +369,22 @@ private int RemoveRelationship(uint identity1, uint identity2) public bool SendMessage(uint identityFrom, uint identityTo) { EstablishRelationship(identityFrom, identityTo); - RaM[(identityFrom, identityTo)]++; + RelationshipsAndMessages[(identityFrom, identityTo)]++; _messagesCount++; return true; } private void RemoveMessage(uint identityFrom, uint identityTo) { - if (!RaM.ContainsKey((identityFrom, identityTo))) return; + if (!RelationshipsAndMessages.ContainsKey((identityFrom, identityTo))) return; - RaM[(identityFrom, identityTo)]--; + RelationshipsAndMessages[(identityFrom, identityTo)]--; _messagesCount--; } public object Clone() { - var ret = new SolutionRepresentation(RaM, counters: (relationshipCount: _relationshipCount, messagesCount: _messagesCount), createdAt: _createdAt); + var ret = new SolutionRepresentation(RelationshipsAndMessages, counters: (relationshipCount: _relationshipCount, messagesCount: _messagesCount), createdAt: _createdAt); return ret; } @@ -392,8 +392,7 @@ public void RemoveRandomMessage() { if (_messagesCount <= 0) return; - var raMWithMessages = RaM.Where(m => m.Value > 0).ToDictionary(); - var (a, b) = _localRandom.GetRandomKey(raMWithMessages); + var (a, b) = _localRandom.GetRandomKey(RelationshipsAndMessages.Where(m => m.Value > 0).ToDictionary()); RemoveMessage(a, b); } @@ -407,14 +406,14 @@ public int RemoveRandomRelationship() { if (_relationshipCount <= 0) return -1; - var (a, b) = _localRandom.GetRandomKey(RaM); + var (a, b) = _localRandom.GetRandomKey(RelationshipsAndMessages); return RemoveRelationship(a, b); } public long GetInvalidRelationshipCount(Dictionary identities) { var res = 0; - foreach (var ((from, to), _) in RaM) + foreach (var ((from, to), _) in RelationshipsAndMessages) { if (from == to) { @@ -450,20 +449,20 @@ public void Print(Dictionary identities, List Expected sent messages: {pools.ExpectedNumberOfSentMessages()}"); Console.WriteLine(" =====> ESTABLISHED RELATIONSHIPS"); - if (RaM.Count / 2 != GetRelationshipCount()) + if (RelationshipsAndMessages.Count / 2 != GetRelationshipCount()) Console.WriteLine("==[ERROR]=> Relationship Count mismatch."); - if (RaM.Sum(x => x.Value) != GetSentMessagesCount()) + if (RelationshipsAndMessages.Sum(x => x.Value) != GetSentMessagesCount()) Console.WriteLine("==[ERROR]=> Message Count mismatch."); - Console.WriteLine($" - Counted {RaM.Count} entries, meaning there are {RaM.Count / 2} relationships."); - Console.WriteLine($" - Counted {RaM.Sum(x => x.Value)} messages."); + Console.WriteLine($" - Counted {RelationshipsAndMessages.Count} entries, meaning there are {RelationshipsAndMessages.Count / 2} relationships."); + Console.WriteLine($" - Counted {RelationshipsAndMessages.Sum(x => x.Value)} messages."); } // reflections may be counted twice here public uint GetNumberOfRelatedIdentities(uint identity) { - return (uint)RaM.Count(r => + return (uint)RelationshipsAndMessages.Count(r => { var ((a, b), _) = r; return a == identity || b == identity; @@ -474,7 +473,7 @@ public uint GetNumberOfRelatedIdentities(uint identity) { var res = new Dictionary(); - foreach (var ((a, b), c) in RaM) + foreach (var ((a, b), c) in RelationshipsAndMessages) { res.TryAdd(a, (0, 0)); res.TryAdd(b, (0, 0)); @@ -488,7 +487,7 @@ public uint GetNumberOfRelatedIdentities(uint identity) public IEnumerable<(uint relatedIdentity, uint messageCount)> GetRelationshipsAndMessageSentCountByIdentity(uint uon) { - return RaM.Where(it => it.Key.a == uon).Select(it => (it.Key.b, it.Value)).ToList(); + return RelationshipsAndMessages.Where(it => it.Key.a == uon).Select(it => (it.Key.b, it.Value)).ToList(); } public string GetAsCSV(Dictionary identitiesDictionary) @@ -496,7 +495,7 @@ public string GetAsCSV(Dictionary identitiesDictionary) var stringBuilder = new StringBuilder(); stringBuilder.AppendLine("Identity1;Identity1Pool;Identity2;Identity2Pool;MessageCount"); - foreach (var ((a, b), c) in RaM) + foreach (var ((a, b), c) in RelationshipsAndMessages) { var identity1Pool = identitiesDictionary[a].Pool.Alias; var identity2Pool = identitiesDictionary[b].Pool.Alias; @@ -506,7 +505,7 @@ public string GetAsCSV(Dictionary identitiesDictionary) return stringBuilder.ToString(); } - internal uint GetIdentityCount() => RaM.Max(r => r.Key.a); + internal uint GetIdentityCount() => RelationshipsAndMessages.Max(r => r.Key.a); } public static class RandomMethodExtensions diff --git a/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/PerformanceSnapshotCreator/Program.cs b/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/tools/snapshot-creator/Program.cs similarity index 54% rename from Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/PerformanceSnapshotCreator/Program.cs rename to Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/tools/snapshot-creator/Program.cs index d0aa963cdb..d7bddc6277 100644 --- a/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/PerformanceSnapshotCreator/Program.cs +++ b/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/tools/snapshot-creator/Program.cs @@ -1,4 +1,4 @@ using System.CommandLine; -using Backbone.PerformanceSnapshotCreator; +using Backbone.ConsumerApi.Tests.Performance.SnapshotCreator; await new MainCommand().InvokeAsync(args); diff --git a/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/tools/snapshot-creator/Properties/launchSettings.json b/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/tools/snapshot-creator/Properties/launchSettings.json new file mode 100644 index 0000000000..e5cf2b303b --- /dev/null +++ b/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/tools/snapshot-creator/Properties/launchSettings.json @@ -0,0 +1,20 @@ +{ + "profiles": { + "Pool Generator Light": { + "commandName": "Project", + "commandLineArgs": "GeneratePools --poolsFile pool-config.light.json" + }, + "Pool Generator Heavy": { + "commandName": "Project", + "commandLineArgs": "GeneratePools --poolsFile pool-config.heavy.json" + }, + "Pool Generator Test": { + "commandName": "Project", + "commandLineArgs": "GeneratePools --poolsFile pool-config.test.json" + }, + "Create Entities Light": { + "commandName": "Project", + "commandLineArgs": "CreateEntities --baseAddress http://localhost:8081 --clientId test --clientSecret test --poolsFile pool-config.test.json --relationshipsAndMessages path\\to\\relationshipsAndMessages.csv" + } + } +} diff --git a/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/PerformanceSnapshotCreator/Tools/IEnumeratorExtensionMethods.cs b/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/tools/snapshot-creator/Tools/IEnumeratorExtensionMethods.cs similarity index 79% rename from Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/PerformanceSnapshotCreator/Tools/IEnumeratorExtensionMethods.cs rename to Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/tools/snapshot-creator/Tools/IEnumeratorExtensionMethods.cs index 1acd8a5d16..6eeff76dd3 100644 --- a/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/PerformanceSnapshotCreator/Tools/IEnumeratorExtensionMethods.cs +++ b/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/tools/snapshot-creator/Tools/IEnumeratorExtensionMethods.cs @@ -1,4 +1,4 @@ -namespace Backbone.PerformanceSnapshotCreator.Tools; +namespace Backbone.ConsumerApi.Tests.Performance.SnapshotCreator.Tools; public static class IEnumeratorExtensionMethods { public static T NextOrFirst(this IEnumerator enumerator) diff --git a/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/PerformanceSnapshotCreator/Tools/ProgressBar.cs b/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/tools/snapshot-creator/Tools/ProgressBar.cs similarity index 97% rename from Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/PerformanceSnapshotCreator/Tools/ProgressBar.cs rename to Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/tools/snapshot-creator/Tools/ProgressBar.cs index e450c099c6..fe8a3b16f6 100644 --- a/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/PerformanceSnapshotCreator/Tools/ProgressBar.cs +++ b/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/tools/snapshot-creator/Tools/ProgressBar.cs @@ -1,6 +1,6 @@ using System.Text; -namespace Backbone.PerformanceSnapshotCreator.Tools; +namespace Backbone.ConsumerApi.Tests.Performance.SnapshotCreator.Tools; public class ProgressBar : IDisposable, IProgress { diff --git a/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/tools/snapshot-creator/packages.lock.json b/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/tools/snapshot-creator/packages.lock.json new file mode 100644 index 0000000000..b37aec8ea7 --- /dev/null +++ b/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/tools/snapshot-creator/packages.lock.json @@ -0,0 +1,463 @@ +{ + "version": 1, + "dependencies": { + "net8.0": { + "Microsoft.Extensions.DependencyInjection": { + "type": "Direct", + "requested": "[8.0.0, )", + "resolved": "8.0.0", + "contentHash": "V8S3bsm50ig6JSyrbcJJ8bW2b9QLGouz+G1miK3UTaOWmMtFwNNNzUf4AleyDWUmTrWMLNnFSLEQtxmxgNQnNQ==", + "dependencies": { + "Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.0" + } + }, + "System.CommandLine": { + "type": "Direct", + "requested": "[2.0.0-beta4.22272.1, )", + "resolved": "2.0.0-beta4.22272.1", + "contentHash": "1uqED/q2H0kKoLJ4+hI2iPSBSEdTuhfCYADeJrAqERmiGQ2NNacYKRNEQ+gFbU4glgVyK8rxI+ZOe1onEtr/Pg==" + }, + "BouncyCastle.Cryptography": { + "type": "Transitive", + "resolved": "2.4.0", + "contentHash": "SwXsAV3sMvAU/Nn31pbjhWurYSjJ+/giI/0n6tCrYoupEK34iIHCuk3STAd9fx8yudM85KkLSVdn951vTng/vQ==" + }, + "FluentAssertions": { + "type": "Transitive", + "resolved": "6.12.1", + "contentHash": "hciWwryyLw3eonfqhFpOMTXyM1/auJChYslEBA+iGJyuBs5O3t/kA8YaeH4iRo/2Fe3ElSYL86C0miivtZ0f3g==", + "dependencies": { + "System.Configuration.ConfigurationManager": "4.4.0" + } + }, + "libsodium": { + "type": "Transitive", + "resolved": "1.0.19", + "contentHash": "tupm/HViwBN6Knd/gckR+cLaJGR39GLmiU4iDMM5hp/1BoczMr8fwJhSU+3/C2V4hi9nBK/4FICRKtTLU30TCA==" + }, + "Microsoft.CSharp": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "P+MBhIM0YX+JqROuf7i306ZLJEjQYA9uUyRDE+OqwUI5sh41e2ZbPQV3LfAPh+29cmceE1pUffXsGfR4eMY3KA==", + "dependencies": { + "System.Collections": "4.3.0", + "System.Diagnostics.Debug": "4.3.0", + "System.Dynamic.Runtime": "4.3.0", + "System.Globalization": "4.3.0", + "System.Linq": "4.3.0", + "System.Linq.Expressions": "4.3.0", + "System.ObjectModel": "4.3.0", + "System.Reflection": "4.3.0", + "System.Reflection.Extensions": "4.3.0", + "System.Reflection.Primitives": "4.3.0", + "System.Reflection.TypeExtensions": "4.3.0", + "System.Resources.ResourceManager": "4.3.0", + "System.Runtime": "4.3.0", + "System.Runtime.Extensions": "4.3.0", + "System.Runtime.InteropServices": "4.3.0", + "System.Threading": "4.3.0" + } + }, + "Microsoft.Extensions.DependencyInjection.Abstractions": { + "type": "Transitive", + "resolved": "8.0.1", + "contentHash": "fGLiCRLMYd00JYpClraLjJTNKLmMJPnqxMaiRzEBIIvevlzxz33mXy39Lkd48hu1G+N21S7QpaO5ZzKsI6FRuA==" + }, + "Microsoft.Extensions.Logging.Abstractions": { + "type": "Transitive", + "resolved": "8.0.1", + "contentHash": "RIFgaqoaINxkM2KTOw72dmilDmTrYA0ns2KW4lDz4gZ2+o6IQ894CzmdL3StM2oh7QQq44nCWiqKqc4qUI9Jmg==", + "dependencies": { + "Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.1" + } + }, + "Microsoft.NETCore.Platforms": { + "type": "Transitive", + "resolved": "1.1.0", + "contentHash": "kz0PEW2lhqygehI/d6XsPCQzD7ff7gUJaVGPVETX611eadGsA3A877GdSlU0LRVMCTH/+P3o2iDTak+S08V2+A==" + }, + "Microsoft.NETCore.Targets": { + "type": "Transitive", + "resolved": "1.1.0", + "contentHash": "aOZA3BWfz9RXjpzt0sRJJMjAscAUm3Hoa4UWAfceV9UTYxgwZ1lZt5nO2myFf+/jetYQo4uTP7zS8sJY67BBxg==" + }, + "Namotion.Reflection": { + "type": "Transitive", + "resolved": "3.1.1", + "contentHash": "Qn0wM7u9TpSpja2x8UVexr2bLHb1DGMNhD2TCz3woklxaY1oH+Sitrw9fg/4YbNoNtczeH2jf+yPdXMQlgvFlQ==", + "dependencies": { + "Microsoft.CSharp": "4.3.0" + } + }, + "Newtonsoft.Json": { + "type": "Transitive", + "resolved": "13.0.3", + "contentHash": "HrC5BXdl00IP9zeV+0Z848QWPAoCr9P3bDEZguI+gkLcBKAOxix/tLEAAHC+UvDNPv4a2d18lOReHMOagPa+zQ==" + }, + "NJsonSchema": { + "type": "Transitive", + "resolved": "11.0.2", + "contentHash": "BOgw+TOd1w7BSRIEWwkiSgHlKWC2eu0DHsSsb1LIwlC1Hq26A0ARZiMjsCsqfXqXdr7hLf1m4M84Z7LW1wmCGA==", + "dependencies": { + "NJsonSchema.Annotations": "11.0.2", + "Namotion.Reflection": "3.1.1", + "Newtonsoft.Json": "13.0.3" + } + }, + "NJsonSchema.Annotations": { + "type": "Transitive", + "resolved": "11.0.2", + "contentHash": "VbA0fmxVyqloGXYz863g6QHyojM1tgejwPQr9LjXdubs9YJt5YfRPCQOV/hnzpP2Bqd7nZFpDn9MCImmLAmqCw==" + }, + "NJsonSchema.NewtonsoftJson": { + "type": "Transitive", + "resolved": "11.0.2", + "contentHash": "tTVG8h7qfw6anxlhXGx3oUz7f3ig+t9jO3yrho73ypvMZ7DCyFtiaF5gG3GqBDZXM49ONogDmTZ+8HTG6AKaNQ==", + "dependencies": { + "NJsonSchema": "11.0.2", + "Newtonsoft.Json": "13.0.3" + } + }, + "NSec.Cryptography": { + "type": "Transitive", + "resolved": "24.4.0", + "contentHash": "R89OF0T5OY9QnPRoTsMCaPKMqtXcWKZSWAO4zyUaFHI+ZRMgXU7WaIwg/rPP3vOfdaLl8HdUHWkDB+2B9FOO7g==", + "dependencies": { + "libsodium": "[1.0.19, 1.0.20)" + } + }, + "System.Buffers": { + "type": "Transitive", + "resolved": "4.5.0", + "contentHash": "pL2ChpaRRWI/p4LXyy4RgeWlYF2sgfj/pnVMvBqwNFr5cXg7CXNnWZWxrOONLg8VGdFB8oB+EG2Qw4MLgTOe+A==" + }, + "System.Collections": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "3Dcj85/TBdVpL5Zr+gEEBUuFe2icOnLalmEh9hfck1PTYbbyWuZgh4fmm2ysCLTrqLQw6t3TgTyJ+VLp+Qb+Lw==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "Microsoft.NETCore.Targets": "1.1.0", + "System.Runtime": "4.3.0" + } + }, + "System.Configuration.ConfigurationManager": { + "type": "Transitive", + "resolved": "4.4.0", + "contentHash": "gWwQv/Ug1qWJmHCmN17nAbxJYmQBM/E94QxKLksvUiiKB1Ld3Sc/eK1lgmbSjDFxkQhVuayI/cGFZhpBSodLrg==", + "dependencies": { + "System.Security.Cryptography.ProtectedData": "4.4.0" + } + }, + "System.Diagnostics.Debug": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "ZUhUOdqmaG5Jk3Xdb8xi5kIyQYAA4PnTNlHx1mu9ZY3qv4ELIdKbnL/akbGaKi2RnNUWaZsAs31rvzFdewTj2g==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "Microsoft.NETCore.Targets": "1.1.0", + "System.Runtime": "4.3.0" + } + }, + "System.Dynamic.Runtime": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "SNVi1E/vfWUAs/WYKhE9+qlS6KqK0YVhnlT0HQtr8pMIA8YX3lwy3uPMownDwdYISBdmAF/2holEIldVp85Wag==", + "dependencies": { + "System.Collections": "4.3.0", + "System.Diagnostics.Debug": "4.3.0", + "System.Linq": "4.3.0", + "System.Linq.Expressions": "4.3.0", + "System.ObjectModel": "4.3.0", + "System.Reflection": "4.3.0", + "System.Reflection.Emit": "4.3.0", + "System.Reflection.Emit.ILGeneration": "4.3.0", + "System.Reflection.Primitives": "4.3.0", + "System.Reflection.TypeExtensions": "4.3.0", + "System.Resources.ResourceManager": "4.3.0", + "System.Runtime": "4.3.0", + "System.Runtime.Extensions": "4.3.0", + "System.Threading": "4.3.0" + } + }, + "System.Globalization": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "kYdVd2f2PAdFGblzFswE4hkNANJBKRmsfa2X5LG2AcWE1c7/4t0pYae1L8vfZ5xvE2nK/R9JprtToA61OSHWIg==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "Microsoft.NETCore.Targets": "1.1.0", + "System.Runtime": "4.3.0" + } + }, + "System.IO": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "3qjaHvxQPDpSOYICjUoTsmoq5u6QJAFRUITgeT/4gqkF1bajbSmb1kwSxEA8AHlofqgcKJcM8udgieRNhaJ5Cg==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "Microsoft.NETCore.Targets": "1.1.0", + "System.Runtime": "4.3.0", + "System.Text.Encoding": "4.3.0", + "System.Threading.Tasks": "4.3.0" + } + }, + "System.Linq": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "5DbqIUpsDp0dFftytzuMmc0oeMdQwjcP/EWxsksIz/w1TcFRkZ3yKKz0PqiYFMmEwPSWw+qNVqD7PJ889JzHbw==", + "dependencies": { + "System.Collections": "4.3.0", + "System.Diagnostics.Debug": "4.3.0", + "System.Resources.ResourceManager": "4.3.0", + "System.Runtime": "4.3.0", + "System.Runtime.Extensions": "4.3.0" + } + }, + "System.Linq.Expressions": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "PGKkrd2khG4CnlyJwxwwaWWiSiWFNBGlgXvJpeO0xCXrZ89ODrQ6tjEWS/kOqZ8GwEOUATtKtzp1eRgmYNfclg==", + "dependencies": { + "System.Collections": "4.3.0", + "System.Diagnostics.Debug": "4.3.0", + "System.Globalization": "4.3.0", + "System.IO": "4.3.0", + "System.Linq": "4.3.0", + "System.ObjectModel": "4.3.0", + "System.Reflection": "4.3.0", + "System.Reflection.Emit": "4.3.0", + "System.Reflection.Emit.ILGeneration": "4.3.0", + "System.Reflection.Emit.Lightweight": "4.3.0", + "System.Reflection.Extensions": "4.3.0", + "System.Reflection.Primitives": "4.3.0", + "System.Reflection.TypeExtensions": "4.3.0", + "System.Resources.ResourceManager": "4.3.0", + "System.Runtime": "4.3.0", + "System.Runtime.Extensions": "4.3.0", + "System.Threading": "4.3.0" + } + }, + "System.Memory": { + "type": "Transitive", + "resolved": "4.5.3", + "contentHash": "3oDzvc/zzetpTKWMShs1AADwZjQ/36HnsufHRPcOjyRAAMLDlu2iD33MBI2opxnezcVUtXyqDXXjoFMOU9c7SA==" + }, + "System.ObjectModel": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "bdX+80eKv9bN6K4N+d77OankKHGn6CH711a6fcOpMQu2Fckp/Ft4L/kW9WznHpyR0NRAvJutzOMHNNlBGvxQzQ==", + "dependencies": { + "System.Collections": "4.3.0", + "System.Diagnostics.Debug": "4.3.0", + "System.Resources.ResourceManager": "4.3.0", + "System.Runtime": "4.3.0", + "System.Threading": "4.3.0" + } + }, + "System.Reflection": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "KMiAFoW7MfJGa9nDFNcfu+FpEdiHpWgTcS2HdMpDvt9saK3y/G4GwprPyzqjFH9NTaGPQeWNHU+iDlDILj96aQ==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "Microsoft.NETCore.Targets": "1.1.0", + "System.IO": "4.3.0", + "System.Reflection.Primitives": "4.3.0", + "System.Runtime": "4.3.0" + } + }, + "System.Reflection.Emit": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "228FG0jLcIwTVJyz8CLFKueVqQK36ANazUManGaJHkO0icjiIypKW7YLWLIWahyIkdh5M7mV2dJepllLyA1SKg==", + "dependencies": { + "System.IO": "4.3.0", + "System.Reflection": "4.3.0", + "System.Reflection.Emit.ILGeneration": "4.3.0", + "System.Reflection.Primitives": "4.3.0", + "System.Runtime": "4.3.0" + } + }, + "System.Reflection.Emit.ILGeneration": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "59tBslAk9733NXLrUJrwNZEzbMAcu8k344OYo+wfSVygcgZ9lgBdGIzH/nrg3LYhXceynyvTc8t5/GD4Ri0/ng==", + "dependencies": { + "System.Reflection": "4.3.0", + "System.Reflection.Primitives": "4.3.0", + "System.Runtime": "4.3.0" + } + }, + "System.Reflection.Emit.Lightweight": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "oadVHGSMsTmZsAF864QYN1t1QzZjIcuKU3l2S9cZOwDdDueNTrqq1yRj7koFfIGEnKpt6NjpL3rOzRhs4ryOgA==", + "dependencies": { + "System.Reflection": "4.3.0", + "System.Reflection.Emit.ILGeneration": "4.3.0", + "System.Reflection.Primitives": "4.3.0", + "System.Runtime": "4.3.0" + } + }, + "System.Reflection.Extensions": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "rJkrJD3kBI5B712aRu4DpSIiHRtr6QlfZSQsb0hYHrDCZORXCFjQfoipo2LaMUHoT9i1B7j7MnfaEKWDFmFQNQ==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "Microsoft.NETCore.Targets": "1.1.0", + "System.Reflection": "4.3.0", + "System.Runtime": "4.3.0" + } + }, + "System.Reflection.Primitives": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "5RXItQz5As4xN2/YUDxdpsEkMhvw3e6aNveFXUn4Hl/udNTCNhnKp8lT9fnc3MhvGKh1baak5CovpuQUXHAlIA==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "Microsoft.NETCore.Targets": "1.1.0", + "System.Runtime": "4.3.0" + } + }, + "System.Reflection.TypeExtensions": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "7u6ulLcZbyxB5Gq0nMkQttcdBTx57ibzw+4IOXEfR+sXYQoHvjW5LTLyNr8O22UIMrqYbchJQJnos4eooYzYJA==", + "dependencies": { + "System.Reflection": "4.3.0", + "System.Runtime": "4.3.0" + } + }, + "System.Resources.ResourceManager": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "/zrcPkkWdZmI4F92gL/TPumP98AVDu/Wxr3CSJGQQ+XN6wbRZcyfSKVoPo17ilb3iOr0cCRqJInGwNMolqhS8A==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "Microsoft.NETCore.Targets": "1.1.0", + "System.Globalization": "4.3.0", + "System.Reflection": "4.3.0", + "System.Runtime": "4.3.0" + } + }, + "System.Runtime": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "JufQi0vPQ0xGnAczR13AUFglDyVYt4Kqnz1AZaiKZ5+GICq0/1MH/mO/eAJHt/mHW1zjKBJd7kV26SrxddAhiw==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "Microsoft.NETCore.Targets": "1.1.0" + } + }, + "System.Runtime.Extensions": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "guW0uK0fn5fcJJ1tJVXYd7/1h5F+pea1r7FLSOz/f8vPEqbR2ZAknuRDvTQ8PzAilDveOxNjSfr0CHfIQfFk8g==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "Microsoft.NETCore.Targets": "1.1.0", + "System.Runtime": "4.3.0" + } + }, + "System.Runtime.Handles": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "OKiSUN7DmTWeYb3l51A7EYaeNMnvxwE249YtZz7yooT4gOZhmTjIn48KgSsw2k2lYdLgTKNJw/ZIfSElwDRVgg==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "Microsoft.NETCore.Targets": "1.1.0", + "System.Runtime": "4.3.0" + } + }, + "System.Runtime.InteropServices": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "uv1ynXqiMK8mp1GM3jDqPCFN66eJ5w5XNomaK2XD+TuCroNTLFGeZ+WCmBMcBDyTFKou3P6cR6J/QsaqDp7fGQ==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "Microsoft.NETCore.Targets": "1.1.0", + "System.Reflection": "4.3.0", + "System.Reflection.Primitives": "4.3.0", + "System.Runtime": "4.3.0", + "System.Runtime.Handles": "4.3.0" + } + }, + "System.Security.Cryptography.ProtectedData": { + "type": "Transitive", + "resolved": "4.4.0", + "contentHash": "cJV7ScGW7EhatRsjehfvvYVBvtiSMKgN8bOVI0bQhnF5bU7vnHVIsH49Kva7i7GWaWYvmEzkYVk1TC+gZYBEog==" + }, + "System.Text.Encoding": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "BiIg+KWaSDOITze6jGQynxg64naAPtqGHBwDrLaCtixsa5bKiR8dpPOHA7ge3C0JJQizJE+sfkz1wV+BAKAYZw==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "Microsoft.NETCore.Targets": "1.1.0", + "System.Runtime": "4.3.0" + } + }, + "System.Threading": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "VkUS0kOBcUf3Wwm0TSbrevDDZ6BlM+b/HRiapRFWjM5O0NS0LviG0glKmFK+hhPDd1XFeSdU1GmlLhb2CoVpIw==", + "dependencies": { + "System.Runtime": "4.3.0", + "System.Threading.Tasks": "4.3.0" + } + }, + "System.Threading.Tasks": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "LbSxKEdOUhVe8BezB/9uOGGppt+nZf6e1VFyw6v3DN6lqitm0OSn2uXMOdtP0M3W4iMcqcivm2J6UgqiwwnXiA==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "Microsoft.NETCore.Targets": "1.1.0", + "System.Runtime": "4.3.0" + } + }, + "UrlBase64": { + "type": "Transitive", + "resolved": "2.0.0", + "contentHash": "b8tTEqBi0IEHU03MMG8raeKjn4P5EiFYfbx9mIotiGNGhl18b7p8qX0So4pawR1kSYIJWGQVngeWXHMFzZgq4g==", + "dependencies": { + "System.Buffers": "4.5.0", + "System.Memory": "4.5.3" + } + }, + "Backbone.BuildingBlocks.SDK": { + "type": "Project", + "dependencies": { + "Backbone.Tooling": "[1.0.0, )", + "FluentAssertions": "[6.12.1, )", + "NJsonSchema.NewtonsoftJson": "[11.0.2, )" + } + }, + "Backbone.ConsumerApi.Sdk": { + "type": "Project", + "dependencies": { + "Backbone.BuildingBlocks.SDK": "[1.0.0, )", + "Backbone.Crypto": "[1.0.0, )", + "Backbone.Tooling": "[1.0.0, )", + "Newtonsoft.Json": "[13.0.3, )" + } + }, + "Backbone.Crypto": { + "type": "Project", + "dependencies": { + "BouncyCastle.Cryptography": "[2.4.0, )", + "NSec.Cryptography": "[24.4.0, )" + } + }, + "Backbone.Tooling": { + "type": "Project", + "dependencies": { + "Microsoft.Extensions.Logging.Abstractions": "[8.0.1, )", + "UrlBase64": "[2.0.0, )" + } + } + } + } +} \ No newline at end of file diff --git a/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/PerformanceSnapshotCreator/pool-config.heavy.json b/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/tools/snapshot-creator/pool-config.heavy.json similarity index 98% rename from Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/PerformanceSnapshotCreator/pool-config.heavy.json rename to Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/tools/snapshot-creator/pool-config.heavy.json index 3efa9b15fe..77f67062a4 100644 --- a/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/PerformanceSnapshotCreator/pool-config.heavy.json +++ b/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/tools/snapshot-creator/pool-config.heavy.json @@ -53,7 +53,7 @@ "name": "ConnectorLight", "alias": "c1", "amount": 10, - "numberOfRelationshipTemplates": 0, + "numberOfRelationshipTemplates": 1, "numberOfRelationships": 0, "totalNumberOfMessages": 0, "numberOfDatawalletModifications": 0, diff --git a/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/PerformanceSnapshotCreator/pool-config.light.json b/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/tools/snapshot-creator/pool-config.light.json similarity index 98% rename from Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/PerformanceSnapshotCreator/pool-config.light.json rename to Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/tools/snapshot-creator/pool-config.light.json index b04a206e4b..9f521197ec 100644 --- a/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/PerformanceSnapshotCreator/pool-config.light.json +++ b/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/tools/snapshot-creator/pool-config.light.json @@ -53,7 +53,7 @@ "name": "ConnectorLight", "alias": "c1", "amount": 2, - "numberOfRelationshipTemplates": 0, + "numberOfRelationshipTemplates": 1, "numberOfRelationships": 0, "totalNumberOfMessages": 0, "numberOfDatawalletModifications": 0, diff --git a/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/PerformanceSnapshotCreator/pool-config.test.json b/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/tools/snapshot-creator/pool-config.test.json similarity index 98% rename from Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/PerformanceSnapshotCreator/pool-config.test.json rename to Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/tools/snapshot-creator/pool-config.test.json index dbff6c6be0..4de4f9e8a1 100644 --- a/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/PerformanceSnapshotCreator/pool-config.test.json +++ b/Applications/ConsumerApi/test/ConsumerApi.Tests.Performance/tools/snapshot-creator/pool-config.test.json @@ -53,7 +53,7 @@ "name": "ConnectorLight", "alias": "c1", "amount": 1, - "numberOfRelationshipTemplates": 0, + "numberOfRelationshipTemplates": 1, "numberOfRelationships": 0, "totalNumberOfMessages": 0, "numberOfDatawalletModifications": 0, diff --git a/Backbone.sln b/Backbone.sln index c0130e5701..3c6b532481 100644 --- a/Backbone.sln +++ b/Backbone.sln @@ -235,7 +235,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Files.Infrastructure.Tests" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Messages.Domain.Tests", "Modules\Messages\test\Messages.Domain.Tests\Messages.Domain.Tests.csproj", "{83A86879-670B-4F22-8835-EE1D0AB49AA9}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PerformanceSnapshotCreator", "Applications\ConsumerApi\test\ConsumerApi.Tests.Performance\PerformanceSnapshotCreator\PerformanceSnapshotCreator.csproj", "{B74B8655-8A94-4520-8BAB-212D7123EDB4}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PerformanceSnapshotCreator", "Applications\ConsumerApi\test\ConsumerApi.Tests.Performance\tools\snapshot-creator\ConsumerApi.Tests.Performance.SnapshotCreator.csproj", "{B74B8655-8A94-4520-8BAB-212D7123EDB4}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tokens.Domain.Tests", "Modules\Tokens\test\Tokens.Domain.Tests\Tokens.Domain.Tests.csproj", "{EDCB84BE-54C3-4CAD-977E-45EEBEFA1402}" EndProject diff --git a/Infrastructure/UserContext/AspNetCoreUserContext.cs b/Infrastructure/UserContext/AspNetCoreUserContext.cs index b84ab5b821..21b359e4bc 100644 --- a/Infrastructure/UserContext/AspNetCoreUserContext.cs +++ b/Infrastructure/UserContext/AspNetCoreUserContext.cs @@ -28,7 +28,6 @@ public IdentityAddress GetAddress() public IdentityAddress? GetAddressOrNull() { var address = GetHttpContext().User.FindFirstValue(ADDRESS_CLAIM); - return address == null ? null : IdentityAddress.Parse(address); } @@ -41,7 +40,6 @@ public DeviceId GetDeviceId() public DeviceId? GetDeviceIdOrNull() { var deviceId = GetHttpContext().User.FindFirstValue(DEVICE_ID_CLAIM); - return deviceId == null ? null : DeviceId.Parse(deviceId); } @@ -54,7 +52,6 @@ public string GetUserId() public string? GetUserIdOrNull() { var userId = GetHttpContext().User.FindFirstValue(USER_ID_CLAIM); - return userId; } diff --git a/docker-compose/dumps/dump-files/.gitignore b/docker-compose/dumps/dump-files/.gitignore deleted file mode 100644 index f59ec20aab..0000000000 --- a/docker-compose/dumps/dump-files/.gitignore +++ /dev/null @@ -1 +0,0 @@ -* \ No newline at end of file diff --git a/docker-compose/dumps/dump_postgres.bat b/docker-compose/dumps/dump_postgres.bat deleted file mode 100644 index 001e553789..0000000000 --- a/docker-compose/dumps/dump_postgres.bat +++ /dev/null @@ -1,3 +0,0 @@ - -docker exec --env PGPASSWORD=admin -it bkb-postgres pg_dump -h postgres -U postgres enmeshed -f tmp/enmeshed.pg -docker cp bkb-postgres:/tmp/enmeshed.pg ./dumps/enmeshed.pg \ No newline at end of file diff --git a/docker-compose/dumps/dump_sqlServer.sh b/docker-compose/dumps/dump_sqlServer.sh deleted file mode 100644 index 660e1e4803..0000000000 --- a/docker-compose/dumps/dump_sqlServer.sh +++ /dev/null @@ -1,5 +0,0 @@ -#!/usr/bin/sh - -/opt/mssql-tools/bin/sqlcmd -b -V16 -S localhost -U SA -P Passw0rd -Q "SELECT TABLE_SCHEMA + \".\" + TABLE_NAME as NAME FROM enmeshed.INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE='BASE TABLE'" | tail --lines=+3 | head --lines=-2 > /tmp/tables.list -echo "" > /tmp/dump.sql ->/tmp/dump.sql && /opt/mssql-tools/bin/sqlcmd -b -V16 -P Passw0rd -S localhost -U SA -Q \"SET NOCOUNT ON; SELECT * FROM enmeshed.{}\" -s',' >> /tmp/dump.sql" \ No newline at end of file diff --git a/docker-compose/dumps/dump_sqlserver_bak.bat b/docker-compose/dumps/dump_sqlserver_bak.bat deleted file mode 100644 index 37182de0e9..0000000000 --- a/docker-compose/dumps/dump_sqlserver_bak.bat +++ /dev/null @@ -1,2 +0,0 @@ -docker exec -it bkb-mssql_server /opt/mssql-tools/bin/sqlcmd -b -V16 -P Passw0rd -S localhost -U SA -Q "BACKUP DATABASE enmeshed TO DISK = N'/tmp/enmeshed.bak' with NOREWIND" -docker cp bkb-mssql_server:/tmp/enmeshed.bak ./dumps/enmeshed.bak \ No newline at end of file diff --git a/docker-compose/dumps/dump_sqlserver_csv.bat b/docker-compose/dumps/dump_sqlserver_csv.bat deleted file mode 100644 index e3f2ce81e6..0000000000 --- a/docker-compose/dumps/dump_sqlserver_csv.bat +++ /dev/null @@ -1,3 +0,0 @@ -docker cp dump_sqlserver.sh bkb-mssql_server:/tmp/dump_sqlserver.sh -docker exec -it bkb-mssql_server /tmp/dump_sqlserver.sh -docker cp bkb-mssql_server:/tmp/dump.sql ./dumps/enmeshed.csv \ No newline at end of file diff --git a/docker-compose/dumps/load_postgres.bat b/docker-compose/dumps/load_postgres.bat deleted file mode 100644 index 7e9e461a0c..0000000000 --- a/docker-compose/dumps/load_postgres.bat +++ /dev/null @@ -1,6 +0,0 @@ -docker cp ./dumps/enmeshed.pg bkb-postgres:/tmp/enmeshed.sql - -docker exec --env PGPASSWORD=admin -it bkb-postgres psql -h postgres -U postgres postgres -c "DELETE DATABASE enmeshed;" -docker exec --env PGPASSWORD=admin -it bkb-postgres psql -h postgres -U postgres postgres -c "CREATE DATABASE enmeshed WITH TEMPLATE = template0 ENCODING = 'UTF8' LOCALE_PROVIDER = libc LOCALE = 'en_US.utf8'" -docker exec --env PGPASSWORD=admin -it bkb-postgres psql -h postgres -U postgres postgres -c "ALTER DATABASE enmeshed OWNER TO postgres;" -docker exec --env PGPASSWORD=admin -it bkb-postgres psql -h postgres -U postgres enmeshed -f /tmp/enmeshed.sql \ No newline at end of file diff --git a/docker-compose/dumps/load_sqlserver_bak.bat b/docker-compose/dumps/load_sqlserver_bak.bat deleted file mode 100644 index 2b01645e6a..0000000000 --- a/docker-compose/dumps/load_sqlserver_bak.bat +++ /dev/null @@ -1,2 +0,0 @@ -docker cp ./dumps/enmeshed.bak bkb-mssql_server:/tmp/enmeshed.bak -docker exec -it bkb-mssql_server /opt/mssql-tools/bin/sqlcmd -b -V16 -P Passw0rd -S localhost -U SA -Q "RESTORE DATABASE enmeshed FROM DISK = N'/tmp/enmeshed.bak'" \ No newline at end of file diff --git a/scripts/windows/dumps/dump-postgres.ps1 b/scripts/windows/dumps/dump-postgres.ps1 new file mode 100644 index 0000000000..66bede7ceb --- /dev/null +++ b/scripts/windows/dumps/dump-postgres.ps1 @@ -0,0 +1,21 @@ +# Parameters with default values (can be overridden by arguments) +param ( + [string]$Hostname = "host.docker.internal", + [string]$Username = "postgres", + [string]$Password = "admin", + [string]$DbName = "enmeshed" +) + +$DumpFile = "enmeshed.pg" + +docker run --rm -v "$PSScriptRoot\dump-files:/dump" --env PGPASSWORD="admin" postgres pg_dump -h $Hostname -U $Username $DbName -f /dump/$DumpFile + +if ($LASTEXITCODE -ne 0) { + throw "Error: Database export to $DumpFile failed." +} + +if (-not (Test-Path $PSScriptRoot\dump-files\$DumpFile)) { + throw "Snapshot file not found in the 'snapshots' folder." +} + +Write-Host "Database export to $DumpFile successful." diff --git a/scripts/windows/dumps/dump-sqlserver.ps1 b/scripts/windows/dumps/dump-sqlserver.ps1 new file mode 100644 index 0000000000..12cfc61a61 --- /dev/null +++ b/scripts/windows/dumps/dump-sqlserver.ps1 @@ -0,0 +1,21 @@ +# Parameters with default values (can be overridden by arguments) +param ( + [string]$Hostname = "host.docker.internal", + [string]$Username = "SA", + [string]$Password = "Passw0rd" + [string]$DbName = "enmeshed", +) + +$DumpFile = "enmeshed.bacpac" + +docker run --rm -v "$PSScriptRoot\dump-files:/dump" ormico/sqlpackage sqlpackage /Action:Export /SourceServerName:$Hostname /SourceDatabaseName:$DbName /TargetFile:/tmp/$DumpFile /SourceUser:$Username /SourcePassword:$Password /SourceTrustServerCertificate:True + +if ($LASTEXITCODE -ne 0) { + throw "Error: Database export to $DumpFile failed." +} + +if (-not (Test-Path $PSScriptRoot\dump-files\$DumpFile)) { + throw "Snapshot file not found in the 'snapshots' folder." +} + +Write-Host "Database export to $DumpFile successful." diff --git a/scripts/windows/dumps/load-postgres.ps1 b/scripts/windows/dumps/load-postgres.ps1 new file mode 100644 index 0000000000..7cc1e7bb90 --- /dev/null +++ b/scripts/windows/dumps/load-postgres.ps1 @@ -0,0 +1,23 @@ +# Parameters with default values (can be overridden by arguments) +param ( + [string]$Hostname = "host.docker.internal", + [string]$Username = "postgres", + [string]$Password = "admin", + [string]$DbName = "enmeshed", + [string]$DumpFile = "enmeshed.pg" +) + +$ContainerName = "tmp-postgres-container" + +docker run -d --rm --name $ContainerName -v "$PSScriptRoot\dump-files:/dump" -e POSTGRES_PASSWORD="admin" postgres + +docker exec --env PGPASSWORD=$Password -it $containerName psql -h $Hostname -U $Username postgres -c "DROP DATABASE IF EXISTS $DbName" +docker exec --env PGPASSWORD=$Password -it $containerName psql -h $Hostname -U $Username postgres -c "CREATE DATABASE $DbName" +docker exec --env PGPASSWORD=$Password -it $containerName psql -h $Hostname -U $Username postgres -c "ALTER DATABASE $DbName OWNER TO $Username;" +docker exec --env PGPASSWORD=$Password -it $containerName psql -h $Hostname -U $Username $DbName -f /dump/$DumpFile + +if ($LASTEXITCODE -eq 0) { + Write-Host "Database import successful." +} + +docker stop $ContainerName diff --git a/scripts/windows/dumps/load-sqlserver.ps1 b/scripts/windows/dumps/load-sqlserver.ps1 new file mode 100644 index 0000000000..f6b823326f --- /dev/null +++ b/scripts/windows/dumps/load-sqlserver.ps1 @@ -0,0 +1,21 @@ +# Parameters with default values (can be overridden by arguments) +param ( + [string]$Hostname = "host.docker.internal", + [string]$Username = "sa", + [string]$Password = "Passw0rd" + [string]$DbName = "enmeshed", + [string]$DumpFile = "enmeshed.bacpac", +) + +$ContainerName = "tmp-mssql-server" + +docker run -d --rm --name $ContainerName -v "$PSScriptRoot\dump-files:/dump" ormico/sqlpackage sleep infinity + +docker exec -it $ContainerName /opt/mssql-tools/bin/sqlcmd -S $Hostname -U $Username -P $Password -Q "DROP DATABASE IF EXISTS $DbName" +docker exec -ti $ContainerName sqlpackage /Action:Import /TargetServerName:$Hostname /TargetDatabaseName:$DbName /SourceFile:$ContainerDumpDir/$DumpFile /TargetUser:$Username /TargetPassword:$Password /TargetTrustServerCertificate:True + +if ($LASTEXITCODE -eq 0) { + Write-Host "Database import successful." +} + +docker stop $ContainerName